1 module tests.it.runtime.dub;
2 
3 
4 import tests.it.runtime;
5 import reggae.reggae;
6 import reggae.path: deabsolutePath;
7 import std.path: buildPath;
8 
9 
10 @("dub project with no reggaefile ninja")
11 @Tags(["dub", "ninja"])
12 unittest {
13 
14     import std.string: join;
15 
16     with(immutable ReggaeSandbox("dub")) {
17         shouldNotExist("reggaefile.d");
18         writelnUt("\n\nReggae output:\n\n", runReggae("-b", "ninja", "--dflags=-g -debug").lines.join("\n"), "-----\n");
19         shouldExist("reggaefile.d");
20         auto output = ninja.shouldExecuteOk;
21         output.shouldContain("-g -debug");
22 
23         shouldSucceed("atest").shouldEqual(
24             ["Why hello!",
25              "",
26              "I'm immortal!"]
27         );
28 
29         // there's only one UT in main.d which always fails
30         shouldFail("ut");
31     }
32 }
33 
34 @("dub project with no reggaefile tup")
35 @Tags(["dub", "tup"])
36 unittest {
37     with(immutable ReggaeSandbox("dub")) {
38         runReggae("-b", "tup", "--dflags=-g -debug").
39             shouldThrowWithMessage("dub integration not supported with the tup backend");
40     }
41 }
42 
43 
44 @("dub project with no reggaefile and prebuild command")
45 @Tags(["dub", "ninja"])
46 unittest {
47     with(immutable ReggaeSandbox("dub_prebuild")) {
48         runReggae("-b", "ninja", "--dflags=-g -debug");
49         ninja.shouldExecuteOk;
50         shouldSucceed("ut");
51     }
52 }
53 
54 
55 @("dub project with postbuild command")
56 @Tags(["dub", "ninja"])
57 unittest {
58     with(immutable ReggaeSandbox("dub_postbuild")) {
59         runReggae("-b", "ninja", "--dflags=-g -debug");
60         ninja.shouldExecuteOk;
61         shouldExist("foo.txt");
62         shouldSucceed("postbuild");
63     }
64 }
65 
66 
67 @("project with dependencies not on file system already no dub.selections.json")
68 @Tags(["dub", "ninja"])
69 unittest {
70 
71     import std.file: exists, rmdirRecurse;
72     import std.process: environment;
73     import std.path: buildPath;
74 
75     const cerealedDir = buildPath(environment["HOME"], ".dub/packages/cerealed-0.6.8");
76     if(cerealedDir.exists)
77         rmdirRecurse(cerealedDir);
78 
79     with(immutable ReggaeSandbox()) {
80         writeFile("dub.json", `
81         {
82           "name": "depends_on_cerealed",
83           "license": "MIT",
84           "targetType": "executable",
85           "dependencies": { "cerealed": "==0.6.8" }
86         }`);
87         writeFile("source/app.d", "void main() {}");
88 
89         runReggae("-b", "ninja");
90     }
91 }
92 
93 
94 @("simple dub project with no main function but with unit tests")
95 @Tags(["dub", "ninja"])
96 unittest {
97     import std.file: mkdirRecurse;
98     import std.path: buildPath;
99 
100     with(immutable ReggaeSandbox()) {
101         writeFile("dub.json", `
102             {
103               "name": "depends_on_cerealed",
104               "license": "MIT",
105               "targetType": "executable",
106               "dependencies": { "cerealed": "==0.6.8" }
107             }`);
108 
109         writeFile("reggaefile.d", q{
110             import reggae;
111             mixin build!(dubTestTarget!(CompilerFlags("-g -debug")));
112         });
113 
114         mkdirRecurse(buildPath(testPath, "source"));
115         writeFile("source/foo.d", `unittest { assert(false); }`);
116         runReggae("-b", "ninja");
117         ninja.shouldExecuteOk;
118 
119         shouldFail("ut");
120     }
121 }
122 
123 
124 @("reggae/dub build should rebuild if dub.selections.json changes")
125 @Tags(["dub", "make"])
126 unittest {
127 
128     import std.process: execute;
129     import std.path: buildPath;
130 
131     with(immutable ReggaeSandbox("dub")) {
132         runReggae("-b", "make", "--dflags=-g -debug");
133         make(["VERBOSE=1"]).shouldExecuteOk.shouldContain("-g -debug");
134         {
135             const ret = execute(["touch", buildPath(testPath, "dub.selections.json")]);
136             ret.status.shouldEqual(0);
137         }
138         {
139             const ret = execute(["make", "-C", testPath]);
140             ret.output.shouldContain("eggae");
141         }
142     }
143 }
144 
145 @("version from main package is used in dependent packages")
146 @Tags(["dub", "ninja"])
147 unittest {
148     with(immutable ReggaeSandbox()) {
149         writeFile("dub.sdl", `
150             name "foo"
151             versions "lefoo"
152             targetType "executable"
153             dependency "bar" path="bar"
154         `);
155         writeFile("source/app.d", q{
156             void main() {
157                 import bar;
158                 import std.stdio;
159                 writeln(lebar);
160             }
161         });
162         writeFile("bar/dub.sdl", `
163             name "bar"
164         `);
165         writeFile("bar/source/bar.d", q{
166             module bar;
167             version(lefoo)
168                 int lebar() { return 3; }
169             else
170                 int lebar() { return 42; }
171         });
172         runReggae("-b", "ninja");
173         ninja.shouldExecuteOk;
174         shouldSucceed("foo").shouldEqual(
175             [
176                 "3",
177             ]
178         );
179     }
180 }
181 
182 
183 @("sourceLibrary dependency")
184 @Tags(["dub", "ninja"])
185 unittest {
186     with(immutable ReggaeSandbox()) {
187         writeFile("dub.sdl", `
188             name "foo"
189             targetType "executable"
190             dependency "bar" path="bar"
191         `);
192         writeFile("source/app.d", q{
193             void main() {
194                 import bar;
195                 import std.stdio;
196                 writeln(lebar);
197             }
198         });
199         writeFile("bar/dub.sdl", `
200             name "bar"
201             targetType "sourceLibrary"
202         `);
203         writeFile("bar/source/bar.d", q{
204             module bar;
205             int lebar() { return 3; }
206         });
207         runReggae("-b", "ninja");
208         ninja.shouldExecuteOk;
209     }
210 }
211 
212 @("object source files")
213 @Tags(["dub", "ninja"])
214 unittest {
215     with(immutable ReggaeSandbox()) {
216         writeFile("dub.sdl", `
217             name "foo"
218             targetType "executable"
219             dependency "bar" path="bar"
220         `);
221         writeFile("source/app.d", q{
222             extern(C) int lebaz();
223             void main() {
224                 import bar;
225                 import std.stdio;
226                 writeln(lebar);
227                 writeln(lebaz);
228             }
229         });
230         writeFile("bar/dub.sdl", `
231             name "bar"
232             sourceFiles "../baz.o"
233         `);
234         writeFile("bar/source/bar.d", q{
235             module bar;
236             int lebar() { return 3; }
237         });
238         writeFile("baz.d", q{
239             module baz;
240             extern(C) int lebaz() { return 42; }
241         });
242 
243         ["dmd", "-c", "baz.d"].shouldExecuteOk;
244         runReggae("-b", "ninja");
245         ninja.shouldExecuteOk;
246     }
247 }
248 
249 
250 @("dub objs option path dependency")
251 @Tags("dub", "ninja", "dubObjsDir")
252 unittest {
253 
254     with(immutable ReggaeSandbox()) {
255 
256         writeFile("reggaefile.d", q{
257             import reggae;
258             mixin build!(dubDefaultTarget!());
259         });
260 
261         writeFile("dub.sdl",`
262             name "foo"
263             targetType "executable"
264             dependency "bar" path="bar"
265         `);
266 
267         writeFile("source/app.d", q{
268             import bar;
269             void main() { add(2, 3); }
270         });
271 
272         writeFile("bar/dub.sdl", `
273             name "bar"
274         `);
275 
276         writeFile("bar/source/bar.d", q{
277             module bar;
278             int add(int i, int j) { return i + j; }
279         });
280 
281         const dubObjsDir = buildPath(testPath, "objsdir");
282         const output = runReggae("-b", "ninja", "--dub-objs-dir=" ~ dubObjsDir);
283         writelnUt(output);
284         ninja.shouldExecuteOk;
285 
286         import std.path: buildPath;
287         shouldExist(buildPath("objsdir",
288                               testPath.deabsolutePath,
289                               "foo.objs",
290                               testPath.deabsolutePath,
291                               "bar",
292                               "source.o"));
293     }
294 }
295 
296 @("dub objs option registry dependency")
297 @Tags("dub", "ninja", "dubObjsDir")
298 unittest {
299 
300     import reggae.path: dubPackagesDir, deabsolutePath;
301 
302     with(immutable ReggaeSandbox()) {
303 
304         writeFile("reggaefile.d", q{
305             import reggae;
306             mixin build!(dubDefaultTarget!());
307         });
308 
309         writeFile("dub.sdl",`
310             name "foo"
311             targetType "executable"
312             dependency "dubnull" version="==0.0.1"
313         `);
314 
315         writeFile("source/app.d", q{
316             import dubnull;
317             void main() { dummy(); }
318         });
319 
320         const dubObjsDir = buildPath(testPath, "objsdir");
321         const output = runReggae("-b", "ninja", "--dub-objs-dir=" ~ dubObjsDir);
322         writelnUt(output);
323 
324         ninja.shouldExecuteOk;
325 
326         import std.path: buildPath;
327         const dubNullDir = buildPath(dubPackagesDir, "dubnull-0.0.1", "dubnull").deabsolutePath;
328         shouldExist(buildPath("objsdir",
329                               testPath.deabsolutePath,
330                               "foo.objs",
331                               dubNullDir,
332                               "source.o"));
333     }
334 }
335 
336 
337 @("object source files with dub objs option")
338 @Tags("dub", "ninja", "dubObjsDir")
339 unittest {
340     with(immutable ReggaeSandbox()) {
341         writeFile("dub.sdl", `
342             name "foo"
343             targetType "executable"
344             dependency "bar" path="bar"
345         `);
346         writeFile("source/app.d", q{
347             extern(C) int lebaz();
348             void main() {
349                 import bar;
350                 import std.stdio;
351                 writeln(lebar);
352                 writeln(lebaz);
353             }
354         });
355         writeFile("bar/dub.sdl", `
356             name "bar"
357             sourceFiles "../baz.o"
358         `);
359         writeFile("bar/source/bar.d", q{
360             module bar;
361             int lebar() { return 3; }
362         });
363         writeFile("baz.d", q{
364             module baz;
365             extern(C) int lebaz() { return 42; }
366         });
367 
368         ["dmd", "-c", "baz.d"].shouldExecuteOk;
369 
370         const output = runReggae("-b", "ninja", "--dub-objs-dir=" ~ testPath);
371         writelnUt(output);
372 
373         ninja.shouldExecuteOk;
374     }
375 }
376 
377 
378 @("dub project that depends on package with prebuild")
379 @Tags(["dub", "ninja"])
380 unittest {
381 
382     import std.path;
383 
384     with(immutable ReggaeSandbox("dub_depends_on_prebuild")) {
385 
386         copyProject("dub_prebuild", buildPath("..", "dub_prebuild"));
387 
388         runReggae("-b", "ninja", "--dflags=-g -debug");
389         ninja.shouldExecuteOk;
390         shouldSucceed("app");
391         shouldExist(inSandboxPath("../dub_prebuild/el_prebuildo.txt"));
392     }
393 }
394 
395 
396 @("static library")
397 @Tags(["dub", "ninja"])
398 unittest {
399 
400     with(immutable ReggaeSandbox()) {
401         writeFile("dub.sdl", `
402             name "foo"
403             targetType "executable"
404             targetName "d++"
405 
406             configuration "executable" {
407             }
408 
409             configuration "library" {
410                 targetType "library"
411                 targetName "dpp"
412                 excludedSourceFiles "source/main.d"
413             }
414         `);
415 
416         writeFile("reggaefile.d",
417                   q{
418                       import reggae;
419                       alias lib = dubConfigurationTarget!(Configuration("library"));
420                       enum mainObj = objectFile(SourceFile("source/main.d"));
421                       alias exe = link!(ExeName("d++"), targetConcat!(lib, mainObj));
422                       mixin build!(exe);
423                   });
424 
425         writeFile("source/main.d", "void main() {}");
426         writeFile("source/foo/bar/mod.d", "module foo.bar.mod; int add1(int i, int j) { return i + j + 1; }");
427 
428         runReggae("-b", "ninja");
429         ninja.shouldExecuteOk;
430         shouldSucceed("d++");
431     }
432 }
433 
434 
435 @("dub project with failing prebuild command")
436 @Tags(["dub", "ninja"])
437 unittest {
438     with(immutable ReggaeSandbox("dub_prebuild_oops")) {
439         runReggae("-b", "ninja", "--dflags=-g -debug")
440             .shouldThrowWithMessage(
441                 "Error calling foo bar baz quux:\n/bin/sh: foo: command not found\n");
442     }
443 }