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 }