extern crate rsproperties;
use rsproperties::{PROP_DIRNAME, PROP_VALUE_MAX};
mod common;
use common::init_test;
fn init_properties() {
init_test();
}
#[test]
fn test_constants_validation() {
assert_eq!(
PROP_VALUE_MAX, 92,
"PROP_VALUE_MAX must match Android specification"
);
assert_eq!(
PROP_DIRNAME, "/dev/__properties__",
"PROP_DIRNAME must match Android default"
);
println!("✓ Constants validation passed");
println!(" PROP_VALUE_MAX = {PROP_VALUE_MAX}");
println!(" PROP_DIRNAME = '{PROP_DIRNAME}'");
}
#[test]
fn test_get_with_default_basic() {
init_properties();
let result = rsproperties::get_or("test.nonexistent.basic", "default_value".to_string());
assert_eq!(result, "default_value");
println!("✓ Basic get_with_default test passed");
}
#[test]
fn test_get_with_default_edge_cases() {
init_properties();
let test_cases = [
("test.empty.default", "", "empty default value"),
("test.spaces", "value with spaces", "default with spaces"),
("test.special", "!@#$%^&*()", "special characters"),
("test.unicode", "üñíçødé", "unicode characters"),
(
"test.long.name.with.many.segments",
"default",
"long property name",
),
];
for (prop, default, description) in &test_cases {
let result = rsproperties::get_or(prop, default.to_string());
assert_eq!(result, *default, "Failed for {description}");
}
println!(
"✓ get_with_default edge cases passed ({} test cases)",
test_cases.len()
);
}
#[test]
fn test_get_nonexistent_returns_error() {
init_properties();
let nonexistent_props = [
"definitely.not.there",
"fake.property.12345",
"test.nonexistent.long.name.that.should.not.exist.anywhere",
];
for prop in &nonexistent_props {
let result: Result<String, _> = rsproperties::get(prop);
assert!(
result.is_err(),
"Property '{prop}' should not exist and should return error"
);
}
println!("✓ get nonexistent properties test passed");
}
#[test]
fn test_dirname_function() {
init_properties();
let dirname = rsproperties::properties_dir();
let dirname_str = dirname.to_string_lossy();
assert!(!dirname_str.is_empty(), "dirname should not be empty");
println!("✓ dirname function test passed");
println!(" dirname = '{dirname_str}'");
}
#[test]
fn test_value_length_limits() {
let max_value = "x".repeat(PROP_VALUE_MAX);
assert_eq!(max_value.len(), PROP_VALUE_MAX);
let too_long_value = "x".repeat(PROP_VALUE_MAX + 1);
assert_eq!(too_long_value.len(), PROP_VALUE_MAX + 1);
init_properties();
let result1 = rsproperties::get_or("test.max.length", max_value.clone());
assert_eq!(result1, max_value);
let result2 = rsproperties::get_or("test.too.long", too_long_value.clone());
assert_eq!(result2, too_long_value);
println!("✓ Value length limits test passed");
}
#[test]
fn test_thread_safety_basic() {
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
init_properties();
let counter = Arc::new(AtomicUsize::new(0));
let mut handles = vec![];
for i in 0..5 {
let counter_clone = Arc::clone(&counter);
let handle = thread::spawn(move || {
for j in 0..10 {
let prop_name = format!("test.thread.{i}.{j}");
let _result = rsproperties::get_or(&prop_name, "default".to_string());
counter_clone.fetch_add(1, Ordering::SeqCst);
let _result: Result<String, _> = rsproperties::get(&prop_name);
counter_clone.fetch_add(1, Ordering::SeqCst);
let _dirname = rsproperties::properties_dir();
counter_clone.fetch_add(1, Ordering::SeqCst);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().expect("Thread should complete");
}
let final_count = counter.load(Ordering::SeqCst);
assert_eq!(final_count, 5 * 10 * 3, "All operations should complete");
println!("✓ Thread safety test passed ({final_count} operations)");
}
#[test]
fn test_performance_baseline() {
use std::time::Instant;
init_properties();
let start = Instant::now();
let iterations = 1000;
for i in 0..iterations {
let prop = format!("perf.test.{i}");
let _result = rsproperties::get_or(&prop, "default".to_string());
}
let elapsed = start.elapsed();
let ops_per_sec = iterations as f64 / elapsed.as_secs_f64();
println!("✓ Performance baseline test completed");
println!(" {iterations} iterations in {elapsed:?} ({ops_per_sec:.0} ops/sec)");
assert!(
ops_per_sec > 500.0,
"Performance should be reasonable, got {ops_per_sec:.0} ops/sec"
);
}
#[test]
fn test_error_conditions() {
init_properties();
let edge_cases = [
"", ".", "..", "...", ".test", "test.", ];
for case in &edge_cases {
let _result1: Result<String, _> = rsproperties::get(case);
let _result2 = rsproperties::get_or(case, "default".to_string());
}
println!("✓ Error conditions test completed");
}
#[cfg(feature = "builder")]
mod builder_tests {
use super::*;
#[test]
fn test_set_various_values() {
init_properties();
let values = [
("test.set.empty", ""),
("test.set.simple", "value"),
("test.set.numbers", "12345"),
("test.set.special", "!@#$%"),
("test.set.spaces", "with spaces"),
];
for (prop, value) in &values {
match rsproperties::set(prop, value) {
Ok(_) => println!("✓ Set '{prop}' = '{value}'"),
Err(e) => println!("⚠ Failed to set '{prop}': {e}"),
}
}
}
#[test]
fn test_set_length_limits() {
init_properties();
let max_value = "x".repeat(PROP_VALUE_MAX);
let result1 = rsproperties::set("test.set.max", &max_value);
let too_long = "x".repeat(PROP_VALUE_MAX + 1);
let result2 = rsproperties::set("test.set.long", &too_long);
match result1 {
Ok(_) => println!("✓ Max length property set successfully"),
Err(e) => println!("⚠ Max length set failed: {e}"),
}
match result2 {
Ok(_) => println!("⚠ Too long property unexpectedly succeeded"),
Err(_) => println!("✓ Too long property correctly rejected"),
}
}
#[test]
fn test_property_update() {
init_properties();
let prop = "test.update.prop";
match rsproperties::set(prop, "initial") {
Ok(_) => {
match rsproperties::set(prop, "updated") {
Ok(_) => {
let value: Result<String, _> = rsproperties::get(prop);
assert_eq!(value.unwrap(), "updated");
println!("✓ Property update verified");
}
Err(e) => println!("⚠ Update failed: {e}"),
}
}
Err(e) => println!("⚠ Initial set failed: {e}"),
}
}
}
#[test]
fn test_comprehensive_integration() {
init_properties();
assert_eq!(PROP_VALUE_MAX, 92);
assert_eq!(PROP_DIRNAME, "/dev/__properties__");
let dirname = rsproperties::properties_dir();
assert!(!dirname.to_string_lossy().is_empty());
let props = ["int.test.1", "int.test.2", "int.test.3"];
for (i, prop) in props.iter().enumerate() {
let default = format!("default_{i}");
let result = rsproperties::get_or(prop, default.clone());
assert_eq!(result, default);
}
for prop in &props {
let result: Result<String, _> = rsproperties::get(prop);
assert!(result.is_err());
}
println!("✓ Comprehensive integration test passed");
println!(" All API components working correctly together");
}