cuelang.org/go@v0.10.1/internal/filetypes/filetypes_test.go (about) 1 // Copyright 2020 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 filetypes 16 17 import ( 18 "strings" 19 "testing" 20 21 "github.com/google/go-cmp/cmp" 22 "github.com/google/go-cmp/cmp/cmpopts" 23 24 "cuelang.org/go/cue/build" 25 "cuelang.org/go/cue/errors" 26 ) 27 28 func check(t *testing.T, want, x interface{}, err error) { 29 t.Helper() 30 if err != nil { 31 x = errors.String(err.(errors.Error)) 32 } 33 if diff := cmp.Diff(want, x, cmpopts.EquateEmpty()); diff != "" { 34 t.Errorf("unexpected result; -want +got\n%s", diff) 35 } 36 } 37 38 func TestFromFile(t *testing.T) { 39 testCases := []struct { 40 name string 41 in build.File 42 mode Mode 43 out interface{} 44 }{{ 45 name: "must specify encoding", 46 in: build.File{}, 47 out: `modes.input.FileInfo: field not found: encoding`, 48 }, { 49 // Default without any 50 name: "cue", 51 in: build.File{ 52 Filename: "", 53 Encoding: build.CUE, 54 }, 55 mode: Def, 56 out: &FileInfo{ 57 File: &build.File{ 58 Filename: "", 59 Encoding: "cue", 60 Form: "schema", 61 }, 62 Definitions: true, 63 Data: true, 64 Optional: true, 65 Constraints: true, 66 References: true, 67 Cycles: true, 68 KeepDefaults: true, 69 Incomplete: true, 70 Imports: true, 71 Docs: true, 72 Attributes: true, 73 }, 74 }, { 75 // CUE encoding in data form. 76 name: "data: cue", 77 in: build.File{ 78 Filename: "", 79 Form: build.Data, 80 Encoding: build.CUE, 81 }, 82 mode: Input, 83 out: &FileInfo{ 84 File: &build.File{ 85 Filename: "", 86 Encoding: "cue", 87 Form: "data", 88 }, 89 Data: true, 90 Docs: true, 91 Attributes: true, 92 }, 93 }, { 94 // Filename starting with a . but no other extension. 95 name: "filename-with-dot", 96 in: build.File{ 97 Filename: ".json", 98 }, 99 mode: Def, 100 out: `modes.def.FileInfo: field not found: encoding`, 101 }, { 102 name: "yaml", 103 mode: Def, 104 in: build.File{ 105 Filename: "foo.yaml", 106 }, 107 out: &FileInfo{ 108 File: &build.File{ 109 Filename: "foo.yaml", 110 Encoding: "yaml", 111 Form: "graph", 112 }, 113 Data: true, 114 References: true, 115 Cycles: true, 116 Stream: true, 117 Docs: true, 118 Attributes: true, 119 }, 120 }, { 121 name: "yaml+openapi", 122 in: build.File{ 123 Filename: "foo.yaml", 124 Interpretation: "openapi", 125 }, 126 out: &FileInfo{ 127 File: &build.File{ 128 Filename: "foo.yaml", 129 Encoding: "yaml", 130 Interpretation: "openapi", 131 Form: "schema", 132 }, 133 Definitions: true, 134 Data: true, 135 Optional: true, 136 Constraints: true, 137 References: true, 138 Cycles: true, 139 KeepDefaults: true, 140 Incomplete: true, 141 Imports: true, 142 Docs: true, 143 Attributes: true, 144 }, 145 }, { 146 name: "JSONDefault", 147 mode: Input, 148 in: build.File{ 149 Filename: "data.json", 150 }, 151 out: &FileInfo{ 152 File: &build.File{ 153 Filename: "data.json", 154 Encoding: "json", 155 Interpretation: "auto", 156 Form: "schema", 157 }, 158 Definitions: true, 159 Data: true, 160 Optional: true, 161 Constraints: true, 162 References: true, 163 Cycles: true, 164 KeepDefaults: true, 165 Incomplete: true, 166 Imports: true, 167 Docs: true, 168 Attributes: true, 169 }, 170 }, { 171 name: "JSONSchema", 172 in: build.File{ 173 Filename: "foo.json", 174 Interpretation: "jsonschema", 175 }, 176 out: &FileInfo{ 177 File: &build.File{ 178 Filename: "foo.json", 179 Encoding: "json", 180 Interpretation: "jsonschema", 181 Form: "schema", 182 }, 183 Definitions: true, 184 Data: true, 185 Optional: true, 186 Constraints: true, 187 References: true, 188 Cycles: true, 189 KeepDefaults: true, 190 Incomplete: true, 191 Imports: true, 192 Docs: true, 193 Attributes: true, 194 }, 195 }, { 196 name: "JSONOpenAPI", 197 in: build.File{ 198 Filename: "foo.json", 199 Interpretation: "openapi", 200 }, 201 mode: Def, 202 out: &FileInfo{ 203 File: &build.File{ 204 Filename: "foo.json", 205 Encoding: "json", 206 Interpretation: "openapi", 207 Form: "schema", 208 }, 209 Definitions: true, 210 Data: true, 211 Optional: true, 212 Constraints: true, 213 References: true, 214 Cycles: true, 215 KeepDefaults: true, 216 Incomplete: true, 217 Imports: true, 218 Docs: true, 219 Attributes: true, 220 }, 221 }, { 222 name: "OpenAPIDefaults", 223 in: build.File{ 224 Filename: "-", 225 Interpretation: "openapi", 226 }, 227 mode: Def, 228 out: &FileInfo{ 229 File: &build.File{ 230 Filename: "-", 231 Encoding: "json", 232 Interpretation: "openapi", 233 Form: "schema", 234 }, 235 Definitions: true, 236 Data: true, 237 Optional: true, 238 Constraints: true, 239 References: true, 240 Cycles: true, 241 KeepDefaults: true, 242 Incomplete: true, 243 Imports: true, 244 Docs: true, 245 Attributes: true, 246 }, 247 }, { 248 name: "Go", 249 in: build.File{ 250 Filename: "foo.go", 251 }, 252 mode: Def, 253 out: &FileInfo{ 254 File: &build.File{ 255 Filename: "foo.go", 256 Encoding: "code", 257 Form: "schema", 258 Tags: map[string]string{"lang": "go"}, 259 }, 260 Definitions: true, 261 Data: true, 262 Optional: true, 263 Constraints: true, 264 References: true, 265 Cycles: true, 266 KeepDefaults: true, 267 Incomplete: true, 268 Imports: true, 269 Stream: false, 270 Docs: true, 271 Attributes: true, 272 }, 273 }} 274 for _, tc := range testCases { 275 t.Run(tc.name, func(t *testing.T) { 276 info, err := FromFile(&tc.in, tc.mode) 277 check(t, tc.out, info, err) 278 }) 279 } 280 } 281 282 func TestParseFile(t *testing.T) { 283 // TODO(errors): wrong path? 284 testCases := []struct { 285 in string 286 mode Mode 287 out interface{} 288 }{{ 289 in: "file.json", 290 mode: Input, 291 out: &build.File{ 292 Filename: "file.json", 293 Encoding: "json", 294 Interpretation: "auto", 295 }, 296 }, { 297 in: ".json", 298 mode: Input, 299 out: `no encoding specified for file ".json"`, 300 }, { 301 in: ".json.yaml", 302 mode: Input, 303 out: &build.File{ 304 Filename: ".json.yaml", 305 Encoding: "yaml", 306 Interpretation: "auto", 307 }, 308 }, { 309 in: "file.json", 310 mode: Def, 311 out: &build.File{ 312 Filename: "file.json", 313 Encoding: "json", 314 }, 315 }, { 316 in: "schema:file.json", 317 out: &build.File{ 318 Filename: "file.json", 319 Encoding: "json", 320 Interpretation: "auto", 321 Form: "schema", 322 }, 323 }, { 324 in: "openapi:-", 325 out: &build.File{ 326 Filename: "-", 327 Encoding: "json", 328 Interpretation: "openapi", 329 }, 330 }, { 331 in: "cue:file.json", 332 out: &build.File{ 333 Filename: "file.json", 334 Encoding: "cue", 335 }, 336 }, { 337 in: "cue+schema:-", 338 out: &build.File{ 339 Filename: "-", 340 Encoding: "cue", 341 Form: "schema", 342 }, 343 }, { 344 in: "code+lang=js:foo.x", 345 out: &build.File{ 346 Filename: "foo.x", 347 Encoding: "code", 348 Tags: map[string]string{"lang": "js"}, 349 }, 350 }, { 351 in: "foo:file.bar", 352 out: `unknown filetype foo`, 353 }, { 354 in: "file.bar", 355 out: `unknown file extension .bar`, 356 }, { 357 in: "-", 358 mode: Input, 359 out: &build.File{ 360 Filename: "-", 361 Encoding: "cue", 362 }, 363 }, { 364 in: "-", 365 mode: Export, 366 out: &build.File{ 367 Filename: "-", 368 Encoding: "json", 369 }, 370 }} 371 for _, tc := range testCases { 372 t.Run(tc.in, func(t *testing.T) { 373 f, err := ParseFile(tc.in, tc.mode) 374 check(t, tc.out, f, err) 375 }) 376 } 377 } 378 379 func TestParseArgs(t *testing.T) { 380 testCases := []struct { 381 in string 382 out interface{} 383 }{{ 384 in: "foo.json baz.yaml", 385 out: []*build.File{ 386 { 387 Filename: "foo.json", 388 Encoding: "json", 389 Interpretation: "auto", 390 }, 391 { 392 Filename: "baz.yaml", 393 Encoding: "yaml", 394 Interpretation: "auto", 395 }, 396 }, 397 }, { 398 in: "data: foo.cue", 399 out: []*build.File{ 400 {Filename: "foo.cue", Encoding: "cue", Form: "data"}, 401 }, 402 }, { 403 in: "json: foo.json bar.data jsonschema: bar.schema", 404 out: []*build.File{ 405 {Filename: "foo.json", Encoding: "json"}, // no auto! 406 {Filename: "bar.data", Encoding: "json"}, 407 { 408 Filename: "bar.schema", 409 Encoding: "json", 410 Interpretation: "jsonschema", 411 }, 412 }, 413 }, { 414 in: `json: c:\foo.json c:\path\to\file.dat`, 415 out: []*build.File{ 416 {Filename: `c:\foo.json`, Encoding: "json"}, 417 {Filename: `c:\path\to\file.dat`, Encoding: "json"}, 418 }, 419 }, { 420 in: "json: json+schema: bar.schema", 421 out: `scoped qualifier "json:" without file`, 422 }, { 423 in: "json:", 424 out: `scoped qualifier "json:" without file`, 425 }, { 426 in: "json:foo:bar.yaml", 427 out: `unsupported file name "json:foo:bar.yaml": may not have ':'`, 428 }} 429 for _, tc := range testCases { 430 t.Run(tc.in, func(t *testing.T) { 431 files, err := ParseArgs(strings.Split(tc.in, " ")) 432 check(t, tc.out, files, err) 433 }) 434 } 435 }