Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions examples/comprehensive_patterns.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use cheetah_string::CheetahString;

fn main() {
println!("=== Testing starts_with ===");
let s = CheetahString::from("+attribute");
println!("s.starts_with('+'): {}", s.starts_with('+'));
println!("s.starts_with(\"+attr\"): {}", s.starts_with("+attr"));

println!("\n=== Testing ends_with ===");
let s2 = CheetahString::from("hello-world");
println!("s2.ends_with('d'): {}", s2.ends_with('d'));
println!("s2.ends_with(\"-world\"): {}", s2.ends_with("-world"));

println!("\n=== Testing contains ===");
let path = CheetahString::from("C:\\Users\\test");
println!("path.contains('\\\\'): {}", path.contains('\\'));
println!("path.contains(\"Users\"): {}", path.contains("Users"));

println!("\n=== Testing split with char ===");
let csv = CheetahString::from("a_b_c");
let parts: Vec<&str> = csv.split('_').collect();
println!("csv.split('_'): {:?}", parts);

println!("\n=== Testing split with str ===");
let data = CheetahString::from("item1::item2::item3");
let items: Vec<&str> = data.split("::").collect();
println!("data.split(\"::\"): {:?}", items);

println!("\n=== Testing chars with reverse ===");
let crc = CheetahString::from("12345");
let reversed: Vec<char> = crc.chars().rev().collect();
println!("crc.chars().rev(): {:?}", reversed);

println!("\n=== Combined example (similar to error case) ===");
let content = CheetahString::from("file_name_123");
let vec: Vec<&str> = content.split('_').collect();
println!("content.split('_'): {:?}", vec);

let key = CheetahString::from("+property");
if key.starts_with('+') {
println!("Key '{}' starts with '+'", key);
}

let key2 = CheetahString::from("-attribute");
if key2.starts_with('-') {
println!("Key '{}' starts with '-'", key2);
}
}
27 changes: 27 additions & 0 deletions examples/pattern_matching.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use cheetah_string::CheetahString;

fn main() {
let s = CheetahString::from("+hello-world");

// Test starts_with with char
println!("starts_with('+'): {}", s.starts_with('+'));
println!("starts_with('-'): {}", s.starts_with('-'));

// Test starts_with with &str
println!("starts_with(\"+hello\"): {}", s.starts_with("+hello"));
println!("starts_with(\"hello\"): {}", s.starts_with("hello"));

// Test ends_with with char
println!("ends_with('d'): {}", s.ends_with('d'));
println!("ends_with('+'): {}", s.ends_with('+'));

// Test ends_with with &str
println!("ends_with(\"-world\"): {}", s.ends_with("-world"));
println!("ends_with(\"world\"): {}", s.ends_with("world"));

// Example similar to the error case
let key = CheetahString::from("+attribute");
if key.starts_with('+') {
println!("\nKey '{}' starts with '+'", key);
}
}
37 changes: 37 additions & 0 deletions examples/test_empty_pattern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use cheetah_string::CheetahString;

