1use std::cmp::Ordering;
7
8use crate::parser::ast::Value;
9
10use super::compare_values;
11
12const FLOAT_EPSILON: f64 = f64::EPSILON;
17
18fn floats_equal(a: f64, b: f64) -> bool {
26 if a.is_nan() || b.is_nan() {
27 return false;
28 }
29 if a.is_infinite() || b.is_infinite() {
32 #[allow(clippy::float_cmp)]
33 return a == b;
34 }
35 (a - b).abs() <= FLOAT_EPSILON
36}
37
38#[must_use]
81pub fn apply_equal(left: &Value, right: &Value) -> bool {
82 if let (Value::Float(a), Value::Float(b)) = (left, right) {
83 return floats_equal(*a, *b);
84 }
85 match (left, right) {
92 (Value::String(s), Value::Bytes(b)) | (Value::Bytes(b), Value::String(s)) => {
93 return s.as_bytes() == b.as_slice();
94 }
95 _ => {}
96 }
97 compare_values(left, right) == Some(Ordering::Equal)
98}
99
100#[must_use]
137pub fn apply_not_equal(left: &Value, right: &Value) -> bool {
138 !apply_equal(left, right)
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn test_apply_equal_uint_same_value() {
147 let left = Value::Uint(42);
148 let right = Value::Uint(42);
149 assert!(apply_equal(&left, &right));
150 }
151
152 #[test]
153 fn test_apply_equal_uint_different_value() {
154 let left = Value::Uint(42);
155 let right = Value::Uint(24);
156 assert!(!apply_equal(&left, &right));
157 }
158
159 #[test]
160 fn test_apply_equal_uint_zero() {
161 let left = Value::Uint(0);
162 let right = Value::Uint(0);
163 assert!(apply_equal(&left, &right));
164 }
165
166 #[test]
167 fn test_apply_equal_uint_max_value() {
168 let left = Value::Uint(u64::MAX);
169 let right = Value::Uint(u64::MAX);
170 assert!(apply_equal(&left, &right));
171 }
172
173 #[test]
174 fn test_apply_equal_int_same_value() {
175 let left = Value::Int(42);
176 let right = Value::Int(42);
177 assert!(apply_equal(&left, &right));
178 }
179
180 #[test]
181 fn test_apply_equal_int_different_value() {
182 let left = Value::Int(42);
183 let right = Value::Int(-42);
184 assert!(!apply_equal(&left, &right));
185 }
186
187 #[test]
188 fn test_apply_equal_int_negative() {
189 let left = Value::Int(-100);
190 let right = Value::Int(-100);
191 assert!(apply_equal(&left, &right));
192 }
193
194 #[test]
195 fn test_apply_equal_int_zero() {
196 let left = Value::Int(0);
197 let right = Value::Int(0);
198 assert!(apply_equal(&left, &right));
199 }
200
201 #[test]
202 fn test_apply_equal_int_extreme_values() {
203 let left = Value::Int(i64::MAX);
204 let right = Value::Int(i64::MAX);
205 assert!(apply_equal(&left, &right));
206
207 let left = Value::Int(i64::MIN);
208 let right = Value::Int(i64::MIN);
209 assert!(apply_equal(&left, &right));
210 }
211
212 #[test]
213 fn test_apply_equal_bytes_same_value() {
214 let left = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
215 let right = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
216 assert!(apply_equal(&left, &right));
217 }
218
219 #[test]
220 fn test_apply_equal_bytes_different_value() {
221 let left = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
222 let right = Value::Bytes(vec![0x50, 0x4b, 0x03, 0x04]);
223 assert!(!apply_equal(&left, &right));
224 }
225
226 #[test]
227 fn test_apply_equal_bytes_empty() {
228 let left = Value::Bytes(vec![]);
229 let right = Value::Bytes(vec![]);
230 assert!(apply_equal(&left, &right));
231 }
232
233 #[test]
234 fn test_apply_equal_bytes_different_length() {
235 let left = Value::Bytes(vec![0x7f, 0x45]);
236 let right = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
237 assert!(!apply_equal(&left, &right));
238 }
239
240 #[test]
241 fn test_apply_equal_bytes_single_byte() {
242 let left = Value::Bytes(vec![0x7f]);
243 let right = Value::Bytes(vec![0x7f]);
244 assert!(apply_equal(&left, &right));
245
246 let left = Value::Bytes(vec![0x7f]);
247 let right = Value::Bytes(vec![0x45]);
248 assert!(!apply_equal(&left, &right));
249 }
250
251 #[test]
252 fn test_apply_equal_string_same_value() {
253 let left = Value::String("hello".to_string());
254 let right = Value::String("hello".to_string());
255 assert!(apply_equal(&left, &right));
256 }
257
258 #[test]
259 fn test_apply_equal_string_different_value() {
260 let left = Value::String("hello".to_string());
261 let right = Value::String("world".to_string());
262 assert!(!apply_equal(&left, &right));
263 }
264
265 #[test]
266 fn test_apply_equal_string_empty() {
267 let left = Value::String(String::new());
268 let right = Value::String(String::new());
269 assert!(apply_equal(&left, &right));
270 }
271
272 #[test]
273 fn test_apply_equal_string_case_sensitive() {
274 let left = Value::String("Hello".to_string());
275 let right = Value::String("hello".to_string());
276 assert!(!apply_equal(&left, &right));
277 }
278
279 #[test]
280 fn test_apply_equal_string_unicode() {
281 let left = Value::String("\u{1f980} Rust".to_string());
282 let right = Value::String("\u{1f980} Rust".to_string());
283 assert!(apply_equal(&left, &right));
284
285 let left = Value::String("\u{1f980} Rust".to_string());
286 let right = Value::String("\u{1f40d} Python".to_string());
287 assert!(!apply_equal(&left, &right));
288 }
289
290 #[test]
291 fn test_apply_equal_string_whitespace() {
292 let left = Value::String("hello world".to_string());
293 let right = Value::String("hello world".to_string());
294 assert!(apply_equal(&left, &right));
295
296 let left = Value::String("hello world".to_string());
297 let right = Value::String("hello world".to_string()); assert!(!apply_equal(&left, &right));
299 }
300
301 #[test]
303 fn test_apply_equal_uint_vs_int() {
304 let left = Value::Uint(42);
306 let right = Value::Int(42);
307 assert!(apply_equal(&left, &right));
308
309 let left = Value::Uint(0);
310 let right = Value::Int(0);
311 assert!(apply_equal(&left, &right));
312
313 let left = Value::Uint(42);
315 let right = Value::Int(-42);
316 assert!(!apply_equal(&left, &right));
317
318 let left = Value::Uint(u64::MAX);
320 let right = Value::Int(-1);
321 assert!(!apply_equal(&left, &right));
322 }
323
324 #[test]
325 fn test_apply_equal_uint_vs_bytes() {
326 let left = Value::Uint(42);
327 let right = Value::Bytes(vec![42]);
328 assert!(!apply_equal(&left, &right));
329 }
330
331 #[test]
332 fn test_apply_equal_uint_vs_string() {
333 let left = Value::Uint(42);
334 let right = Value::String("42".to_string());
335 assert!(!apply_equal(&left, &right));
336 }
337
338 #[test]
339 fn test_apply_equal_int_vs_bytes() {
340 let left = Value::Int(-42);
341 let right = Value::Bytes(vec![214]); assert!(!apply_equal(&left, &right));
343 }
344
345 #[test]
346 fn test_apply_equal_int_vs_string() {
347 let left = Value::Int(-42);
348 let right = Value::String("-42".to_string());
349 assert!(!apply_equal(&left, &right));
350 }
351
352 #[test]
353 fn test_apply_equal_bytes_vs_string() {
354 let left = Value::Bytes(vec![104, 101, 108, 108, 111]); let right = Value::String("hello".to_string());
362 assert!(apply_equal(&left, &right));
363 let other = Value::String("world".to_string());
365 assert!(!apply_equal(&left, &other));
366 }
367
368 #[test]
369 fn test_apply_equal_all_cross_type_combinations() {
370 let values = [
371 Value::Uint(42),
372 Value::Int(42),
373 Value::Bytes(vec![42]),
374 Value::String("42".to_string()),
375 ];
376
377 for (i, left) in values.iter().enumerate() {
379 for (j, right) in values.iter().enumerate() {
380 if i != j {
381 let result = apply_equal(left, right);
382 if (i <= 1) && (j <= 1) {
384 assert!(
385 result,
386 "Integer cross-type comparison should be true: {left:?} vs {right:?}"
387 );
388 } else {
389 assert!(
390 !result,
391 "Non-integer cross-type comparison should be false: {left:?} vs {right:?}"
392 );
393 }
394 }
395 }
396 }
397 }
398
399 #[test]
400 fn test_apply_equal_reflexivity() {
401 let values = vec![
402 Value::Uint(42),
403 Value::Int(-42),
404 Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]),
405 Value::String("hello".to_string()),
406 ];
407
408 for value in values {
410 assert!(
411 apply_equal(&value, &value),
412 "Value should be equal to itself: {value:?}"
413 );
414 }
415 }
416
417 #[test]
418 fn test_apply_equal_symmetry() {
419 let test_cases = vec![
420 (Value::Uint(42), Value::Uint(42)),
421 (Value::Int(-100), Value::Int(-100)),
422 (Value::Bytes(vec![1, 2, 3]), Value::Bytes(vec![1, 2, 3])),
423 (
424 Value::String("test".to_string()),
425 Value::String("test".to_string()),
426 ),
427 ];
428
429 for (left, right) in test_cases {
431 let left_to_right = apply_equal(&left, &right);
432 let right_to_left = apply_equal(&right, &left);
433 assert_eq!(
434 left_to_right, right_to_left,
435 "Equality should be symmetric: {left:?} vs {right:?}"
436 );
437 }
438 }
439
440 #[test]
441 fn test_apply_equal_transitivity() {
442 let a = Value::Uint(123);
444 let b = Value::Uint(123);
445 let c = Value::Uint(123);
446
447 assert!(apply_equal(&a, &b));
448 assert!(apply_equal(&b, &c));
449 assert!(apply_equal(&a, &c));
450 }
451
452 #[test]
453 fn test_apply_equal_edge_cases() {
454 let max_unsigned = Value::Uint(u64::MAX);
456 let max_signed = Value::Int(i64::MAX);
457 let min_int = Value::Int(i64::MIN);
458
459 assert!(apply_equal(&max_unsigned, &max_unsigned));
460 assert!(apply_equal(&max_signed, &max_signed));
461 assert!(apply_equal(&min_int, &min_int));
462
463 assert!(!apply_equal(&max_unsigned, &Value::Int(-1)));
466 assert!(apply_equal(&Value::Uint(i64::MAX as u64), &max_signed));
468
469 let empty_bytes = Value::Bytes(vec![]);
471 let empty_string = Value::String(String::new());
472
473 assert!(apply_equal(&empty_bytes, &empty_bytes));
474 assert!(apply_equal(&empty_string, &empty_string));
475 assert!(apply_equal(&empty_bytes, &empty_string));
479 }
480
481 #[test]
491 fn test_apply_not_equal_consistency_with_equal() {
492 let test_cases = vec![
493 (Value::Uint(42), Value::Uint(42)),
495 (Value::Uint(42), Value::Uint(24)),
496 (Value::Uint(0), Value::Uint(0)),
497 (Value::Uint(u64::MAX), Value::Uint(u64::MAX)),
498 (Value::Uint(u64::MAX), Value::Uint(0)),
499 (Value::Int(42), Value::Int(42)),
501 (Value::Int(42), Value::Int(-42)),
502 (Value::Int(-100), Value::Int(-100)),
503 (Value::Int(-100), Value::Int(100)),
504 (Value::Int(0), Value::Int(0)),
505 (Value::Int(i64::MAX), Value::Int(i64::MAX)),
506 (Value::Int(i64::MIN), Value::Int(i64::MIN)),
507 (Value::Int(i64::MAX), Value::Int(i64::MIN)),
508 (
510 Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]),
511 Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]),
512 ),
513 (
514 Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]),
515 Value::Bytes(vec![0x50, 0x4b, 0x03, 0x04]),
516 ),
517 (Value::Bytes(vec![]), Value::Bytes(vec![])),
518 (
519 Value::Bytes(vec![0x7f, 0x45]),
520 Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]),
521 ),
522 (Value::Bytes(vec![0x7f]), Value::Bytes(vec![0x7f])),
523 (Value::Bytes(vec![0x7f]), Value::Bytes(vec![0x45])),
524 (
526 Value::String("hello".to_string()),
527 Value::String("hello".to_string()),
528 ),
529 (
530 Value::String("hello".to_string()),
531 Value::String("world".to_string()),
532 ),
533 (Value::String(String::new()), Value::String(String::new())),
534 (
535 Value::String("Hello".to_string()),
536 Value::String("hello".to_string()),
537 ),
538 (
539 Value::String("\u{1f980} Rust".to_string()),
540 Value::String("\u{1f980} Rust".to_string()),
541 ),
542 (
543 Value::String("\u{1f980} Rust".to_string()),
544 Value::String("\u{1f40d} Python".to_string()),
545 ),
546 (
547 Value::String("hello world".to_string()),
548 Value::String("hello world".to_string()),
549 ),
550 (
551 Value::String("hello world".to_string()),
552 Value::String("hello world".to_string()),
553 ),
554 (Value::Uint(42), Value::Int(42)),
556 (Value::Uint(0), Value::Int(0)),
557 (Value::Uint(42), Value::Int(-42)),
558 (Value::Uint(42), Value::Bytes(vec![42])),
559 (Value::Uint(42), Value::String("42".to_string())),
560 (Value::Int(-42), Value::Bytes(vec![214])),
561 (Value::Int(-42), Value::String("-42".to_string())),
562 (
563 Value::Bytes(vec![104, 101, 108, 108, 111]),
564 Value::String("hello".to_string()),
565 ),
566 (Value::Bytes(vec![42]), Value::Uint(42)),
567 (Value::Bytes(vec![]), Value::String(String::new())),
569 ];
570
571 for (left, right) in test_cases {
573 let equal_result = apply_equal(&left, &right);
574 let not_equal_result = apply_not_equal(&left, &right);
575 assert_eq!(
576 equal_result, !not_equal_result,
577 "apply_not_equal should be negation of apply_equal: {left:?} vs {right:?}"
578 );
579 }
580 }
581
582 #[test]
587 fn test_apply_equal_float_exact_same_value() {
588 assert!(apply_equal(&Value::Float(1.0), &Value::Float(1.0)));
589 assert!(apply_equal(&Value::Float(0.0), &Value::Float(0.0)));
590 assert!(apply_equal(&Value::Float(-3.125), &Value::Float(-3.125)));
591 }
592
593 #[test]
594 fn test_apply_equal_float_near_equal_within_epsilon() {
595 let a = 1.0_f64;
597 let b = a + f64::EPSILON;
598 assert!(
599 apply_equal(&Value::Float(a), &Value::Float(b)),
600 "values differing by f64::EPSILON should be equal"
601 );
602 }
603
604 #[test]
605 fn test_apply_equal_float_clearly_unequal() {
606 assert!(!apply_equal(&Value::Float(1.0), &Value::Float(2.0)));
607 assert!(!apply_equal(&Value::Float(0.0), &Value::Float(1.0)));
608 assert!(!apply_equal(&Value::Float(-1.0), &Value::Float(1.0)));
609 }
610
611 #[test]
612 fn test_apply_equal_float_infinity() {
613 let pos_inf = f64::INFINITY;
614 let neg_inf = f64::NEG_INFINITY;
615
616 assert!(apply_equal(&Value::Float(pos_inf), &Value::Float(pos_inf)));
617 assert!(apply_equal(&Value::Float(neg_inf), &Value::Float(neg_inf)));
618 assert!(!apply_equal(&Value::Float(pos_inf), &Value::Float(neg_inf)));
619 assert!(!apply_equal(&Value::Float(pos_inf), &Value::Float(1.0)));
620 }
621
622 #[test]
623 fn test_apply_equal_float_nan() {
624 let nan = f64::NAN;
625 assert!(!apply_equal(&Value::Float(nan), &Value::Float(nan)));
626 assert!(!apply_equal(&Value::Float(nan), &Value::Float(0.0)));
627 assert!(!apply_equal(&Value::Float(0.0), &Value::Float(nan)));
628 }
629
630 #[test]
631 fn test_apply_not_equal_float_consistency_with_equal() {
632 let nan = f64::NAN;
636 let near_a = 1.0_f64;
637 let near_b = near_a + f64::EPSILON;
638 let test_cases = vec![
639 (Value::Float(1.0), Value::Float(1.0)),
640 (Value::Float(0.0), Value::Float(0.0)),
641 (Value::Float(near_a), Value::Float(near_b)),
642 (Value::Float(1.0), Value::Float(2.0)),
643 (Value::Float(-1.0), Value::Float(1.0)),
644 (Value::Float(nan), Value::Float(nan)),
645 (Value::Float(nan), Value::Float(0.0)),
646 (Value::Float(0.0), Value::Float(nan)),
647 (Value::Float(f64::INFINITY), Value::Float(f64::INFINITY)),
648 (
649 Value::Float(f64::NEG_INFINITY),
650 Value::Float(f64::NEG_INFINITY),
651 ),
652 (Value::Float(f64::INFINITY), Value::Float(f64::NEG_INFINITY)),
653 (Value::Float(f64::INFINITY), Value::Float(1.0)),
654 ];
655 for (left, right) in test_cases {
656 let equal_result = apply_equal(&left, &right);
657 let not_equal_result = apply_not_equal(&left, &right);
658 assert_eq!(
659 equal_result, !not_equal_result,
660 "apply_not_equal should be negation of apply_equal: {left:?} vs {right:?}"
661 );
662 }
663 }
664}