package hcl import ( "bufio" "reflect" "testing" "github.com/davecgh/go-spew/spew" ) func TestPosScanner(t *testing.T) { tests := map[string]struct { Input string Want []Range WantToks [][]byte }{ "empty": { "", []Range{}, [][]byte{}, }, "single line": { "hello", []Range{ { Start: Pos{Byte: 0, Line: 1, Column: 1}, End: Pos{Byte: 5, Line: 1, Column: 6}, }, }, [][]byte{ []byte("hello"), }, }, "single line with trailing UNIX newline": { "hello\n", []Range{ { Start: Pos{Byte: 0, Line: 1, Column: 1}, End: Pos{Byte: 5, Line: 1, Column: 6}, }, }, [][]byte{ []byte("hello"), }, }, "single line with trailing Windows newline": { "hello\r\n", []Range{ { Start: Pos{Byte: 0, Line: 1, Column: 1}, End: Pos{Byte: 5, Line: 1, Column: 6}, }, }, [][]byte{ []byte("hello"), }, }, "two lines with UNIX newline": { "hello\nworld", []Range{ { Start: Pos{Byte: 0, Line: 1, Column: 1}, End: Pos{Byte: 5, Line: 1, Column: 6}, }, { Start: Pos{Byte: 6, Line: 2, Column: 1}, End: Pos{Byte: 11, Line: 2, Column: 6}, }, }, [][]byte{ []byte("hello"), []byte("world"), }, }, "two lines with Windows newline": { "hello\r\nworld", []Range{ { Start: Pos{Byte: 0, Line: 1, Column: 1}, End: Pos{Byte: 5, Line: 1, Column: 6}, }, { Start: Pos{Byte: 7, Line: 2, Column: 1}, End: Pos{Byte: 12, Line: 2, Column: 6}, }, }, [][]byte{ []byte("hello"), []byte("world"), }, }, "blank line with UNIX newlines": { "hello\n\nworld", []Range{ { Start: Pos{Byte: 0, Line: 1, Column: 1}, End: Pos{Byte: 5, Line: 1, Column: 6}, }, { Start: Pos{Byte: 6, Line: 2, Column: 1}, End: Pos{Byte: 6, Line: 2, Column: 1}, }, { Start: Pos{Byte: 7, Line: 3, Column: 1}, End: Pos{Byte: 12, Line: 3, Column: 6}, }, }, [][]byte{ []byte("hello"), []byte(""), []byte("world"), }, }, "blank line with Windows newlines": { "hello\r\n\r\nworld", []Range{ { Start: Pos{Byte: 0, Line: 1, Column: 1}, End: Pos{Byte: 5, Line: 1, Column: 6}, }, { Start: Pos{Byte: 7, Line: 2, Column: 1}, End: Pos{Byte: 7, Line: 2, Column: 1}, }, { Start: Pos{Byte: 9, Line: 3, Column: 1}, End: Pos{Byte: 14, Line: 3, Column: 6}, }, }, [][]byte{ []byte("hello"), []byte(""), []byte("world"), }, }, "two lines with combiner and UNIX newline": { "foo \U0001f469\U0001f3ff bar\nbaz", []Range{ { Start: Pos{Byte: 0, Line: 1, Column: 1}, End: Pos{Byte: 16, Line: 1, Column: 10}, }, { Start: Pos{Byte: 17, Line: 2, Column: 1}, End: Pos{Byte: 20, Line: 2, Column: 4}, }, }, [][]byte{ []byte("foo \U0001f469\U0001f3ff bar"), []byte("baz"), }, }, "two lines with combiner and Windows newline": { "foo \U0001f469\U0001f3ff bar\r\nbaz", []Range{ { Start: Pos{Byte: 0, Line: 1, Column: 1}, End: Pos{Byte: 16, Line: 1, Column: 10}, }, { Start: Pos{Byte: 18, Line: 2, Column: 1}, End: Pos{Byte: 21, Line: 2, Column: 4}, }, }, [][]byte{ []byte("foo \U0001f469\U0001f3ff bar"), []byte("baz"), }, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { src := []byte(test.Input) sc := NewRangeScanner(src, "", bufio.ScanLines) got := make([]Range, 0) gotToks := make([][]byte, 0) for sc.Scan() { got = append(got, sc.Range()) gotToks = append(gotToks, sc.Bytes()) } if sc.Err() != nil { t.Fatalf("unexpected error: %s", sc.Err()) } if !reflect.DeepEqual(got, test.Want) { t.Errorf("incorrect ranges\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(test.Want)) } if !reflect.DeepEqual(gotToks, test.WantToks) { t.Errorf("incorrect tokens\ngot: %swant: %s", spew.Sdump(gotToks), spew.Sdump(test.WantToks)) } }) } }