diff options
Diffstat (limited to 'parser/reader_test.go')
-rw-r--r-- | parser/reader_test.go | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/parser/reader_test.go b/parser/reader_test.go new file mode 100644 index 0000000..f80f52c --- /dev/null +++ b/parser/reader_test.go @@ -0,0 +1,178 @@ +package parser + +import ( + "bufio" + "io" + "strings" + "testing" +) + +func TestPeekRune(t *testing.T) { + s := "Ta’ Ħaġrat" + reader := reader{r: bufio.NewReader(strings.NewReader(s))} + + for _, r := range s { + r1, err := reader.peekRune() + if err != nil && !(err == io.EOF && r == 't') { + t.Fatalf("reader.peekRune() failed with ‘%T’ at rune ‘%c’", err, r) + } + + r2, _ := reader.readRune() + if r1 != r2 { + t.Fatalf("reader.peekRune() peaked ‘%c’ but the next read rune was ‘%c’", r1, r2) + } + } +} + +func TestUnreadRune(t *testing.T) { + s := "Ta’ Ħaġrat" + reader := reader{r: bufio.NewReader(strings.NewReader(s))} + + for range s { + r1, _ := reader.readRune() + if err := reader.unreadRune(); err != nil { + t.Fatalf("reader.unreadRune() failed with ‘%T’ when unreading rune ‘%c’", err, r1) + } + r2, _ := reader.readRune() + if r1 != r2 { + t.Fatalf("reader.readRune() returned ‘%c’ after unreading ‘%c’", r2, r1) + } + } +} + +func TestUnreadRunePosTracking(t *testing.T) { + s := "Ta’ Ħaġrat\nIJsselmeer" + reader := reader{r: bufio.NewReader(strings.NewReader(s))} + + for i := range []rune(s) { + r, _ := reader.readRune() + + if err := reader.unreadRune(); err != nil { + t.Fatalf("reader.unreadRune() failed with ‘%T’ when unreading rune ‘%c’", err, r) + } + + // Ensure we tracked the row correctly + switch { + case i < 11 && reader.pos.row != 0: + t.Fatalf("Expected reader to be on row 0 after unreading rune ‘%c’ but got row %d", r, reader.pos.row) + case i >= 11 && reader.pos.row != 1: + t.Fatalf("Expected reader to be on row 1 after unreading rune ‘%c’ but got row %d", r, reader.pos.row) + } + + // Ensure we tracked the column correctly + switch { + case i < 11 && reader.pos.col != uint(i): + t.Fatalf("Expected reader to be on col %d after unreading rune ‘%c’ but got col %d", i, r, reader.pos.col) + case i == 11 && reader.pos.col != 0: + t.Fatalf("Expected reader to be on col 0 after unreading rune ‘\\n’ but got col %d", reader.pos.col) + case i > 11 && reader.pos.col != uint(i)-11: + t.Fatalf("Expected reader to be on col %d after unreading rune ‘%c’ but got col %d", i-10, r, reader.pos.col) + } + + reader.readRune() + } +} + +func TestReadRune(t *testing.T) { + s := "Ta’ Ħaġrat" + reader := reader{r: bufio.NewReader(strings.NewReader(s))} + + for _, r1 := range s { + r2, err := reader.readRune() + if err != nil { + t.Fatalf("reader.readRune() failed with ‘%T’", err) + } + if r1 != r2 { + t.Fatalf("reader.readRune() read ‘%c’ but ‘%c’ was expected", r1, r2) + } + } + + _, err := reader.readRune() + switch { + case err == nil: + t.Fatal("reader.readRune() expected to fail but didn’t") + case err != io.EOF: + t.Fatalf("reader.readRune() expected to fail with io.EOF but got ‘%T’", err) + } +} + +func TestReadRunePosTracking(t *testing.T) { + s := "Ta’ Ħaġrat\nIJsselmeer" + line1 := true + reader := reader{r: bufio.NewReader(strings.NewReader(s))} + + for i := range []rune(s) { + // Track the line we’re on + r, _ := reader.readRune() + if r == '\n' { + line1 = false + } + + // Ensure we tracked the row correctly + switch { + case line1 && reader.pos.row != 0: + t.Fatalf("Expected reader to be on row 0 when reading rune ‘%c’ but got row %d", r, reader.pos.row) + case !line1 && reader.pos.row != 1: + t.Fatalf("Expected reader to be on row 1 when reading rune ‘%c’ but got row %d", r, reader.pos.row) + } + + // Ensure we tracked the column correctly + switch { + case i < 10 && reader.pos.col != uint(i)+1: + t.Fatalf("Expected reader to be on col %d when reading rune ‘%c’ but got col %d", i, r, reader.pos.col) + case i == 10 && reader.pos.col != 0: + t.Fatalf("Expected reader to be on col 0 when reading rune ‘\\n’ but got col %d", reader.pos.col) + case i > 10 && reader.pos.col != uint(i)-10: + t.Fatalf("Expected reader to be on col %d when reading rune ‘%c’ but got col %d", i-10, r, reader.pos.col) + } + } +} + +func TestReadNonSpaceRune(t *testing.T) { + s := "Ta’ Ħaġrat \t\n IJsselmeer" + reader := reader{r: bufio.NewReader(strings.NewReader(s))} + readUntil := func(target rune) { + for { + if r, _ := reader.readRune(); r == target { + break + } + } + } + assertNext := func(target rune) { + if r, err := reader.readNonSpaceRune(); err != nil { + t.Fatalf("reader.readNonSpaceRune() failed with ‘%T’", err) + } else if r != target { + t.Fatalf("reader.readNonSpaceRune() expected to return ‘%c’ but returned ‘%c’", target, r) + } + } + + readUntil('’') + assertNext('Ħ') + readUntil('t') + assertNext('IJ') +} + +func TestSkipSpaces(t *testing.T) { + s := "Ta’ Ħaġrat \t\n IJsselmeer" + reader := reader{r: bufio.NewReader(strings.NewReader(s))} + readUntil := func(target rune) { + for { + if r, _ := reader.readRune(); r == target { + break + } + } + } + assertNext := func(target rune) { + if err := reader.skipSpaces(); err != nil { + t.Fatalf("reader.skipSpaces() failed with ‘%T’", err) + } + if r, _ := reader.readRune(); r != target { + t.Fatalf("reader.readRune() expected to return ‘%c’ but returned ‘%c’", target, r) + } + } + + readUntil('’') + assertNext('Ħ') + readUntil('t') + assertNext('IJ') +} |