cuelang.org/go@v0.10.1/internal/encoding/yaml/decode_test.go (about)

     1  // Many test cases in this file were originally ported from
     2  // github.com/go-yaml/yaml, also known as gopkg.in/yaml.v3.
     3  //
     4  // Copyright 2011-2016 Canonical Ltd.
     5  // Copyright 2020 CUE Authors
     6  //
     7  // Licensed under the Apache License, Version 2.0 (the "License");
     8  // you may not use this file except in compliance with the License.
     9  // You may obtain a copy of the License at
    10  //
    11  //     http://www.apache.org/licenses/LICENSE-2.0
    12  //
    13  // Unless required by applicable law or agreed to in writing, software
    14  // distributed under the License is distributed on an "AS IS" BASIS,
    15  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  // See the License for the specific language governing permissions and
    17  // limitations under the License.
    18  
    19  package yaml_test
    20  
    21  import (
    22  	"fmt"
    23  	"io"
    24  	"os"
    25  	"strconv"
    26  	"strings"
    27  	"testing"
    28  
    29  	"github.com/go-quicktest/qt"
    30  	"github.com/google/go-cmp/cmp"
    31  
    32  	"cuelang.org/go/cue/ast"
    33  	"cuelang.org/go/cue/format"
    34  	"cuelang.org/go/internal"
    35  	"cuelang.org/go/internal/cueexperiment"
    36  	"cuelang.org/go/internal/cuetest"
    37  	"cuelang.org/go/internal/encoding/yaml"
    38  )
    39  
    40  // These tests are only for the new YAML decoder.
    41  // The old YAML decoder has its own tests in internal/third_party/yaml.
    42  func init() { cueexperiment.Flags.YAMLV3Decoder = true }
    43  
    44  var unmarshalTests = []struct {
    45  	data string
    46  	want string
    47  }{
    48  	{
    49  		"",
    50  		"null",
    51  	},
    52  	{
    53  		"{}",
    54  		"",
    55  	}, {
    56  		"v: hi",
    57  		`v: "hi"`,
    58  	}, {
    59  		"v: hi",
    60  		`v: "hi"`,
    61  	}, {
    62  		"v: true",
    63  		"v: true",
    64  	}, {
    65  		"v: 10",
    66  		"v: 10",
    67  	}, {
    68  		"v: 0b10",
    69  		"v: 0b10",
    70  	}, {
    71  		"v: 0xA",
    72  		"v: 0xA",
    73  	}, {
    74  		"v: 4294967296",
    75  		"v: 4294967296",
    76  	}, {
    77  		"v: 0.1",
    78  		"v: 0.1",
    79  	}, {
    80  		"v: .1",
    81  		"v: 0.1",
    82  	}, {
    83  		"v: .Inf",
    84  		"v: +Inf",
    85  	}, {
    86  		"v: -.Inf",
    87  		"v: -Inf",
    88  	}, {
    89  		"v: -10",
    90  		"v: -10",
    91  	}, {
    92  		"v: --10",
    93  		`v: "--10"`,
    94  	}, {
    95  		"v: -.1",
    96  		"v: -0.1",
    97  	},
    98  
    99  	// Simple values.
   100  	{
   101  		"123",
   102  		"123",
   103  	},
   104  
   105  	// Floats from spec
   106  	{
   107  		"canonical: 6.8523e+5",
   108  		"canonical: 6.8523e+5",
   109  	}, {
   110  		"expo: 685.230_15e+03",
   111  		"expo: 685.230_15e+03",
   112  	}, {
   113  		"fixed: 685_230.15",
   114  		"fixed: 685_230.15",
   115  	}, {
   116  		"neginf: -.inf",
   117  		"neginf: -Inf",
   118  	}, {
   119  		"fixed: 685_230.15",
   120  		"fixed: 685_230.15",
   121  	},
   122  	//{"sexa: 190:20:30.15", map[string]interface{}{"sexa": 0}}, // Unsupported
   123  	//{"notanum: .NaN", map[string]interface{}{"notanum": math.NaN()}}, // Equality of NaN fails.
   124  
   125  	// Bools from spec
   126  	{
   127  		"canonical: y",
   128  		`canonical: "y"`,
   129  	}, {
   130  		"answer: n",
   131  		`answer: "n"`,
   132  	}, {
   133  		"answer: NO",
   134  		`answer: "NO"`,
   135  	}, {
   136  		"logical: True",
   137  		"logical: true",
   138  	}, {
   139  		"option: on",
   140  		`option: "on"`,
   141  	}, {
   142  		"answer: off",
   143  		`answer: "off"`,
   144  	},
   145  	// Ints from spec
   146  	{
   147  		"canonical: 685230",
   148  		"canonical: 685230",
   149  	}, {
   150  		"decimal: +685_230",
   151  		"decimal: +685_230",
   152  	}, {
   153  		"octal_yaml11: 02472256",
   154  		"octal_yaml11: 0o2472256",
   155  	}, {
   156  		"octal_yaml12: 0o2472256",
   157  		"octal_yaml12: 0o2472256",
   158  	}, {
   159  		"not_octal_yaml11: 0123456789",
   160  		`not_octal_yaml11: "0123456789"`,
   161  	}, {
   162  		"not_octal_yaml12: 0o123456789",
   163  		`not_octal_yaml12: "0o123456789"`,
   164  	}, {
   165  		// TODO(mvdan): 01234 is not a valid numeric literal in CUE.
   166  		"float_octal_yaml11: !!float 01234",
   167  		"float_octal_yaml11: number & 01234",
   168  	}, {
   169  		"float_octal_yaml12: !!float 0o1234",
   170  		"float_octal_yaml12: number & 0o1234",
   171  	}, {
   172  		"hexa: 0x_0A_74_AE",
   173  		"hexa: 0x_0A_74_AE",
   174  	}, {
   175  		"bin: 0b1010_0111_0100_1010_1110",
   176  		"bin: 0b1010_0111_0100_1010_1110",
   177  	}, {
   178  		"bin: -0b101010",
   179  		"bin: -0b101010",
   180  	}, {
   181  		"bin: -0b1000000000000000000000000000000000000000000000000000000000000000",
   182  		"bin: -0b1000000000000000000000000000000000000000000000000000000000000000",
   183  	}, {
   184  		"decimal: +685_230",
   185  		"decimal: +685_230",
   186  	},
   187  
   188  	//{"sexa: 190:20:30", map[string]interface{}{"sexa": 0}}, // Unsupported
   189  
   190  	// Nulls from spec
   191  	{
   192  		"empty:",
   193  		"empty: null",
   194  	}, {
   195  		"canonical: ~",
   196  		"canonical: null",
   197  	}, {
   198  		"english: null",
   199  		"english: null",
   200  	}, {
   201  		"_foo: 1",
   202  		`"_foo": 1`,
   203  	}, {
   204  		`"#foo": 1`,
   205  		`"#foo": 1`,
   206  	}, {
   207  		"_#foo: 1",
   208  		`"_#foo": 1`,
   209  	}, {
   210  		"~: null key",
   211  		`"null": "null key"`,
   212  	}, {
   213  		`empty:
   214  apple: "newline"`,
   215  		`empty: null
   216  apple: "newline"`,
   217  	},
   218  
   219  	// Flow sequence
   220  	{
   221  		"seq: [A,B]",
   222  		`seq: ["A", "B"]`,
   223  	}, {
   224  		"seq: [A,B,C,]",
   225  		`seq: ["A", "B", "C"]`,
   226  	}, {
   227  		"seq: [A,1,C]",
   228  		`seq: ["A", 1, "C"]`,
   229  	},
   230  	// Block sequence
   231  	{
   232  		"seq:\n - A\n - B",
   233  		`seq: [
   234  	"A",
   235  	"B",
   236  ]`,
   237  	}, {
   238  		"seq:\n - A\n - B\n - C",
   239  		`seq: [
   240  	"A",
   241  	"B",
   242  	"C",
   243  ]`,
   244  	}, {
   245  		"seq:\n - A\n - 1\n - C",
   246  		`seq: [
   247  	"A",
   248  	1,
   249  	"C",
   250  ]`,
   251  	},
   252  
   253  	// Literal block scalar
   254  	{
   255  		"scalar: | # Comment\n\n literal\n\n \ttext\n\n",
   256  		`scalar: """
   257  
   258  	literal
   259  
   260  	\ttext
   261  
   262  	""" // Comment`,
   263  	},
   264  
   265  	// Folded block scalar
   266  	{
   267  		"scalar: > # Comment\n\n folded\n line\n \n next\n line\n  * one\n  * two\n\n last\n line\n\n",
   268  		`scalar: """
   269  
   270  	folded line
   271  	next line
   272  	 * one
   273  	 * two
   274  
   275  	last line
   276  
   277  	""" // Comment`,
   278  	},
   279  
   280  	// Structs
   281  	{
   282  		"a: {b: c}",
   283  		`a: {b: "c"}`,
   284  	},
   285  	{
   286  		"hello: world",
   287  		`hello: "world"`,
   288  	}, {
   289  		"a:",
   290  		"a: null",
   291  	}, {
   292  		"a: 1",
   293  		"a: 1",
   294  	}, {
   295  		"a: 1.0",
   296  		"a: 1.0",
   297  	}, {
   298  		"a: [1, 2]",
   299  		"a: [1, 2]",
   300  	}, {
   301  		"a: y",
   302  		`a: "y"`,
   303  	}, {
   304  		"{ a: 1, b: {c: 1} }",
   305  		`a: 1, b: {c: 1}`,
   306  	}, {
   307  		`
   308  True: 1
   309  Null: 1
   310  .Inf: 2
   311  `,
   312  		`"true": 1
   313  "null": 1
   314  "+Inf": 2`,
   315  	},
   316  
   317  	// Some cross type conversions
   318  	{
   319  		"v: 42",
   320  		"v: 42",
   321  	}, {
   322  		"v: -42",
   323  		"v: -42",
   324  	}, {
   325  		"v: 4294967296",
   326  		"v: 4294967296",
   327  	}, {
   328  		"v: -4294967296",
   329  		"v: -4294967296",
   330  	},
   331  
   332  	// int
   333  	{
   334  		"int_max: 2147483647",
   335  		"int_max: 2147483647",
   336  	},
   337  	{
   338  		"int_min: -2147483648",
   339  		"int_min: -2147483648",
   340  	},
   341  	{
   342  		"int_overflow: 9223372036854775808", // math.MaxInt64 + 1
   343  		"int_overflow: 9223372036854775808", // math.MaxInt64 + 1
   344  	},
   345  
   346  	// int64
   347  	{
   348  		"int64_max: 9223372036854775807",
   349  		"int64_max: 9223372036854775807",
   350  	},
   351  	{
   352  		"int64_max_base2: 0b111111111111111111111111111111111111111111111111111111111111111",
   353  		"int64_max_base2: 0b111111111111111111111111111111111111111111111111111111111111111",
   354  	},
   355  	{
   356  		"int64_min: -9223372036854775808",
   357  		"int64_min: -9223372036854775808",
   358  	},
   359  	{
   360  		"int64_neg_base2: -0b111111111111111111111111111111111111111111111111111111111111111",
   361  		"int64_neg_base2: -0b111111111111111111111111111111111111111111111111111111111111111",
   362  	},
   363  	{
   364  		"int64_overflow: 9223372036854775808", // math.MaxInt64 + 1
   365  		"int64_overflow: 9223372036854775808", // math.MaxInt64 + 1
   366  	},
   367  
   368  	// uint
   369  	{
   370  		"uint_max: 4294967295",
   371  		"uint_max: 4294967295",
   372  	},
   373  
   374  	// uint64
   375  	{
   376  		"uint64_max: 18446744073709551615",
   377  		"uint64_max: 18446744073709551615",
   378  	},
   379  	{
   380  		"uint64_max_base2: 0b1111111111111111111111111111111111111111111111111111111111111111",
   381  		"uint64_max_base2: 0b1111111111111111111111111111111111111111111111111111111111111111",
   382  	},
   383  	{
   384  		"uint64_maxint64: 9223372036854775807",
   385  		"uint64_maxint64: 9223372036854775807",
   386  	},
   387  
   388  	// float32
   389  	{
   390  		"float32_max: 3.40282346638528859811704183484516925440e+38",
   391  		"float32_max: 3.40282346638528859811704183484516925440e+38",
   392  	},
   393  	{
   394  		"float32_nonzero: 1.401298464324817070923729583289916131280e-45",
   395  		"float32_nonzero: 1.401298464324817070923729583289916131280e-45",
   396  	},
   397  	{
   398  		"float32_maxuint64: 18446744073709551615",
   399  		"float32_maxuint64: 18446744073709551615",
   400  	},
   401  	{
   402  		"float32_maxuint64+1: 18446744073709551616",
   403  		`"float32_maxuint64+1": number & 18446744073709551616`,
   404  	},
   405  
   406  	// float64
   407  	{
   408  		"float64_max: 1.797693134862315708145274237317043567981e+308",
   409  		"float64_max: 1.797693134862315708145274237317043567981e+308",
   410  	},
   411  	{
   412  		"float64_nonzero: 4.940656458412465441765687928682213723651e-324",
   413  		"float64_nonzero: 4.940656458412465441765687928682213723651e-324",
   414  	},
   415  	{
   416  		"float64_maxuint64: 18446744073709551615",
   417  		"float64_maxuint64: 18446744073709551615",
   418  	},
   419  	// TODO(mvdan): yaml.v3 uses strconv APIs like ParseUint to try to detect
   420  	// whether a scalar should be considered a YAML integer or a float.
   421  	// Integers in CUE aren't limited to 64 bits, so we should arguably not decode
   422  	// large integers that don't fit in 64 bits as floats via `number &`.
   423  	{
   424  		"float64_maxuint64+1: 18446744073709551616",
   425  		`"float64_maxuint64+1": number & 18446744073709551616`,
   426  	},
   427  
   428  	// Overflow cases.
   429  	{
   430  		"v: 4294967297",
   431  		"v: 4294967297",
   432  	}, {
   433  		"v: 128",
   434  		"v: 128",
   435  	},
   436  
   437  	// Quoted values.
   438  	{
   439  		"'1': '\"2\"'",
   440  		`"1": "\"2\""`,
   441  	}, {
   442  		"v:\n- A\n- 'B\n\n  C'\n",
   443  		`v: [
   444  	"A",
   445  	"""
   446  		B
   447  		C
   448  		""",
   449  ]`,
   450  	}, {
   451  		`"\0"`,
   452  		`"\u0000"`,
   453  	},
   454  
   455  	// Explicit tags.
   456  	{
   457  		"v: !!float '1.1'",
   458  		"v: 1.1",
   459  	}, {
   460  		"v: !!float 0",
   461  		"v: number & 0",
   462  	}, {
   463  		"v: !!float -1",
   464  		"v: number & -1",
   465  	}, {
   466  		"v: !!null ''",
   467  		"v: null",
   468  	}, {
   469  		"%TAG !y! tag:yaml.org,2002:\n---\nv: !y!int '1'",
   470  		"v: 1",
   471  	},
   472  
   473  	// Non-specific tag (Issue #75)
   474  	{
   475  		`v: ! test`,
   476  		`v: "test"`,
   477  	},
   478  
   479  	// Anchors and aliases.
   480  	{
   481  		"a: &x 1\nb: &y 2\nc: *x\nd: *y\n",
   482  		`a: 1
   483  b: 2
   484  c: 1
   485  d: 2`,
   486  	}, {
   487  		"a: &a {c: 1}\nb: *a",
   488  		`a: {c: 1}
   489  b: {
   490  	c: 1
   491  }`,
   492  	}, {
   493  		"a: &a [1, 2]\nb: *a",
   494  		"a: [1, 2]\nb: [1, 2]", // TODO: a: [1, 2], b: a
   495  	},
   496  
   497  	{
   498  		"foo: ''",
   499  		`foo: ""`,
   500  	}, {
   501  		"foo: null",
   502  		"foo: null",
   503  	},
   504  
   505  	// Support for ~
   506  	{
   507  		"foo: ~",
   508  		"foo: null",
   509  	},
   510  
   511  	// Bug #1191981
   512  	{
   513  		"" +
   514  			"%YAML 1.1\n" +
   515  			"--- !!str\n" +
   516  			`"Generic line break (no glyph)\n\` + "\n" +
   517  			` Generic line break (glyphed)\n\` + "\n" +
   518  			` Line separator\u2028\` + "\n" +
   519  			` Paragraph separator\u2029"` + "\n",
   520  		`"""
   521  	Generic line break (no glyph)
   522  	Generic line break (glyphed)
   523  	Line separator\u2028Paragraph separator\u2029
   524  	"""`,
   525  	},
   526  
   527  	// bug 1243827
   528  	{
   529  		"a: -b_c",
   530  		`a: "-b_c"`,
   531  	},
   532  	{
   533  		"a: +b_c",
   534  		`a: "+b_c"`,
   535  	},
   536  	{
   537  		"a: 50cent_of_dollar",
   538  		`a: "50cent_of_dollar"`,
   539  	},
   540  
   541  	// issue #295 (allow scalars with colons in flow mappings and sequences)
   542  	{
   543  		"a: {b: https://github.com/go-yaml/yaml}",
   544  		`a: {b: "https://github.com/go-yaml/yaml"}`,
   545  	},
   546  	{
   547  		"a: [https://github.com/go-yaml/yaml]",
   548  		`a: ["https://github.com/go-yaml/yaml"]`,
   549  	},
   550  
   551  	// Duration
   552  	{
   553  		"a: 3s",
   554  		`a: "3s"`, // for now
   555  	},
   556  
   557  	// Issue #24.
   558  	{
   559  		"a: <foo>",
   560  		`a: "<foo>"`,
   561  	},
   562  
   563  	// Base 60 floats are obsolete and unsupported.
   564  	{
   565  		"a: 1:1\n",
   566  		`a: "1:1"`,
   567  	},
   568  
   569  	// Binary data.
   570  	{
   571  		"a: !!binary gIGC\n",
   572  		`a: '\x80\x81\x82'`,
   573  	}, {
   574  		"a: !!binary |\n  " + strings.Repeat("kJCQ", 17) + "kJ\n  CQ\n",
   575  		"a: '" + strings.Repeat(`\x90`, 54) + "'",
   576  	}, {
   577  		"a: !!binary |\n  " + strings.Repeat("A", 70) + "\n  ==\n",
   578  		"a: '" + strings.Repeat(`\x00`, 52) + "'",
   579  	},
   580  
   581  	// Ordered maps.
   582  	{
   583  		"{b: 2, a: 1, d: 4, c: 3, sub: {e: 5}}",
   584  		`b: 2, a: 1, d: 4, c: 3, sub: {e: 5}`,
   585  	},
   586  
   587  	// Spacing
   588  	{
   589  		`
   590  a: {}
   591  b: {
   592  }
   593  c: 1
   594  d: [
   595  ]
   596  e: []
   597  `,
   598  		// TODO(mvdan): keep the separated opening/closing tokens once yaml.v3 exposes end positions.
   599  		`a: {}
   600  b: {}
   601  c: 1
   602  d: []
   603  e: []`,
   604  	},
   605  
   606  	{
   607  		`
   608  a:
   609    - { "a": 1, "b": 2 }
   610    - { "c": 1, "d": 2 }
   611  `,
   612  		`a: [{
   613  	a: 1, b: 2
   614  }, {
   615  	c: 1, d: 2
   616  }]`,
   617  	},
   618  
   619  	{
   620  		"a:\n b:\n  c: d\n  e: f\n",
   621  		`a: {
   622  	b: {
   623  		c: "d"
   624  		e: "f"
   625  	}
   626  }`,
   627  	},
   628  
   629  	// Issue #39.
   630  	{
   631  		"a:\n b:\n  c: d\n",
   632  		`a: {
   633  	b: {
   634  		c: "d"
   635  	}
   636  }`,
   637  	},
   638  
   639  	// Timestamps
   640  	{
   641  		// Date only.
   642  		"a: 2015-01-01\n",
   643  		`a: "2015-01-01"`,
   644  	},
   645  	{
   646  		// RFC3339
   647  		"a: 2015-02-24T18:19:39.12Z\n",
   648  		`a: "2015-02-24T18:19:39.12Z"`,
   649  	},
   650  	{
   651  		// RFC3339 with short dates.
   652  		"a: 2015-2-3T3:4:5Z",
   653  		`a: "2015-2-3T3:4:5Z"`,
   654  	},
   655  	{
   656  		// ISO8601 lower case t
   657  		"a: 2015-02-24t18:19:39Z\n",
   658  		`a: "2015-02-24t18:19:39Z"`,
   659  	},
   660  	{
   661  		// space separate, no time zone
   662  		"a: 2015-02-24 18:19:39\n",
   663  		`a: "2015-02-24 18:19:39"`,
   664  	},
   665  	// Some cases not currently handled. Uncomment these when
   666  	// the code is fixed.
   667  	//	{
   668  	//		// space separated with time zone
   669  	//		"a: 2001-12-14 21:59:43.10 -5",
   670  	//		map[string]interface{}{"a": time.Date(2001, 12, 14, 21, 59, 43, .1e9, time.UTC)},
   671  	//	},
   672  	//	{
   673  	//		// arbitrary whitespace between fields
   674  	//		"a: 2001-12-14 \t\t \t21:59:43.10 \t Z",
   675  	//		map[string]interface{}{"a": time.Date(2001, 12, 14, 21, 59, 43, .1e9, time.UTC)},
   676  	//	},
   677  	{
   678  		// explicit string tag
   679  		"a: !!str 2015-01-01",
   680  		`a: "2015-01-01"`,
   681  	},
   682  	{
   683  		// explicit timestamp tag on quoted string
   684  		"a: !!timestamp \"2015-01-01\"",
   685  		`a: "2015-01-01"`,
   686  	},
   687  	{
   688  		// explicit timestamp tag on unquoted string
   689  		"a: !!timestamp 2015-01-01",
   690  		`a: "2015-01-01"`,
   691  	},
   692  	{
   693  		// quoted string that's a valid timestamp
   694  		"a: \"2015-01-01\"",
   695  		"a: \"2015-01-01\"",
   696  	},
   697  
   698  	// Empty list
   699  	{
   700  		"a: []",
   701  		"a: []",
   702  	},
   703  
   704  	// Floating comments.
   705  	// TODO(mvdan): all empty lines separating comments should stay in place.
   706  	// TODO(mvdan): avoid losing comments in empty lists and objects.
   707  	{
   708  		"# Start\n\na: 123\n\n# Middle\n\nb: 456\n\n# End",
   709  		"// Start\na: 123\n\n// Middle\nb: 456\n// End",
   710  	},
   711  	{
   712  		"a: [\n\t# Comment\n]",
   713  		"a: []",
   714  	},
   715  	{
   716  		"a: {\n\t# Comment\n}",
   717  		"a: {}",
   718  	},
   719  
   720  	// Attached comments.
   721  	{
   722  		"start: 100\n\n# Before\na: 123 # Inline\n# After\n\nend: 200",
   723  		"start: 100\n\n// Before\n// After\na:   123 // Inline\nend: 200",
   724  	},
   725  	{
   726  		"# One\none: null\n\n# Two\ntwo: [2, 2]\n\n# Three\nthree: {val: 3}",
   727  		"// One\none: null\n\n// Two\ntwo: [2, 2]\n\n// Three\nthree: {val: 3}",
   728  	},
   729  
   730  	// UTF-16-LE
   731  	{
   732  		"\xff\xfe\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00\n\x00",
   733  		`ñoño: "very yes"`,
   734  	},
   735  	// UTF-16-LE with surrogate.
   736  	{
   737  		"\xff\xfe\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00 \x00=\xd8\xd4\xdf\n\x00",
   738  		`ñoño: "very yes 🟔"`,
   739  	},
   740  
   741  	// UTF-16-BE
   742  	{
   743  		"\xfe\xff\x00\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00\n",
   744  		`ñoño: "very yes"`,
   745  	},
   746  	// UTF-16-BE with surrogate.
   747  	{
   748  		"\xfe\xff\x00\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00 \xd8=\xdf\xd4\x00\n",
   749  		`ñoño: "very yes 🟔"`,
   750  	},
   751  
   752  	// This *is* in fact a float number, per the spec. #171 was a mistake.
   753  	{
   754  		"a: 123456e1\n",
   755  		`a: 123456e1`,
   756  	}, {
   757  		"a: 123456E1\n",
   758  		`a: 123456e1`,
   759  	},
   760  	// Other float formats:
   761  	{
   762  		"x: .1",
   763  		"x: 0.1",
   764  	},
   765  	{
   766  		"x: .1e-3",
   767  		"x: 0.1e-3",
   768  	},
   769  	{
   770  		"x: 1.2E4",
   771  		"x: 1.2e4",
   772  	},
   773  	{
   774  		"x: 1.2E+4",
   775  		"x: 1.2e+4",
   776  	},
   777  	// yaml-test-suite 3GZX: Spec Example 7.1. Alias Nodes
   778  	{
   779  		"First occurrence: &anchor Foo\nSecond occurrence: *anchor\nOverride anchor: &anchor Bar\nReuse anchor: *anchor\n",
   780  		`"First occurrence":  "Foo"
   781  "Second occurrence": "Foo"
   782  "Override anchor":   "Bar"
   783  "Reuse anchor":      "Bar"`,
   784  	},
   785  }
   786  
   787  type M map[interface{}]interface{}
   788  
   789  func cueStr(node ast.Node) string {
   790  	if node == nil {
   791  		return ""
   792  	}
   793  	b, _ := format.Node(internal.ToFile(node))
   794  	return strings.TrimSpace(string(b))
   795  }
   796  
   797  func newDecoder(t *testing.T, data string) yaml.Decoder {
   798  	t.Helper()
   799  	t.Logf("  yaml:\n%s", data)
   800  	return yaml.NewDecoder("test.yaml", []byte(data))
   801  }
   802  
   803  func callUnmarshal(t *testing.T, data string) (ast.Expr, error) {
   804  	t.Helper()
   805  	t.Logf("  yaml:\n%s", data)
   806  	return yaml.Unmarshal("test.yaml", []byte(data))
   807  }
   808  
   809  func TestUnmarshal(t *testing.T) {
   810  	for i, item := range unmarshalTests {
   811  		t.Run(strconv.Itoa(i), func(t *testing.T) {
   812  			t.Logf("test %d: %q", i, item.data)
   813  			expr, err := callUnmarshal(t, item.data)
   814  			if err != nil {
   815  				t.Fatalf("expected error to be nil: %v", err)
   816  			}
   817  			if got := cueStr(expr); got != item.want {
   818  				t.Errorf("\n    got:\n%v\n    want:\n%v", got, item.want)
   819  			}
   820  		})
   821  	}
   822  }
   823  
   824  // For debug purposes: do not delete.
   825  func TestX(t *testing.T) {
   826  	y := `
   827  `
   828  	y = strings.TrimSpace(y)
   829  	if len(y) == 0 {
   830  		t.Skip()
   831  	}
   832  
   833  	expr, err := callUnmarshal(t, y)
   834  	if err != nil {
   835  		t.Fatal(err)
   836  	}
   837  	t.Error(cueStr(expr))
   838  }
   839  
   840  func TestDecoderSingleDocument(t *testing.T) {
   841  	// Test that Decoder.Decode works as expected on
   842  	// all the unmarshal tests.
   843  	for i, item := range unmarshalTests {
   844  		t.Run(fmt.Sprintf("test %d: %q", i, item.data), func(t *testing.T) {
   845  			if item.data == "" {
   846  				// Behaviour differs when there's no YAML.
   847  				return
   848  			}
   849  			expr, err := newDecoder(t, item.data).Decode()
   850  			if err != nil {
   851  				t.Errorf("err should be nil, was %v", err)
   852  			}
   853  			if got := cueStr(expr); got != item.want {
   854  				t.Errorf("\n    got:\n%v\n    want:\n%v", got, item.want)
   855  			}
   856  		})
   857  	}
   858  }
   859  
   860  var decoderTests = []struct {
   861  	data string
   862  	want string
   863  }{{
   864  	"",
   865  	"null",
   866  }, {
   867  	"a: b",
   868  	`a: "b"`,
   869  }, {
   870  	"---\na: b\n...\n",
   871  	`a: "b"`,
   872  }, {
   873  	"---\na: b\n---\n---\n",
   874  	"a: \"b\"\nnull\nnull",
   875  }, {
   876  	"---\n---\n---\na: b\n",
   877  	"null\nnull\na: \"b\"",
   878  }, {
   879  	"---\n'hello'\n...\n---\ngoodbye\n...\n",
   880  	`"hello"` + "\n" + `"goodbye"`,
   881  }}
   882  
   883  func TestDecoder(t *testing.T) {
   884  	for i, item := range decoderTests {
   885  		t.Run(fmt.Sprintf("test %d: %q", i, item.data), func(t *testing.T) {
   886  			var values []string
   887  			dec := newDecoder(t, item.data)
   888  			for {
   889  				expr, err := dec.Decode()
   890  				if err == io.EOF {
   891  					break
   892  				}
   893  				if err != nil {
   894  					t.Errorf("err should be nil, was %v", err)
   895  				}
   896  				values = append(values, cueStr(expr))
   897  			}
   898  			got := strings.Join(values, "\n")
   899  			if got != item.want {
   900  				t.Errorf("\n    got:\n%v\n    want:\n%v", got, item.want)
   901  			}
   902  		})
   903  	}
   904  }
   905  
   906  func TestUnmarshalNaN(t *testing.T) {
   907  	expr, err := callUnmarshal(t, "notanum: .NaN")
   908  	if err != nil {
   909  		t.Fatal("unexpected error", err)
   910  	}
   911  	got := cueStr(expr)
   912  	want := "notanum: NaN"
   913  	if got != want {
   914  		t.Errorf("got %v; want %v", got, want)
   915  	}
   916  }
   917  
   918  var unmarshalErrorTests = []struct {
   919  	data, error string
   920  }{
   921  	{"\nv: !!float 'error'", `test.yaml:2: cannot decode "error" as !!float: illegal number start "error"`},
   922  	{"\nv: !!int 'error'", `test.yaml:2: cannot decode "error" as !!int: illegal number start "error"`},
   923  	{"\nv: !!int 123.456", `test.yaml:2: cannot decode "123.456" as !!int: not a literal number`},
   924  	{"v: [A,", "test.yaml:1: did not find expected node content"},
   925  	{"v:\n- [A,", "test.yaml:2: did not find expected node content"},
   926  	{"a:\n- b: *,", "test.yaml:2: did not find expected alphabetic or numeric character"},
   927  	{"a: *b\n", "test.yaml: unknown anchor 'b' referenced"},
   928  	{"a: &a\n  b: *a\n", `test.yaml:2: anchor "a" value contains itself`},
   929  	{"value: -", "test.yaml: block sequence entries are not allowed in this context"},
   930  	{"a: !!binary ==", "test.yaml:1: !!binary value contains invalid base64 data"},
   931  	{"{[.]}", `test.yaml:1: invalid map key: !!seq`},
   932  	{"{{.}}", `test.yaml:1: invalid map key: !!map`},
   933  	{"b: *a\na: &a {c: 1}", `test.yaml: unknown anchor 'a' referenced`},
   934  	{"%TAG !%79! tag:yaml.org,2002:\n---\nv: !%79!int '1'", "test.yaml: did not find expected whitespace"},
   935  }
   936  
   937  func TestUnmarshalErrors(t *testing.T) {
   938  	for i, item := range unmarshalErrorTests {
   939  		t.Run(fmt.Sprintf("test %d: %q", i, item.data), func(t *testing.T) {
   940  			expr, err := callUnmarshal(t, item.data)
   941  			val := ""
   942  			if expr != nil {
   943  				val = cueStr(expr)
   944  			}
   945  			if err == nil || err.Error() != item.error {
   946  				t.Errorf("got %v; want %v; (value %v)", err, item.error, val)
   947  			}
   948  		})
   949  	}
   950  }
   951  
   952  func TestDecoderErrors(t *testing.T) {
   953  	for i, item := range unmarshalErrorTests {
   954  		t.Run(fmt.Sprintf("test %d: %q", i, item.data), func(t *testing.T) {
   955  			_, err := newDecoder(t, item.data).Decode()
   956  			if err == nil || err.Error() != item.error {
   957  				t.Errorf("got %v; want %v", err, item.error)
   958  			}
   959  		})
   960  	}
   961  }
   962  
   963  func TestFiles(t *testing.T) {
   964  	files := []string{"merge"}
   965  	for _, test := range files {
   966  		t.Run(test, func(t *testing.T) {
   967  			testname := fmt.Sprintf("testdata/%s.test", test)
   968  			filename := fmt.Sprintf("testdata/%s.out", test)
   969  			mergeTests, err := os.ReadFile(testname)
   970  			if err != nil {
   971  				t.Fatal(err)
   972  			}
   973  			expr, err := yaml.Unmarshal("test.yaml", mergeTests)
   974  			if err != nil {
   975  				t.Fatal(err)
   976  			}
   977  			got := cueStr(expr)
   978  			if cuetest.UpdateGoldenFiles {
   979  				os.WriteFile(filename, []byte(got), 0644)
   980  				return
   981  			}
   982  			b, err := os.ReadFile(filename)
   983  			if err != nil {
   984  				t.Fatal(err)
   985  			}
   986  			if want := string(b); got != want {
   987  				t.Error(cmp.Diff(want, got))
   988  			}
   989  		})
   990  	}
   991  }
   992  
   993  func TestTrailingInput(t *testing.T) {
   994  	for _, input := range []string{
   995  		"---\nfirst\n...\n}invalid yaml",
   996  		"---\nfirst\n---\nsecond\n",
   997  	} {
   998  		t.Run("", func(t *testing.T) {
   999  			// Unmarshal should fail as it expects one value.
  1000  			wantErr := ".*expected a single YAML document.*"
  1001  			_, err := callUnmarshal(t, input)
  1002  			qt.Assert(t, qt.ErrorMatches(err, wantErr))
  1003  
  1004  			// A single Decode call should succeed, no matter whether there is any valid or invalid trailing input.
  1005  			wantFirst := `"first"`
  1006  			dec := newDecoder(t, input)
  1007  			expr, err := dec.Decode()
  1008  			qt.Assert(t, qt.IsNil(err))
  1009  			gotFirst := cueStr(expr)
  1010  			qt.Assert(t, qt.Equals(gotFirst, wantFirst))
  1011  		})
  1012  	}
  1013  
  1014  }