1 module tests.ut.backend.binary;
2 
3 import reggae;
4 import unit_threaded;
5 import tests.utils;
6 
7 @("Target selection") unittest {
8 
9     bool fooCalled;
10     bool barCalled;
11     void resetCalls() { fooCalled = false; barCalled = false;}
12 
13     auto foo = Target("foo", (in string[] i, in string[] o) { fooCalled = true; }, Target("foo.d"));
14     auto bar = Target("bar", (in string[] i, in string[] o) { barCalled = true; }, Target("bar.d"));
15     auto binary = Binary(Build(foo, bar), getOptions(["reggae", "--export"]));
16 
17     {
18         scope(exit) resetCalls;
19         binary.run(["prog", "--norerun"]);
20         fooCalled.shouldBeTrue;
21         barCalled.shouldBeTrue;
22     }
23 
24     {
25         scope(exit) resetCalls;
26         binary.run(["prog", "--norerun", "foo", "bar"]);
27         fooCalled.shouldBeTrue;
28         barCalled.shouldBeTrue;
29     }
30 
31     {
32         scope(exit) resetCalls;
33         binary.run(["prog", "--norerun", "foo"]);
34         fooCalled.shouldBeTrue;
35         barCalled.shouldBeFalse;
36     }
37 
38     {
39         scope(exit) resetCalls;
40         binary.run(["prog", "--norerun", "bar"]);
41         fooCalled.shouldBeFalse;
42         barCalled.shouldBeTrue;
43     }
44 
45     {
46         scope(exit) resetCalls;
47         binary.run(["prog", "--norerun", "nonexistent"]).shouldThrow;
48         fooCalled.shouldBeFalse;
49         barCalled.shouldBeFalse;
50     }
51 }
52 
53 @("Top-level targets") unittest {
54     import reggae.path: buildPath;
55 
56     auto foo = Target("foo", "", Target("foo.d"));
57     auto bar = Target("bar", "", Target("bar.d"));
58     auto binary = Binary(Build(foo, bar), Options());
59 
60     auto newFoo = Target("foo", "", Target(buildPath("$project/foo.d")));
61     auto newBar = Target("bar", "", Target(buildPath("$project/bar.d")));
62 
63     binary.topLevelTargets(["foo"]).shouldEqual([newFoo]);
64     binary.topLevelTargets(["bar"]).shouldEqual([newBar]);
65     binary.topLevelTargets([]).shouldEqual([newFoo, newBar]);
66     binary.topLevelTargets(["oops"]).shouldBeEmpty;
67 }
68 
69 
70 private Build binaryBuild() {
71     mixin build!(Target("app", "dmd -of$out $in", [Target("foo.o"), Target("bar.o") ]),
72                  optional(Target.phony(`opt`, `echo Optional!`)));
73     return buildFunc();
74 }
75 
76 @("Listing targets") unittest {
77     import std.stdio: stdout, File;
78 
79     auto file = FakeFile();
80     auto binary = Binary(binaryBuild, getOptions(["./reggae", "-b", "binary"]), file);
81     binary.run(["./build", "--norerun", "-l"]);
82 
83     file.lines.shouldEqual(
84         ["List of available top-level targets:",
85          "- app",
86          "- opt (optional)"]);
87 }
88 
89 
90 @("Unknown target") unittest {
91     import std.stdio: stdout, File;
92 
93     auto binary = Binary(binaryBuild, getOptions(["./reggae", "-b", "binary"]));
94     binary.run(["./build", "--norerun", "oops"]).
95         shouldThrowWithMessage("Unknown target(s) 'oops'");
96 }
97 
98 @("Unknown targets") unittest {
99     import std.stdio: stdout, File;
100 
101     auto binary = Binary(binaryBuild, getOptions(["./reggae", "-b", "binary"]));
102     binary.run(["./build", "--norerun", "oops", "woopsie"]).
103         shouldThrowWithMessage("Unknown target(s) 'oops' 'woopsie'");
104 }
105 
106 
107 @("Non-phony target with no dependencies gets built if output doesn't exist")
108 unittest {
109     bool ran;
110     auto build = Build(Target("foo.txt",
111                               (in string[], in string[]) { ran = true; }));
112     auto binary = Binary(build, getOptions(["reggae", "-b", "binary"]));
113     binary.run(["./build", "--norerun"]);
114     ran.shouldBeTrue;
115 }