@@ -82,6 +82,19 @@ fn test_struct() {
82
82
} ,
83
83
} ) ,
84
84
) ;
85
+
86
+ check_error_span_exclusive :: < NewType > (
87
+ "NewType" ,
88
+ Err ( SpannedError {
89
+ code : Error :: ExpectedNamedStructLike ( "NewType" ) ,
90
+ span : Span {
91
+ start : Position { line : 1 , col : 1 } ,
92
+ end : Position { line : 1 , col : 8 } ,
93
+ } ,
94
+ } ) ,
95
+ "NewType" ,
96
+ ) ;
97
+
85
98
check_from_str_bytes_reader :: < UnnamedNewType > (
86
99
"" ,
87
100
Err ( SpannedError {
@@ -93,6 +106,7 @@ fn test_struct() {
93
106
} ) ,
94
107
) ;
95
108
check_from_str_bytes_reader ( "(33)" , Ok ( UnnamedNewType ( 33 ) ) ) ;
109
+
96
110
check_from_str_bytes_reader :: < UnnamedNewType > (
97
111
"Newtype" ,
98
112
Err ( SpannedError {
@@ -103,6 +117,17 @@ fn test_struct() {
103
117
} ,
104
118
} ) ,
105
119
) ;
120
+ check_error_span_exclusive :: < UnnamedNewType > (
121
+ "Newtype" ,
122
+ Err ( SpannedError {
123
+ code : Error :: ExpectedNamedStructLike ( "" ) ,
124
+ span : Span {
125
+ start : Position { line : 1 , col : 1 } ,
126
+ end : Position { line : 1 , col : 8 } ,
127
+ } ,
128
+ } ) ,
129
+ "Newtype" ,
130
+ ) ;
106
131
107
132
check_from_str_bytes_reader ( "TupleStruct(2,5,)" , Ok ( TupleStruct ( 2.0 , 5.0 ) ) ) ;
108
133
check_from_str_bytes_reader ( "(3,4)" , Ok ( TupleStruct ( 3.0 , 4.0 ) ) ) ;
@@ -116,6 +141,7 @@ fn test_struct() {
116
141
} ,
117
142
} ) ,
118
143
) ;
144
+
119
145
check_from_str_bytes_reader :: < UnnamedTupleStruct > (
120
146
"TupleStruct(2,5,)" ,
121
147
Err ( SpannedError {
@@ -126,6 +152,19 @@ fn test_struct() {
126
152
} ,
127
153
} ) ,
128
154
) ;
155
+
156
+ check_error_span_exclusive :: < UnnamedTupleStruct > (
157
+ "TupleStruct(2,5,)" ,
158
+ Err ( SpannedError {
159
+ code : Error :: ExpectedNamedStructLike ( "" ) ,
160
+ span : Span {
161
+ start : Position { line : 1 , col : 1 } ,
162
+ end : Position { line : 1 , col : 12 } ,
163
+ } ,
164
+ } ) ,
165
+ "TupleStruct" ,
166
+ ) ;
167
+
129
168
check_from_str_bytes_reader ( "(3,4)" , Ok ( UnnamedTupleStruct ( 3.0 , 4.0 ) ) ) ;
130
169
check_from_str_bytes_reader :: < UnnamedTupleStruct > (
131
170
"" ,
@@ -438,10 +477,21 @@ fn test_err_wrong_value() {
438
477
"MyStruct(\n x: true)" ,
439
478
err ( Error :: ExpectedFloat , ( 2 , 7 ) , ( 2 , 8 ) ) ,
440
479
) ;
480
+ check_error_span_inclusive :: < MyStruct > (
481
+ "MyStruct(\n x: true)" ,
482
+ err ( Error :: ExpectedFloat , ( 2 , 7 ) , ( 2 , 8 ) ) ,
483
+ " t" ,
484
+ ) ;
485
+
441
486
check_from_str_bytes_reader :: < MyStruct > (
442
487
"MyStruct(\n x: 3.5, \n y:)" ,
443
488
err ( Error :: ExpectedFloat , ( 3 , 7 ) , ( 3 , 7 ) ) ,
444
489
) ;
490
+ check_error_span_inclusive :: < MyStruct > (
491
+ "MyStruct(\n x: 3.5, \n y:)" ,
492
+ err ( Error :: ExpectedFloat , ( 3 , 7 ) , ( 3 , 7 ) ) ,
493
+ ")" ,
494
+ ) ;
445
495
}
446
496
447
497
#[ test]
@@ -480,6 +530,18 @@ fn untagged() {
480
530
} ,
481
531
} ) ,
482
532
) ;
533
+
534
+ check_error_span_exclusive :: < Untagged > (
535
+ "Value(()" ,
536
+ Err ( crate :: error:: SpannedError {
537
+ code : crate :: Error :: Eof ,
538
+ span : Span {
539
+ start : Position { line : 1 , col : 8 } ,
540
+ end : crate :: error:: Position { line : 1 , col : 9 } ,
541
+ } ,
542
+ } ) ,
543
+ ")" ,
544
+ ) ;
483
545
}
484
546
485
547
#[ test]
@@ -508,6 +570,18 @@ fn forgot_apostrophes() {
508
570
} ,
509
571
} ) ,
510
572
) ;
573
+
574
+ check_error_span_exclusive :: < ( i32 , String ) > (
575
+ "(4, \" Hello)" ,
576
+ Err ( SpannedError {
577
+ code : Error :: ExpectedStringEnd ,
578
+ span : Span {
579
+ start : Position { line : 1 , col : 5 } ,
580
+ end : Position { line : 1 , col : 6 } ,
581
+ } ,
582
+ } ) ,
583
+ "\" "
584
+ ) ;
511
585
}
512
586
513
587
#[ test]
@@ -524,6 +598,11 @@ fn expected_attribute_end() {
524
598
"#![enable(unwrap_newtypes) \" Hello\" " ,
525
599
err ( Error :: ExpectedAttributeEnd , ( 1 , 27 ) , ( 1 , 28 ) ) ,
526
600
) ;
601
+ check_error_span_inclusive :: < String > (
602
+ "#![enable(unwrap_newtypes) \" Hello\" " ,
603
+ err ( Error :: ExpectedAttributeEnd , ( 1 , 27 ) , ( 1 , 28 ) ) ,
604
+ " \" "
605
+ ) ;
527
606
}
528
607
529
608
#[ test]
@@ -536,6 +615,16 @@ fn invalid_attribute() {
536
615
( 1 , 18 ) ,
537
616
) ,
538
617
) ;
618
+
619
+ check_error_span_exclusive :: < String > (
620
+ "#![enable(invalid)] \" Hello\" " ,
621
+ err (
622
+ Error :: NoSuchExtension ( "invalid" . to_string ( ) ) ,
623
+ ( 1 , 11 ) ,
624
+ ( 1 , 18 ) ,
625
+ ) ,
626
+ "invalid"
627
+ ) ;
539
628
}
540
629
541
630
#[ test]
@@ -699,7 +788,7 @@ fn test_leading_whitespace() {
699
788
check_from_str_bytes_reader ( " EmptyStruct1" , Ok ( EmptyStruct1 ) ) ;
700
789
}
701
790
702
- fn check_from_str_bytes_reader < T : serde:: de:: DeserializeOwned + PartialEq + core:: fmt:: Debug > (
791
+ pub fn check_from_str_bytes_reader < T : serde:: de:: DeserializeOwned + PartialEq + core:: fmt:: Debug > (
703
792
ron : & str ,
704
793
check : SpannedResult < T > ,
705
794
) {
@@ -716,6 +805,63 @@ fn check_from_str_bytes_reader<T: serde::de::DeserializeOwned + PartialEq + core
716
805
}
717
806
}
718
807
808
+ /// Given a string `ron`, a SpannedResult, and a substring, verify that trying to parse `ron` results in an error
809
+ /// equal to the SpannedResult with a Span that exclusively (as in \[start..end\]) selects that substring.
810
+ /// Note that there are two versions of this helper, inclusive and exclusive. This is because while the parser cursor
811
+ /// arithmetic that computes span positions always produces exclusive spans (as in \[start..end\]),
812
+ /// when doing validation against a target substring, the inclusive check including the final grapheme that triggered
813
+ /// the error is often a more intuitive target to check against.
814
+ /// Meanwhile, if the parser threw an EOF, for example, there is no final grapheme to check, and so
815
+ /// only the exclusive check would produce a meaningful result.
816
+ fn check_error_span_exclusive < T : serde:: de:: DeserializeOwned + PartialEq + core:: fmt:: Debug > (
817
+ ron : & str ,
818
+ check : SpannedResult < T > ,
819
+ substr : & str ,
820
+ ) {
821
+ let res_str = super :: from_str :: < T > ( ron) ;
822
+ assert_eq ! ( res_str, check) ;
823
+
824
+ let res_bytes = super :: from_bytes :: < T > ( ron. as_bytes ( ) ) ;
825
+ assert_eq ! ( res_bytes, check) ;
826
+
827
+ #[ cfg( feature = "std" ) ]
828
+ {
829
+ let res_reader = super :: from_reader :: < & [ u8 ] , T > ( ron. as_bytes ( ) ) ;
830
+ assert_eq ! ( res_reader, check) ;
831
+ }
832
+
833
+ assert_eq ! (
834
+ check. unwrap_err( ) . span. substring_exclusive( ron) . unwrap( ) ,
835
+ substr
836
+ ) ;
837
+ }
838
+
839
+ /// Given a string `ron`, a SpannedResult, and a substring, verify that trying to parse `ron` results in an error
840
+ /// equal to the SpannedResult with a Span that inclusively (as in \[start..=end\]) selects that substring.
841
+ /// See [check_error_span_exclusive] for the rationale behind both versions of this helper.
842
+ fn check_error_span_inclusive < T : serde:: de:: DeserializeOwned + PartialEq + core:: fmt:: Debug > (
843
+ ron : & str ,
844
+ check : SpannedResult < T > ,
845
+ substr : & str ,
846
+ ) {
847
+ let res_str = super :: from_str :: < T > ( ron) ;
848
+ assert_eq ! ( res_str, check) ;
849
+
850
+ let res_bytes = super :: from_bytes :: < T > ( ron. as_bytes ( ) ) ;
851
+ assert_eq ! ( res_bytes, check) ;
852
+
853
+ #[ cfg( feature = "std" ) ]
854
+ {
855
+ let res_reader = super :: from_reader :: < & [ u8 ] , T > ( ron. as_bytes ( ) ) ;
856
+ assert_eq ! ( res_reader, check) ;
857
+ }
858
+
859
+ assert_eq ! (
860
+ check. unwrap_err( ) . span. substring_inclusive( ron) . unwrap( ) ,
861
+ substr
862
+ ) ;
863
+ }
864
+
719
865
#[ test]
720
866
fn test_remainder ( ) {
721
867
let mut deserializer = super :: Deserializer :: from_str ( " 42 " ) . unwrap ( ) ;
0 commit comments