@@ -54,20 +54,26 @@ impl<R: Read> SkipWhitespace<R> {
5454
5555impl < R : Read > Read for SkipWhitespace < R > {
5656 fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
57- let n = self . inner . read ( buf) ?;
57+ loop {
58+ let n = self . inner . read ( buf) ?;
59+ if n == 0 {
60+ return Ok ( 0 ) ;
61+ }
5862
59- let mut written = 0 ;
60- for read in 0 ..n {
61- if !buf[ read] . is_ascii_whitespace ( ) {
62- buf[ written] = buf[ read] ;
63- written += 1 ;
63+ let mut written = 0 ;
64+ for read in 0 ..n {
65+ if !buf[ read] . is_ascii_whitespace ( ) {
66+ buf[ written] = buf[ read] ;
67+ written += 1 ;
68+ }
6469 }
65- }
6670
67- Ok ( written)
71+ if written > 0 {
72+ return Ok ( written) ;
73+ }
74+ }
6875 }
6976}
70- //
7177
7278pub fn unwrap_envelope_v1 ( tx_env : TransactionEnvelope ) -> Result < Transaction , Error > {
7379 let TransactionEnvelope :: Tx ( TransactionV1Envelope { tx, .. } ) = tx_env else {
@@ -83,3 +89,93 @@ pub fn add_op(tx_env: TransactionEnvelope, op: Operation) -> Result<TransactionE
8389 tx. operations = ops. try_into ( ) . map_err ( |_| Error :: TooManyOperations ) ?;
8490 Ok ( tx. into ( ) )
8591}
92+
93+ #[ cfg( test) ]
94+ mod tests {
95+ use super :: * ;
96+ use std:: io:: Cursor ;
97+
98+ struct ChunkedReader {
99+ chunks : Vec < Vec < u8 > > ,
100+ pos : usize ,
101+ }
102+
103+ impl ChunkedReader {
104+ fn new ( chunks : Vec < & [ u8 ] > ) -> Self {
105+ Self {
106+ chunks : chunks. iter ( ) . map ( |c| c. to_vec ( ) ) . collect ( ) ,
107+ pos : 0 ,
108+ }
109+ }
110+ }
111+
112+ impl Read for ChunkedReader {
113+ fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
114+ if self . pos >= self . chunks . len ( ) {
115+ return Ok ( 0 ) ;
116+ }
117+ let chunk = & self . chunks [ self . pos ] ;
118+ let n = chunk. len ( ) . min ( buf. len ( ) ) ;
119+ buf[ ..n] . copy_from_slice ( & chunk[ ..n] ) ;
120+ self . pos += 1 ;
121+ Ok ( n)
122+ }
123+ }
124+
125+ #[ test]
126+ fn skip_whitespace_preserves_content ( ) {
127+ let input = Cursor :: new ( b"helloworld" ) ;
128+ let mut reader = SkipWhitespace :: new ( input) ;
129+ let mut result = String :: new ( ) ;
130+ reader. read_to_string ( & mut result) . unwrap ( ) ;
131+ assert_eq ! ( result, "helloworld" ) ;
132+ }
133+
134+ #[ test]
135+ fn skip_whitespace_strips_all_whitespace_types ( ) {
136+ let input = Cursor :: new ( b"hello \t \n \r world" ) ;
137+ let mut reader = SkipWhitespace :: new ( input) ;
138+ let mut result = String :: new ( ) ;
139+ reader. read_to_string ( & mut result) . unwrap ( ) ;
140+ assert_eq ! ( result, "helloworld" ) ;
141+ }
142+
143+ #[ test]
144+ fn skip_whitespace_handles_only_whitespace ( ) {
145+ let input = Cursor :: new ( b"\n \t \r \n " ) ;
146+ let mut reader = SkipWhitespace :: new ( input) ;
147+ let mut result = String :: new ( ) ;
148+ reader. read_to_string ( & mut result) . unwrap ( ) ;
149+ assert_eq ! ( result, "" ) ;
150+ }
151+
152+ #[ test]
153+ fn skip_whitespace_handles_empty_input ( ) {
154+ let input = Cursor :: new ( b"" ) ;
155+ let mut reader = SkipWhitespace :: new ( input) ;
156+ let mut result = String :: new ( ) ;
157+ reader. read_to_string ( & mut result) . unwrap ( ) ;
158+ assert_eq ! ( result, "" ) ;
159+ }
160+
161+ #[ test]
162+ fn skip_whitespace_loops_past_whitespace_only_chunks ( ) {
163+ // Exercises the loop iterating more than once: first chunk is all
164+ // whitespace, second chunk has content. A Cursor would satisfy both
165+ // reads in one shot and would never trigger the loop.
166+ let reader = ChunkedReader :: new ( vec ! [ b"\n \n " , b"hello" , b"" ] ) ;
167+ let mut skipper = SkipWhitespace :: new ( reader) ;
168+ let mut result = String :: new ( ) ;
169+ skipper. read_to_string ( & mut result) . unwrap ( ) ;
170+ assert_eq ! ( result, "hello" ) ;
171+ }
172+
173+ #[ test]
174+ fn skip_whitespace_handles_leading_trailing_whitespace ( ) {
175+ let input = Cursor :: new ( b"\n \n hello\n \n " ) ;
176+ let mut reader = SkipWhitespace :: new ( input) ;
177+ let mut result = String :: new ( ) ;
178+ reader. read_to_string ( & mut result) . unwrap ( ) ;
179+ assert_eq ! ( result, "hello" ) ;
180+ }
181+ }
0 commit comments