package parsekit import ( "io" "strings" "testing" "unicode/utf8" "git.makaay.nl/mauricem/go-parsekit/assert" ) func TestCallingNextRune_ReturnsNextRune(t *testing.T) { r, _ := mkInput().NextRune() assert.Equal(t, 'T', r, "first rune") } func TestInputCanAcceptRunesFromReader(t *testing.T) { i := mkInput() i.NextRune() i.Accept() i.NextRune() i.Accept() i.NextRune() i.Accept() assert.Equal(t, "Tes", i.Result().String(), "i.Result().String()") } func TestCallingNextRuneTwice_Panics(t *testing.T) { assert.Panic(t, assert.PanicT{ Function: func() { i := mkInput() i.NextRune() i.NextRune() }, Regexp: true, Expect: `parsekit\.TokenAPI\.NextRune\(\): NextRune\(\) called without ` + `a prior call to Accept\(\) from .*TestCallingNextRuneTwice_Panics.* at /.*_test.go:\d+`, }) } func TestCallingAcceptWithoutCallingNextRune_Panics(t *testing.T) { assert.Panic(t, assert.PanicT{ Function: mkInput().Accept, Regexp: true, Expect: `parsekit\.TokenAPI\.Accept\(\): Accept\(\) called without ` + `first calling NextRune\(\) from .* at /.*:\d+`, }) } func TestCallingMergeOnNonForkedChild_Panics(t *testing.T) { assert.Panic(t, assert.PanicT{ Function: func() { i := mkInput() i.Merge() }, Expect: "parsekit.TokenAPI.Merge(): Cannot call Merge() on a non-forked TokenAPI", }) } func TestCallingNextRuneOnForkedParent_DetachesForkedChild(t *testing.T) { assert.Panic(t, assert.PanicT{ Function: func() { i := mkInput() f := i.Fork() i.NextRune() f.Merge() }, Expect: "parsekit.TokenAPI.Merge(): Cannot call Merge() on a non-forked TokenAPI", }) } func TestCallingForkOnForkedParent_DetachesForkedChild(t *testing.T) { assert.Panic(t, assert.PanicT{ Function: func() { i := mkInput() f := i.Fork() i.Fork() f.Merge() }, Expect: "parsekit.TokenAPI.Merge(): Cannot call Merge() on a non-forked TokenAPI", }) } func TestGivenMultipleLevelsOfForks_WhenReturningToRootInput_ForksAreDetached(t *testing.T) { i := mkInput() f1 := i.Fork() f2 := f1.Fork() f3 := f2.Fork() f4 := f1.Fork() // secret subtest: this Fork() detaches both forks f2 and f3 f5 := f4.Fork() assert.Equal(t, true, i.parent == nil, "i.parent == nil") assert.Equal(t, true, i.child == f1, "i.child == f1") assert.Equal(t, true, f1.parent == i, "f1.parent == i") assert.Equal(t, true, f1.child == f4, "f1.child == f4") assert.Equal(t, true, f2.child == nil, "f2.child == nil") assert.Equal(t, true, f2.parent == nil, "f2.parent == nil") assert.Equal(t, true, f3.child == nil, "f3.child == nil") assert.Equal(t, true, f3.parent == nil, "f3.parent == nil") assert.Equal(t, true, f4.parent == f1, "f4.parent == f1") assert.Equal(t, true, f4.child == f5, "f4.child == f5") assert.Equal(t, true, f5.parent == f4, "f5.parent == f4") assert.Equal(t, true, f5.child == nil, "f5.child == nil") i.NextRune() assert.Equal(t, true, i.parent == nil, "i.parent == nil") assert.Equal(t, true, i.child == nil, "i.child == nil") assert.Equal(t, true, f1.parent == nil, "f1.parent == nil") assert.Equal(t, true, f1.child == nil, "f1.child == nil") assert.Equal(t, true, f2.child == nil, "f2.child == nil") assert.Equal(t, true, f2.parent == nil, "f2.parent == nil") assert.Equal(t, true, f3.child == nil, "f3.child == nil") assert.Equal(t, true, f3.parent == nil, "f3.parent == nil") assert.Equal(t, true, f4.parent == nil, "f4.parent == nil") assert.Equal(t, true, f4.child == nil, "f4.child == nil") assert.Equal(t, true, f5.parent == nil, "f5.parent == nil") assert.Equal(t, true, f5.child == nil, "f5.child == nil") } func TestForkingInput_ClearsLastRune(t *testing.T) { assert.Panic(t, assert.PanicT{ Function: func() { i := mkInput() i.NextRune() i.Fork() i.Accept() }, Regexp: true, Expect: `parsekit\.TokenAPI\.Accept\(\): Accept\(\) called without ` + `first calling NextRune\(\) from .* at /.*:\d+`, }) } func TestCallingAcceptAfterNextRune_AcceptsRuneAndMovesReadOffsetForward(t *testing.T) { i := mkInput() r, _ := i.NextRune() assert.Equal(t, 'T', r, "result from 1st call to NextRune()") // TODO still (*runeInfo) case needed? assert.NotEqual(t, (*runeInfo)(nil), i.result.lastRune, "Input.lastRune after NextRune()") i.Accept() assert.Equal(t, (*runeInfo)(nil), i.result.lastRune, "Input.lastRune after Accept()") assert.Equal(t, 1, i.offset, "Input.offset") assert.Equal(t, 'T', i.reader.buffer[0], "Input.buffer[0]") r, _ = i.NextRune() assert.Equal(t, 'e', r, "result from 2nd call to NextRune()") } func TestCallingMultipleAccepts_FillsInputWithData(t *testing.T) { i := mkInput() for j := 0; j < 7; j++ { i.NextRune() i.Accept() } assert.Equal(t, "Testing", string(i.reader.buffer), "reader input buffer") assert.Equal(t, "Testing", i.Result().String(), "i.Result().String()") } func TestAccept_UpdatesCursor(t *testing.T) { i := NewTokenAPI(strings.NewReader("input\r\nwith\r\nnewlines")) assert.Equal(t, "line 1, column 1", i.cursor.String(), "cursor 1") for j := 0; j < 6; j++ { // read "input\r", cursor end up at "\n" i.NextRune() i.Accept() } assert.Equal(t, "line 1, column 7", i.cursor.String(), "cursor 2") i.NextRune() // read "\n", cursor ends up at start of new line i.Accept() assert.Equal(t, "line 2, column 1", i.cursor.String(), "cursor 3") for j := 0; j < 10; j++ { // read "with\r\nnewl", cursor end up at "i" i.NextRune() i.Accept() } assert.Equal(t, "line 3, column 5", i.cursor.String(), "cursor 4") assert.Equal(t, *i.cursor, i.Cursor(), "i.Cursor()") } func TestFork_CreatesForkOfInputAtSameCursorPosition(t *testing.T) { // Create input, accept the first rune. i := mkInput() i.NextRune() i.Accept() // T assert.Equal(t, "T", i.Result().String(), "accepted rune in input") // Fork f := i.Fork() assert.Equal(t, f, i.child, "Input.child (must be f)") assert.Equal(t, i, f.parent, "Input.parent (must be i)") assert.Equal(t, 1, i.cursor.Byte, "i.child.cursor.Byte") assert.Equal(t, 1, i.child.cursor.Byte, "i.child.cursor.Byte") // Accept two runes via fork. f.NextRune() f.Accept() // e f.NextRune() f.Accept() // s assert.Equal(t, "es", f.Result().String(), "result runes in fork") assert.Equal(t, 1, i.cursor.Byte, "i.child.cursor.Byte") assert.Equal(t, 3, i.child.cursor.Byte, "i.child.cursor.Byte") // Merge fork back into parent f.Merge() assert.Equal(t, "Tes", i.Result().String(), "result runes in parent Input after Merge()") assert.Equal(t, 3, i.cursor.Byte, "i.child.cursor.Byte") } func TestGivenForkedChildWhichAcceptedRune_AfterMerging_RuneEndsUpInParentResult(t *testing.T) { i := mkInput() i.NextRune() i.Accept() f1 := i.Fork() f1.NextRune() f1.Accept() f2 := f1.Fork() f2.NextRune() f2.Accept() assert.Equal(t, "T", i.Result().String(), "i.Result().String()") assert.Equal(t, 1, i.offset, "i.offset") assert.Equal(t, "e", f1.Result().String(), "f1.Result().String()") assert.Equal(t, 2, f1.offset, "f1.offset") assert.Equal(t, "s", f2.Result().String(), "f2.Result().String()") assert.Equal(t, 3, f2.offset, "f2.offset") f2.Merge() assert.Equal(t, "T", i.Result().String(), "i.Result().String()") assert.Equal(t, 1, i.offset, "i.offset") assert.Equal(t, "es", f1.Result().String(), "f1.Result().String()") assert.Equal(t, 3, f1.offset, "f1.offset") assert.Equal(t, "", f2.Result().String(), "f2.Result().String()") assert.Equal(t, 3, f2.offset, "f2.offset") f1.Merge() assert.Equal(t, "Tes", i.Result().String(), "i.Result().String()") assert.Equal(t, 3, i.offset, "i.offset") assert.Equal(t, "", f1.Result().String(), "f1.Result().String()") assert.Equal(t, 3, f1.offset, "f1.offset") assert.Equal(t, "", f2.Result().String(), "f2.Result().String()") assert.Equal(t, 3, f2.offset, "f2.offset") } func TestGivenForkedChild_FlushReaderBuffer_Panics(t *testing.T) { assert.Panic(t, assert.PanicT{ Function: func() { i := mkInput() f := i.Fork() f.FlushReaderBuffer(1) }, Expect: "parsekit.input.TokenAPI.FlushReaderBuffer(): Flushbuffer() " + "can only be called on the root TokenAPI, not on a forked child", }) } func TestGivenRootWithSomeRunesRead_FlushReaderBuffer_ClearsReaderBuffer(t *testing.T) { i := mkInput() i.NextRune() i.Accept() i.NextRune() i.Accept() i.FlushReaderBuffer(2) assert.Equal(t, "Te", i.Result().String(), "i.Result()") assert.Equal(t, 0, i.offset, "i.offset") i.NextRune() i.Accept() i.NextRune() i.Accept() assert.Equal(t, 2, i.offset, "i.offset") i.FlushReaderBuffer(2) assert.Equal(t, "Test", i.Result().String(), "i.Result()") assert.Equal(t, 0, i.offset, "i.offset") } func TestWhenCallingNextRuneAtEndOfFile_EOFIsReturned(t *testing.T) { i := NewTokenAPI(strings.NewReader("X")) i.NextRune() i.Accept() r, err := i.NextRune() assert.Equal(t, true, r == utf8.RuneError, "returned rune from NextRune()") assert.Equal(t, true, err == io.EOF, "returned error from NextRune()") } func TestAfterReadingRuneAtEndOfFile_EarlierRunesCanStillBeAccessed(t *testing.T) { i := NewTokenAPI(strings.NewReader("X")) f := i.Fork() f.NextRune() f.Accept() r, err := f.NextRune() assert.Equal(t, true, r == utf8.RuneError, "returned rune from 2nd NextRune()") r, err = i.NextRune() assert.Equal(t, 'X', r, "returned rune from 2nd NextRune()") assert.Equal(t, true, err == nil, "returned error from 2nd NextRune()") } func mkInput() *TokenAPI { return NewTokenAPI(strings.NewReader("Testing")) }