-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrestache_test.go
206 lines (197 loc) · 5.23 KB
/
restache_test.go
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package restache_test
import (
"os"
"path/filepath"
"sort"
"strings"
"testing"
"github.com/tetsuo/restache"
)
func TestTranspileFileInvalidInputFile(t *testing.T) {
for _, tt := range []struct {
desc string
inputFile string
wantErr string
}{
{
"empty input path",
"",
"input file path is empty",
},
{
"filename with invalid char",
"/components/bad$name.stache",
"contains invalid character '$'",
},
{
"empty stem",
"/components/.stache",
"is not valid",
},
{
"starts with symbol",
"/components/_hidden.stache",
"must start with a letter",
},
{
"input is root slash",
"/",
"must start with a letter",
},
{
"input is series of slashes",
"///",
"must start with a letter",
},
{
"input is '.' (current directory)",
".",
": is a directory", // handled during parse()
},
{
"input is '..' (parent directory)",
"..",
": is a directory", // handled during parse()
},
{
"input doesn't exist",
"/i/am/not/exist.stache",
"no such file or directory",
},
} {
t.Run(tt.desc, func(t *testing.T) {
_, err := restache.TranspileFile(tt.inputFile, "")
if err == nil || !strings.Contains(err.Error(), tt.wantErr) {
t.Errorf("got err = %v, want err containing %q", err, tt.wantErr)
}
})
}
}
func TestParseModuleDeps(t *testing.T) {
tests := []struct {
name string
recursive bool
}{
{name: "card_grid"},
{name: "deep_tree"},
{name: "diamond"},
{name: "fan_out_and_in"},
{name: "fruits_basic"},
{name: "many_to_one"},
{name: "mixed_recursive", recursive: true},
{name: "nested_panels"},
{name: "one_to_many"},
{name: "recursive_tree", recursive: true},
{name: "standalone"},
}
for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
baseDir := filepath.Join("testdata", "module_deps", tc.name)
_, relPaths := mustGlobFiles(t, baseDir, "*.stache")
expectedAttrs := mustParseDepsFile(t, baseDir)
recursiveMap := make(map[string]bool)
for from, attrs := range expectedAttrs {
filtered := attrs[:0]
for _, attr := range attrs {
if attr.Key == from {
recursiveMap[from] = true
continue
}
filtered = append(filtered, attr)
}
expectedAttrs[from] = filtered
}
nodes, err := restache.ParseModule(baseDir, restache.WithIncludes(relPaths))
if err != nil {
t.Fatalf("ParseModule failed: %v", err)
}
for _, node := range nodes {
if node.Type != restache.ComponentNode {
t.Errorf("expected node %q to be ComponentNode, got %v", node.Data, node.Type)
}
if len(node.Path) != 2 {
t.Errorf("expected node %q Path len=2, got %d", node.Data, len(node.Path))
} else {
if node.Path[0].Key != node.Data {
t.Errorf("expected Path[0] == Data (%q), got %q", node.Data, node.Path[0].Key)
}
if node.Path[1].Key != ".stache" {
t.Errorf("expected Path[1] == .stache, got %q", node.Path[1].Key)
}
}
isRecursive := recursiveMap[node.Data]
if isRecursive {
if node.DataAtom != 1 {
t.Errorf("expected recursive node %q to have DataAtom=1, got %v", node.Data, node.DataAtom)
}
for _, attr := range node.Attr {
if attr.Key == node.Data {
t.Errorf("recursive node %q should not have itself in Attrs", node.Data)
}
}
} else {
if node.DataAtom != 0 {
t.Errorf("expected non-recursive node %q to have DataAtom=0, got %v", node.Data, node.DataAtom)
}
}
expected := expectedAttrs[node.Data]
if len(node.Attr) != len(expected) {
t.Errorf("node %q: expected %d Attrs, got %d", node.Data, len(expected), len(node.Attr))
continue
}
sort.Slice(expected, func(i, j int) bool {
return expected[i].Key < expected[j].Key
})
sort.Slice(node.Attr, func(i, j int) bool {
return node.Attr[i].Key < node.Attr[j].Key
})
for i := range node.Attr {
if node.Attr[i] != expected[i] {
t.Errorf("node %q Attr[%d] mismatch: expected %+v, got %+v", node.Data, i, expected[i], node.Attr[i])
}
}
}
})
}
}
func mustGlobFiles(t *testing.T, dir, pattern string) ([]string, []string) {
matches, err := filepath.Glob(filepath.Join(dir, pattern))
if err != nil {
t.Fatalf("failed to glob stache files: %v", err)
}
if len(matches) == 0 {
t.Fatalf("no .stache files found in %s", dir)
}
// Build relative paths
var relPaths []string
for _, m := range matches {
rel, err := filepath.Rel(dir, m)
if err != nil {
t.Fatalf("failed to get relative path: %v", err)
}
relPaths = append(relPaths, rel)
}
return matches, relPaths
}
func mustParseDepsFile(t *testing.T, dir string) map[string][]restache.Attribute {
depsPath := filepath.Join(dir, "deps.txt")
expectedAttrs := make(map[string][]restache.Attribute) // key = component name
if content, err := os.ReadFile(depsPath); err == nil {
lines := strings.SplitSeq(string(content), "\n")
for line := range lines {
fields := strings.Fields(line)
if len(fields) == 2 {
from, to := fields[0], fields[1]
expectedAttrs[from] = append(expectedAttrs[from], restache.Attribute{
Key: to,
Val: to,
IsExpr: false,
})
}
}
} else if !os.IsNotExist(err) {
t.Fatalf("failed to read deps.txt: %v", err)
}
return expectedAttrs
}