This repository has no description
1package engine
2
3import (
4 "strings"
5 "testing"
6)
7
8type testManifest struct {
9 Image string `yaml:"image"`
10 Registry map[string]any `yaml:"registry"`
11 Dependencies []string `yaml:"dependencies"`
12 Nested map[string][]string `yaml:"nested"`
13 Steps []struct {
14 Name string `yaml:"name"`
15 } `yaml:"steps"`
16}
17
18func TestDescribeManifestError(t *testing.T) {
19 cases := []struct {
20 name string
21 raw string
22 want []string // substrings the message must contain
23 }{
24 {
25 name: "map field written as list",
26 raw: "registry:\n - nixpkgs: github:nixos/nixpkgs\n",
27 want: []string{"registry", "a mapping", "a list"},
28 },
29 {
30 name: "list field written as scalar",
31 raw: "dependencies: bun\n",
32 want: []string{"dependencies", "a list", "a scalar value"},
33 },
34 {
35 name: "scalar field written as mapping",
36 raw: "image:\n name: nixos\n",
37 want: []string{"image", "a scalar value", "a mapping"},
38 },
39 {
40 name: "nested map value mis-shaped",
41 raw: "nested:\n foo: bar\n", // foo should be a list of strings
42 want: []string{"nested.foo", "a list", "a scalar value"},
43 },
44 {
45 name: "field inside a list element mis-shaped",
46 raw: "steps:\n - name:\n x: y\n", // steps[0].name should be a scalar
47 want: []string{"steps[0].name", "a scalar value", "a mapping"},
48 },
49 {
50 name: "unknown top-level field (typo)",
51 raw: "dependancies:\n - bun\n",
52 want: []string{"unknown field", "dependancies"},
53 },
54 {
55 name: "unknown field inside a list element",
56 raw: "steps:\n - name: x\n cmd: y\n", // it's `command`, not `cmd`
57 want: []string{"unknown field", "steps[0].cmd"},
58 },
59 {
60 // `name` (filename-sourced, yaml:"-") must be tolerated so the real
61 // typo `registre` on a later line is the thing that surfaces.
62 name: "tolerated name does not mask a later typo",
63 raw: "name: mill\nengine: microvm\nregistre:\n - x: y\n",
64 want: []string{"unknown field", "registre"},
65 },
66 }
67 for _, tc := range cases {
68 t.Run(tc.name, func(t *testing.T) {
69 err := DescribeManifestError(tc.raw, testManifest{})
70 if err == nil {
71 t.Fatalf("expected an error, got nil")
72 }
73 for _, w := range tc.want {
74 if !strings.Contains(err.Error(), w) {
75 t.Errorf("error %q missing %q", err, w)
76 }
77 }
78 })
79 }
80}
81
82func TestDescribeManifestErrorNoFalsePositives(t *testing.T) {
83 cases := []string{
84 // well-formed manifest
85 "image: nixos\nregistry:\n nixpkgs: github:nixos/nixpkgs\ndependencies:\n - bun\n",
86 // empty value is harmless, not a mismatch
87 "image: nixos\nregistry:\n",
88 // generic workflow keys live in the same doc and aren't engine fields,
89 // but must not be flagged as unknown at the root
90 "engine: microvm\nwhen:\n - event: [push]\nclone:\n skip: true\nimage: nixos\n",
91 // `any` map values accept any shape, including nested lists/maps
92 "registry:\n k:\n - a\n - b\n",
93 // well-formed nested map-of-lists
94 "nested:\n foo:\n - a\n - b\n",
95 // user-defined map keys are data, never flagged as unknown fields
96 "nested:\n any-package-name:\n - a\n",
97 }
98 for _, raw := range cases {
99 if err := DescribeManifestError(raw, testManifest{}); err != nil {
100 t.Errorf("DescribeManifestError(%q) = %v, want nil", raw, err)
101 }
102 }
103}
104
105func TestDescribeManifestErrorPointerSchema(t *testing.T) {
106 // nixery passes a pointer to an anonymous struct
107 schema := &testManifest{}
108 err := DescribeManifestError("nested: oops\n", schema)
109 if err == nil || !strings.Contains(err.Error(), "nested") {
110 t.Fatalf("expected an error naming `nested`, got %v", err)
111 }
112}