Home

gen @e423ae92176cc817abac3a983cb7990c809d063e - refs - log -
-
https://git.jolheiser.com/gen.git
Generate Go flags and Nix module
gen / main_test.go
- raw -
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main

import (
	"flag"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"cuelang.org/go/cue/cuecontext"
)

var update = flag.Bool("update", false, "rewrite golden files")

func TestGolden(t *testing.T) {
	cases := []struct {
		schema, goType, suffix, pkg string
	}{
		{"ugit.cue", "cliArgs", "Args", "main"},
		{"kitchen.cue", "config", "Config", "kitchen"},
	}
	for _, tc := range cases {
		t.Run(tc.schema, func(t *testing.T) {
			v, err := loadSchema(filepath.Join("testdata", tc.schema))
			if err != nil {
				t.Fatal(err)
			}
			root, err := buildModel(v, tc.goType, tc.suffix, newNamer(nil))
			if err != nil {
				t.Fatal(err)
			}
			goSrc, err := genGo(root, tc.pkg, tc.schema)
			if err != nil {
				t.Fatal(err)
			}
			nixSrc, err := genNix(root, tc.schema)
			if err != nil {
				t.Fatal(err)
			}
			base := strings.TrimSuffix(tc.schema, ".cue")
			golden(t, filepath.Join("testdata", base+".go.golden"), goSrc)
			golden(t, filepath.Join("testdata", base+".nix.golden"), nixSrc)
		})
	}
}

func golden(t *testing.T, path string, got []byte) {
	t.Helper()
	if *update {
		if err := os.WriteFile(path, got, 0o644); err != nil {
			t.Fatal(err)
		}
		return
	}
	want, err := os.ReadFile(path)
	if err != nil {
		t.Fatalf("%v (run go test -update)", err)
	}
	if string(got) != string(want) {
		t.Errorf("%s is out of date (run go test -update and review the diff)", path)
	}
}

func TestErrors(t *testing.T) {
	cases := []struct{ name, src, want string }{
		{"mixed disjunction", `a: int | string`, "a: unsupported type"},
		{"non-literal disjunction", `a: string | =~"x"`, "only enums of literal values"},
		{"map", `a: [string]: int`, "a: structs with pattern constraints"},
		{"nested list", `a: [...[...int]]`, "a: lists of list"},
		{"list of structs", `a: [...{b: int}]`, "a: lists of struct"},
		{"closed list", `a: [int, int]`, "a: only open lists"},
		{"unknown attr key", `a: int @go(nmae=X)`, `unknown key "nmae" in @go`},
		{"type without parse", `a: string @go(type=foo.Bar)`, "must be set together"},
		{"bad nix default", `a: int & <10 | *1 @nix(default=20)`, "@nix(default=20)"},
		{"nix apply on struct", `a: {b: int} @nix(apply=f)`, "@nix(apply) is not allowed on structs"},
		{"reserved nix import", `a: int @nix(import=types)`, `"types" can't be a Nix function argument`},
		{"field collision", `"a-b": int, a_b: int`, "Go field name AB is also used by a-b"},
		{"type collision", `x: log: {a: int}, y: log: {b: int}`, "Go type logArgs is also used by x.log"},
		{"bad label", `"123": int`, "not a valid Go identifier"},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			v := cuecontext.New().CompileString(tc.src)
			if err := v.Err(); err != nil {
				t.Fatal(err)
			}
			_, err := buildModel(v, "cliArgs", "Args", newNamer(nil))
			if err == nil || !strings.Contains(err.Error(), tc.want) {
				t.Errorf("got error %v, want one containing %q", err, tc.want)
			}
		})
	}
}

func TestSplitWords(t *testing.T) {
	cases := map[string]string{
		"clone-url":    "clone url",
		"clone_url":    "clone url",
		"cloneURL":     "clone url",
		"URLPath":      "url path",
		"show-private": "show private",
		"utf8Name":     "utf8 name",
	}
	for in, want := range cases {
		if got := strings.Join(splitWords(in), " "); got != want {
			t.Errorf("splitWords(%q) = %q, want %q", in, got, want)
		}
	}
}

func TestEREFull(t *testing.T) {
	cases := []struct {
		in, want string
		ok       bool
	}{
		{"^[a-z]+$", "[a-z]+", true},
		{"^https://", "https://.*", true},
		{"foo", ".*foo.*", true},
		{"a|b", ".*(a|b).*", true},
		{"^a|b$", "", false},
		{`^\d+$`, "", false},
		{"a+?", "", false},
		{`price\$`, `.*price\$.*`, true},
	}
	for _, tc := range cases {
		got, ok := ereFull(tc.in)
		if got != tc.want || ok != tc.ok {
			t.Errorf("ereFull(%q) = %q, %v; want %q, %v", tc.in, got, ok, tc.want, tc.ok)
		}
	}
}