1 package d2ir_test
2
3 import (
4 "testing"
5
6 "oss.terrastruct.com/util-go/assert"
7
8 "oss.terrastruct.com/d2/d2ir"
9 )
10
11 func testCompileImports(t *testing.T) {
12 t.Parallel()
13
14 tca := []testCase{
15 {
16 name: "value",
17 run: func(t testing.TB) {
18 m, err := compileFS(t, "index.d2", map[string]string{
19 "index.d2": "x: @x.d2",
20 "x.d2": `shape: circle
21 label: meow`,
22 })
23 assert.Success(t, err)
24 assertQuery(t, m, 3, 0, nil, "")
25 assertQuery(t, m, 2, 0, nil, "x")
26 assertQuery(t, m, 0, 0, "circle", "x.shape")
27 assertQuery(t, m, 0, 0, "meow", "x.label")
28 },
29 },
30 {
31 name: "nested/map",
32 run: func(t testing.TB) {
33 m, err := compileFS(t, "index.d2", map[string]string{
34 "index.d2": "x: @x.y",
35 "x.d2": `y: {
36 shape: circle
37 label: meow
38 }`,
39 })
40 assert.Success(t, err)
41 assertQuery(t, m, 3, 0, nil, "")
42 assertQuery(t, m, 2, 0, nil, "x")
43 assertQuery(t, m, 0, 0, "circle", "x.shape")
44 assertQuery(t, m, 0, 0, "meow", "x.label")
45 },
46 },
47 {
48 name: "nested/array",
49 run: func(t testing.TB) {
50 m, err := compileFS(t, "index.d2", map[string]string{
51 "index.d2": "x: @x.y",
52 "x.d2": `y: [1, 2]`,
53 })
54 assert.Success(t, err)
55 assertQuery(t, m, 1, 0, nil, "")
56 x := assertQuery(t, m, 0, 0, nil, "x")
57 xf, ok := x.(*d2ir.Field)
58 assert.True(t, ok)
59 assert.Equal(t, `[1, 2]`, xf.Composite.String())
60 },
61 },
62 {
63 name: "nested/scalar",
64 run: func(t testing.TB) {
65 m, err := compileFS(t, "index.d2", map[string]string{
66 "index.d2": "x: @x.y",
67 "x.d2": `y: meow`,
68 })
69 assert.Success(t, err)
70 assertQuery(t, m, 1, 0, nil, "")
71 assertQuery(t, m, 0, 0, "meow", "x")
72 },
73 },
74 {
75 name: "boards",
76 run: func(t testing.TB) {
77 m, err := compileFS(t, "index.d2", map[string]string{
78 "index.d2": `x.link: layers.x; layers: { x: @x }`,
79 "x.d2": `y.link: layers.y; layers: { y: @y }`,
80 "y.d2": `meow`,
81 })
82 assert.Success(t, err)
83 assertQuery(t, m, 0, 0, "root.layers.x", "x.link")
84 assertQuery(t, m, 0, 0, "root.layers.x.layers.y", "layers.x.y.link")
85 },
86 },
87 {
88 name: "boards-deep",
89 run: func(t testing.TB) {
90 m, err := compileFS(t, "index.d2", map[string]string{
91 "index.d2": `a.link: layers.b; layers: { b: @b }`,
92 "b.d2": `b.link: layers.c; layers: { c: @c }`,
93 "c.d2": `c.link: layers.d; layers: { d: @d }`,
94 "d.d2": `d`,
95 })
96 assert.Success(t, err)
97 assertQuery(t, m, 0, 0, "root.layers.b.layers.c.layers.d", "layers.b.layers.c.c.link")
98 },
99 },
100 {
101 name: "steps-inheritence",
102 run: func(t testing.TB) {
103 m, err := compileFS(t, "index.d2", map[string]string{
104 "index.d2": `z; steps: { 1: @x; 2: @y }; scenarios: { x: @x; y: @y }`,
105 "x.d2": `a`,
106 "y.d2": `b`,
107 })
108 assert.Success(t, err)
109 assertQuery(t, m, 2, 0, nil, "scenarios.x")
110 assertQuery(t, m, 2, 0, nil, "scenarios.y")
111 assertQuery(t, m, 2, 0, nil, "steps.1")
112 assertQuery(t, m, 3, 0, nil, "steps.2")
113 },
114 },
115 {
116 name: "spread",
117 run: func(t testing.TB) {
118 m, err := compileFS(t, "index.d2", map[string]string{
119 "index.d2": "...@x.d2",
120 "x.d2": "x: wowa",
121 })
122 assert.Success(t, err)
123 assertQuery(t, m, 1, 0, nil, "")
124 assertQuery(t, m, 0, 0, "wowa", "x")
125 },
126 },
127 {
128 name: "nested/spread",
129 run: func(t testing.TB) {
130 m, err := compileFS(t, "index.d2", map[string]string{
131 "index.d2": "...@x.y",
132 "x.d2": "y: { jon; jan }",
133 })
134 assert.Success(t, err)
135 assertQuery(t, m, 2, 0, nil, "")
136 assertQuery(t, m, 0, 0, nil, "jan")
137 assertQuery(t, m, 0, 0, nil, "jon")
138 },
139 },
140 {
141 name: "nested/spread_primary",
142 run: func(t testing.TB) {
143 m, err := compileFS(t, "index.d2", map[string]string{
144 "index.d2": "q: { ...@x.y }",
145 "x.d2": "y: meow { jon; jan }",
146 })
147 assert.Success(t, err)
148 assertQuery(t, m, 3, 0, nil, "")
149 assertQuery(t, m, 2, 0, "meow", "q")
150 assertQuery(t, m, 0, 0, nil, "q.jan")
151 assertQuery(t, m, 0, 0, nil, "q.jon")
152 },
153 },
154 {
155 name: "vars/1",
156 run: func(t testing.TB) {
157 m, err := compileFS(t, "index.d2", map[string]string{
158 "index.d2": "vars: { ...@x }; q: ${meow}",
159 "x.d2": "meow: var replaced",
160 })
161 assert.Success(t, err)
162 assertQuery(t, m, 0, 0, "var replaced", "q")
163 },
164 },
165 {
166 name: "vars/2",
167 run: func(t testing.TB) {
168 m, err := compileFS(t, "index.d2", map[string]string{
169 "index.d2": "vars: { x: 1 }; ...@a",
170 "a.d2": "vars: { x: 2 }; hi: ${x}",
171 })
172 assert.Success(t, err)
173 assertQuery(t, m, 0, 0, 2, "hi")
174 },
175 },
176 {
177 name: "vars/3",
178 run: func(t testing.TB) {
179 m, err := compileFS(t, "index.d2", map[string]string{
180 "index.d2": "...@a; vars: { x: 1 }; hi: ${x}",
181 "a.d2": "vars: { x: 2 }",
182 })
183 assert.Success(t, err)
184 assertQuery(t, m, 0, 0, 1, "hi")
185 },
186 },
187 {
188 name: "pattern-value",
189 run: func(t testing.TB) {
190 _, err := compileFS(t, "index.d2", map[string]string{
191 "index.d2": `userWebsite
192 userMobile
193
194 user*: @x
195 `,
196 "x.d2": `shape: person
197 label: meow`,
198 })
199 assert.Success(t, err)
200 },
201 },
202 {
203 name: "merge-arrays",
204 run: func(t testing.TB) {
205 _, err := compileFS(t, "index.d2", map[string]string{
206 "index.d2": `x.class: [a]
207 ...@d
208 `,
209 "d.d2": `x.class: [b]`,
210 })
211 assert.Success(t, err)
212 },
213 },
214 }
215
216 runa(t, tca)
217
218 t.Run("errors", func(t *testing.T) {
219 tca := []testCase{
220 {
221 name: "not_exist",
222 run: func(t testing.TB) {
223 _, err := compileFS(t, "index.d2", map[string]string{
224 "index.d2": "...@x.d2",
225 })
226 assert.ErrorString(t, err, `index.d2:1:1: failed to import "x.d2": open x.d2: no such file or directory`)
227 },
228 },
229 {
230 name: "escape",
231 run: func(t testing.TB) {
232 _, err := compileFS(t, "index.d2", map[string]string{
233 "index.d2": "...@'./../x.d2'",
234 })
235 assert.ErrorString(t, err, `index.d2:1:1: failed to import "../x.d2": stat ../x.d2: invalid argument`)
236 },
237 },
238 {
239 name: "absolute",
240 run: func(t testing.TB) {
241 _, err := compileFS(t, "index.d2", map[string]string{
242 "index.d2": "...@/x.d2",
243 })
244 assert.ErrorString(t, err, `index.d2:1:1: import paths must be relative`)
245 },
246 },
247 {
248 name: "parse",
249 run: func(t testing.TB) {
250 _, err := compileFS(t, "index.d2", map[string]string{
251 "index.d2": "...@x.d2",
252 "x.d2": "x<><><<>q",
253 })
254 assert.ErrorString(t, err, `x.d2:1:1: connection missing destination
255 x.d2:1:4: connection missing source
256 x.d2:1:4: connection missing destination
257 x.d2:1:6: connection missing source
258 x.d2:1:6: connection missing destination
259 x.d2:1:7: connection missing source`)
260 },
261 },
262 {
263 name: "cyclic",
264 run: func(t testing.TB) {
265 _, err := compileFS(t, "index.d2", map[string]string{
266 "index.d2": "...@x",
267 "x.d2": "...@y",
268 "y.d2": "...@q",
269 "q.d2": "...@x",
270 })
271 assert.ErrorString(t, err, `q.d2:1:1: detected cyclic import chain: x.d2 -> y.d2 -> q.d2 -> x.d2`)
272 },
273 },
274 {
275 name: "spread_non_map",
276 run: func(t testing.TB) {
277 _, err := compileFS(t, "index.d2", map[string]string{
278 "index.d2": "...@x.y",
279 "x.d2": "y: meow",
280 })
281 assert.ErrorString(t, err, `index.d2:1:1: cannot spread import non map into map`)
282 },
283 },
284 }
285 runa(t, tca)
286 })
287 }
288
View as plain text