11use super :: collections:: { ListMap , Equality , DefaultEquality } ;
22
3- use std:: cmp:: Ordering ;
3+ use std:: fmt:: { Debug , Display , Formatter } ;
4+ use itertools:: Itertools ;
45
5- pub fn vec_eq_no_order < ' a , T , A , B > ( left : A , right : B ) -> Option < String >
6- where
7- T : ' a + PartialEq + std:: fmt:: Debug ,
8- A : Iterator < Item =& ' a T > ,
9- B : Iterator < Item =& ' a T > ,
10- {
11- compare_vec_no_order ( left, right, DefaultEquality { } ) . as_string ( )
12- }
13-
14- pub fn compare_vec_no_order < ' a , T , A , B , E > ( left : A , right : B , _cmp : E ) -> VecDiff < ' a , T , E >
6+ pub fn compare_vec_no_order < ' a , T , A , B , E > ( actual : A , expected : B , _cmp : E ) -> VecDiff < ' a , T , E >
157where
168 A : Iterator < Item =& ' a T > ,
179 B : Iterator < Item =& ' a T > ,
1810 E : Equality < & ' a T > ,
1911{
20- let mut left_count: ListMap < & T , usize , E > = ListMap :: new ( ) ;
21- let mut right_count: ListMap < & T , usize , E > = ListMap :: new ( ) ;
22- for i in left {
23- * left_count. entry ( & i) . or_insert ( 0 ) += 1 ;
12+ let mut diff: ListMap < & T , Count , E > = ListMap :: new ( ) ;
13+ for i in actual {
14+ diff. entry ( & i) . or_default ( ) . actual += 1 ;
2415 }
25- for i in right {
26- * right_count . entry ( & i) . or_insert ( 0 ) += 1 ;
16+ for i in expected {
17+ diff . entry ( & i) . or_default ( ) . expected += 1 ;
2718 }
28- VecDiff { left_count, right_count }
19+ diff = diff. into_iter ( ) . filter ( |( _v, c) | c. actual != c. expected ) . collect ( ) ;
20+ VecDiff { diff }
21+ }
22+
23+ #[ derive( Default ) ]
24+ struct Count {
25+ actual : usize ,
26+ expected : usize ,
2927}
3028
3129pub struct VecDiff < ' a , T , E : Equality < & ' a T > > {
32- left_count : ListMap < & ' a T , usize , E > ,
33- right_count : ListMap < & ' a T , usize , E > ,
30+ diff : ListMap < & ' a T , Count , E > ,
31+ }
32+
33+ struct FormatAsDebug < T : Debug > ( T ) ;
34+ impl < T : Debug > Display for FormatAsDebug < T > {
35+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
36+ Debug :: fmt ( & self . 0 , f)
37+ }
3438}
3539
36- trait DiffVisitor < ' a , T > {
37- fn diff ( & mut self , item : & ' a T , left : usize , right : usize ) -> bool ;
40+ struct FormatAsDisplay < T : Display > ( T ) ;
41+ impl < T : Display > Display for FormatAsDisplay < T > {
42+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
43+ Display :: fmt ( & self . 0 , f)
44+ }
3845}
3946
40- impl < ' a , T : std :: fmt :: Debug , E : Equality < & ' a T > > VecDiff < ' a , T , E > {
47+ impl < ' a , T , E : Equality < & ' a T > > VecDiff < ' a , T , E > {
4148 pub fn has_diff ( & self ) -> bool {
42- #[ derive( Default ) ]
43- struct FindDiff {
44- diff : bool ,
45- }
46- impl < T : std:: fmt:: Debug > DiffVisitor < ' _ , T > for FindDiff {
47- fn diff ( & mut self , _item : & T , left : usize , right : usize ) -> bool {
48- if left == right {
49- false
50- } else {
51- self . diff = true ;
52- true
53- }
54- }
55- }
56- let mut f = FindDiff :: default ( ) ;
57- self . visit ( & mut f) ;
58- f. diff
49+ !self . diff . is_empty ( )
5950 }
6051
61- pub fn as_string ( & self ) -> Option < String > {
62- #[ derive( Default ) ]
63- struct StringDiff {
64- diff : Option < String > ,
65- }
66- impl < ' a , T : std:: fmt:: Debug > DiffVisitor < ' a , T > for StringDiff {
67- fn diff ( & mut self , item : & ' a T , left : usize , right : usize ) -> bool {
68- match left. cmp ( & right) {
69- Ordering :: Less => {
70- self . diff = Some ( format ! ( "Missed result: {:?}" , item) ) ;
71- true
72- } ,
73- Ordering :: Greater => {
74- self . diff = Some ( format ! ( "Excessive result: {:?}" , item) ) ;
75- true
76- } ,
77- Ordering :: Equal => false ,
78- }
79- }
80- }
81- let mut d = StringDiff { diff : None } ;
82- self . visit ( & mut d) ;
83- d. diff
52+ pub fn as_display ( & self ) -> Option < String > where T : Display {
53+ self . as_string ( FormatAsDisplay )
8454 }
8555
86- fn visit < ' b , V : DiffVisitor < ' b , T > > ( & ' b self , visitor : & mut V ) {
87- for e in self . right_count . iter ( ) {
88- let count = self . left_count . get ( e. 0 ) . unwrap_or ( & 0 ) ;
89- if visitor. diff ( e. 0 , * count, * e. 1 ) { return }
90- }
91- for e in self . left_count . iter ( ) {
92- let count = self . right_count . get ( e. 0 ) . unwrap_or ( & 0 ) ;
93- if visitor. diff ( e. 0 , * e. 1 , * count) { return }
56+ pub fn as_debug ( & self ) -> Option < String > where T : Debug {
57+ self . as_string ( FormatAsDebug )
58+ }
59+
60+ fn as_string < F , I : Display > ( & self , f : F ) -> Option < String >
61+ where F : Fn ( & ' a T ) -> I
62+ {
63+ let mut diff = String :: new ( ) ;
64+ if self . has_diff ( ) {
65+ let mut missed = self . diff . iter ( )
66+ . filter ( |( _v, c) | c. actual < c. expected )
67+ . flat_map ( |( v, c) | std:: iter:: repeat_n ( v, c. expected - c. actual ) )
68+ . map ( |v| f ( v) )
69+ . peekable ( ) ;
70+ let mut excessive = self . diff . iter ( )
71+ . filter ( |( _v, c) | c. actual > c. expected )
72+ . flat_map ( |( v, c) | std:: iter:: repeat_n ( v, c. actual - c. expected ) )
73+ . map ( |v| f ( v) )
74+ . peekable ( ) ;
75+ if missed. peek ( ) . is_some ( ) {
76+ diff. push_str ( format ! ( "Missed results: {}" , missed. format( ", " ) ) . as_str ( ) ) ;
77+ }
78+ if excessive. peek ( ) . is_some ( ) {
79+ if !diff. is_empty ( ) {
80+ diff. push_str ( "\n " ) ;
81+ }
82+ diff. push_str ( format ! ( "Excessive results: {}" , excessive. format( ", " ) ) . as_str ( ) ) ;
83+ }
84+ Some ( diff)
85+ } else {
86+ None
9487 }
9588 }
9689}
9790
9891#[ macro_export]
9992macro_rules! assert_eq_no_order {
100- ( $left : expr, $right : expr) => {
93+ ( $actual : expr, $expected : expr) => {
10194 {
102- assert!( $crate:: common:: assert:: vec_eq_no_order( $left. iter( ) , $right. iter( ) ) == None ,
103- "(left == right some order)\n left: {:?}\n right: {:?}" , $left, $right) ;
95+ let diff = $crate:: common:: assert:: compare_vec_no_order( $actual. iter( ) , $expected. iter( ) ,
96+ $crate:: common:: collections:: DefaultEquality { } ) . as_debug( ) ;
97+ assert!( diff. is_none( ) ,
98+ "(actual != expected)\n Actual: {:?}\n Expected: {:?}\n {}" ,
99+ $actual, $expected, diff. unwrap( ) ) ;
104100 }
105101 }
106102}
107103
108- pub fn metta_results_eq < T : PartialEq + std :: fmt :: Debug > (
109- left : & Result < Vec < Vec < T > > , String > , right : & Result < Vec < Vec < T > > , String > ) -> bool
104+ pub fn metta_results_eq < T : PartialEq > (
105+ actual : & Result < Vec < Vec < T > > , String > , expected : & Result < Vec < Vec < T > > , String > ) -> bool
110106{
111- match ( left, right) {
112- ( Ok ( left) , Ok ( right) ) if left. len ( ) == right. len ( ) => {
113- for ( left, right) in left. iter ( ) . zip ( right. iter ( ) ) {
114- if vec_eq_no_order ( left. iter ( ) , right. iter ( ) ) . is_some ( ) {
107+ match ( actual, expected) {
108+ ( Ok ( actual) , Ok ( expected) ) if actual. len ( ) == expected. len ( ) => {
109+ for ( actual, expected) in actual. iter ( ) . zip ( expected. iter ( ) ) {
110+ let diff = compare_vec_no_order ( actual. iter ( ) , expected. iter ( ) , DefaultEquality { } ) ;
111+ if diff. has_diff ( ) {
115112 return false ;
116113 }
117114 }
@@ -123,12 +120,12 @@ pub fn metta_results_eq<T: PartialEq + std::fmt::Debug>(
123120
124121#[ macro_export]
125122macro_rules! assert_eq_metta_results {
126- ( $left : expr, $right : expr) => {
123+ ( $actual : expr, $expected : expr) => {
127124 {
128- let left = & $left ;
129- let right = & $right ;
130- assert!( $crate:: common:: assert:: metta_results_eq( left , right ) ,
131- "(left == right )\n left : {:?}\n right : {:?}" , left , right ) ;
125+ let actual = & $actual ;
126+ let expected = & $expected ;
127+ assert!( $crate:: common:: assert:: metta_results_eq( actual , expected ) ,
128+ "(actual == expected )\n actual : {:?}\n expected : {:?}" , actual , expected ) ;
132129 }
133130 }
134131}
0 commit comments