@@ -362,3 +362,107 @@ private struct BufferViewTests {
362362 }
363363 }
364364}
365+
366+ @Suite ( " BufferReader " )
367+ private struct BufferReaderTests {
368+
369+ @Test ( " Line number counting with standalone newlines " )
370+ func lineNumberCounting( ) {
371+ // Test case designed to expose the bug: second byte is 'A' (not a newline),
372+ // but there are newlines at positions 3, 5, and 7.
373+ // With the bug, fullBuffer[offset: 1] would check byte 1 ('A') and never count
374+ // the newlines at positions 3, 5, and 7.
375+ let testString = " A \n B \n C \n D "
376+ let bytes = Array ( testString. utf8)
377+
378+ bytes. withUnsafeBufferPointer {
379+ let bufferView = BufferView ( unsafeBufferPointer: $0)
380+ #expect( bufferView != nil )
381+ guard let bufferView else { return }
382+
383+ var reader = BufferReader ( bytes: bufferView)
384+
385+ // Advance reader to the end to test lineNumber calculation
386+ while !reader. isAtEnd {
387+ _ = reader. read ( )
388+ }
389+
390+ // Should count 4 lines: initial line + 3 newlines
391+ #expect( reader. lineNumber == 4 , " Expected 4 lines, got \( reader. lineNumber) " )
392+ }
393+ }
394+
395+ @Test ( " Line number counting with CRLF sequences " )
396+ func lineNumberCountingWithCRLF( ) {
397+ // Test CRLF handling: \r\n should count as one line break
398+ let testString = " Line1 \r \n Line2 \r \n Line3 "
399+ let bytes = Array ( testString. utf8)
400+
401+ bytes. withUnsafeBufferPointer {
402+ let bufferView = BufferView ( unsafeBufferPointer: $0)
403+ #expect( bufferView != nil )
404+ guard let bufferView else { return }
405+
406+ var reader = BufferReader ( bytes: bufferView)
407+
408+ while !reader. isAtEnd {
409+ _ = reader. read ( )
410+ }
411+
412+ // Should count 3 lines: initial line + 2 CRLF sequences
413+ #expect( reader. lineNumber == 3 , " Expected 3 lines, got \( reader. lineNumber) " )
414+ }
415+ }
416+
417+ @Test ( " Line number counting with mixed newlines " )
418+ func lineNumberCountingMixed( ) {
419+ // Test mixed \n and \r\n sequences
420+ // Second byte is 'a' (not a newline) to ensure bug would be exposed
421+ let testString = " a \n b \r \n c \n d "
422+ let bytes = Array ( testString. utf8)
423+
424+ bytes. withUnsafeBufferPointer {
425+ let bufferView = BufferView ( unsafeBufferPointer: $0)
426+ #expect( bufferView != nil )
427+ guard let bufferView else { return }
428+
429+ var reader = BufferReader ( bytes: bufferView)
430+
431+ while !reader. isAtEnd {
432+ _ = reader. read ( )
433+ }
434+
435+ // Should count 4 lines: initial line + 3 line breaks (one \n, one \r\n, one \n)
436+ #expect( reader. lineNumber == 4 , " Expected 4 lines, got \( reader. lineNumber) " )
437+ }
438+ }
439+
440+ @Test ( " Line number at different read positions " )
441+ func lineNumberAtPosition( ) {
442+ let testString = " Line1 \n Line2 \n Line3 "
443+ let bytes = Array ( testString. utf8)
444+
445+ bytes. withUnsafeBufferPointer {
446+ let bufferView = BufferView ( unsafeBufferPointer: $0)
447+ #expect( bufferView != nil )
448+ guard let bufferView else { return }
449+
450+ var reader = BufferReader ( bytes: bufferView)
451+
452+ // Read up to first newline
453+ while reader. readIndex < bufferView. endIndex {
454+ let byte = reader. read ( )
455+ if byte == UInt8 ( ascii: " \n " ) {
456+ break
457+ }
458+ }
459+ #expect( reader. lineNumber == 2 , " After first newline, expected 2 lines, got \( reader. lineNumber) " )
460+
461+ // Read to end
462+ while !reader. isAtEnd {
463+ _ = reader. read ( )
464+ }
465+ #expect( reader. lineNumber == 3 , " At end, expected 3 lines, got \( reader. lineNumber) " )
466+ }
467+ }
468+ }
0 commit comments