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