fn main() {
println!("=== Testing empty pattern behavior ===\n");

// Standard library empty pattern behavior
let std_result: Vec<&str> = "hello".split("").collect();
println!("std \"hello\".split(\"\"):");
println!(" Result: {:?}", std_result);
println!(" Length: {}", std_result.len());

// CheetahString empty pattern behavior
let cheetah = CheetahString::from("hello");
let cheetah_result: Vec<&str> = cheetah.split("").collect();
println!("\nCheetahString \"hello\".split(\"\"):");
println!(" Result: {:?}", cheetah_result);
println!(" Length: {}", cheetah_result.len());

if std_result == cheetah_result {
println!("\n[OK] Behavior matches");
} else {
println!("\n[FAIL] Behavior mismatch!");
println!("Note: Standard library splits empty pattern between each character");
println!("Current implementation returns the whole string for simplicity");
}
Comment on lines +19 to +25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Address the empty pattern behavior mismatch with standard library.

This example documents a significant behavioral inconsistency: the standard library's split("") splits between each character, but CheetahString returns the whole string "for simplicity". This breaks compatibility with Rust's standard library semantics and will confuse users who expect standard behavior.

The example itself prints "[FAIL] Behavior mismatch!" which indicates this is a known issue. Users migrating from String to CheetahString will encounter unexpected behavior.

Consider either:

  1. Implementing standard library-compatible empty pattern behavior
  2. Documenting this limitation prominently in the API documentation if there's a technical reason for the difference
  3. Panicking on empty patterns (like some other string operations do) to prevent silent behavioral differences

Based on the related code in tests/split_edge_cases.rs which has a test called test_empty_pattern that only prints without assertions, it appears this behavioral difference may still be under development.

🤖 Prompt for AI Agents
In @examples/test_empty_pattern.rs around lines 19-25, The example shows a
behavioral mismatch: CheetahString's split("") returns the whole string while
Rust's standard String.split("") yields splits between every character; update
the implementation or example to resolve this. Either (A) change
CheetahString::split (and any related split internals) to mirror
std::string::String::split on an empty pattern so split("") produces
empty-string-separated characters, (B) if intentional, add a clear API doc
comment on CheetahString::split and surface this limitation in examples and
tests (update examples/test_empty_pattern.rs and tests/split_edge_cases.rs to
document the difference), or (C) make CheetahString::split panic on empty
pattern to avoid silent divergence; pick one approach and apply it consistently
across the split implementation, its public docs, the example
(examples/test_empty_pattern.rs) and the test test_empty_pattern in
tests/split_edge_cases.rs.


// Test empty string with empty pattern
println!("\n=== Empty string + empty pattern ===");
let std_empty: Vec<&str> = "".split("").collect();
println!("std \"\".split(\"\"):");
println!(" Result: {:?}", std_empty);

let cheetah_empty = CheetahString::from("");
let cheetah_empty_result: Vec<&str> = cheetah_empty.split("").collect();
println!("\nCheetahString \"\".split(\"\"):");
println!(" Result: {:?}", cheetah_empty_result);
}
72 changes: 72 additions & 0 deletions examples/test_split_behavior.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use cheetah_string::CheetahString;

fn main() {
println!("=== Comparing CheetahString and std::str split behavior ===\n");

let test_cases = vec![
("a,b,c", ','),
("", ','),
(",a,b", ','),
("a,b,", ','),
("a,,b", ','),
(",", ','),
(",,", ','),
("no_separator", ','),
];

for (input, sep) in test_cases {
let std_result: Vec<&str> = input.split(sep).collect();

let cheetah = CheetahString::from(input);
let cheetah_result: Vec<&str> = cheetah.split(sep).collect();

let match_str = if std_result == cheetah_result {
"[OK]"
} else {
"[FAIL]"
};

println!("{} Input: {:?}, Sep: {:?}", match_str, input, sep);
println!(" std: {:?}", std_result);
println!(" cheetah: {:?}", cheetah_result);

if std_result != cheetah_result {
println!(" WARNING: MISMATCH!");
}
println!();
}

println!("\n=== Testing string patterns ===\n");

let str_test_cases = vec![
("a::b::c", "::"),
("", "::"),
("::a::b", "::"),
("a::b::", "::"),
("::", "::"),
("a::::b", "::"),
("no separator", "::"),
];

for (input, sep) in str_test_cases {
let std_result: Vec<&str> = input.split(sep).collect();

let cheetah = CheetahString::from(input);
let cheetah_result: Vec<&str> = cheetah.split(sep).collect();

let match_str = if std_result == cheetah_result {
"[OK]"
} else {
"[FAIL]"
};

println!("{} Input: {:?}, Sep: {:?}", match_str, input, sep);
println!(" std: {:?}", std_result);
println!(" cheetah: {:?}", cheetah_result);

if std_result != cheetah_result {
println!(" WARNING: MISMATCH!");
}
println!();
}
}
Loading
Loading