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     import std.algorithm: filter;
16 
17     with(immutable ReggaeSandbox("dub")) {
18         shouldNotExist("reggaefile.d");
19         writelnUt("\n\nReggae output:\n\n", runReggae("-b", "ninja").lines.join("\n"), "-----\n");
20         shouldExist("reggaefile.d");
21         auto output = ninja.shouldExecuteOk;
22         output.shouldContain("-debug -g");
23 
24         shouldSucceed("atest").filter!(a => a != "").should ==
25             [
26                 "Why hello!",
27                 "I'm immortal!"
28             ];
29 
30         // there's only one UT in main.d which always fails
31         shouldFail("ut");
32     }
33 }
34 
35 @("noreggaefile.tup")
36 @Tags(["dub", "tup"])
37 unittest {
38     with(immutable ReggaeSandbox("dub")) {
39         runReggae("-b", "tup").
40             shouldThrowWithMessage("dub integration not supported with the tup backend");
41     }
42 }
43 
44 
45 @("prebuild")
46 @Tags(["dub", "ninja"])
47 unittest {
48     with(immutable ReggaeSandbox("dub_prebuild")) {
49         runReggae("-b", "ninja");
50         ninja.shouldExecuteOk;
51         shouldSucceed("ut");
52     }
53 }
54 
55 
56 @("postbuild")
57 @Tags(["dub", "ninja", "posix"])
58 unittest {
59     with(immutable ReggaeSandbox("dub_postbuild")) {
60         runReggae("-b", "ninja");
61         ninja.shouldExecuteOk;
62         shouldExist("foo.txt");
63         shouldSucceed("postbuild");
64     }
65 }
66 
67 
68 @("dependencies not on file system already no dub.selections.json")
69 @Tags(["dub", "ninja"])
70 unittest {
71 
72     import std.file: exists, rmdirRecurse;
73     import std.process: environment;
74     import std.path: buildPath;
75 
76     const cerealedDir = buildPath(environment["HOME"], ".dub/packages/cerealed-0.6.8");
77     if(cerealedDir.exists)
78         rmdirRecurse(cerealedDir);
79 
80     with(immutable ReggaeSandbox()) {
81         writeFile("dub.json", `
82         {
83           "name": "depends_on_cerealed",
84           "license": "MIT",
85           "targetType": "executable",
86           "dependencies": { "cerealed": "==0.6.8" }
87         }`);
88         writeFile("source/app.d", "void main() {}");
89 
90         runReggae("-b", "ninja");
91     }
92 }
93 
94 
95 @("no main function but with unit tests")
96 @Tags(["dub", "ninja"])
97 unittest {
98     import std.file: mkdirRecurse;
99     import std.path: buildPath;
100 
101     with(immutable ReggaeSandbox()) {
102         writeFile("dub.json", `
103             {
104               "name": "depends_on_cerealed",
105               "license": "MIT",
106               "targetType": "executable",
107               "dependencies": { "cerealed": "==0.6.8" }
108             }`);
109 
110         writeFile("reggaefile.d", q{
111             import reggae;
112             mixin build!(dubTestTarget!());
113         });
114 
115         mkdirRecurse(buildPath(testPath, "source"));
116         writeFile("source/foo.d", `unittest { assert(false); }`);
117         runReggae("-b", "ninja");
118         ninja.shouldExecuteOk;
119 
120         shouldFail("ut");
121     }
122 }
123 
124 
125 @("reggae/dub build should rebuild if dub.selections.json changes")
126 @Tags(["dub", "make"])
127 unittest {
128 
129     import std.process: execute;
130     import std.path: buildPath;
131 
132     with(immutable ReggaeSandbox("dub")) {
133         runReggae("-b", "make");
134         make(["VERBOSE=1"]).shouldExecuteOk.shouldContain("-debug -g");
135         {
136             const ret = execute(["touch", buildPath(testPath, "dub.selections.json")]);
137             ret.status.shouldEqual(0);
138         }
139         {
140             const ret = execute(["make", "-C", testPath]);
141             ret.output.shouldContain("eggae");
142         }
143     }
144 }
145 
146 @("version from main package is used in dependent packages")
147 @Tags(["dub", "ninja"])
148 unittest {
149     with(immutable ReggaeSandbox()) {
150         writeFile("dub.sdl", `
151             name "foo"
152             versions "lefoo"
153             targetType "executable"
154             dependency "bar" path="bar"
155         `);
156         writeFile("source/app.d", q{
157             void main() {
158                 import bar;
159                 import std.stdio;
160                 writeln(lebar);
161             }
162         });
163         writeFile("bar/dub.sdl", `
164             name "bar"
165         `);
166         writeFile("bar/source/bar.d", q{
167             module bar;
168             version(lefoo)
169                 int lebar() { return 3; }
170             else
171                 int lebar() { return 42; }
172         });
173         runReggae("-b", "ninja");
174         ninja.shouldExecuteOk;
175         shouldSucceed("foo").shouldEqual(
176             [
177                 "3",
178             ]
179         );
180     }
181 }
182 
183 
184 @("sourceLibrary dependency")
185 @Tags(["dub", "ninja"])
186 unittest {
187     with(immutable ReggaeSandbox()) {
188         writeFile("dub.sdl", `
189             name "foo"
190             targetType "executable"
191             dependency "bar" path="bar"
192         `);
193         writeFile("source/app.d", q{
194             void main() {
195                 import bar;
196                 import std.stdio;
197                 writeln(lebar);
198             }
199         });
200         writeFile("bar/dub.sdl", `
201             name "bar"
202             targetType "sourceLibrary"
203         `);
204         writeFile("bar/source/bar.d", q{
205             module bar;
206             int lebar() { return 3; }
207         });
208         runReggae("-b", "ninja");
209         ninja.shouldExecuteOk;
210     }
211 }
212 
213 @("object source files.simple")
214 @Tags(["dub", "ninja"])
215 unittest {
216     with(immutable ReggaeSandbox()) {
217         writeFile("dub.sdl", `
218             name "foo"
219             targetType "executable"
220             dependency "bar" path="bar"
221         `);
222         writeFile("source/app.d", q{
223             extern(C) int lebaz();
224             void main() {
225                 import bar;
226                 import std.stdio;
227                 writeln(lebar);
228                 writeln(lebaz);
229             }
230         });
231         writeFile("bar/dub.sdl", `
232             name "bar"
233             sourceFiles "../baz.o"
234         `);
235         writeFile("bar/source/bar.d", q{
236             module bar;
237             int lebar() { return 3; }
238         });
239         writeFile("baz.d", q{
240             module baz;
241             extern(C) int lebaz() { return 42; }
242         });
243 
244         ["dmd", "-c", "baz.d"].shouldExecuteOk;
245         runReggae("-b", "ninja");
246         ninja.shouldExecuteOk;
247     }
248 }
249 
250 
251 @("dub objs option path dependency")
252 @Tags("dub", "ninja", "dubObjsDir")
253 unittest {
254 
255     with(immutable ReggaeSandbox()) {
256 
257         writeFile("reggaefile.d", q{
258             import reggae;
259             mixin build!(dubDefaultTarget!());
260         });
261 
262         writeFile("dub.sdl",`
263             name "foo"
264             targetType "executable"
265             dependency "bar" path="bar"
266         `);
267 
268         writeFile("source/app.d", q{
269             import bar;
270             void main() { add(2, 3); }
271         });
272 
273         writeFile("bar/dub.sdl", `
274             name "bar"
275         `);
276 
277         writeFile("bar/source/bar.d", q{
278             module bar;
279             int add(int i, int j) { return i + j; }
280         });
281 
282         const dubObjsDir = buildPath(testPath, "objsdir");
283         const output = runReggae("-b", "ninja", "--dub-objs-dir=" ~ dubObjsDir, "--dub-deps-objs");
284         writelnUt(output);
285         ninja.shouldExecuteOk;
286 
287         import std.path: buildPath;
288         shouldExist(buildPath("objsdir",
289                               testPath.deabsolutePath,
290                               "foo.objs",
291                               testPath.deabsolutePath,
292                               "bar",
293                               "source_bar.o"));
294     }
295 }
296 
297 
298 @("dub objs option registry dependency")
299 @Tags("dub", "ninja", "dubObjsDir")
300 unittest {
301 
302     import reggae.path: dubPackagesDir, deabsolutePath;
303 
304     with(immutable ReggaeSandbox()) {
305 
306         writeFile("reggaefile.d", q{
307             import reggae;
308             mixin build!(dubDefaultTarget!());
309         });
310 
311         writeFile("dub.sdl",`
312             name "foo"
313             targetType "executable"
314             dependency "dubnull" version="==0.0.1"
315         `);
316 
317         writeFile("source/app.d", q{
318             import dubnull;
319             void main() { dummy(); }
320         });
321 
322         const dubObjsDir = buildPath(testPath, "objsdir");
323         const output = runReggae("-b", "ninja", "--dub-objs-dir=" ~ dubObjsDir, "--dub-deps-objs");
324         writelnUt(output);
325 
326         ninja.shouldExecuteOk;
327 
328         import std.path: buildPath;
329         const dubNullDir = buildPath(dubPackagesDir, "dubnull-0.0.1", "dubnull").deabsolutePath;
330         shouldExist(buildPath("objsdir",
331                               testPath.deabsolutePath,
332                               "foo.objs",
333                               dubNullDir,
334                               "source_dubnull.o"));
335     }
336 }
337 
338 
339 @("object source files.with dub objs option")
340 @Tags("dub", "ninja", "dubObjsDir")
341 unittest {
342     with(immutable ReggaeSandbox()) {
343         writeFile("dub.sdl", `
344             name "foo"
345             targetType "executable"
346             dependency "bar" path="bar"
347         `);
348         writeFile("source/app.d", q{
349             extern(C) int lebaz();
350             void main() {
351                 import bar;
352                 import std.stdio;
353                 writeln(lebar);
354                 writeln(lebaz);
355             }
356         });
357         writeFile("bar/dub.sdl", `
358             name "bar"
359             sourceFiles "../baz.o"
360         `);
361         writeFile("bar/source/bar.d", q{
362             module bar;
363             int lebar() { return 3; }
364         });
365         writeFile("baz.d", q{
366             module baz;
367             extern(C) int lebaz() { return 42; }
368         });
369 
370         ["dmd", "-c", "baz.d"].shouldExecuteOk;
371 
372         const output = runReggae("-b", "ninja", "--dub-objs-dir=" ~ testPath);
373         writelnUt(output);
374 
375         ninja.shouldExecuteOk;
376     }
377 }
378 
379 
380 @("depends on package with prebuild")
381 @Tags(["dub", "ninja"])
382 unittest {
383 
384     import std.path;
385 
386     with(immutable ReggaeSandbox("dub_depends_on_prebuild")) {
387 
388         copyProject("dub_prebuild", buildPath("..", "dub_prebuild"));
389 
390         runReggae("-b", "ninja");
391         ninja.shouldExecuteOk;
392         shouldSucceed("app");
393         shouldExist(inSandboxPath("../dub_prebuild/el_prebuildo.txt"));
394     }
395 }
396 
397 
398 // See #73 for "posix"
399 @("staticLibrary.implicit")
400 @Tags(["dub", "ninja", "posix"])
401 unittest {
402 
403     with(immutable ReggaeSandbox()) {
404         writeFile("dub.sdl", `
405             name "foo"
406             targetType "executable"
407             targetName "d++"
408 
409             configuration "executable" {
410             }
411 
412             configuration "library" {
413                 targetType "library"
414                 targetName "dpp"
415                 excludedSourceFiles "source/main.d"
416             }
417         `);
418 
419         writeFile("reggaefile.d",
420                   q{
421                       import reggae;
422                       alias lib = dubConfigurationTarget!(Configuration("library"));
423                       enum mainObj = objectFile(SourceFile("source/main.d"));
424                       alias exe = link!(ExeName("d++"), targetConcat!(lib, mainObj));
425                       mixin build!(exe);
426                   });
427 
428         writeFile("source/main.d", "void main() {}");
429         writeFile("source/foo/bar/mod.d", "module foo.bar.mod; int add1(int i, int j) { return i + j + 1; }");
430 
431         runReggae("-b", "ninja");
432         ninja.shouldExecuteOk;
433         shouldSucceed("d++");
434     }
435 }
436 
437 
438 @("staticLibrary.explicit")
439 @Tags(["dub", "ninja"])
440 unittest {
441 
442     with(immutable ReggaeSandbox()) {
443         writeFile("dub.sdl", `
444             name "foo"
445             targetType "executable"
446             targetName "d++"
447 
448             configuration "executable" {
449             }
450 
451             configuration "library" {
452                 targetType "staticLibrary"
453                 targetName "dpp"
454                 excludedSourceFiles "source/main.d"
455             }
456         `);
457 
458         writeFile("reggaefile.d",
459                   q{
460                       import reggae;
461                       alias lib = dubConfigurationTarget!(Configuration("library"));
462                       enum mainObj = objectFile(SourceFile("source/main.d"));
463                       alias exe = link!(ExeName("d++"), targetConcat!(lib, mainObj));
464                       mixin build!(exe);
465                   });
466 
467         writeFile("source/main.d", "void main() {}");
468         writeFile("source/foo/bar/mod.d", "module foo.bar.mod; int add1(int i, int j) { return i + j + 1; }");
469 
470         runReggae("-b", "ninja");
471         ninja.shouldExecuteOk;
472         shouldSucceed("d++");
473     }
474 }
475 
476 
477 @("failing prebuild command")
478 @Tags(["dub", "ninja"])
479 unittest {
480     with(immutable ReggaeSandbox("dub_prebuild_oops")) {
481         auto thrownInfo = runReggae("-b", "ninja").shouldThrow;
482         "Error calling foo bar baz quux:".should.be in thrownInfo.msg;
483         "not found".should.be in thrownInfo.msg;
484     }
485 }
486 
487 
488 @("libs.plain")
489 @Tags(["dub", "ninja"])
490 unittest {
491     with(immutable ReggaeSandbox()) {
492         writeFile("dub.sdl", `
493             name "foo"
494             targetType "executable"
495             libs "utils"
496             lflags "-L$PACKAGE_DIR"
497 
498             configuration "executable" {
499             }
500 
501             configuration "library" {
502                 targetType "library"
503                 targetName "dpp"
504                 excludedSourceFiles "source/main.d"
505             }
506         `);
507 
508         writeFile("reggaefile.d",
509                   q{
510                       import reggae;
511                       alias exe = dubDefaultTarget!(
512                       );
513                       mixin build!(exe);
514                   });
515 
516         writeFile("source/main.d",
517                   q{
518                       extern(C) int twice(int);
519                       void main() {
520                           assert(twice(2) == 4);
521                           assert(twice(3) == 6);
522                       }
523                   });
524 
525         writeFile("utils.c", "int twice(int i) { return i * 2; }");
526         shouldExecuteOk(["gcc", "-o", inSandboxPath("utils.o"), "-c", inSandboxPath("utils.c")]);
527         shouldExecuteOk(["ar", "rcs", inSandboxPath("libutils.a"), inSandboxPath("utils.o")]);
528 
529         runReggae("-b", "ninja");
530         ninja.shouldExecuteOk;
531         shouldSucceed("foo");
532     }
533 }
534 
535 
536 @("libs.posix")
537 @Tags(["dub", "ninja"])
538 unittest {
539     with(immutable ReggaeSandbox()) {
540         writeFile("dub.sdl", `
541             name "foo"
542             targetType "executable"
543             libs "utils" platform="posix"
544             lflags "-L$PACKAGE_DIR"
545 
546             configuration "executable" {
547             }
548 
549             configuration "library" {
550                 targetType "library"
551                 targetName "dpp"
552                 excludedSourceFiles "source/main.d"
553             }
554         `);
555 
556         writeFile("reggaefile.d",
557                   q{
558                       import reggae;
559                       alias exe = dubDefaultTarget!(
560                       );
561                       mixin build!(exe);
562                   });
563 
564         writeFile("source/main.d",
565                   q{
566                       extern(C) int twice(int);
567                       void main() {
568                           assert(twice(2) == 4);
569                           assert(twice(3) == 6);
570                       }
571                   });
572 
573         writeFile("utils.c", "int twice(int i) { return i * 2; }");
574         shouldExecuteOk(["gcc", "-o", inSandboxPath("utils.o"), "-c", inSandboxPath("utils.c")]);
575         shouldExecuteOk(["ar", "rcs", inSandboxPath("libutils.a"), inSandboxPath("utils.o")]);
576 
577         runReggae("-b", "ninja");
578         ninja.shouldExecuteOk;
579         shouldSucceed("foo");
580     }
581 }
582 
583 
584 @("libs.dependency")
585 @Tags(["dub", "ninja"])
586 unittest {
587     with(immutable ReggaeSandbox()) {
588         writeFile("dub.sdl", `
589             name "foo"
590             targetType "executable"
591             dependency "bar" path="bar"
592         `);
593 
594         writeFile("reggaefile.d",
595                   q{
596                       import reggae;
597                       mixin build!(dubDefaultTarget!());
598                   });
599 
600         writeFile("source/main.d",
601                   q{
602                       import bar;
603                       void main() {
604                           assert(times4(2) == 8);
605                           assert(times4(3) == 12);
606                       }
607                   });
608 
609         writeFile("bar/dub.sdl", `
610             name "bar"
611             targetType "library"
612             lflags "-L$PACKAGE_DIR"
613             libs "utils"
614         `);
615 
616         writeFile("bar/source/bar.d", q{
617                 module bar;
618                 extern(C) int twice(int);
619                 int times4(int i) { return 2 * twice(i); }
620             }
621         );
622 
623         writeFile("bar/utils.c", "int twice(int i) { return i * 2; }");
624         shouldExecuteOk(["gcc", "-o", inSandboxPath("bar/utils.o"), "-c", inSandboxPath("bar/utils.c")]);
625         shouldExecuteOk(["ar", "rcs", inSandboxPath("bar/libutils.a"), inSandboxPath("bar/utils.o")]);
626 
627         runReggae("-b", "ninja");
628         ninja.shouldExecuteOk;
629         shouldSucceed("foo");
630     }
631 }
632 
633 
634 @("dflags.debug")
635 @Tags("dub", "ninja")
636 unittest {
637     with(immutable ReggaeSandbox()) {
638         writeFile("dub.sdl", `
639             name "foo"
640             targetType "executable"
641         `);
642 
643         writeFile("source/main.d",
644                   q{
645                       void main() {
646                           debug assert(false);
647                       }
648                   });
649 
650         runReggae("-b", "ninja");
651         ninja.shouldExecuteOk;
652         shouldFail("foo");
653     }
654 }
655 
656 
657 @("unittest.dependency")
658 @Tags(["dub", "ninja"])
659 unittest {
660     with(immutable ReggaeSandbox()) {
661         writeFile("dub.sdl", `
662             name "foo"
663             targetType "executable"
664             dependency "bar" path="bar"
665         `);
666         writeFile("source/app.d", q{
667             void main() {
668             }
669         });
670         writeFile("bar/dub.sdl", `
671             name "bar"
672         `);
673         writeFile("bar/source/bar.d", q{
674             module bar;
675             unittest {
676                 assert(1 == 2);
677             }
678         });
679         runReggae("-b", "ninja");
680         ninja.shouldExecuteOk;
681         shouldSucceed("ut");
682     }
683 }
684 
685 
686 @("unittest.self")
687 @Tags(["dub", "ninja"])
688 unittest {
689     with(immutable ReggaeSandbox()) {
690         writeFile("dub.sdl", `
691             name "foo"
692             targetType "executable"
693         `);
694         writeFile("source/app.d", q{
695             void main() {
696             }
697 
698             unittest { assert(1 == 2); }
699         });
700         runReggae("-b", "ninja");
701         ninja.shouldExecuteOk;
702         shouldFail("ut");
703     }
704 }
705 
706 
707 @("subpackages")
708 @Tags(["dub", "ninja"])
709 unittest {
710     with(immutable ReggaeSandbox()) {
711         writeFile("dub.json", `
712             {
713                 "name": "oops",
714                 "targetType": "none",
715                 "subPackages": [
716                     {
717                         "name": "pkg1",
718                         "targetType": "staticLibrary"
719                     },
720                     {
721                         "name": "pkg2",
722                         "targetType": "executable",
723                         "sourceFiles": ["main.d"],
724                         "dependencies": {
725                             "oops:pkg1": "*"
726                         }
727                     }
728                 ],
729                 "dependencies": {
730                     "oops:pkg1": "*",
731                     "oops:pkg2": "*"
732                 }
733             }
734         `);
735         writeFile("main.d", q{
736             void main() {
737                 import oops;
738                 import std.stdio;
739                 writeln(3.twice);
740             }
741         });
742         writeFile("source/oops.d", q{
743             module oops;
744             int twice(int i) { return i * 2; }
745         });
746 
747         runReggae("-b", "ninja");
748         ninja.shouldExecuteOk;
749         shouldFail("ut");
750     }
751 }
752 
753 
754 @("buildtype.release")
755 @Tags("dub", "ninja")
756 unittest {
757 
758     import std.string: splitLines;
759 
760     with(immutable ReggaeSandbox()) {
761         writeFile(
762             "dub.sdl",
763             [
764                 `name "foo"`,
765                 `targetType "executable"`,
766             ],
767         );
768         writeFile(
769             "source/app.d",
770             [
771                 q{void main() {}},
772             ],
773         );
774 
775         runReggae("-b", "ninja", "--dub-build-type=release");
776         const buildLines = ninja.shouldExecuteOk;
777         const firstLine = buildLines[0];
778         "-release ".should.be in firstLine;
779         "-O ".should.be in firstLine;
780         "-inline ".should.be in firstLine;
781     }
782 
783 }