Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions contentstream/scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,47 @@ func TestReadDictValueErrors(t *testing.T) {
})
}
}

// Every readArray element kind, including the ones TJ rarely uses (bool, null,
// name, nested array/dict).
func TestArrayMixedElementKinds(t *testing.T) {
ops := collect(t, "[42 3.14 /Nm (s) <41> true false null [1 2] << /K 9 >>] TJ")
if len(ops) != 1 || ops[0].Operator != "TJ" {
t.Fatalf("want one TJ op, got %+v", ops)
}
got := ops[0].Operands[0].Array
wantKinds := []contentstream.Kind{
contentstream.KindNumber, contentstream.KindNumber, contentstream.KindName,
contentstream.KindString, contentstream.KindString, contentstream.KindBool,
contentstream.KindBool, contentstream.KindNull, contentstream.KindArray,
contentstream.KindDict,
}
if len(got) != len(wantKinds) {
t.Fatalf("array len = %d, want %d", len(got), len(wantKinds))
}
for i, want := range wantKinds {
if got[i].Kind != want {
t.Errorf("element %d Kind = %v, want %v", i, got[i].Kind, want)
}
}
}

func TestArrayElementErrors(t *testing.T) {
for _, src := range []string{"[ foo ] n", "[1 2"} { // bad keyword in array; unterminated
t.Run(src, func(t *testing.T) {
if _, err := contentstream.New([]byte(src)).Next(); err == nil {
t.Fatal("expected an error, got nil")
}
})
}
}

// Int must report ok=false on int64 overflow (not silently wrap) and for non-numbers.
func TestOperandIntEdgeCases(t *testing.T) {
if _, ok := collect(t, "/Name n")[0].Operands[0].Int(); ok {
t.Error("name operand yielded an int")
}
if _, ok := collect(t, "99999999999999999999999999 n")[0].Operands[0].Int(); ok {
t.Error("overflowing integer literal yielded an int")
}
}
64 changes: 64 additions & 0 deletions internal/lex/lex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,67 @@ func TestLexerAccessors(t *testing.T) {
t.Errorf("Remaining = %q, want world", got)
}
}

// Literal-string escapes/newlines (§7.3.4.2) not already in TestLexerLiteralString.
func TestLexerLiteralStringEscapes(t *testing.T) {
cases := []struct {
name, in, want string
}{
{"named_escapes", "(\\t\\b\\f\\r)", "\t\b\f\r"},
{"cr_line_continuation", "(a\\\rb)", "ab"},
{"crlf_line_continuation", "(a\\\r\nb)", "ab"},
{"unknown_escape_keeps_char", "(\\q)", "q"},
{"bare_cr_to_lf", "(a\rb)", "a\nb"},
{"bare_crlf_to_lf", "(a\r\nb)", "a\nb"},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
tok, err := New([]byte(c.in)).Next()
if err != nil {
t.Fatalf("Next: %v", err)
}
if tok.Kind != LitString {
t.Fatalf("kind = %v, want LitString", tok.Kind)
}
if string(tok.Bytes) != c.want {
t.Errorf("got %q, want %q", tok.Bytes, c.want)
}
})
}
}

func TestLexerLiteralStringErrors(t *testing.T) {
for _, in := range []string{"(\\", "(abc"} { // trailing backslash; unterminated
if _, err := New([]byte(in)).Next(); err == nil {
t.Errorf("%q: expected an error, got nil", in)
}
}
}

// A misclassified delimiter byte (§7.2.2) would break tokenisation, so pin the set.
func TestIsDelimiter(t *testing.T) {
for _, c := range []byte("()<>[]{}/%") {
if !IsDelimiter(c) {
t.Errorf("IsDelimiter(%q) = false, want true", c)
}
}
for _, c := range []byte("aZ0 \t.\\") {
if IsDelimiter(c) {
t.Errorf("IsDelimiter(%q) = true, want false", c)
}
}
}

func TestHexDigit(t *testing.T) {
valid := map[byte]int{'0': 0, '9': 9, 'a': 10, 'f': 15, 'A': 10, 'F': 15}
for c, want := range valid {
if v, ok := hexDigit(c); !ok || v != want {
t.Errorf("hexDigit(%q) = (%d, %v), want (%d, true)", c, v, ok, want)
}
}
for _, c := range []byte("gG/ \x00") {
if _, ok := hexDigit(c); ok {
t.Errorf("hexDigit(%q) = ok, want not-ok", c)
}
}
}
19 changes: 19 additions & 0 deletions xref_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,3 +440,22 @@ func TestSkipEOL(t *testing.T) {
})
}
}

func TestIndexEOL(t *testing.T) {
cases := []struct {
buf string
pos int
want int
}{
{"ab\ncd", 0, 2},
{"ab\rcd", 0, 2},
{"abcd", 0, -1},
{"a\nb", 2, -1},
{"", 0, -1},
}
for _, tc := range cases {
if got := indexEOL([]byte(tc.buf), tc.pos); got != tc.want {
t.Errorf("indexEOL(%q, %d) = %d, want %d", tc.buf, tc.pos, got, tc.want)
}
}
}