cuelang.org/go@v0.13.0/encoding/yaml/yaml_test.go (about)

     1  // Copyright 2019 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package yaml
    16  
    17  import (
    18  	"strings"
    19  	"testing"
    20  
    21  	"cuelang.org/go/cue/cuecontext"
    22  	"cuelang.org/go/cue/format"
    23  )
    24  
    25  func TestYAML(t *testing.T) {
    26  	testCases := []struct {
    27  		name     string
    28  		yaml     string
    29  		yamlOut  string
    30  		want     string
    31  		isStream bool
    32  	}{{
    33  		name:    "empty",
    34  		yaml:    "",
    35  		yamlOut: "null",
    36  		want:    "*null | _",
    37  	}, {
    38  		name:     "empty stream",
    39  		want:     "*null | _",
    40  		isStream: true,
    41  	}, {
    42  		name: "string literal",
    43  		yaml: `foo`,
    44  		want: `"foo"`,
    45  	}, {
    46  		name: "struct",
    47  		yaml: `a: foo
    48  b: bar`,
    49  		want: `a: "foo"
    50  b: "bar"`,
    51  	}, {
    52  		name: "stream",
    53  		yaml: `a: foo
    54  ---
    55  b: bar
    56  c: baz
    57  `,
    58  		want: `[{
    59  	a: "foo"
    60  }, {
    61  	b: "bar"
    62  	c: "baz"
    63  }]`,
    64  		isStream: true,
    65  	}, {
    66  		name: "stream with null",
    67  		yaml: `
    68  ---
    69  a: foo
    70  ---
    71  ---
    72  b: bar
    73  c: baz
    74  ---
    75  `,
    76  		// Not sure if a leading document separator should be gobbled, but the
    77  		// YAML parser seems to think so. This could have something to do with
    78  		// the fact that the document separator is really an "end of directives"
    79  		// marker, while ... means "end of document". YAML is hard!
    80  		yamlOut: `a: foo
    81  ---
    82  null
    83  ---
    84  b: bar
    85  c: baz
    86  ---
    87  null
    88  `,
    89  		// TODO(bug): seems like bug in yaml parser. Try moving to yaml.v3,
    90  		// or validate that this is indeed a correct interpretation.
    91  		want: `[{
    92  	a: "foo"
    93  }, null, {
    94  	b: "bar"
    95  	c: "baz"
    96  }, null]`,
    97  		isStream: true,
    98  	}}
    99  	ctx := cuecontext.New()
   100  	for _, tc := range testCases {
   101  		t.Run(tc.name, func(t *testing.T) {
   102  			f, err := Extract(tc.name, tc.yaml)
   103  			if err != nil {
   104  				t.Fatal(err)
   105  			}
   106  			b, _ := format.Node(f)
   107  			if got := strings.TrimSpace(string(b)); got != tc.want {
   108  				t.Errorf("Extract:\ngot  %q\nwant %q", got, tc.want)
   109  			}
   110  
   111  			file, err := Extract(tc.name, tc.yaml)
   112  			if err != nil {
   113  				t.Fatal(err)
   114  			}
   115  			b, _ = format.Node(file)
   116  			if got := strings.TrimSpace(string(b)); got != tc.want {
   117  				t.Errorf("Decode:\ngot  %q\nwant %q", got, tc.want)
   118  			}
   119  
   120  			yamlOut := tc.yaml
   121  			if tc.yamlOut != "" {
   122  				yamlOut = tc.yamlOut
   123  			}
   124  
   125  			wantVal := ctx.CompileString(tc.want)
   126  			if !tc.isStream {
   127  				b, err = Encode(wantVal)
   128  				if err != nil {
   129  					t.Error(err)
   130  				}
   131  				if got := strings.TrimSpace(string(b)); got != yamlOut {
   132  					t.Errorf("Encode:\ngot  %q\nwant %q", got, yamlOut)
   133  				}
   134  			} else {
   135  				iter, _ := wantVal.List()
   136  				b, err := EncodeStream(iter)
   137  				if err != nil {
   138  					t.Error(err)
   139  				}
   140  				if got := string(b); got != yamlOut {
   141  					t.Errorf("EncodeStream:\ngot  %q\nwant %q", got, yamlOut)
   142  				}
   143  			}
   144  		})
   145  	}
   146  }
   147  
   148  func TestYAMLValues(t *testing.T) {
   149  	testCases := []struct {
   150  		cue  string
   151  		yaml string
   152  	}{
   153  		// strings
   154  		{`"""
   155  	single
   156  	"""`, "single"}, // TODO: CUE simplifies this.
   157  
   158  		{`"""
   159  	aaaa
   160  	bbbb
   161  	"""`, `|-
   162    aaaa
   163    bbbb`},
   164  
   165  		// keep as is
   166  		{`"non"`, `non`},
   167  
   168  		// Non-strings in v1.2. These are single-quoted by the go-yaml.v3 package.
   169  		{`"#cloudmon"`, `'#cloudmon'`},
   170  
   171  		// Strings that mimic numeric values are double quoted by the go-yaml.v3
   172  		// package.
   173  		{`".inf"`, `".inf"`},
   174  		{`".Inf"`, `".Inf"`},
   175  		{`".INF"`, `".INF"`},
   176  		{`".NaN"`, `".NaN"`},
   177  		{`"+.Inf"`, `"+.Inf"`},
   178  		{`"-.Inf"`, `"-.Inf"`},
   179  		{`"2002"`, `"2002"`},
   180  		{`"685_230.15"`, `"685_230.15"`},
   181  		// Note that go-yaml doesn't quote strings which look like hexadecimal numbers,
   182  		// but we do in our fork. See: https://github.com/go-yaml/yaml/issues/847
   183  		{`"0x123456789012345678901234567890"`, `"0x123456789012345678901234567890"`},
   184  
   185  		// Legacy values.format.
   186  		{`"no"`, `"no"`},
   187  		{`"on"`, `"on"`},
   188  		{`".Nan"`, `".Nan"`},
   189  
   190  		// binary
   191  		{`'no'`, `!!binary bm8=`},
   192  
   193  		// floats
   194  		{`.2`, "0.2"},
   195  		{`2.`, "2."},
   196  		{`".inf"`, `".inf"`},
   197  		{`685_230.15`, `685230.15`},
   198  
   199  		// Date and time-like
   200  		{`"2001-12-15T02:59:43.1Z"`, `"2001-12-15T02:59:43.1Z"`},
   201  		{`"2001-12-14t21:59:43.10-05:00"`, `"2001-12-14t21:59:43.10-05:00"`},
   202  		{`"2001-12-14 21:59:43.10 -5"`, `"2001-12-14 21:59:43.10 -5"`},
   203  		{`"2001-12-15 2:59:43.10"`, `"2001-12-15 2:59:43.10"`},
   204  		{`"2002-12-14"`, `"2002-12-14"`},
   205  		{`"12-12-12"`, `"12-12-12"`},
   206  
   207  		// legacy base60 floats
   208  		{`"2222:22"`, `"2222:22"`},
   209  
   210  		// hostport
   211  		{`"hostname:22"`, `hostname:22`},
   212  
   213  		// maps
   214  		{
   215  			cue: `
   216  			true:   1
   217  			True:   2
   218  			".Nan": 3
   219  			".Inf": 4
   220  			y:      5
   221  			`,
   222  			yaml: `"true": 1
   223  "True": 2
   224  ".Nan": 3
   225  ".Inf": 4
   226  "y": 5`,
   227  		},
   228  	}
   229  	for _, tc := range testCases {
   230  		t.Run(tc.cue, func(t *testing.T) {
   231  			c := cuecontext.New()
   232  			v := c.CompileString(tc.cue)
   233  
   234  			b, err := Encode(v)
   235  			if err != nil {
   236  				t.Error(err)
   237  			}
   238  			if got := strings.TrimSpace(string(b)); got != tc.yaml {
   239  				t.Errorf("Encode:\ngot  %q\nwant %q", got, tc.yaml)
   240  			}
   241  
   242  		})
   243  	}
   244  }