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 @("noreggaefile.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").lines.join("\n"), "-----\n");
19         shouldExist("reggaefile.d");
20         auto output = ninja.shouldExecuteOk;
21         output.shouldContain("-debug -g");
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 @("noreggaefile.tup")
35 @Tags(["dub", "tup"])
36 unittest {
37     with(immutable ReggaeSandbox("dub")) {
38         runReggae("-b", "tup").
39             shouldThrowWithMessage("dub integration not supported with the tup backend");
40     }
41 }
42 
43 
44 @("prebuild")
45 @Tags(["dub", "ninja"])
46 unittest {
47     with(immutable ReggaeSandbox("dub_prebuild")) {
48         runReggae("-b", "ninja");
49         ninja.shouldExecuteOk;
50         shouldSucceed("ut");
51     }
52 }
53 
54 
55 @("postbuild")
56 @Tags(["dub", "ninja"])
57 unittest {
58     with(immutable ReggaeSandbox("dub_postbuild")) {
59         runReggae("-b", "ninja");
60         ninja.shouldExecuteOk;
61         shouldExist("foo.txt");
62         shouldSucceed("postbuild");
63     }
64 }
65 
66 
67 @("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 @("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!());
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");
133         make(["VERBOSE=1"]).shouldExecuteOk.shouldContain("-debug -g");
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.simple")
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, "--dub-deps-objs");
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_bar.o"));
293     }
294 }
295 
296 
297 @("dub objs option registry dependency")
298 @Tags("dub", "ninja", "dubObjsDir")
299 unittest {
300 
301     import reggae.path: dubPackagesDir, deabsolutePath;
302 
303     with(immutable ReggaeSandbox()) {
304 
305         writeFile("reggaefile.d", q{
306             import reggae;
307             mixin build!(dubDefaultTarget!());
308         });
309 
310         writeFile("dub.sdl",`
311             name "foo"
312             targetType "executable"
313             dependency "dubnull" version="==0.0.1"
314         `);
315 
316         writeFile("source/app.d", q{
317             import dubnull;
318             void main() { dummy(); }
319         });
320 
321         const dubObjsDir = buildPath(testPath, "objsdir");
322         const output = runReggae("-b", "ninja", "--dub-objs-dir=" ~ dubObjsDir, "--dub-deps-objs");
323         writelnUt(output);
324 
325         ninja.shouldExecuteOk;
326 
327         import std.path: buildPath;
328         const dubNullDir = buildPath(dubPackagesDir, "dubnull-0.0.1", "dubnull").deabsolutePath;
329         shouldExist(buildPath("objsdir",
330                               testPath.deabsolutePath,
331                               "foo.objs",
332                               dubNullDir,
333                               "source_dubnull.o"));
334     }
335 }
336 
337 
338 @("object source files.with dub objs option")
339 @Tags("dub", "ninja", "dubObjsDir")
340 unittest {
341     with(immutable ReggaeSandbox()) {
342         writeFile("dub.sdl", `
343             name "foo"
344             targetType "executable"
345             dependency "bar" path="bar"
346         `);
347         writeFile("source/app.d", q{
348             extern(C) int lebaz();
349             void main() {
350                 import bar;
351                 import std.stdio;
352                 writeln(lebar);
353                 writeln(lebaz);
354             }
355         });
356         writeFile("bar/dub.sdl", `
357             name "bar"
358             sourceFiles "../baz.o"
359         `);
360         writeFile("bar/source/bar.d", q{
361             module bar;
362             int lebar() { return 3; }
363         });
364         writeFile("baz.d", q{
365             module baz;
366             extern(C) int lebaz() { return 42; }
367         });
368 
369         ["dmd", "-c", "baz.d"].shouldExecuteOk;
370 
371         const output = runReggae("-b", "ninja", "--dub-objs-dir=" ~ testPath);
372         writelnUt(output);
373 
374         ninja.shouldExecuteOk;
375     }
376 }
377 
378 
379 @("depends on package with prebuild")
380 @Tags(["dub", "ninja"])
381 unittest {
382 
383     import std.path;
384 
385     with(immutable ReggaeSandbox("dub_depends_on_prebuild")) {
386 
387         copyProject("dub_prebuild", buildPath("..", "dub_prebuild"));
388 
389         runReggae("-b", "ninja");
390         ninja.shouldExecuteOk;
391         shouldSucceed("app");
392         shouldExist(inSandboxPath("../dub_prebuild/el_prebuildo.txt"));
393     }
394 }
395 
396 
397 @("staticLibrary.implicit")
398 @Tags(["dub", "ninja"])
399 unittest {
400 
401     with(immutable ReggaeSandbox()) {
402         writeFile("dub.sdl", `
403             name "foo"
404             targetType "executable"
405             targetName "d++"
406 
407             configuration "executable" {
408             }
409 
410             configuration "library" {
411                 targetType "library"
412                 targetName "dpp"
413                 excludedSourceFiles "source/main.d"
414             }
415         `);
416 
417         writeFile("reggaefile.d",
418                   q{
419                       import reggae;
420                       alias lib = dubConfigurationTarget!(Configuration("library"));
421                       enum mainObj = objectFile(SourceFile("source/main.d"));
422                       alias exe = link!(ExeName("d++"), targetConcat!(lib, mainObj));
423                       mixin build!(exe);
424                   });
425 
426         writeFile("source/main.d", "void main() {}");
427         writeFile("source/foo/bar/mod.d", "module foo.bar.mod; int add1(int i, int j) { return i + j + 1; }");
428 
429         runReggae("-b", "ninja");
430         ninja.shouldExecuteOk;
431         shouldSucceed("d++");
432     }
433 }
434 
435 
436 @("staticLibrary.explicit")
437 @Tags(["dub", "ninja"])
438 unittest {
439 
440     with(immutable ReggaeSandbox()) {
441         writeFile("dub.sdl", `
442             name "foo"
443             targetType "executable"
444             targetName "d++"
445 
446             configuration "executable" {
447             }
448 
449             configuration "library" {
450                 targetType "staticLibrary"
451                 targetName "dpp"
452                 excludedSourceFiles "source/main.d"
453             }
454         `);
455 
456         writeFile("reggaefile.d",
457                   q{
458                       import reggae;
459                       alias lib = dubConfigurationTarget!(Configuration("library"));
460                       enum mainObj = objectFile(SourceFile("source/main.d"));
461                       alias exe = link!(ExeName("d++"), targetConcat!(lib, mainObj));
462                       mixin build!(exe);
463                   });
464 
465         writeFile("source/main.d", "void main() {}");
466         writeFile("source/foo/bar/mod.d", "module foo.bar.mod; int add1(int i, int j) { return i + j + 1; }");
467 
468         runReggae("-b", "ninja");
469         ninja.shouldExecuteOk;
470         shouldSucceed("d++");
471     }
472 }
473 
474 
475 @("failing prebuild command")
476 @Tags(["dub", "ninja"])
477 unittest {
478     with(immutable ReggaeSandbox("dub_prebuild_oops")) {
479         auto thrownInfo = runReggae("-b", "ninja").shouldThrow;
480         "Error calling foo bar baz quux:".should.be in thrownInfo.msg;
481         "not found".should.be in thrownInfo.msg;
482     }
483 }
484 
485 
486 @("libs.plain")
487 @Tags(["dub", "ninja"])
488 unittest {
489     with(immutable ReggaeSandbox()) {
490         writeFile("dub.sdl", `
491             name "foo"
492             targetType "executable"
493             libs "utils"
494             lflags "-L$PACKAGE_DIR"
495 
496             configuration "executable" {
497             }
498 
499             configuration "library" {
500                 targetType "library"
501                 targetName "dpp"
502                 excludedSourceFiles "source/main.d"
503             }
504         `);
505 
506         writeFile("reggaefile.d",
507                   q{
508                       import reggae;
509                       alias exe = dubDefaultTarget!(
510                       );
511                       mixin build!(exe);
512                   });
513 
514         writeFile("source/main.d",
515                   q{
516                       extern(C) int twice(int);
517                       void main() {
518                           assert(twice(2) == 4);
519                           assert(twice(3) == 6);
520                       }
521                   });
522 
523         writeFile("utils.c", "int twice(int i) { return i * 2; }");
524         shouldExecuteOk(["gcc", "-o", inSandboxPath("utils.o"), "-c", inSandboxPath("utils.c")]);
525         shouldExecuteOk(["ar", "rcs", inSandboxPath("libutils.a"), inSandboxPath("utils.o")]);
526 
527         runReggae("-b", "ninja");
528         ninja.shouldExecuteOk;
529         shouldSucceed("foo");
530     }
531 }
532 
533 
534 @("libs.posix")
535 @Tags(["dub", "ninja"])
536 unittest {
537     with(immutable ReggaeSandbox()) {
538         writeFile("dub.sdl", `
539             name "foo"
540             targetType "executable"
541             libs "utils" platform="posix"
542             lflags "-L$PACKAGE_DIR"
543 
544             configuration "executable" {
545             }
546 
547             configuration "library" {
548                 targetType "library"
549                 targetName "dpp"
550                 excludedSourceFiles "source/main.d"
551             }
552         `);
553 
554         writeFile("reggaefile.d",
555                   q{
556                       import reggae;
557                       alias exe = dubDefaultTarget!(
558                       );
559                       mixin build!(exe);
560                   });
561 
562         writeFile("source/main.d",
563                   q{
564                       extern(C) int twice(int);
565                       void main() {
566                           assert(twice(2) == 4);
567                           assert(twice(3) == 6);
568                       }
569                   });
570 
571         writeFile("utils.c", "int twice(int i) { return i * 2; }");
572         shouldExecuteOk(["gcc", "-o", inSandboxPath("utils.o"), "-c", inSandboxPath("utils.c")]);
573         shouldExecuteOk(["ar", "rcs", inSandboxPath("libutils.a"), inSandboxPath("utils.o")]);
574 
575         runReggae("-b", "ninja");
576         ninja.shouldExecuteOk;
577         shouldSucceed("foo");
578     }
579 }
580 
581 
582 @("libs.dependency")
583 @Tags(["dub", "ninja"])
584 unittest {
585     with(immutable ReggaeSandbox()) {
586         writeFile("dub.sdl", `
587             name "foo"
588             targetType "executable"
589             dependency "bar" path="bar"
590         `);
591 
592         writeFile("reggaefile.d",
593                   q{
594                       import reggae;
595                       mixin build!(dubDefaultTarget!());
596                   });
597 
598         writeFile("source/main.d",
599                   q{
600                       import bar;
601                       void main() {
602                           assert(times4(2) == 8);
603                           assert(times4(3) == 12);
604                       }
605                   });
606 
607         writeFile("bar/dub.sdl", `
608             name "bar"
609             targetType "library"
610             lflags "-L$PACKAGE_DIR"
611             libs "utils"
612         `);
613 
614         writeFile("bar/source/bar.d", q{
615                 module bar;
616                 extern(C) int twice(int);
617                 int times4(int i) { return 2 * twice(i); }
618             }
619         );
620 
621         writeFile("bar/utils.c", "int twice(int i) { return i * 2; }");
622         shouldExecuteOk(["gcc", "-o", inSandboxPath("bar/utils.o"), "-c", inSandboxPath("bar/utils.c")]);
623         shouldExecuteOk(["ar", "rcs", inSandboxPath("bar/libutils.a"), inSandboxPath("bar/utils.o")]);
624 
625         runReggae("-b", "ninja");
626         ninja.shouldExecuteOk;
627         shouldSucceed("foo");
628     }
629 }
630 
631 
632 @("dflags.debug")
633 @Tags("dub", "ninja")
634 unittest {
635     with(immutable ReggaeSandbox()) {
636         writeFile("dub.sdl", `
637             name "foo"
638             targetType "executable"
639         `);
640 
641         writeFile("source/main.d",
642                   q{
643                       void main() {
644                           debug assert(false);
645                       }
646                   });
647 
648         runReggae("-b", "ninja");
649         ninja.shouldExecuteOk;
650         shouldFail("foo");
651     }
652 }
653 
654 
655 @("unittest.dependency")
656 @Tags(["dub", "ninja"])
657 unittest {
658     with(immutable ReggaeSandbox()) {
659         writeFile("dub.sdl", `
660             name "foo"
661             targetType "executable"
662             dependency "bar" path="bar"
663         `);
664         writeFile("source/app.d", q{
665             void main() {
666             }
667         });
668         writeFile("bar/dub.sdl", `
669             name "bar"
670         `);
671         writeFile("bar/source/bar.d", q{
672             module bar;
673             unittest {
674                 assert(1 == 2);
675             }
676         });
677         runReggae("-b", "ninja");
678         ninja.shouldExecuteOk;
679         shouldSucceed("ut");
680     }
681 }
682 
683 
684 @("unittest.self")
685 @Tags(["dub", "ninja"])
686 unittest {
687     with(immutable ReggaeSandbox()) {
688         writeFile("dub.sdl", `
689             name "foo"
690             targetType "executable"
691         `);
692         writeFile("source/app.d", q{
693             void main() {
694             }
695 
696             unittest { assert(1 == 2); }
697         });
698         runReggae("-b", "ninja");
699         ninja.shouldExecuteOk;
700         shouldFail("ut");
701     }
702 }
703 
704 
705 @("subpackages")
706 @Tags(["dub", "ninja"])
707 unittest {
708     with(immutable ReggaeSandbox()) {
709         writeFile("dub.json", `
710             {
711                 "name": "oops",
712                 "targetType": "none",
713                 "subPackages": [
714                     {
715                         "name": "pkg1",
716                         "targetType": "staticLibrary"
717                     },
718                     {
719                         "name": "pkg2",
720                         "targetType": "executable",
721                         "sourceFiles": ["main.d"],
722                         "dependencies": {
723                             "oops:pkg1": "*"
724                         }
725                     }
726                 ],
727                 "dependencies": {
728                     "oops:pkg1": "*",
729                     "oops:pkg2": "*"
730                 }
731             }
732         `);
733         writeFile("main.d", q{
734             void main() {
735                 import oops;
736                 import std.stdio;
737                 writeln(3.twice);
738             }
739         });
740         writeFile("source/oops.d", q{
741             module oops;
742             int twice(int i) { return i * 2; }
743         });
744 
745         runReggae("-b", "ninja");
746         ninja.shouldExecuteOk;
747         shouldFail("ut");
748     }
749 }