Some checks are pending
Rhai Tests / Run Rhai Tests (push) Waiting to run
- Add a new `sal-os` package containing OS interaction utilities. - Update workspace members to include the new package. - Add README and basic usage examples for the new package.
310 lines
9.0 KiB
Rust
310 lines
9.0 KiB
Rust
//! Unit tests for text replacement functionality
|
|
//!
|
|
//! These tests validate the TextReplacer including:
|
|
//! - Literal string replacement
|
|
//! - Regex pattern replacement
|
|
//! - Multiple chained replacements
|
|
//! - File operations (read, write, in-place)
|
|
//! - Error handling and edge cases
|
|
|
|
use sal_text::TextReplacer;
|
|
use std::fs;
|
|
use tempfile::NamedTempFile;
|
|
|
|
#[test]
|
|
fn test_text_replacer_literal_single() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern("hello")
|
|
.replacement("hi")
|
|
.regex(false)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
let result = replacer.replace("hello world, hello universe");
|
|
assert_eq!(result, "hi world, hi universe");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_regex_single() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern(r"\d+")
|
|
.replacement("NUMBER")
|
|
.regex(true)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
let result = replacer.replace("There are 123 items and 456 more");
|
|
assert_eq!(result, "There are NUMBER items and NUMBER more");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_multiple_operations() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern(r"\d+")
|
|
.replacement("NUMBER")
|
|
.regex(true)
|
|
.and()
|
|
.pattern("world")
|
|
.replacement("universe")
|
|
.regex(false)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
let result = replacer.replace("Hello world, there are 123 items");
|
|
assert_eq!(result, "Hello universe, there are NUMBER items");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_chained_operations() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern("cat")
|
|
.replacement("dog")
|
|
.regex(false)
|
|
.and()
|
|
.pattern("dog")
|
|
.replacement("animal")
|
|
.regex(false)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
// Operations are applied in sequence, so "cat" -> "dog" -> "animal"
|
|
let result = replacer.replace("The cat sat on the mat");
|
|
assert_eq!(result, "The animal sat on the mat");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_regex_capture_groups() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern(r"(\d{4})-(\d{2})-(\d{2})")
|
|
.replacement("$3/$2/$1")
|
|
.regex(true)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
let result = replacer.replace("Date: 2023-12-01");
|
|
assert_eq!(result, "Date: 01/12/2023");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_case_sensitive() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern("Hello")
|
|
.replacement("Hi")
|
|
.regex(false)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
let result = replacer.replace("Hello world, hello universe");
|
|
assert_eq!(result, "Hi world, hello universe");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_regex_case_insensitive() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern(r"(?i)hello")
|
|
.replacement("Hi")
|
|
.regex(true)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
let result = replacer.replace("Hello world, HELLO universe");
|
|
assert_eq!(result, "Hi world, Hi universe");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_empty_input() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern("test")
|
|
.replacement("replacement")
|
|
.regex(false)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
let result = replacer.replace("");
|
|
assert_eq!(result, "");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_no_matches() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern("xyz")
|
|
.replacement("abc")
|
|
.regex(false)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
let input = "Hello world";
|
|
let result = replacer.replace(input);
|
|
assert_eq!(result, input);
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_file_operations() {
|
|
// Create a temporary file with test content
|
|
let temp_file = NamedTempFile::new().expect("Failed to create temp file");
|
|
let test_content = "Hello world, there are 123 items";
|
|
fs::write(temp_file.path(), test_content).expect("Failed to write to temp file");
|
|
|
|
let replacer = TextReplacer::builder()
|
|
.pattern(r"\d+")
|
|
.replacement("NUMBER")
|
|
.regex(true)
|
|
.and()
|
|
.pattern("world")
|
|
.replacement("universe")
|
|
.regex(false)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
// Test replace_file
|
|
let result = replacer
|
|
.replace_file(temp_file.path())
|
|
.expect("Failed to replace file content");
|
|
assert_eq!(result, "Hello universe, there are NUMBER items");
|
|
|
|
// Verify original file is unchanged
|
|
let original_content =
|
|
fs::read_to_string(temp_file.path()).expect("Failed to read original file");
|
|
assert_eq!(original_content, test_content);
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_file_in_place() {
|
|
// Create a temporary file with test content
|
|
let temp_file = NamedTempFile::new().expect("Failed to create temp file");
|
|
let test_content = "Hello world, there are 123 items";
|
|
fs::write(temp_file.path(), test_content).expect("Failed to write to temp file");
|
|
|
|
let replacer = TextReplacer::builder()
|
|
.pattern("world")
|
|
.replacement("universe")
|
|
.regex(false)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
// Test replace_file_in_place
|
|
replacer
|
|
.replace_file_in_place(temp_file.path())
|
|
.expect("Failed to replace file in place");
|
|
|
|
// Verify file content was changed
|
|
let new_content = fs::read_to_string(temp_file.path()).expect("Failed to read modified file");
|
|
assert_eq!(new_content, "Hello universe, there are 123 items");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_file_to_file() {
|
|
// Create source file
|
|
let source_file = NamedTempFile::new().expect("Failed to create source file");
|
|
let test_content = "Hello world, there are 123 items";
|
|
fs::write(source_file.path(), test_content).expect("Failed to write to source file");
|
|
|
|
// Create destination file
|
|
let dest_file = NamedTempFile::new().expect("Failed to create dest file");
|
|
|
|
let replacer = TextReplacer::builder()
|
|
.pattern(r"\d+")
|
|
.replacement("NUMBER")
|
|
.regex(true)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
// Test replace_file_to
|
|
replacer
|
|
.replace_file_to(source_file.path(), dest_file.path())
|
|
.expect("Failed to replace file to destination");
|
|
|
|
// Verify source file is unchanged
|
|
let source_content =
|
|
fs::read_to_string(source_file.path()).expect("Failed to read source file");
|
|
assert_eq!(source_content, test_content);
|
|
|
|
// Verify destination file has replaced content
|
|
let dest_content = fs::read_to_string(dest_file.path()).expect("Failed to read dest file");
|
|
assert_eq!(dest_content, "Hello world, there are NUMBER items");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_invalid_regex() {
|
|
let result = TextReplacer::builder()
|
|
.pattern("[invalid regex")
|
|
.replacement("test")
|
|
.regex(true)
|
|
.build();
|
|
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_builder_default_regex_false() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern(r"\d+")
|
|
.replacement("NUMBER")
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
// Should treat as literal since regex defaults to false
|
|
let result = replacer.replace(r"Match \d+ pattern");
|
|
assert_eq!(result, "Match NUMBER pattern");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_complex_regex() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern(r"(\w+)@(\w+\.\w+)")
|
|
.replacement("EMAIL_ADDRESS")
|
|
.regex(true)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
let result = replacer.replace("Contact john@example.com or jane@test.org");
|
|
assert_eq!(result, "Contact EMAIL_ADDRESS or EMAIL_ADDRESS");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_multiline_text() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern(r"^\s*//.*$")
|
|
.replacement("")
|
|
.regex(true)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
let input =
|
|
"function test() {\n // This is a comment\n return true;\n // Another comment\n}";
|
|
let result = replacer.replace(input);
|
|
|
|
// Note: This test depends on how the regex engine handles multiline mode
|
|
// The actual behavior might need adjustment based on regex flags
|
|
assert!(result.contains("function test()"));
|
|
assert!(result.contains("return true;"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_unicode_text() {
|
|
let replacer = TextReplacer::builder()
|
|
.pattern("café")
|
|
.replacement("coffee")
|
|
.regex(false)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
let result = replacer.replace("I love café in the morning");
|
|
assert_eq!(result, "I love coffee in the morning");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_replacer_large_text() {
|
|
let large_text = "word ".repeat(10000);
|
|
|
|
let replacer = TextReplacer::builder()
|
|
.pattern("word")
|
|
.replacement("term")
|
|
.regex(false)
|
|
.build()
|
|
.expect("Failed to build replacer");
|
|
|
|
let result = replacer.replace(&large_text);
|
|
assert_eq!(result, "term ".repeat(10000));
|
|
}
|