regress 0.11.0

A regular expression engine targeting EcmaScript syntax
Documentation
//! Tests for Pattern trait implementation

#![cfg(feature = "pattern")]
#![feature(pattern)]

use regress::Regex;

#[test]
fn test_pattern_find() {
    let re = Regex::new(r"\d+").unwrap();
    let text = "abc123def456ghi";

    // Test with &Regex
    assert_eq!(text.find(&re), Some(3));

    // Test another pattern
    let re2 = Regex::new(r"def").unwrap();
    assert_eq!(text.find(&re2), Some(6));
}

#[test]
fn test_pattern_contains() {
    let re = Regex::new(r"\d+").unwrap();

    assert!(!"abc".contains(&re));
    assert!("abc123".contains(&re));
    assert!("123abc".contains(&re));
    assert!("abc123def".contains(&re));
}

#[test]
fn test_pattern_starts_with() {
    let re = Regex::new(r"\d+").unwrap();

    assert!(!"abc123".starts_with(&re));
    assert!("123abc".starts_with(&re));
    assert!("456".starts_with(&re));
}

#[test]
fn test_pattern_ends_with() {
    let re = Regex::new(r"\d+").unwrap();

    assert!(!"123abc".ends_with(&re));
    assert!("abc123".ends_with(&re));
    assert!("456".ends_with(&re));
}

#[test]
fn test_pattern_split() {
    let re = Regex::new(r"\s+").unwrap();
    let text = "hello    world\t\nfoo  bar";

    let parts: Vec<&str> = text.split(&re).collect();
    assert_eq!(parts, vec!["hello", "world", "foo", "bar"]);
}

#[test]
fn test_pattern_split_inclusive() {
    let re = Regex::new(r"\s+").unwrap();
    let text = "hello world foo";

    let parts: Vec<&str> = text.split_inclusive(&re).collect();
    assert_eq!(parts, vec!["hello ", "world ", "foo"]);
}

#[test]
fn test_pattern_matches() {
    let re = Regex::new(r"\w+").unwrap();
    let text = "hello world 123 test";

    let matches: Vec<&str> = text.matches(&re).collect();
    assert_eq!(matches, vec!["hello", "world", "123", "test"]);
}

#[test]
fn test_pattern_match_indices() {
    let re = Regex::new(r"\d+").unwrap();
    let text = "abc123def456ghi";

    let indices: Vec<(usize, &str)> = text.match_indices(&re).collect();
    assert_eq!(indices, vec![(3, "123"), (9, "456")]);
}

#[test]
fn test_pattern_replacen() {
    let re = Regex::new(r"\d+").unwrap();
    let text = "abc123def456ghi789";

    let result = text.replacen(&re, "XXX", 2);
    assert_eq!(result, "abcXXXdefXXXghi789");
}

#[test]
fn test_pattern_replace() {
    let re = Regex::new(r"\d+").unwrap();
    let text = "abc123def456ghi789";

    let result = text.replace(&re, "XXX");
    assert_eq!(result, "abcXXXdefXXXghiXXX");
}

#[test]
fn test_pattern_strip_prefix() {
    let re = Regex::new(r"\d+").unwrap();

    assert_eq!("123abc".strip_prefix(&re), Some("abc"));
    assert_eq!("abc123".strip_prefix(&re), None);
    assert_eq!("456def789".strip_prefix(&re), Some("def789"));
}

#[test]
fn test_pattern_strip_suffix() {
    let re = Regex::new(r"\d+").unwrap();

    assert_eq!("abc123".strip_suffix(&re), Some("abc"));
    assert_eq!("123abc".strip_suffix(&re), None);
    assert_eq!("789def456".strip_suffix(&re), Some("789def"));
}

#[test]
fn test_pattern_with_anchors() {
    let re = Regex::new(r"^\d+").unwrap();
    let text = "123abc456";

    assert_eq!(text.find(&re), Some(0));
    assert!(text.starts_with(&re));
    assert!(!text.ends_with(&re));
}

#[test]
fn test_pattern_zero_width_match() {
    let re = Regex::new(r"\b").unwrap(); // word boundary
    let text = "hello world";

    // Test that we can find word boundaries
    assert_eq!(text.find(&re), Some(0));

    // Test simple contains instead of matches to avoid infinite loop
    assert!(text.contains(&re));
}

#[test]
fn test_pattern_overlapping_pattern() {
    let re = Regex::new(r"aa").unwrap();
    let text = "aaaa";

    // Should find non-overlapping matches
    let matches: Vec<&str> = text.matches(&re).collect();
    assert_eq!(matches, vec!["aa", "aa"]);
}

#[test]
fn test_pattern_empty_regex() {
    let re = Regex::new(r"").unwrap();
    let text = "abc";

    // Empty regex should match at the beginning
    assert_eq!(text.find(&re), Some(0));
    assert!(text.contains(&re));

    // Test starts_with instead of matches to avoid infinite loop
    assert!(text.starts_with(&re));
}

#[test]
fn test_pattern_case_insensitive() {
    let re = Regex::with_flags(r"hello", "i").unwrap();
    let text = "HELLO world Hello";

    assert!(text.contains(&re));
    let matches: Vec<&str> = text.matches(&re).collect();
    assert_eq!(matches, vec!["HELLO", "Hello"]);
}

#[test]
fn test_pattern_multiline() {
    let re = Regex::with_flags(r"^test", "m").unwrap();
    let text = "hello\ntest world\ntest again";

    let matches: Vec<&str> = text.matches(&re).collect();
    assert_eq!(matches, vec!["test", "test"]);
}

#[test]
fn test_pattern_no_match() {
    let re = Regex::new(r"\d+").unwrap();
    let text = "hello world";

    assert_eq!(text.find(&re), None);
    assert!(!text.contains(&re));
    assert!(!text.starts_with(&re));
    assert!(!text.ends_with(&re));

    let matches: Vec<&str> = text.matches(&re).collect();
    assert!(matches.is_empty());
}

#[test]
fn test_pattern_comprehensive_example() {
    // This test demonstrates the various str methods that work with Pattern
    let text = "The year 2023 was followed by 2024, and then 2025.";
    let year_regex = Regex::new(r"\d{4}").unwrap();

    // Basic pattern operations
    assert!(text.contains(&year_regex));
    assert_eq!(text.find(&year_regex), Some(9)); // Position of "2023"
    assert!(!text.starts_with(&year_regex));
    assert!(!text.ends_with(&year_regex));

    // Find all years
    let years: Vec<&str> = text.matches(&year_regex).collect();
    assert_eq!(years, vec!["2023", "2024", "2025"]);

    // Find year positions
    let positions: Vec<(usize, &str)> = text.match_indices(&year_regex).collect();
    // "The year 2023 was followed by 2024, and then 2025."
    //  0123456789012345678901234567890123456789012345678901
    //           ^                    ^              ^
    //           9                   30             45
    assert_eq!(positions, vec![(9, "2023"), (30, "2024"), (45, "2025")]);

    // Split on years
    let parts: Vec<&str> = text.split(&year_regex).collect();
    assert_eq!(
        parts,
        vec!["The year ", " was followed by ", ", and then ", "."]
    );

    // Replace years
    let masked = text.replace(&year_regex, "YEAR");
    assert_eq!(masked, "The year YEAR was followed by YEAR, and then YEAR.");

    // Replace first two years only
    let partial = text.replacen(&year_regex, "XXXX", 2);
    assert_eq!(
        partial,
        "The year XXXX was followed by XXXX, and then 2025."
    );
}