1 module tests.ut.cpprules;
2 
3 
4 import reggae;
5 import reggae.options;
6 import reggae.backend.ninja;
7 import unit_threaded;
8 
9 
10 void testNoIncludePaths() {
11     auto build = Build(objectFile(SourceFile("path/to/src/foo.cpp")));
12     auto ninja = Ninja(build, "/tmp/myproject");
13     ninja.buildEntries.shouldEqual(
14         [NinjaEntry("build path/to/src/foo.o: _cppcompile /tmp/myproject/path/to/src/foo.cpp",
15                     ["DEPFILE = path/to/src/foo.o.dep"]),
16             ]);
17 }
18 
19 
20 void testIncludePaths() {
21     auto build = Build(objectFile(SourceFile("path/to/src/foo.cpp"), Flags(""),
22                                    IncludePaths(["path/to/src", "other/path"])));
23     auto ninja = Ninja(build, "/tmp/myproject");
24     ninja.buildEntries.shouldEqual(
25         [NinjaEntry("build path/to/src/foo.o: _cppcompile /tmp/myproject/path/to/src/foo.cpp",
26                     ["includes = -I/tmp/myproject/path/to/src -I/tmp/myproject/other/path",
27                      "DEPFILE = path/to/src/foo.o.dep"]),
28             ]);
29 }
30 
31 
32 void testFlagsCompileC() {
33     auto build = Build(objectFile(SourceFile("path/to/src/foo.c"), Flags("-m64 -fPIC -O3")));
34     auto ninja = Ninja(build, "/tmp/myproject");
35     ninja.buildEntries.shouldEqual(
36         [NinjaEntry("build path/to/src/foo.o: _ccompile /tmp/myproject/path/to/src/foo.c",
37                     ["flags = -m64 -fPIC -O3",
38                      "DEPFILE = path/to/src/foo.o.dep"]),
39             ]);
40 }
41 
42 void testFlagsCompileCpp() {
43     auto build = Build(objectFile(SourceFile("path/to/src/foo.cpp"), Flags("-m64 -fPIC -O3")));
44     auto ninja = Ninja(build, "/tmp/myproject");
45     ninja.buildEntries.shouldEqual(
46         [NinjaEntry("build path/to/src/foo.o: _cppcompile /tmp/myproject/path/to/src/foo.cpp",
47                     ["flags = -m64 -fPIC -O3",
48                      "DEPFILE = path/to/src/foo.o.dep"]),
49             ]);
50 }
51 
52 void testCppCompile() {
53     auto mathsObj = objectFile(SourceFile("src/cpp/maths.cpp"),
54                                 Flags("-m64 -fPIC -O3"),
55                                 IncludePaths(["headers"]));
56 
57     import reggae.config: gDefaultOptions;
58     mathsObj.shellCommand(gDefaultOptions.withProjectPath("/path/to")).shouldEqual(
59         "g++ -m64 -fPIC -O3 -I/path/to/headers -MMD -MT src/cpp/maths.o -MF src/cpp/maths.o.dep " ~
60         "-o src/cpp/maths.o -c /path/to/src/cpp/maths.cpp");
61 }
62 
63 void testCCompile() {
64     auto mathsObj = objectFile(SourceFile("src/c/maths.c"),
65                                 Flags("-m64 -fPIC -O3"),
66                                 IncludePaths(["headers"]));
67 
68     mathsObj.shellCommand(gDefaultOptions.withProjectPath("/path/to")).shouldEqual(
69         "gcc -m64 -fPIC -O3 -I/path/to/headers -MMD -MT src/c/maths.o -MF src/c/maths.o.dep " ~
70         "-o src/c/maths.o -c /path/to/src/c/maths.c");
71 }
72 
73 
74 void testUnityNoFiles() {
75     string[] files;
76     immutable projectPath = "";
77     unityFileContents(projectPath, files).shouldThrow;
78 }
79 
80 
81 private void shouldEqualLines(string actual, string[] expected,
82                               in string file = __FILE__, in size_t line = __LINE__) {
83     import std.string;
84     actual.split("\n").shouldEqual(expected, file, line);
85 }
86 
87 void testUnityCppFiles() {
88     auto files = ["src/foo.cpp", "src/bar.cpp"];
89     unityFileContents("/path/to/proj/", files).shouldEqualLines(
90         [`#include "/path/to/proj/src/foo.cpp"`,
91          `#include "/path/to/proj/src/bar.cpp"`]);
92 }
93 
94 
95 void testUnityCFiles() {
96     auto files = ["src/foo.c", "src/bar.c"];
97     unityFileContents("/foo/bar/", files).shouldEqualLines(
98         [`#include "/foo/bar/src/foo.c"`,
99          `#include "/foo/bar/src/bar.c"`]);
100 }
101 
102 void testUnityMixedLanguages() {
103     auto files = ["src/foo.cpp", "src/bar.c"];
104     unityFileContents("/project", files).shouldThrow;
105 }
106 
107 void testUnityDFiles() {
108     auto files = ["src/foo.d", "src/bar.d"];
109     unityFileContents("/project", files).shouldThrow;
110 }
111 
112 
113 void testUnityTargetCpp() @trusted {
114     import reggae.config: gDefaultOptions;
115 
116     enum files = ["src/foo.cpp", "src/bar.cpp", "src/baz.cpp"];
117     Target[] dependencies() @safe pure nothrow {
118         return [Target("$builddir/mylib.a")];
119     }
120 
121     immutable projectPath = "/path/to/proj";
122     auto target = unityTarget!(ExeName("leapp"),
123                                 projectPath,
124                                 files,
125                                 Flags("-g -O0"),
126                                 IncludePaths(["headers"]),
127                                 dependencies);
128     target.rawOutputs.shouldEqual(["leapp"]);
129     target.shellCommand(gDefaultOptions.withProjectPath(projectPath)).shouldEqual(
130         "g++ -g -O0 -I/path/to/proj/headers -MMD -MT leapp -MF leapp.dep -o leapp " ~
131         ".reggae/objs/leapp.objs/unity.cpp mylib.a");
132     target.dependencyTargets.shouldEqual([Target.phony("$builddir/.reggae/objs/leapp.objs/unity.cpp",
133                                                        "",
134                                                        [],
135                                                        [Target("src/foo.cpp"),
136                                                         Target("src/bar.cpp"),
137                                                         Target("src/baz.cpp")]),
138                                           Target("$builddir/mylib.a")]);
139 }
140 
141 void testUnityTargetC() @trusted {
142     import reggae.config: gDefaultOptions;
143 
144     enum files = ["src/foo.c", "src/bar.c", "src/baz.c"];
145     Target[] dependencies() @safe pure nothrow {
146         return [Target("$builddir/mylib.a")];
147     }
148 
149     immutable projectPath = "/path/to/proj";
150     auto target = unityTarget!(ExeName("leapp"),
151                                 projectPath,
152                                 files,
153                                 Flags("-g -O0"),
154                                 IncludePaths(["headers"]),
155                                 dependencies);
156     target.rawOutputs.shouldEqual(["leapp"]);
157     target.shellCommand(gDefaultOptions.withProjectPath(projectPath)).shouldEqual(
158         "gcc -g -O0 -I/path/to/proj/headers -MMD -MT leapp -MF leapp.dep -o leapp " ~
159         ".reggae/objs/leapp.objs/unity.c mylib.a");
160     target.dependencyTargets.shouldEqual([Target.phony("$builddir/.reggae/objs/leapp.objs/unity.c",
161                                                        "",
162                                                        [],
163                                                        [Target("src/foo.c"),
164                                                         Target("src/bar.c"),
165                                                         Target("src/baz.c")]),
166                                      Target("$builddir/mylib.a")]);
167 }