github.com/whiteCcinn/protobuf-go@v1.0.9/internal/encoding/text/decode_test.go (about)

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package text_test
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"strings"
    11  	"testing"
    12  	"unicode/utf8"
    13  
    14  	"github.com/google/go-cmp/cmp"
    15  
    16  	"github.com/whiteCcinn/protobuf-go/internal/encoding/text"
    17  	"github.com/whiteCcinn/protobuf-go/internal/flags"
    18  )
    19  
    20  var eofErr = text.ErrUnexpectedEOF.Error()
    21  
    22  type R struct {
    23  	// K is expected Kind of the returned Token object from calling Decoder.Read.
    24  	K text.Kind
    25  	// E is expected error substring from calling Decoder.Read if set.
    26  	E string
    27  	// T contains NT (if K is Name) or ST (if K is Scalar) or nil (others)
    28  	T interface{}
    29  	// P is expected Token.Pos if set > 0.
    30  	P int
    31  	// RS is expected result from Token.RawString() if not empty.
    32  	RS string
    33  }
    34  
    35  // NT contains data for checking against a name token.
    36  type NT struct {
    37  	K text.NameKind
    38  	// Sep is true if name token should have separator character, else false.
    39  	Sep bool
    40  	// If K is IdentName or TypeName, invoke corresponding getter and compare against this field.
    41  	S string
    42  	// If K is FieldNumber, invoke getter and compare against this field.
    43  	N int32
    44  }
    45  
    46  // ST contains data for checking against a scalar token.
    47  type ST struct {
    48  	// checker that is expected to return OK.
    49  	ok checker
    50  	// checker that is expected to return not OK.
    51  	nok checker
    52  }
    53  
    54  // checker provides API for the token wrapper API call types Str, Enum, Bool,
    55  // Uint64, Uint32, Int64, Int32, Float64, Float32.
    56  type checker interface {
    57  	// checkOk checks and expects for token API call to return ok and compare
    58  	// against implementation-stored value. Returns empty string if success,
    59  	// else returns error message describing the error.
    60  	checkOk(text.Token) string
    61  	// checkNok checks and expects for token API call to return not ok. Returns
    62  	// empty string if success, else returns error message describing the error.
    63  	checkNok(text.Token) string
    64  }
    65  
    66  type Str struct {
    67  	val string
    68  }
    69  
    70  func (s Str) checkOk(tok text.Token) string {
    71  	got, ok := tok.String()
    72  	if !ok {
    73  		return fmt.Sprintf("Token.String() returned not OK for token: %v", tok.RawString())
    74  	}
    75  	if got != s.val {
    76  		return fmt.Sprintf("Token.String() got %q want %q for token: %v", got, s.val, tok.RawString())
    77  	}
    78  	return ""
    79  }
    80  
    81  func (s Str) checkNok(tok text.Token) string {
    82  	if _, ok := tok.String(); ok {
    83  		return fmt.Sprintf("Token.String() returned OK for token: %v", tok.RawString())
    84  	}
    85  	return ""
    86  }
    87  
    88  type Enum struct {
    89  	val string
    90  }
    91  
    92  func (e Enum) checkOk(tok text.Token) string {
    93  	got, ok := tok.Enum()
    94  	if !ok {
    95  		return fmt.Sprintf("Token.Enum() returned not OK for token: %v", tok.RawString())
    96  	}
    97  	if got != e.val {
    98  		return fmt.Sprintf("Token.Enum() got %q want %q for token: %v", got, e.val, tok.RawString())
    99  	}
   100  	return ""
   101  }
   102  
   103  func (e Enum) checkNok(tok text.Token) string {
   104  	if _, ok := tok.Enum(); ok {
   105  		return fmt.Sprintf("Token.Enum() returned OK for token: %v", tok.RawString())
   106  	}
   107  	return ""
   108  }
   109  
   110  type Bool struct {
   111  	val bool
   112  }
   113  
   114  func (b Bool) checkOk(tok text.Token) string {
   115  	got, ok := tok.Bool()
   116  	if !ok {
   117  		return fmt.Sprintf("Token.Bool() returned not OK for token: %v", tok.RawString())
   118  	}
   119  	if got != b.val {
   120  		return fmt.Sprintf("Token.Bool() got %v want %v for token: %v", got, b.val, tok.RawString())
   121  	}
   122  	return ""
   123  }
   124  
   125  func (b Bool) checkNok(tok text.Token) string {
   126  	if _, ok := tok.Bool(); ok {
   127  		return fmt.Sprintf("Token.Bool() returned OK for token: %v", tok.RawString())
   128  	}
   129  	return ""
   130  }
   131  
   132  type Uint64 struct {
   133  	val uint64
   134  }
   135  
   136  func (n Uint64) checkOk(tok text.Token) string {
   137  	got, ok := tok.Uint64()
   138  	if !ok {
   139  		return fmt.Sprintf("Token.Uint64() returned not OK for token: %v", tok.RawString())
   140  	}
   141  	if got != n.val {
   142  		return fmt.Sprintf("Token.Uint64() got %v want %v for token: %v", got, n.val, tok.RawString())
   143  	}
   144  	return ""
   145  }
   146  
   147  func (n Uint64) checkNok(tok text.Token) string {
   148  	if _, ok := tok.Uint64(); ok {
   149  		return fmt.Sprintf("Token.Uint64() returned OK for token: %v", tok.RawString())
   150  	}
   151  	return ""
   152  }
   153  
   154  type Uint32 struct {
   155  	val uint32
   156  }
   157  
   158  func (n Uint32) checkOk(tok text.Token) string {
   159  	got, ok := tok.Uint32()
   160  	if !ok {
   161  		return fmt.Sprintf("Token.Uint32() returned not OK for token: %v", tok.RawString())
   162  	}
   163  	if got != n.val {
   164  		return fmt.Sprintf("Token.Uint32() got %v want %v for token: %v", got, n.val, tok.RawString())
   165  	}
   166  	return ""
   167  }
   168  
   169  func (n Uint32) checkNok(tok text.Token) string {
   170  	if _, ok := tok.Uint32(); ok {
   171  		return fmt.Sprintf("Token.Uint32() returned OK for token: %v", tok.RawString())
   172  	}
   173  	return ""
   174  }
   175  
   176  type Int64 struct {
   177  	val int64
   178  }
   179  
   180  func (n Int64) checkOk(tok text.Token) string {
   181  	got, ok := tok.Int64()
   182  	if !ok {
   183  		return fmt.Sprintf("Token.Int64() returned not OK for token: %v", tok.RawString())
   184  	}
   185  	if got != n.val {
   186  		return fmt.Sprintf("Token.Int64() got %v want %v for token: %v", got, n.val, tok.RawString())
   187  	}
   188  	return ""
   189  }
   190  
   191  func (n Int64) checkNok(tok text.Token) string {
   192  	if _, ok := tok.Int64(); ok {
   193  		return fmt.Sprintf("Token.Int64() returned OK for token: %v", tok.RawString())
   194  	}
   195  	return ""
   196  }
   197  
   198  type Int32 struct {
   199  	val int32
   200  }
   201  
   202  func (n Int32) checkOk(tok text.Token) string {
   203  	got, ok := tok.Int32()
   204  	if !ok {
   205  		return fmt.Sprintf("Token.Int32() returned not OK for token: %v", tok.RawString())
   206  	}
   207  	if got != n.val {
   208  		return fmt.Sprintf("Token.Int32() got %v want %v for token: %v", got, n.val, tok.RawString())
   209  	}
   210  	return ""
   211  }
   212  
   213  func (n Int32) checkNok(tok text.Token) string {
   214  	if _, ok := tok.Int32(); ok {
   215  		return fmt.Sprintf("Token.Int32() returned OK for token: %v", tok.RawString())
   216  	}
   217  	return ""
   218  }
   219  
   220  type Float64 struct {
   221  	val float64
   222  }
   223  
   224  func (n Float64) checkOk(tok text.Token) string {
   225  	got, ok := tok.Float64()
   226  	if !ok {
   227  		return fmt.Sprintf("Token.Float64() returned not OK for token: %v", tok.RawString())
   228  	}
   229  	if math.Float64bits(got) != math.Float64bits(n.val) {
   230  		return fmt.Sprintf("Token.Float64() got %v want %v for token: %v", got, n.val, tok.RawString())
   231  	}
   232  	return ""
   233  }
   234  
   235  func (n Float64) checkNok(tok text.Token) string {
   236  	if _, ok := tok.Float64(); ok {
   237  		return fmt.Sprintf("Token.Float64() returned OK for token: %v", tok.RawString())
   238  	}
   239  	return ""
   240  }
   241  
   242  type Float32 struct {
   243  	val float32
   244  }
   245  
   246  func (n Float32) checkOk(tok text.Token) string {
   247  	got, ok := tok.Float32()
   248  	if !ok {
   249  		return fmt.Sprintf("Token.Float32() returned not OK for token: %v", tok.RawString())
   250  	}
   251  	if math.Float32bits(got) != math.Float32bits(n.val) {
   252  		return fmt.Sprintf("Token.Float32() got %v want %v for token: %v", got, n.val, tok.RawString())
   253  	}
   254  	return ""
   255  }
   256  
   257  func (n Float32) checkNok(tok text.Token) string {
   258  	if _, ok := tok.Float32(); ok {
   259  		return fmt.Sprintf("Token.Float32() returned OK for token: %v", tok.RawString())
   260  	}
   261  	return ""
   262  }
   263  
   264  func TestDecoder(t *testing.T) {
   265  	const space = " \n\r\t"
   266  	tests := []struct {
   267  		in string
   268  		// want is a list of expected Tokens returned from calling Decoder.Read.
   269  		// An item makes the test code invoke Decoder.Read and compare against
   270  		// R.K and R.E. If R.K is Name, it compares
   271  		want []R
   272  	}{
   273  		{
   274  			in:   "",
   275  			want: []R{{K: text.EOF}},
   276  		},
   277  		{
   278  			in:   "# comment",
   279  			want: []R{{K: text.EOF}},
   280  		},
   281  		{
   282  			in:   space + "# comment" + space,
   283  			want: []R{{K: text.EOF}},
   284  		},
   285  		{
   286  			in:   space,
   287  			want: []R{{K: text.EOF, P: len(space)}},
   288  		},
   289  		{
   290  			// Calling Read after EOF will keep returning EOF for
   291  			// succeeding Read calls.
   292  			in: space,
   293  			want: []R{
   294  				{K: text.EOF},
   295  				{K: text.EOF},
   296  				{K: text.EOF},
   297  			},
   298  		},
   299  		{
   300  			// NUL is an invalid whitespace since C++ uses C-strings.
   301  			in:   "\x00",
   302  			want: []R{{E: "invalid field name: \x00"}},
   303  		},
   304  
   305  		// Field names.
   306  		{
   307  			in: "name",
   308  			want: []R{
   309  				{K: text.Name, T: NT{K: text.IdentName, S: "name"}, RS: "name"},
   310  				{E: eofErr},
   311  			},
   312  		},
   313  		{
   314  			in: space + "name:" + space,
   315  			want: []R{
   316  				{K: text.Name, T: NT{K: text.IdentName, Sep: true, S: "name"}},
   317  				{E: eofErr},
   318  			},
   319  		},
   320  		{
   321  			in: space + "name" + space + ":" + space,
   322  			want: []R{
   323  				{K: text.Name, T: NT{K: text.IdentName, Sep: true, S: "name"}},
   324  				{E: eofErr},
   325  			},
   326  		},
   327  		{
   328  			in: "name # comment",
   329  			want: []R{
   330  				{K: text.Name, T: NT{K: text.IdentName, S: "name"}},
   331  				{E: eofErr},
   332  			},
   333  		},
   334  		{
   335  			// Comments only extend until the newline.
   336  			in: "# comment \nname",
   337  			want: []R{
   338  				{K: text.Name, T: NT{K: text.IdentName, S: "name"}, P: 11},
   339  			},
   340  		},
   341  		{
   342  			in: "name # comment \n:",
   343  			want: []R{
   344  				{K: text.Name, T: NT{K: text.IdentName, Sep: true, S: "name"}},
   345  			},
   346  		},
   347  		{
   348  			in: "name123",
   349  			want: []R{
   350  				{K: text.Name, T: NT{K: text.IdentName, S: "name123"}},
   351  			},
   352  		},
   353  		{
   354  			in: "name_123",
   355  			want: []R{
   356  				{K: text.Name, T: NT{K: text.IdentName, S: "name_123"}},
   357  			},
   358  		},
   359  		{
   360  			in: "_123",
   361  			want: []R{
   362  				{K: text.Name, T: NT{K: text.IdentName, S: "_123"}},
   363  			},
   364  		},
   365  		{
   366  			in:   ":",
   367  			want: []R{{E: "syntax error (line 1:1): invalid field name: :"}},
   368  		},
   369  		{
   370  			in:   "\n\n\n {",
   371  			want: []R{{E: "syntax error (line 4:2): invalid field name: {"}},
   372  		},
   373  		{
   374  			in:   "123name",
   375  			want: []R{{E: "invalid field name: 123name"}},
   376  		},
   377  		{
   378  			in:   `/`,
   379  			want: []R{{E: `invalid field name: /`}},
   380  		},
   381  		{
   382  			in:   `δΈ–η•Œ`,
   383  			want: []R{{E: `invalid field name: δΈ–`}},
   384  		},
   385  		{
   386  			in:   `1a/b`,
   387  			want: []R{{E: `invalid field name: 1a`}},
   388  		},
   389  		{
   390  			in:   `1c\d`,
   391  			want: []R{{E: `invalid field name: 1c`}},
   392  		},
   393  		{
   394  			in:   "\x84f",
   395  			want: []R{{E: "invalid field name: \x84"}},
   396  		},
   397  		{
   398  			in:   "\uFFFDxxx",
   399  			want: []R{{E: "invalid field name: \uFFFD"}},
   400  		},
   401  		{
   402  			in:   "-a234567890123456789012345678901234567890abc",
   403  			want: []R{{E: "invalid field name: -a2345678901234567890123456789012…"}},
   404  		},
   405  		{
   406  			in: "[type]",
   407  			want: []R{
   408  				{K: text.Name, T: NT{K: text.TypeName, S: "type"}, RS: "[type]"},
   409  			},
   410  		},
   411  		{
   412  			// V1 allows this syntax. C++ does not, however, C++ also fails if
   413  			// field is Any and does not contain '/'.
   414  			in: "[/type]",
   415  			want: []R{
   416  				{K: text.Name, T: NT{K: text.TypeName, S: "/type"}},
   417  			},
   418  		},
   419  		{
   420  			in:   "[.type]",
   421  			want: []R{{E: "invalid type URL/extension field name: [.type]"}},
   422  		},
   423  		{
   424  			in: "[pkg.Foo.extension_field]",
   425  			want: []R{
   426  				{K: text.Name, T: NT{K: text.TypeName, S: "pkg.Foo.extension_field"}},
   427  			},
   428  		},
   429  		{
   430  			in: "[domain.com/type]",
   431  			want: []R{
   432  				{K: text.Name, T: NT{K: text.TypeName, S: "domain.com/type"}},
   433  			},
   434  		},
   435  		{
   436  			in: "[domain.com/pkg.type]",
   437  			want: []R{
   438  				{K: text.Name, T: NT{K: text.TypeName, S: "domain.com/pkg.type"}},
   439  			},
   440  		},
   441  		{
   442  			in: "[sub.domain.com\x2fpath\x2fto\x2fproto.package.name]",
   443  			want: []R{
   444  				{
   445  					K: text.Name,
   446  					T: NT{
   447  						K: text.TypeName,
   448  						S: "sub.domain.com/path/to/proto.package.name",
   449  					},
   450  					RS: "[sub.domain.com\x2fpath\x2fto\x2fproto.package.name]",
   451  				},
   452  			},
   453  		},
   454  		{
   455  			// V2 no longer allows a quoted string for the Any type URL.
   456  			in:   `["domain.com/pkg.type"]`,
   457  			want: []R{{E: `invalid type URL/extension field name: ["`}},
   458  		},
   459  		{
   460  			// V2 no longer allows a quoted string for the Any type URL.
   461  			in:   `['domain.com/pkg.type']`,
   462  			want: []R{{E: `invalid type URL/extension field name: ['`}},
   463  		},
   464  		{
   465  			in:   "[pkg.Foo.extension_field:",
   466  			want: []R{{E: "invalid type URL/extension field name: [pkg.Foo.extension_field:"}},
   467  		},
   468  		{
   469  			// V2 no longer allows whitespace within identifier "word".
   470  			in:   "[proto.packa ge.field]",
   471  			want: []R{{E: "invalid type URL/extension field name: [proto.packa g"}},
   472  		},
   473  		{
   474  			// V2 no longer allows comments within identifier "word".
   475  			in:   "[proto.packa # comment\n ge.field]",
   476  			want: []R{{E: "invalid type URL/extension field name: [proto.packa # comment\n g"}},
   477  		},
   478  		{
   479  			in:   "[proto.package.]",
   480  			want: []R{{E: "invalid type URL/extension field name: [proto.package."}},
   481  		},
   482  		{
   483  			in:   "[proto.package/]",
   484  			want: []R{{E: "invalid type URL/extension field name: [proto.package/"}},
   485  		},
   486  		{
   487  			in: `message_field{[bad@]`,
   488  			want: []R{
   489  				{K: text.Name},
   490  				{K: text.MessageOpen},
   491  				{E: `invalid type URL/extension field name: [bad@`},
   492  			},
   493  		},
   494  		{
   495  			in: `message_field{[invalid//type]`,
   496  			want: []R{
   497  				{K: text.Name},
   498  				{K: text.MessageOpen},
   499  				{E: `invalid type URL/extension field name: [invalid//`},
   500  			},
   501  		},
   502  		{
   503  			in: `message_field{[proto.package.]`,
   504  			want: []R{
   505  				{K: text.Name},
   506  				{K: text.MessageOpen},
   507  				{E: `invalid type URL/extension field name: [proto.package.`},
   508  			},
   509  		},
   510  		{
   511  			in:   "[proto.package",
   512  			want: []R{{E: eofErr}},
   513  		},
   514  		{
   515  			in: "[" + space + "type" + space + "]" + space + ":",
   516  			want: []R{
   517  				{
   518  					K: text.Name,
   519  					T: NT{
   520  						K:   text.TypeName,
   521  						Sep: true,
   522  						S:   "type",
   523  					},
   524  					RS: "[" + space + "type" + space + "]",
   525  				},
   526  			},
   527  		},
   528  		{
   529  			// Whitespaces/comments are only allowed betweeb
   530  			in: "[" + space + "domain" + space + "." + space + "com # comment\n" +
   531  				"/" + "pkg" + space + "." + space + "type" + space + "]",
   532  			want: []R{
   533  				{K: text.Name, T: NT{K: text.TypeName, S: "domain.com/pkg.type"}},
   534  			},
   535  		},
   536  		{
   537  			in: "42",
   538  			want: []R{
   539  				{K: text.Name, T: NT{K: text.FieldNumber, N: 42}},
   540  			},
   541  		},
   542  		{
   543  			in:   "0x42:",
   544  			want: []R{{E: "invalid field number: 0x42"}},
   545  		},
   546  		{
   547  			in:   "042:",
   548  			want: []R{{E: "invalid field number: 042"}},
   549  		},
   550  		{
   551  			in:   "123.456:",
   552  			want: []R{{E: "invalid field number: 123.456"}},
   553  		},
   554  		{
   555  			in:   "-123",
   556  			want: []R{{E: "invalid field number: -123"}},
   557  		},
   558  		{
   559  			// Field number > math.MaxInt32.
   560  			in:   "2147483648:",
   561  			want: []R{{E: "invalid field number: 2147483648"}},
   562  		},
   563  
   564  		// String field value. More string parsing specific testing in
   565  		// TestUnmarshalString.
   566  		{
   567  			in: `name: "hello world"`,
   568  			want: []R{
   569  				{K: text.Name},
   570  				{
   571  					K:  text.Scalar,
   572  					T:  ST{ok: Str{"hello world"}, nok: Enum{}},
   573  					RS: `"hello world"`,
   574  				},
   575  				{K: text.EOF},
   576  			},
   577  		},
   578  		{
   579  			in: `name: 'hello'`,
   580  			want: []R{
   581  				{K: text.Name},
   582  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
   583  			},
   584  		},
   585  		{
   586  			in: `name: "hello'`,
   587  			want: []R{
   588  				{K: text.Name},
   589  				{E: eofErr},
   590  			},
   591  		},
   592  		{
   593  			in: `name: 'hello`,
   594  			want: []R{
   595  				{K: text.Name},
   596  				{E: eofErr},
   597  			},
   598  		},
   599  		{
   600  			// Field name without separator is ok. prototext package will need
   601  			// to determine that this is not valid for scalar values.
   602  			in: space + `name` + space + `"hello"` + space,
   603  			want: []R{
   604  				{K: text.Name},
   605  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
   606  			},
   607  		},
   608  		{
   609  			in: `name'hello'`,
   610  			want: []R{
   611  				{K: text.Name},
   612  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
   613  			},
   614  		},
   615  		{
   616  			in: `name: ` + space + `"hello"` + space + `,`,
   617  			want: []R{
   618  				{K: text.Name},
   619  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
   620  				{K: text.EOF},
   621  			},
   622  		},
   623  		{
   624  			in: `name` + space + `:` + `"hello"` + space + `;` + space,
   625  			want: []R{
   626  				{K: text.Name},
   627  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
   628  				{K: text.EOF},
   629  			},
   630  		},
   631  		{
   632  			in: `name:"hello" , ,`,
   633  			want: []R{
   634  				{K: text.Name},
   635  				{K: text.Scalar},
   636  				{E: "(line 1:16): invalid field name: ,"},
   637  			},
   638  		},
   639  		{
   640  			in: `name:"hello" , ;`,
   641  			want: []R{
   642  				{K: text.Name},
   643  				{K: text.Scalar},
   644  				{E: "(line 1:16): invalid field name: ;"},
   645  			},
   646  		},
   647  		{
   648  			in: `name:"hello" name:'world'`,
   649  			want: []R{
   650  				{K: text.Name},
   651  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
   652  				{K: text.Name},
   653  				{K: text.Scalar, T: ST{ok: Str{"world"}}},
   654  				{K: text.EOF},
   655  			},
   656  		},
   657  		{
   658  			in: `name:"hello", name:"world"`,
   659  			want: []R{
   660  				{K: text.Name},
   661  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
   662  				{K: text.Name},
   663  				{K: text.Scalar, T: ST{ok: Str{"world"}}},
   664  				{K: text.EOF},
   665  			},
   666  		},
   667  		{
   668  			in: `name:"hello"; name:"world",`,
   669  			want: []R{
   670  				{K: text.Name},
   671  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
   672  				{K: text.Name},
   673  				{K: text.Scalar, T: ST{ok: Str{"world"}}},
   674  				{K: text.EOF},
   675  			},
   676  		},
   677  		{
   678  			in: `foo:"hello"bar:"world"`,
   679  			want: []R{
   680  				{K: text.Name, T: NT{K: text.IdentName, Sep: true, S: "foo"}},
   681  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
   682  				{K: text.Name, T: NT{K: text.IdentName, Sep: true, S: "bar"}},
   683  				{K: text.Scalar, T: ST{ok: Str{"world"}}},
   684  				{K: text.EOF},
   685  			},
   686  		},
   687  		{
   688  			in: `foo:"hello"[bar]:"world"`,
   689  			want: []R{
   690  				{K: text.Name, T: NT{K: text.IdentName, Sep: true, S: "foo"}},
   691  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
   692  				{K: text.Name, T: NT{K: text.TypeName, Sep: true, S: "bar"}},
   693  				{K: text.Scalar, T: ST{ok: Str{"world"}}},
   694  				{K: text.EOF},
   695  			},
   696  		},
   697  		{
   698  			in: `name:"foo"` + space + `"bar"` + space + `'qux'`,
   699  			want: []R{
   700  				{K: text.Name, T: NT{K: text.IdentName, Sep: true, S: "name"}},
   701  				{K: text.Scalar, T: ST{ok: Str{"foobarqux"}}},
   702  				{K: text.EOF},
   703  			},
   704  		},
   705  		{
   706  			in: `name:"foo"'bar'"qux"`,
   707  			want: []R{
   708  				{K: text.Name, T: NT{K: text.IdentName, Sep: true, S: "name"}},
   709  				{K: text.Scalar, T: ST{ok: Str{"foobarqux"}}},
   710  				{K: text.EOF},
   711  			},
   712  		},
   713  		{
   714  			in: `name:"foo"` + space + `"bar" # comment` + "\n'qux' # comment",
   715  			want: []R{
   716  				{K: text.Name, T: NT{K: text.IdentName, Sep: true, S: "name"}},
   717  				{K: text.Scalar, T: ST{ok: Str{"foobarqux"}}},
   718  				{K: text.EOF},
   719  			},
   720  		},
   721  
   722  		// Lists.
   723  		{
   724  			in: `name: [`,
   725  			want: []R{
   726  				{K: text.Name},
   727  				{K: text.ListOpen},
   728  				{E: eofErr},
   729  			},
   730  		},
   731  		{
   732  			in: `name: []`,
   733  			want: []R{
   734  				{K: text.Name},
   735  				{K: text.ListOpen},
   736  				{K: text.ListClose},
   737  				{K: text.EOF},
   738  			},
   739  		},
   740  		{
   741  			in: `name []`,
   742  			want: []R{
   743  				{K: text.Name},
   744  				{K: text.ListOpen},
   745  				{K: text.ListClose},
   746  				{K: text.EOF},
   747  			},
   748  		},
   749  		{
   750  			in: `name: [,`,
   751  			want: []R{
   752  				{K: text.Name},
   753  				{K: text.ListOpen},
   754  				{E: `(line 1:8): invalid scalar value: ,`},
   755  			},
   756  		},
   757  		{
   758  			in: `name: [0`,
   759  			want: []R{
   760  				{K: text.Name},
   761  				{K: text.ListOpen},
   762  				{K: text.Scalar},
   763  				{E: eofErr},
   764  			},
   765  		},
   766  		{
   767  			in: `name: [` + space + `"hello"` + space + `]` + space,
   768  			want: []R{
   769  				{K: text.Name},
   770  				{K: text.ListOpen},
   771  				{K: text.Scalar, T: ST{ok: Str{"hello"}}, P: len(space) + 7},
   772  				{K: text.ListClose},
   773  				{K: text.EOF},
   774  			},
   775  		},
   776  		{
   777  			in: `name: ["hello",]`,
   778  			want: []R{
   779  				{K: text.Name},
   780  				{K: text.ListOpen},
   781  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
   782  				{E: `invalid scalar value: ]`},
   783  			},
   784  		},
   785  		{
   786  			in: `name: ["foo"` + space + `'bar' "qux"]`,
   787  			want: []R{
   788  				{K: text.Name},
   789  				{K: text.ListOpen},
   790  				{K: text.Scalar, T: ST{ok: Str{"foobarqux"}}},
   791  				{K: text.ListClose},
   792  				{K: text.EOF},
   793  			},
   794  		},
   795  		{
   796  			in: `name:` + space + `["foo",` + space + "'bar', # comment\n\n" + `"qux"]`,
   797  			want: []R{
   798  				{K: text.Name},
   799  				{K: text.ListOpen},
   800  				{K: text.Scalar, T: ST{ok: Str{"foo"}}},
   801  				{K: text.Scalar, T: ST{ok: Str{"bar"}}},
   802  				{K: text.Scalar, T: ST{ok: Str{"qux"}}},
   803  				{K: text.ListClose},
   804  				{K: text.EOF},
   805  			},
   806  		},
   807  
   808  		{
   809  			// List within list is not allowed.
   810  			in: `name: [[]]`,
   811  			want: []R{
   812  				{K: text.Name},
   813  				{K: text.ListOpen},
   814  				{E: `syntax error (line 1:8): invalid scalar value: [`},
   815  			},
   816  		},
   817  		{
   818  			// List items need to be separated by ,.
   819  			in: `name: ["foo" true]`,
   820  			want: []R{
   821  				{K: text.Name},
   822  				{K: text.ListOpen},
   823  				{K: text.Scalar, T: ST{ok: Str{"foo"}}},
   824  				{E: `syntax error (line 1:14): unexpected character 't'`},
   825  			},
   826  		},
   827  		{
   828  			in: `name: ["foo"; "bar"]`,
   829  			want: []R{
   830  				{K: text.Name},
   831  				{K: text.ListOpen},
   832  				{K: text.Scalar, T: ST{ok: Str{"foo"}}},
   833  				{E: `syntax error (line 1:13): unexpected character ';'`},
   834  			},
   835  		},
   836  		{
   837  			in: `name: ["foo", true, ENUM, 1.0]`,
   838  			want: []R{
   839  				{K: text.Name},
   840  				{K: text.ListOpen},
   841  				{K: text.Scalar, T: ST{ok: Str{"foo"}}},
   842  				{K: text.Scalar, T: ST{ok: Enum{"true"}}},
   843  				{K: text.Scalar, T: ST{ok: Enum{"ENUM"}}},
   844  				{K: text.Scalar, T: ST{ok: Float32{1.0}}},
   845  				{K: text.ListClose},
   846  			},
   847  		},
   848  
   849  		// Boolean literal values.
   850  		{
   851  			in: `name: True`,
   852  			want: []R{
   853  				{K: text.Name},
   854  				{
   855  					K: text.Scalar,
   856  					T: ST{ok: Bool{true}},
   857  				},
   858  				{K: text.EOF},
   859  			},
   860  		},
   861  		{
   862  			in: `name false`,
   863  			want: []R{
   864  				{K: text.Name},
   865  				{
   866  					K: text.Scalar,
   867  					T: ST{ok: Bool{false}},
   868  				},
   869  				{K: text.EOF},
   870  			},
   871  		},
   872  		{
   873  			in: `name: [t, f, True, False, true, false, 1, 0, 0x01, 0x00, 01, 00]`,
   874  			want: []R{
   875  				{K: text.Name},
   876  				{K: text.ListOpen},
   877  				{K: text.Scalar, T: ST{ok: Bool{true}}},
   878  				{K: text.Scalar, T: ST{ok: Bool{false}}},
   879  				{K: text.Scalar, T: ST{ok: Bool{true}}},
   880  				{K: text.Scalar, T: ST{ok: Bool{false}}},
   881  				{K: text.Scalar, T: ST{ok: Bool{true}}},
   882  				{K: text.Scalar, T: ST{ok: Bool{false}}},
   883  				{K: text.Scalar, T: ST{ok: Bool{true}}},
   884  				{K: text.Scalar, T: ST{ok: Bool{false}}},
   885  				{K: text.Scalar, T: ST{ok: Bool{true}}},
   886  				{K: text.Scalar, T: ST{ok: Bool{false}}},
   887  				{K: text.Scalar, T: ST{ok: Bool{true}}},
   888  				{K: text.Scalar, T: ST{ok: Bool{false}}},
   889  				{K: text.ListClose},
   890  			},
   891  		},
   892  		{
   893  			// Looks like boolean but not.
   894  			in: `name: [tRUe, falSE, -1, -0, -0x01, -0x00, -01, -00, 0.0]`,
   895  			want: []R{
   896  				{K: text.Name},
   897  				{K: text.ListOpen},
   898  				{K: text.Scalar, T: ST{nok: Bool{}}},
   899  				{K: text.Scalar, T: ST{nok: Bool{}}},
   900  				{K: text.Scalar, T: ST{nok: Bool{}}},
   901  				{K: text.Scalar, T: ST{nok: Bool{}}},
   902  				{K: text.Scalar, T: ST{nok: Bool{}}},
   903  				{K: text.Scalar, T: ST{nok: Bool{}}},
   904  				{K: text.Scalar, T: ST{nok: Bool{}}},
   905  				{K: text.Scalar, T: ST{nok: Bool{}}},
   906  				{K: text.Scalar, T: ST{nok: Bool{}}},
   907  				{K: text.ListClose},
   908  			},
   909  		},
   910  		{
   911  			in: `foo: true[bar] false`,
   912  			want: []R{
   913  				{K: text.Name},
   914  				{K: text.Scalar, T: ST{ok: Bool{true}}},
   915  				{K: text.Name},
   916  				{K: text.Scalar, T: ST{ok: Bool{false}}},
   917  			},
   918  		},
   919  
   920  		// Enum field values.
   921  		{
   922  			in: space + `name: ENUM`,
   923  			want: []R{
   924  				{K: text.Name},
   925  				{K: text.Scalar, T: ST{ok: Enum{"ENUM"}}},
   926  			},
   927  		},
   928  		{
   929  			in: space + `name:[TRUE, FALSE, T, F, t, f]`,
   930  			want: []R{
   931  				{K: text.Name},
   932  				{K: text.ListOpen},
   933  				{K: text.Scalar, T: ST{ok: Enum{"TRUE"}}},
   934  				{K: text.Scalar, T: ST{ok: Enum{"FALSE"}}},
   935  				{K: text.Scalar, T: ST{ok: Enum{"T"}}},
   936  				{K: text.Scalar, T: ST{ok: Enum{"F"}}},
   937  				{K: text.Scalar, T: ST{ok: Enum{"t"}}},
   938  				{K: text.Scalar, T: ST{ok: Enum{"f"}}},
   939  				{K: text.ListClose},
   940  			},
   941  		},
   942  		{
   943  			in: `foo: Enum1[bar]:Enum2`,
   944  			want: []R{
   945  				{K: text.Name},
   946  				{K: text.Scalar, T: ST{ok: Enum{"Enum1"}}},
   947  				{K: text.Name},
   948  				{K: text.Scalar, T: ST{ok: Enum{"Enum2"}}},
   949  			},
   950  		},
   951  		{
   952  			// Invalid enum values.
   953  			in: `name: [-inf, -foo, "string", 42, 1.0, 0x47]`,
   954  			want: []R{
   955  				{K: text.Name},
   956  				{K: text.ListOpen},
   957  				{K: text.Scalar, T: ST{nok: Enum{}}},
   958  				{K: text.Scalar, T: ST{nok: Enum{}}},
   959  				{K: text.Scalar, T: ST{nok: Enum{}}},
   960  				{K: text.Scalar, T: ST{nok: Enum{}}},
   961  				{K: text.Scalar, T: ST{nok: Enum{}}},
   962  				{K: text.Scalar, T: ST{nok: Enum{}}},
   963  				{K: text.ListClose},
   964  			},
   965  		},
   966  		{
   967  			in: `name: true.`,
   968  			want: []R{
   969  				{K: text.Name},
   970  				{E: `invalid scalar value: true.`},
   971  			},
   972  		},
   973  
   974  		// Numeric values.
   975  		{
   976  			in: `nums:42 nums:0x2A nums:052`,
   977  			want: []R{
   978  				{K: text.Name},
   979  				{K: text.Scalar, T: ST{ok: Uint64{42}}},
   980  				{K: text.Name},
   981  				{K: text.Scalar, T: ST{ok: Uint64{42}}},
   982  				{K: text.Name},
   983  				{K: text.Scalar, T: ST{ok: Uint64{42}}},
   984  			},
   985  		},
   986  		{
   987  			in: `nums:[-42, -0x2a, -052]`,
   988  			want: []R{
   989  				{K: text.Name},
   990  				{K: text.ListOpen},
   991  				{K: text.Scalar, T: ST{nok: Uint64{}}},
   992  				{K: text.Scalar, T: ST{nok: Uint64{}}},
   993  				{K: text.Scalar, T: ST{nok: Uint64{}}},
   994  				{K: text.ListClose},
   995  			},
   996  		},
   997  		{
   998  			in: `nums:[-42, -0x2a, -052]`,
   999  			want: []R{
  1000  				{K: text.Name},
  1001  				{K: text.ListOpen},
  1002  				{K: text.Scalar, T: ST{ok: Int64{-42}}},
  1003  				{K: text.Scalar, T: ST{ok: Int64{-42}}},
  1004  				{K: text.Scalar, T: ST{ok: Int64{-42}}},
  1005  				{K: text.ListClose},
  1006  			},
  1007  		},
  1008  		{
  1009  			in: `nums: [0,0x0,00,-9876543210,9876543210,0x0123456789abcdef,-0x0123456789abcdef,01234567,-01234567]`,
  1010  			want: []R{
  1011  				{K: text.Name},
  1012  				{K: text.ListOpen},
  1013  				{K: text.Scalar, T: ST{ok: Uint64{0}}},
  1014  				{K: text.Scalar, T: ST{ok: Int64{0}}},
  1015  				{K: text.Scalar, T: ST{ok: Uint64{0}}},
  1016  				{K: text.Scalar, T: ST{ok: Int64{-9876543210}}},
  1017  				{K: text.Scalar, T: ST{ok: Uint64{9876543210}}},
  1018  				{K: text.Scalar, T: ST{ok: Uint64{0x0123456789abcdef}}},
  1019  				{K: text.Scalar, T: ST{ok: Int64{-0x0123456789abcdef}}},
  1020  				{K: text.Scalar, T: ST{ok: Uint64{01234567}}},
  1021  				{K: text.Scalar, T: ST{ok: Int64{-01234567}}},
  1022  				{K: text.ListClose},
  1023  			},
  1024  		},
  1025  		{
  1026  			in: `nums: [0,0x0,00,-876543210,876543210,0x01234,-0x01234,01234567,-01234567]`,
  1027  			want: []R{
  1028  				{K: text.Name},
  1029  				{K: text.ListOpen},
  1030  				{K: text.Scalar, T: ST{ok: Uint32{0}}},
  1031  				{K: text.Scalar, T: ST{ok: Int32{0}}},
  1032  				{K: text.Scalar, T: ST{ok: Uint32{0}}},
  1033  				{K: text.Scalar, T: ST{ok: Int32{-876543210}}},
  1034  				{K: text.Scalar, T: ST{ok: Uint32{876543210}}},
  1035  				{K: text.Scalar, T: ST{ok: Uint32{0x01234}}},
  1036  				{K: text.Scalar, T: ST{ok: Int32{-0x01234}}},
  1037  				{K: text.Scalar, T: ST{ok: Uint32{01234567}}},
  1038  				{K: text.Scalar, T: ST{ok: Int32{-01234567}}},
  1039  				{K: text.ListClose},
  1040  			},
  1041  		},
  1042  		{
  1043  			in: `nums: [` +
  1044  				fmt.Sprintf("%d", uint64(math.MaxUint64)) + `,` +
  1045  				fmt.Sprintf("%d", uint32(math.MaxUint32)) + `,` +
  1046  				fmt.Sprintf("%d", int64(math.MaxInt64)) + `,` +
  1047  				fmt.Sprintf("%d", int64(math.MinInt64)) + `,` +
  1048  				fmt.Sprintf("%d", int32(math.MaxInt32)) + `,` +
  1049  				fmt.Sprintf("%d", int32(math.MinInt32)) +
  1050  				`]`,
  1051  			want: []R{
  1052  				{K: text.Name},
  1053  				{K: text.ListOpen},
  1054  				{K: text.Scalar, T: ST{ok: Uint64{math.MaxUint64}}},
  1055  				{K: text.Scalar, T: ST{ok: Uint32{math.MaxUint32}}},
  1056  				{K: text.Scalar, T: ST{ok: Int64{math.MaxInt64}}},
  1057  				{K: text.Scalar, T: ST{ok: Int64{math.MinInt64}}},
  1058  				{K: text.Scalar, T: ST{ok: Int32{math.MaxInt32}}},
  1059  				{K: text.Scalar, T: ST{ok: Int32{math.MinInt32}}},
  1060  				{K: text.ListClose},
  1061  			},
  1062  		},
  1063  		{
  1064  			// Integer exceeds range.
  1065  			in: `nums: [` +
  1066  				`18446744073709551616,` + // max uint64 + 1
  1067  				fmt.Sprintf("%d", uint64(math.MaxUint32+1)) + `,` +
  1068  				fmt.Sprintf("%d", uint64(math.MaxInt64+1)) + `,` +
  1069  				`-9223372036854775809,` + // min int64 - 1
  1070  				fmt.Sprintf("%d", uint64(math.MaxInt32+1)) + `,` +
  1071  				fmt.Sprintf("%d", int64(math.MinInt32-1)) + `` +
  1072  				`]`,
  1073  			want: []R{
  1074  				{K: text.Name},
  1075  				{K: text.ListOpen},
  1076  				{K: text.Scalar, T: ST{nok: Uint64{}}},
  1077  				{K: text.Scalar, T: ST{nok: Uint32{}}},
  1078  				{K: text.Scalar, T: ST{nok: Int64{}}},
  1079  				{K: text.Scalar, T: ST{nok: Int64{}}},
  1080  				{K: text.Scalar, T: ST{nok: Int32{}}},
  1081  				{K: text.Scalar, T: ST{nok: Int32{}}},
  1082  				{K: text.ListClose},
  1083  			},
  1084  		},
  1085  		{
  1086  			in: `nums: [0xbeefbeef, 0xbeefbeefbeefbeef]`,
  1087  			want: []R{
  1088  				{K: text.Name},
  1089  				{K: text.ListOpen},
  1090  				{
  1091  					K: text.Scalar,
  1092  					T: func() ST {
  1093  						if flags.ProtoLegacy {
  1094  							return ST{ok: Int32{-1091584273}}
  1095  						}
  1096  						return ST{nok: Int32{}}
  1097  					}(),
  1098  				},
  1099  				{
  1100  					K: text.Scalar,
  1101  					T: func() ST {
  1102  						if flags.ProtoLegacy {
  1103  							return ST{ok: Int64{-4688318750159552785}}
  1104  						}
  1105  						return ST{nok: Int64{}}
  1106  					}(),
  1107  				},
  1108  				{K: text.ListClose},
  1109  			},
  1110  		},
  1111  		{
  1112  			in: `nums: [0.,0f,1f,10f,-0f,-1f,-10f,1.0,0.1e-3,1.5e+5,1e10,.0]`,
  1113  			want: []R{
  1114  				{K: text.Name},
  1115  				{K: text.ListOpen},
  1116  				{K: text.Scalar, T: ST{ok: Float64{0.0}}},
  1117  				{K: text.Scalar, T: ST{ok: Float64{0.0}}},
  1118  				{K: text.Scalar, T: ST{ok: Float64{1.0}}},
  1119  				{K: text.Scalar, T: ST{ok: Float64{10.0}}},
  1120  				{K: text.Scalar, T: ST{ok: Float64{math.Copysign(0, -1)}}},
  1121  				{K: text.Scalar, T: ST{ok: Float64{-1.0}}},
  1122  				{K: text.Scalar, T: ST{ok: Float64{-10.0}}},
  1123  				{K: text.Scalar, T: ST{ok: Float64{1.0}}},
  1124  				{K: text.Scalar, T: ST{ok: Float64{0.1e-3}}},
  1125  				{K: text.Scalar, T: ST{ok: Float64{1.5e+5}}},
  1126  				{K: text.Scalar, T: ST{ok: Float64{1.0e+10}}},
  1127  				{K: text.Scalar, T: ST{ok: Float64{0.0}}},
  1128  				{K: text.ListClose},
  1129  			},
  1130  		},
  1131  		{
  1132  			in: `nums: [0.,0f,1f,10f,-0f,-1f,-10f,1.0,0.1e-3,1.5e+5,1e10,.0]`,
  1133  			want: []R{
  1134  				{K: text.Name},
  1135  				{K: text.ListOpen},
  1136  				{K: text.Scalar, T: ST{ok: Float32{0.0}}},
  1137  				{K: text.Scalar, T: ST{ok: Float32{0.0}}},
  1138  				{K: text.Scalar, T: ST{ok: Float32{1.0}}},
  1139  				{K: text.Scalar, T: ST{ok: Float32{10.0}}},
  1140  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Copysign(0, -1))}}},
  1141  				{K: text.Scalar, T: ST{ok: Float32{-1.0}}},
  1142  				{K: text.Scalar, T: ST{ok: Float32{-10.0}}},
  1143  				{K: text.Scalar, T: ST{ok: Float32{1.0}}},
  1144  				{K: text.Scalar, T: ST{ok: Float32{0.1e-3}}},
  1145  				{K: text.Scalar, T: ST{ok: Float32{1.5e+5}}},
  1146  				{K: text.Scalar, T: ST{ok: Float32{1.0e+10}}},
  1147  				{K: text.Scalar, T: ST{ok: Float32{0.0}}},
  1148  				{K: text.ListClose},
  1149  			},
  1150  		},
  1151  		{
  1152  			in: `nums: [0.,1f,10F,1e1,1.10]`,
  1153  			want: []R{
  1154  				{K: text.Name},
  1155  				{K: text.ListOpen},
  1156  				{K: text.Scalar, T: ST{nok: Int64{}}},
  1157  				{K: text.Scalar, T: ST{nok: Int64{}}},
  1158  				{K: text.Scalar, T: ST{nok: Int64{}}},
  1159  				{K: text.Scalar, T: ST{nok: Int64{}}},
  1160  				{K: text.Scalar, T: ST{nok: Int64{}}},
  1161  				{K: text.ListClose},
  1162  			},
  1163  		},
  1164  		{
  1165  			in: `nums: [0.,1f,10F,1e1,1.10]`,
  1166  			want: []R{
  1167  				{K: text.Name},
  1168  				{K: text.ListOpen},
  1169  				{K: text.Scalar, T: ST{nok: Int32{}}},
  1170  				{K: text.Scalar, T: ST{nok: Int32{}}},
  1171  				{K: text.Scalar, T: ST{nok: Int32{}}},
  1172  				{K: text.Scalar, T: ST{nok: Int32{}}},
  1173  				{K: text.Scalar, T: ST{nok: Int32{}}},
  1174  				{K: text.ListClose},
  1175  			},
  1176  		},
  1177  		{
  1178  			in: `nums: [0.,1f,10F,1e1,1.10]`,
  1179  			want: []R{
  1180  				{K: text.Name},
  1181  				{K: text.ListOpen},
  1182  				{K: text.Scalar, T: ST{nok: Uint64{}}},
  1183  				{K: text.Scalar, T: ST{nok: Uint64{}}},
  1184  				{K: text.Scalar, T: ST{nok: Uint64{}}},
  1185  				{K: text.Scalar, T: ST{nok: Uint64{}}},
  1186  				{K: text.Scalar, T: ST{nok: Uint64{}}},
  1187  				{K: text.ListClose},
  1188  			},
  1189  		},
  1190  		{
  1191  			in: `nums: [0.,1f,10F,1e1,1.10]`,
  1192  			want: []R{
  1193  				{K: text.Name},
  1194  				{K: text.ListOpen},
  1195  				{K: text.Scalar, T: ST{nok: Uint32{}}},
  1196  				{K: text.Scalar, T: ST{nok: Uint32{}}},
  1197  				{K: text.Scalar, T: ST{nok: Uint32{}}},
  1198  				{K: text.Scalar, T: ST{nok: Uint32{}}},
  1199  				{K: text.Scalar, T: ST{nok: Uint32{}}},
  1200  				{K: text.ListClose},
  1201  			},
  1202  		},
  1203  		{
  1204  			in: `nums: [` +
  1205  				fmt.Sprintf("%g", math.MaxFloat32) + `,` +
  1206  				fmt.Sprintf("%g", -math.MaxFloat32) + `,` +
  1207  				fmt.Sprintf("%g", math.MaxFloat32*2) + `,` +
  1208  				fmt.Sprintf("%g", -math.MaxFloat32*2) + `,` +
  1209  				`3.59539e+308,` + // math.MaxFloat64 * 2
  1210  				`-3.59539e+308,` + // -math.MaxFloat64 * 2
  1211  				fmt.Sprintf("%d000", uint64(math.MaxUint64)) +
  1212  				`]`,
  1213  			want: []R{
  1214  				{K: text.Name},
  1215  				{K: text.ListOpen},
  1216  				{K: text.Scalar, T: ST{ok: Float32{float32(math.MaxFloat32)}}},
  1217  				{K: text.Scalar, T: ST{ok: Float32{float32(-math.MaxFloat32)}}},
  1218  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(1))}}},
  1219  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(-1))}}},
  1220  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(1))}}},
  1221  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(-1))}}},
  1222  				{K: text.Scalar, T: ST{ok: Float32{float32(math.MaxUint64) * 1000}}},
  1223  				{K: text.ListClose},
  1224  			},
  1225  		},
  1226  		{
  1227  			in: `nums: [` +
  1228  				fmt.Sprintf("%g", math.MaxFloat64) + `,` +
  1229  				fmt.Sprintf("%g", -math.MaxFloat64) + `,` +
  1230  				`3.59539e+308,` + // math.MaxFloat64 * 2
  1231  				`-3.59539e+308,` + // -math.MaxFloat64 * 2
  1232  				fmt.Sprintf("%d000", uint64(math.MaxUint64)) +
  1233  				`]`,
  1234  			want: []R{
  1235  				{K: text.Name},
  1236  				{K: text.ListOpen},
  1237  				{K: text.Scalar, T: ST{ok: Float64{math.MaxFloat64}}},
  1238  				{K: text.Scalar, T: ST{ok: Float64{-math.MaxFloat64}}},
  1239  				{K: text.Scalar, T: ST{ok: Float64{math.Inf(1)}}},
  1240  				{K: text.Scalar, T: ST{ok: Float64{math.Inf(-1)}}},
  1241  				{K: text.Scalar, T: ST{ok: Float64{float64(math.MaxUint64) * 1000}}},
  1242  				{K: text.ListClose},
  1243  			},
  1244  		},
  1245  		{
  1246  			// -0 is only valid for signed types. It is not valid for unsigned types.
  1247  			in: `num: [-0, -0]`,
  1248  			want: []R{
  1249  				{K: text.Name},
  1250  				{K: text.ListOpen},
  1251  				{K: text.Scalar, T: ST{nok: Uint32{}}},
  1252  				{K: text.Scalar, T: ST{nok: Uint64{}}},
  1253  				{K: text.ListClose},
  1254  			},
  1255  		},
  1256  		{
  1257  			// -0 is only valid for signed types. It is not valid for unsigned types.
  1258  			in: `num: [-0, -0]`,
  1259  			want: []R{
  1260  				{K: text.Name},
  1261  				{K: text.ListOpen},
  1262  				{K: text.Scalar, T: ST{ok: Int32{0}}},
  1263  				{K: text.Scalar, T: ST{ok: Int64{0}}},
  1264  				{K: text.ListClose},
  1265  			},
  1266  		},
  1267  		{
  1268  			// Negative zeros on float64 should preserve sign bit.
  1269  			in: `num: [-0, -.0]`,
  1270  			want: []R{
  1271  				{K: text.Name},
  1272  				{K: text.ListOpen},
  1273  				{K: text.Scalar, T: ST{ok: Float64{math.Copysign(0, -1)}}},
  1274  				{K: text.Scalar, T: ST{ok: Float64{math.Copysign(0, -1)}}},
  1275  				{K: text.ListClose},
  1276  			},
  1277  		},
  1278  		{
  1279  			// Negative zeros on float32 should preserve sign bit.
  1280  			in: `num: [-0, -.0]`,
  1281  			want: []R{
  1282  				{K: text.Name},
  1283  				{K: text.ListOpen},
  1284  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Copysign(0, -1))}}},
  1285  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Copysign(0, -1))}}},
  1286  				{K: text.ListClose},
  1287  			},
  1288  		},
  1289  		{
  1290  			in: `num: +0`,
  1291  			want: []R{
  1292  				{K: text.Name},
  1293  				{E: `invalid scalar value: +`},
  1294  			},
  1295  		},
  1296  		{
  1297  			in: `num: 01.1234`,
  1298  			want: []R{
  1299  				{K: text.Name},
  1300  				{E: `invalid scalar value: 01.1234`},
  1301  			},
  1302  		},
  1303  		{
  1304  			in: `num: 0x`,
  1305  			want: []R{
  1306  				{K: text.Name},
  1307  				{E: `invalid scalar value: 0x`},
  1308  			},
  1309  		},
  1310  		{
  1311  			in: `num: 0xX`,
  1312  			want: []R{
  1313  				{K: text.Name},
  1314  				{E: `invalid scalar value: 0xX`},
  1315  			},
  1316  		},
  1317  		{
  1318  			in: `num: 0800`,
  1319  			want: []R{
  1320  				{K: text.Name},
  1321  				{E: `invalid scalar value: 0800`},
  1322  			},
  1323  		},
  1324  		{
  1325  			in: `num: 1.`,
  1326  			want: []R{
  1327  				{K: text.Name},
  1328  				{K: text.Scalar, T: ST{ok: Float32{1.0}}},
  1329  			},
  1330  		},
  1331  		{
  1332  			in: `num: -.`,
  1333  			want: []R{
  1334  				{K: text.Name},
  1335  				{E: `invalid scalar value: -.`},
  1336  			},
  1337  		},
  1338  
  1339  		// Float special literal values, case-insensitive match.
  1340  		{
  1341  			in: `name:[nan, NaN, Nan, NAN]`,
  1342  			want: []R{
  1343  				{K: text.Name},
  1344  				{K: text.ListOpen},
  1345  				{K: text.Scalar, T: ST{ok: Float64{math.NaN()}}},
  1346  				{K: text.Scalar, T: ST{ok: Float64{math.NaN()}}},
  1347  				{K: text.Scalar, T: ST{ok: Float64{math.NaN()}}},
  1348  				{K: text.Scalar, T: ST{ok: Float64{math.NaN()}}},
  1349  				{K: text.ListClose},
  1350  			},
  1351  		},
  1352  		{
  1353  			in: `name:[inf, INF, infinity, Infinity, INFinity]`,
  1354  			want: []R{
  1355  				{K: text.Name},
  1356  				{K: text.ListOpen},
  1357  				{K: text.Scalar, T: ST{ok: Float64{math.Inf(1)}}},
  1358  				{K: text.Scalar, T: ST{ok: Float64{math.Inf(1)}}},
  1359  				{K: text.Scalar, T: ST{ok: Float64{math.Inf(1)}}},
  1360  				{K: text.Scalar, T: ST{ok: Float64{math.Inf(1)}}},
  1361  				{K: text.Scalar, T: ST{ok: Float64{math.Inf(1)}}},
  1362  				{K: text.ListClose},
  1363  			},
  1364  		},
  1365  		{
  1366  			in: `name:[-inf, -INF, -infinity, -Infinity, -INFinity]`,
  1367  			want: []R{
  1368  				{K: text.Name},
  1369  				{K: text.ListOpen},
  1370  				{K: text.Scalar, T: ST{ok: Float64{math.Inf(-1)}}},
  1371  				{K: text.Scalar, T: ST{ok: Float64{math.Inf(-1)}}},
  1372  				{K: text.Scalar, T: ST{ok: Float64{math.Inf(-1)}}},
  1373  				{K: text.Scalar, T: ST{ok: Float64{math.Inf(-1)}}},
  1374  				{K: text.Scalar, T: ST{ok: Float64{math.Inf(-1)}}},
  1375  				{K: text.ListClose},
  1376  			},
  1377  		},
  1378  		{
  1379  			in: `name:[nan, NaN, Nan, NAN]`,
  1380  			want: []R{
  1381  				{K: text.Name},
  1382  				{K: text.ListOpen},
  1383  				{K: text.Scalar, T: ST{ok: Float32{float32(math.NaN())}}},
  1384  				{K: text.Scalar, T: ST{ok: Float32{float32(math.NaN())}}},
  1385  				{K: text.Scalar, T: ST{ok: Float32{float32(math.NaN())}}},
  1386  				{K: text.Scalar, T: ST{ok: Float32{float32(math.NaN())}}},
  1387  				{K: text.ListClose},
  1388  			},
  1389  		},
  1390  		{
  1391  			in: `name:[inf, INF, infinity, Infinity, INFinity]`,
  1392  			want: []R{
  1393  				{K: text.Name},
  1394  				{K: text.ListOpen},
  1395  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(1))}}},
  1396  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(1))}}},
  1397  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(1))}}},
  1398  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(1))}}},
  1399  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(1))}}},
  1400  				{K: text.ListClose},
  1401  			},
  1402  		},
  1403  		{
  1404  			in: `name:[-inf, -INF, -infinity, -Infinity, -INFinity]`,
  1405  			want: []R{
  1406  				{K: text.Name},
  1407  				{K: text.ListOpen},
  1408  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(-1))}}},
  1409  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(-1))}}},
  1410  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(-1))}}},
  1411  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(-1))}}},
  1412  				{K: text.Scalar, T: ST{ok: Float32{float32(math.Inf(-1))}}},
  1413  				{K: text.ListClose},
  1414  			},
  1415  		},
  1416  		{
  1417  			// C++ permits this, but we currently reject this. It is easy to add
  1418  			// if needed.
  1419  			in: `name: -nan`,
  1420  			want: []R{
  1421  				{K: text.Name},
  1422  				{K: text.Scalar, T: ST{nok: Float64{}}},
  1423  			},
  1424  		},
  1425  		// Messages.
  1426  		{
  1427  			in: `m: {}`,
  1428  			want: []R{
  1429  				{K: text.Name},
  1430  				{K: text.MessageOpen},
  1431  				{K: text.MessageClose},
  1432  				{K: text.EOF},
  1433  			},
  1434  		},
  1435  		{
  1436  			in: `m: <>`,
  1437  			want: []R{
  1438  				{K: text.Name},
  1439  				{K: text.MessageOpen},
  1440  				{K: text.MessageClose},
  1441  				{K: text.EOF},
  1442  			},
  1443  		},
  1444  		{
  1445  			in: space + `m {` + space + "\n# comment\n" + `}` + space,
  1446  			want: []R{
  1447  				{K: text.Name},
  1448  				{K: text.MessageOpen},
  1449  				{K: text.MessageClose},
  1450  			},
  1451  		},
  1452  		{
  1453  			in: `m { foo: < bar: "hello" > }`,
  1454  			want: []R{
  1455  				{K: text.Name, RS: "m"},
  1456  				{K: text.MessageOpen},
  1457  
  1458  				{K: text.Name, RS: "foo"},
  1459  				{K: text.MessageOpen},
  1460  
  1461  				{K: text.Name, RS: "bar"},
  1462  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
  1463  
  1464  				{K: text.MessageClose},
  1465  
  1466  				{K: text.MessageClose},
  1467  			},
  1468  		},
  1469  		{
  1470  			in: `list [ <s:"hello">, {s:"world"} ]`,
  1471  			want: []R{
  1472  				{K: text.Name, RS: "list"},
  1473  				{K: text.ListOpen},
  1474  
  1475  				{K: text.MessageOpen},
  1476  				{K: text.Name, RS: "s"},
  1477  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
  1478  				{K: text.MessageClose},
  1479  
  1480  				{K: text.MessageOpen},
  1481  				{K: text.Name, RS: "s"},
  1482  				{K: text.Scalar, T: ST{ok: Str{"world"}}},
  1483  				{K: text.MessageClose},
  1484  
  1485  				{K: text.ListClose},
  1486  				{K: text.EOF},
  1487  			},
  1488  		},
  1489  		{
  1490  			in: `m: { >`,
  1491  			want: []R{
  1492  				{K: text.Name},
  1493  				{K: text.MessageOpen},
  1494  				{E: `mismatched close character '>'`},
  1495  			},
  1496  		},
  1497  		{
  1498  			in: `m: <s: "hello"}`,
  1499  			want: []R{
  1500  				{K: text.Name},
  1501  				{K: text.MessageOpen},
  1502  
  1503  				{K: text.Name},
  1504  				{K: text.Scalar, T: ST{ok: Str{"hello"}}},
  1505  
  1506  				{E: `mismatched close character '}'`},
  1507  			},
  1508  		},
  1509  		{
  1510  			in:   `{}`,
  1511  			want: []R{{E: `invalid field name: {`}},
  1512  		},
  1513  		{
  1514  			in: `
  1515  m: {
  1516    foo: true;
  1517    bar: {
  1518  	enum: ENUM
  1519  	list: [ < >, { } ] ;
  1520    }
  1521    [qux]: "end"
  1522  }
  1523  				`,
  1524  			want: []R{
  1525  				{K: text.Name},
  1526  				{K: text.MessageOpen},
  1527  
  1528  				{K: text.Name, RS: "foo"},
  1529  				{K: text.Scalar, T: ST{ok: Bool{true}}},
  1530  
  1531  				{K: text.Name, RS: "bar"},
  1532  				{K: text.MessageOpen},
  1533  
  1534  				{K: text.Name, RS: "enum"},
  1535  				{K: text.Scalar, T: ST{ok: Enum{"ENUM"}}},
  1536  
  1537  				{K: text.Name, RS: "list"},
  1538  				{K: text.ListOpen},
  1539  				{K: text.MessageOpen},
  1540  				{K: text.MessageClose},
  1541  				{K: text.MessageOpen},
  1542  				{K: text.MessageClose},
  1543  				{K: text.ListClose},
  1544  
  1545  				{K: text.MessageClose},
  1546  
  1547  				{K: text.Name, RS: "[qux]"},
  1548  				{K: text.Scalar, T: ST{ok: Str{"end"}}},
  1549  
  1550  				{K: text.MessageClose},
  1551  				{K: text.EOF},
  1552  			},
  1553  		},
  1554  
  1555  		// Other syntax errors.
  1556  		{
  1557  			in: "x: -",
  1558  			want: []R{
  1559  				{K: text.Name},
  1560  				{E: `syntax error (line 1:4): invalid scalar value: -`},
  1561  			},
  1562  		},
  1563  		{
  1564  			in: "x:[\"πŸ’©\"x",
  1565  			want: []R{
  1566  				{K: text.Name},
  1567  				{K: text.ListOpen},
  1568  				{K: text.Scalar, T: ST{ok: Str{"πŸ’©"}}, P: 3},
  1569  				{E: `syntax error (line 1:7)`},
  1570  			},
  1571  		},
  1572  		{
  1573  			in: "x:\n\n[\"πŸ”₯πŸ”₯πŸ”₯\"x",
  1574  			want: []R{
  1575  				{K: text.Name},
  1576  				{K: text.ListOpen},
  1577  				{K: text.Scalar, T: ST{ok: Str{"πŸ”₯πŸ”₯πŸ”₯"}}, P: 5},
  1578  				{E: `syntax error (line 3:7)`},
  1579  			},
  1580  		},
  1581  		{
  1582  			// multi-rune emojis; could be column:8
  1583  			in: "x:[\"πŸ‘πŸ»πŸ‘πŸΏ\"x",
  1584  			want: []R{
  1585  				{K: text.Name},
  1586  				{K: text.ListOpen},
  1587  				{K: text.Scalar, T: ST{ok: Str{"πŸ‘πŸ»πŸ‘πŸΏ"}}, P: 3},
  1588  				{E: `syntax error (line 1:10)`},
  1589  			},
  1590  		},
  1591  	}
  1592  
  1593  	for _, tc := range tests {
  1594  		t.Run("", func(t *testing.T) {
  1595  			tc := tc
  1596  			in := []byte(tc.in)
  1597  			dec := text.NewDecoder(in[:len(in):len(in)])
  1598  			for i, want := range tc.want {
  1599  				peekTok, peekErr := dec.Peek()
  1600  				tok, err := dec.Read()
  1601  				if err != nil {
  1602  					if want.E == "" {
  1603  						errorf(t, tc.in, "Read() got unexpected error: %v", err)
  1604  					} else if !strings.Contains(err.Error(), want.E) {
  1605  						errorf(t, tc.in, "Read() got %q, want %q", err, want.E)
  1606  					}
  1607  					return
  1608  				}
  1609  				if want.E != "" {
  1610  					errorf(t, tc.in, "Read() got nil error, want %q", want.E)
  1611  					return
  1612  				}
  1613  				gotK := tok.Kind()
  1614  				if gotK != want.K {
  1615  					errorf(t, tc.in, "Read() got %v, want %v", gotK, want.K)
  1616  					return
  1617  				}
  1618  				checkToken(t, tok, i, want, tc.in)
  1619  				if !cmp.Equal(tok, peekTok, cmp.Comparer(text.TokenEquals)) {
  1620  					errorf(t, tc.in, "Peek() %+v != Read() token %+v", peekTok, tok)
  1621  				}
  1622  				if err != peekErr {
  1623  					errorf(t, tc.in, "Peek() error %v != Read() error %v", err, peekErr)
  1624  				}
  1625  			}
  1626  		})
  1627  	}
  1628  }
  1629  
  1630  func checkToken(t *testing.T, tok text.Token, idx int, r R, in string) {
  1631  	// Validate Token.Pos() if R.P is set.
  1632  	if r.P > 0 {
  1633  		got := tok.Pos()
  1634  		if got != r.P {
  1635  			errorf(t, in, "want#%d: Token.Pos() got %v want %v", idx, got, r.P)
  1636  		}
  1637  	}
  1638  
  1639  	// Validate Token.RawString if R.RS is set.
  1640  	if len(r.RS) > 0 {
  1641  		got := tok.RawString()
  1642  		if got != r.RS {
  1643  			errorf(t, in, "want#%d: Token.RawString() got %v want %v", idx, got, r.P)
  1644  		}
  1645  	}
  1646  
  1647  	// Skip checking for Token details if r.T is not set.
  1648  	if r.T == nil {
  1649  		return
  1650  	}
  1651  
  1652  	switch tok.Kind() {
  1653  	case text.Name:
  1654  		want := r.T.(NT)
  1655  		kind := tok.NameKind()
  1656  		if kind != want.K {
  1657  			errorf(t, in, "want#%d: Token.NameKind() got %v want %v", idx, kind, want.K)
  1658  			return
  1659  		}
  1660  		switch kind {
  1661  		case text.IdentName:
  1662  			got := tok.IdentName()
  1663  			if got != want.S {
  1664  				errorf(t, in, "want#%d: Token.IdentName() got %v want %v", idx, got, want.S)
  1665  			}
  1666  		case text.TypeName:
  1667  			got := tok.TypeName()
  1668  			if got != want.S {
  1669  				errorf(t, in, "want#%d: Token.TypeName() got %v want %v", idx, got, want.S)
  1670  			}
  1671  		case text.FieldNumber:
  1672  			got := tok.FieldNumber()
  1673  			if got != want.N {
  1674  				errorf(t, in, "want#%d: Token.FieldNumber() got %v want %v", idx, got, want.N)
  1675  			}
  1676  		}
  1677  
  1678  	case text.Scalar:
  1679  		want := r.T.(ST)
  1680  		if ok := want.ok; ok != nil {
  1681  			if err := ok.checkOk(tok); err != "" {
  1682  				errorf(t, in, "want#%d: %s", idx, err)
  1683  			}
  1684  		}
  1685  		if nok := want.nok; nok != nil {
  1686  			if err := nok.checkNok(tok); err != "" {
  1687  				errorf(t, in, "want#%d: %s", idx, err)
  1688  			}
  1689  		}
  1690  	}
  1691  }
  1692  
  1693  func errorf(t *testing.T, in string, fmtStr string, args ...interface{}) {
  1694  	t.Helper()
  1695  	vargs := []interface{}{in}
  1696  	for _, arg := range args {
  1697  		vargs = append(vargs, arg)
  1698  	}
  1699  	t.Errorf("input:\n%s\n~end~\n"+fmtStr, vargs...)
  1700  }
  1701  
  1702  func TestUnmarshalString(t *testing.T) {
  1703  	tests := []struct {
  1704  		in string
  1705  		// want is expected string result.
  1706  		want string
  1707  		// err is expected error substring from calling DecodeString if set.
  1708  		err string
  1709  	}{
  1710  		{
  1711  			in: func() string {
  1712  				var b []byte
  1713  				for i := 0; i < utf8.RuneSelf; i++ {
  1714  					switch i {
  1715  					case 0, '\\', '\n', '\'': // these must be escaped, so ignore them
  1716  					default:
  1717  						b = append(b, byte(i))
  1718  					}
  1719  				}
  1720  				return "'" + string(b) + "'"
  1721  			}(),
  1722  			want: "\x01\x02\x03\x04\x05\x06\a\b\t\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f",
  1723  		},
  1724  		{
  1725  			in:  "'\xde\xad\xbe\xef'",
  1726  			err: `invalid UTF-8 detected`,
  1727  		},
  1728  		{
  1729  			// Valid UTF-8 wire encoding, but sub-optimal encoding.
  1730  			in:  "'\xc0\x80'",
  1731  			err: "invalid UTF-8 detected",
  1732  		},
  1733  		{
  1734  			// Valid UTF-8 wire encoding, but invalid rune (surrogate pair).
  1735  			in:  "'\xed\xa0\x80'",
  1736  			err: "invalid UTF-8 detected",
  1737  		},
  1738  		{
  1739  			// Valid UTF-8 wire encoding, but invalid rune (above max rune).
  1740  			in:  "'\xf7\xbf\xbf\xbf'",
  1741  			err: "invalid UTF-8 detected",
  1742  		},
  1743  		{
  1744  			// Valid UTF-8 wire encoding of the RuneError rune.
  1745  			in:   "'\xef\xbf\xbd'",
  1746  			want: string(utf8.RuneError),
  1747  		},
  1748  		{
  1749  			in:   "'hello\u1234world'",
  1750  			want: "hello\u1234world",
  1751  		},
  1752  		{
  1753  			in:   `'\"\'\\\?\a\b\n\r\t\v\f\1\12\123\xA\xaB\x12\uAb8f\U0010FFFF'`,
  1754  			want: "\"'\\?\a\b\n\r\t\v\f\x01\nS\n\xab\x12\uab8f\U0010ffff",
  1755  		},
  1756  		{
  1757  			in:  `str: '\8'`,
  1758  			err: `invalid escape code "\\8" in string`,
  1759  		},
  1760  		{
  1761  			in:   `'\1x'`,
  1762  			want: "\001x",
  1763  		},
  1764  		{
  1765  			in:   `'\12x'`,
  1766  			want: "\012x",
  1767  		},
  1768  		{
  1769  			in:   `'\123x'`,
  1770  			want: "\123x",
  1771  		},
  1772  		{
  1773  			in:   `'\1234x'`,
  1774  			want: "\1234x",
  1775  		},
  1776  		{
  1777  			in:   `'\1'`,
  1778  			want: "\001",
  1779  		},
  1780  		{
  1781  			in:   `'\12'`,
  1782  			want: "\012",
  1783  		},
  1784  		{
  1785  			in:   `'\123'`,
  1786  			want: "\123",
  1787  		},
  1788  		{
  1789  			in:   `'\1234'`,
  1790  			want: "\1234",
  1791  		},
  1792  		{
  1793  			in:   `'\377'`,
  1794  			want: "\377",
  1795  		},
  1796  		{
  1797  			// Overflow octal escape.
  1798  			in:  `'\400'`,
  1799  			err: `invalid octal escape code "\\400" in string`,
  1800  		},
  1801  		{
  1802  			in:   `'\xfx'`,
  1803  			want: "\x0fx",
  1804  		},
  1805  		{
  1806  			in:   `'\xffx'`,
  1807  			want: "\xffx",
  1808  		},
  1809  		{
  1810  			in:   `'\xfffx'`,
  1811  			want: "\xfffx",
  1812  		},
  1813  		{
  1814  			in:   `'\xf'`,
  1815  			want: "\x0f",
  1816  		},
  1817  		{
  1818  			in:   `'\xff'`,
  1819  			want: "\xff",
  1820  		},
  1821  		{
  1822  			in:   `'\xfff'`,
  1823  			want: "\xfff",
  1824  		},
  1825  		{
  1826  			in:  `'\xz'`,
  1827  			err: `invalid hex escape code "\\x" in string`,
  1828  		},
  1829  		{
  1830  			in:  `'\uPo'`,
  1831  			err: eofErr,
  1832  		},
  1833  		{
  1834  			in:  `'\uPoo'`,
  1835  			err: `invalid Unicode escape code "\\uPoo'" in string`,
  1836  		},
  1837  		{
  1838  			in:  `str: '\uPoop'`,
  1839  			err: `invalid Unicode escape code "\\uPoop" in string`,
  1840  		},
  1841  		{
  1842  			// Unmatched surrogate pair.
  1843  			in:  `str: '\uDEAD'`,
  1844  			err: `unexpected EOF`, // trying to reader other half
  1845  		},
  1846  		{
  1847  			// Surrogate pair with invalid other half.
  1848  			in:  `str: '\uDEAD\u0000'`,
  1849  			err: `invalid Unicode escape code "\\u0000" in string`,
  1850  		},
  1851  		{
  1852  			// Properly matched surrogate pair.
  1853  			in:   `'\uD800\uDEAD'`,
  1854  			want: "𐊭",
  1855  		},
  1856  		{
  1857  			// Overflow on Unicode rune.
  1858  			in:  `'\U00110000'`,
  1859  			err: `invalid Unicode escape code "\\U00110000" in string`,
  1860  		},
  1861  		{
  1862  			in:  `'\z'`,
  1863  			err: `invalid escape code "\\z" in string`,
  1864  		},
  1865  		{
  1866  			// Strings cannot have NUL literal since C-style strings forbid them.
  1867  			in:  "'\x00'",
  1868  			err: `invalid character '\x00' in string`,
  1869  		},
  1870  		{
  1871  			// Strings cannot have newline literal. The C++ permits them if an
  1872  			// option is specified to allow them. In Go, we always forbid them.
  1873  			in:  "'\n'",
  1874  			err: `invalid character '\n' in string`,
  1875  		},
  1876  	}
  1877  
  1878  	for _, tc := range tests {
  1879  		t.Run("", func(t *testing.T) {
  1880  			got, err := text.UnmarshalString(tc.in)
  1881  			if err != nil {
  1882  				if tc.err == "" {
  1883  					errorf(t, tc.in, "UnmarshalString() got unexpected error: %q", err)
  1884  				} else if !strings.Contains(err.Error(), tc.err) {
  1885  					errorf(t, tc.in, "UnmarshalString() error got %q, want %q", err, tc.err)
  1886  				}
  1887  				return
  1888  			}
  1889  			if tc.err != "" {
  1890  				errorf(t, tc.in, "UnmarshalString() got nil error, want %q", tc.err)
  1891  				return
  1892  			}
  1893  			if got != tc.want {
  1894  				errorf(t, tc.in, "UnmarshalString()\n[got]\n%s\n[want]\n%s", got, tc.want)
  1895  			}
  1896  		})
  1897  	}
  1898  }
  1899  
  1900  // Tests line and column number produced by Decoder.Position.
  1901  func TestPosition(t *testing.T) {
  1902  	dec := text.NewDecoder([]byte("0123456789\n12345\n789"))
  1903  
  1904  	tests := []struct {
  1905  		pos int
  1906  		row int
  1907  		col int
  1908  	}{
  1909  		{
  1910  			pos: 0,
  1911  			row: 1,
  1912  			col: 1,
  1913  		},
  1914  		{
  1915  			pos: 10,
  1916  			row: 1,
  1917  			col: 11,
  1918  		},
  1919  		{
  1920  			pos: 11,
  1921  			row: 2,
  1922  			col: 1,
  1923  		},
  1924  		{
  1925  			pos: 18,
  1926  			row: 3,
  1927  			col: 2,
  1928  		},
  1929  	}
  1930  
  1931  	for _, tc := range tests {
  1932  		t.Run("", func(t *testing.T) {
  1933  			row, col := dec.Position(tc.pos)
  1934  			if row != tc.row || col != tc.col {
  1935  				t.Errorf("Position(%d) got (%d,%d) want (%d,%d)", tc.pos, row, col, tc.row, tc.col)
  1936  			}
  1937  		})
  1938  	}
  1939  }