1
2
3
4
5 package specgen
6
7 import (
8 "strings"
9 "sync"
10 "testing"
11 )
12
13 var (
14 specPkg *specPackage
15 specLoadErr error
16 loadSpecOnce sync.Once
17 )
18
19 func loadSpec(t *testing.T) *specPackage {
20 loadSpecOnce.Do(func() {
21 var root contextRoot
22 ctx := context{root: &root}
23
24 specPkg = loadSpecPackage(ctx, "../../../internal/spec", &LoadOptions{})
25 if err := root.gatherErrors(); err != nil {
26 specLoadErr = err
27 }
28 })
29 if specLoadErr != nil {
30 t.Fatalf("failed to load spec: %v", specLoadErr)
31 }
32 return specPkg
33 }
34
35 func TestLoadSpec(t *testing.T) {
36 pkg := loadSpec(t)
37
38
39 if len(pkg.Funcs) == 0 {
40 t.Errorf("expected parsed functions, got 0")
41 }
42
43 var foundAdd, foundExtend bool
44 for _, f := range pkg.Funcs {
45 if f.Name == "Add" {
46 foundAdd = true
47 if len(f.TypeParams) != 2 {
48 t.Errorf("Add should have 2 type parameters, got %d", len(f.TypeParams))
49 } else {
50 if f.TypeParams[0].Obj().Name() != "E" || !strings.Contains(f.TypeParams[0].Constraint().String(), "Nums") {
51 t.Errorf("unexpected Add type param 0: %s %s", f.TypeParams[0].Obj().Name(), f.TypeParams[0].Constraint())
52 }
53 if f.TypeParams[1].Obj().Name() != "W" || !strings.Contains(f.TypeParams[1].Constraint().String(), "Width") {
54 t.Errorf("unexpected Add type param 1: %s %s", f.TypeParams[1].Obj().Name(), f.TypeParams[1].Constraint())
55 }
56 }
57 if len(f.Params) != 2 {
58 t.Errorf("Add should have 2 params, got %d", len(f.Params))
59 } else {
60 if f.Params[0].Name() != "x" || !strings.Contains(f.Params[0].Type().String(), "Vec[") {
61 t.Errorf("unexpected Add param 0: %s %s", f.Params[0].Name(), f.Params[0].Type())
62 }
63 if f.Params[1].Name() != "y" || !strings.Contains(f.Params[1].Type().String(), "Vec[") {
64 t.Errorf("unexpected Add param 1: %s %s", f.Params[1].Name(), f.Params[1].Type())
65 }
66 }
67 if len(f.Results) != 1 {
68 t.Errorf("Add should have 1 result, got %d", len(f.Results))
69 } else {
70 if !strings.Contains(f.Results[0].Type().String(), "Vec[") {
71 t.Errorf("unexpected Add result type: %s", f.Results[0].Type())
72 }
73 }
74 }
75
76 if f.Name == "ExtendLoLToZ" {
77 foundExtend = true
78 if len(f.Requirements) != 2 {
79 t.Errorf("expected 2 requirements for ExtendLoLToZ, got %d", len(f.Requirements))
80 } else {
81 if f.Requirements[0] == nil || f.Requirements[1] == nil {
82 t.Errorf("expected non-nil parsed requirements")
83 }
84 }
85 }
86 }
87
88 if !foundAdd {
89 t.Errorf("failed to find function Add in parsed package")
90 }
91 if !foundExtend {
92 t.Errorf("failed to find function ExtendLoLToZ in parsed package")
93 }
94 }
95
96 func TestLoadSpecNameTmpl(t *testing.T) {
97 pkg := loadSpec(t)
98 var found bool
99 for _, f := range pkg.Funcs {
100 if f.Name == "MaskFromBits" {
101 found = true
102 want := "{z}FromBits"
103 if f.NameTmpl.tmpl != want {
104 t.Errorf("MaskFromBits: expected NameTmpl.tmpl %q, got %q", want, f.NameTmpl.tmpl)
105 }
106 break
107 }
108 }
109 if !found {
110 t.Errorf("failed to find function MaskFromBits in parsed package")
111 }
112 }
113
114 func TestNewSpecTemplate(t *testing.T) {
115 tests := []struct {
116 tmpl string
117 want specTemplate
118 wantErr bool
119 }{
120 {
121 tmpl: "",
122 want: specTemplate{tmpl: "", fields: nil},
123 },
124 {
125 tmpl: "Convert",
126 want: specTemplate{tmpl: "Convert", fields: nil},
127 },
128 {
129 tmpl: "Convert{zL}To{zB}{zN}",
130 want: specTemplate{
131 tmpl: "Convert{zL}To{zB}{zN}",
132 fields: [][2]int{{7, 11}, {13, 17}, {17, 21}},
133 },
134 },
135 {
136 tmpl: "Convert{zL",
137 wantErr: true,
138 },
139 {
140 tmpl: "Convert}",
141 wantErr: true,
142 },
143 {
144 tmpl: "Convert{a{b}}",
145 wantErr: true,
146 },
147 }
148
149 for _, tc := range tests {
150 got, err := newSpecTemplate(tc.tmpl)
151 if (err != nil) != tc.wantErr {
152 t.Errorf("newSpecTemplate(%q) returned error: %v, wantErr: %v", tc.tmpl, err, tc.wantErr)
153 continue
154 }
155 if tc.wantErr {
156 continue
157 }
158 if got.tmpl != tc.want.tmpl {
159 t.Errorf("newSpecTemplate(%q) tmpl = %q, want %q", tc.tmpl, got.tmpl, tc.want.tmpl)
160 }
161 if len(got.fields) != len(tc.want.fields) {
162 t.Errorf("newSpecTemplate(%q) fields len = %d, want %d", tc.tmpl, len(got.fields), len(tc.want.fields))
163 } else {
164 for i := range got.fields {
165 if got.fields[i] != tc.want.fields[i] {
166 t.Errorf("newSpecTemplate(%q) fields[%d] = %v, want %v", tc.tmpl, i, got.fields[i], tc.want.fields[i])
167 }
168 }
169 }
170 }
171 }
172
173 func TestSpecTemplateExpand(t *testing.T) {
174 tmpl, err := newSpecTemplate("Convert{zL}To{zB}{zN}")
175 if err != nil {
176 t.Fatalf("unexpected error parsing template: %v", err)
177 }
178
179 lookup := func(name string) string {
180 switch name {
181 case "zL":
182 return "4"
183 case "zB":
184 return "Float"
185 case "zN":
186 return "32"
187 }
188 return ""
189 }
190
191 got := tmpl.expand(lookup)
192 want := "Convert4ToFloat32"
193 if got != want {
194 t.Errorf("expected expanded string %q, got %q", want, got)
195 }
196 }
197
View as plain text