-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathtest_build_profile.cpp
More file actions
187 lines (158 loc) · 8.03 KB
/
Copy pathtest_build_profile.cpp
File metadata and controls
187 lines (158 loc) · 8.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// The profile axis: profile selection, and the invariant that the resolved
// profile knobs participate in the fingerprint.
//
// Both halves were broken together. `[profile.<name>]` lands its knobs in
// buildConfig.optLevel/debug/lto/strip and flags.cppm turns them into
// -O<n>/-g/-flto, but canonical_compile_flags serialized only cflags/cxxflags/
// ldflags — so `--dev`, `--release` and `--profile dist` produced ONE
// fingerprint, hence one target/<triple>/<fp>/ directory and one global cache
// entry. Meanwhile `.build_cache` keyed its fast-path entries by target triple
// alone and the fast path only refused to run for an EXPLICIT profile flag, so
// `mcpp build --release` followed by a bare `mcpp build` reported success in
// 0.00s and left the release artifacts in place.
#include <gtest/gtest.h>
import std;
import mcpp.build.prepare;
import mcpp.manifest;
namespace {
mcpp::manifest::Manifest base() {
mcpp::manifest::Manifest m;
m.package.name = "demo";
m.package.version = "0.1.0";
m.package.standard = "c++23";
m.buildConfig.optLevel = "2";
return m;
}
} // namespace
// ── resolve_profile_name: the ONE rule, shared with the fast paths ───────────
TEST(BuildProfile, OverrideBeatsManifestDefault) {
auto m = base();
m.buildConfig.defaultProfile = "release";
EXPECT_EQ(mcpp::build::resolve_profile_name(m, "dev"), "dev");
}
TEST(BuildProfile, ManifestDefaultBeatsGlobalDefault) {
auto m = base();
m.buildConfig.defaultProfile = "release";
EXPECT_EQ(mcpp::build::resolve_profile_name(m, ""), "release");
}
TEST(BuildProfile, GlobalDefaultIsDev) {
EXPECT_EQ(mcpp::build::resolve_profile_name(base(), ""), "dev");
}
TEST(BuildProfile, CustomProfileNamePassesThrough) {
EXPECT_EQ(mcpp::build::resolve_profile_name(base(), "contracts"), "contracts");
}
// ── the fingerprint invariant ────────────────────────────────────────────────
TEST(BuildProfile, OptLevelIsInTheCanonicalFlags) {
auto a = base();
auto b = base(); b.buildConfig.optLevel = "0";
EXPECT_NE(mcpp::build::canonical_compile_flags(a),
mcpp::build::canonical_compile_flags(b));
}
TEST(BuildProfile, DebugLtoStripAreInTheCanonicalFlags) {
auto ref = mcpp::build::canonical_compile_flags(base());
{ auto m = base(); m.buildConfig.debug = true;
EXPECT_NE(mcpp::build::canonical_compile_flags(m), ref); }
{ auto m = base(); m.buildConfig.lto = true;
EXPECT_NE(mcpp::build::canonical_compile_flags(m), ref); }
{ auto m = base(); m.buildConfig.strip = true;
EXPECT_NE(mcpp::build::canonical_compile_flags(m), ref); }
}
// The exact shape the three built-in profiles resolve to (prepare_build's
// profile block). Asserting on the flag string rather than on a fingerprint hex
// keeps the failure legible when someone adds a knob and forgets to serialize it.
TEST(BuildProfile, BuiltInProfilesProduceDistinctCanonicalFlags) {
auto dev = base();
dev.buildConfig.optLevel = "0";
dev.buildConfig.debug = true;
auto release = base();
release.buildConfig.optLevel = "2";
auto dist = base();
dist.buildConfig.optLevel = "3";
dist.buildConfig.strip = true;
auto fdev = mcpp::build::canonical_compile_flags(dev);
auto frelease = mcpp::build::canonical_compile_flags(release);
auto fdist = mcpp::build::canonical_compile_flags(dist);
EXPECT_NE(fdev, frelease);
EXPECT_NE(frelease, fdist);
EXPECT_NE(fdev, fdist);
}
TEST(BuildProfile, CanonicalFlagsStillCoverTheNonProfileKnobs) {
auto ref = mcpp::build::canonical_compile_flags(base());
{ auto m = base(); m.package.standard = "c++26";
EXPECT_NE(mcpp::build::canonical_compile_flags(m), ref); }
{ auto m = base(); m.buildConfig.cxxflags = {"-DFOO"};
EXPECT_NE(mcpp::build::canonical_compile_flags(m), ref); }
{ auto m = base(); m.buildConfig.cflags = {"-DBAR"};
EXPECT_NE(mcpp::build::canonical_compile_flags(m), ref); }
{ auto m = base(); m.buildConfig.ldflags = {"-lm"};
EXPECT_NE(mcpp::build::canonical_compile_flags(m), ref); }
{ auto m = base(); m.buildConfig.dialectCxxflags = {"-freflection"};
EXPECT_NE(mcpp::build::canonical_compile_flags(m), ref); }
{ auto m = base(); m.buildConfig.cStandard = "c17";
EXPECT_NE(mcpp::build::canonical_compile_flags(m), ref); }
}
// ── cache-mode parsing ──────────────────────────────────────────────────────
TEST(BuildProfile, CacheModeParsesTheThreeModes) {
using mcpp::build::CacheMode;
EXPECT_EQ(mcpp::build::parse_cache_mode("global"), CacheMode::Global);
EXPECT_EQ(mcpp::build::parse_cache_mode("local"), CacheMode::Local);
EXPECT_EQ(mcpp::build::parse_cache_mode("off"), CacheMode::Off);
// `none` accepted as a synonym for off; anything else is refused rather
// than silently meaning "global", which would be the worst default for a
// typo to land on.
EXPECT_EQ(mcpp::build::parse_cache_mode("none"), CacheMode::Off);
EXPECT_FALSE(mcpp::build::parse_cache_mode("on").has_value());
EXPECT_FALSE(mcpp::build::parse_cache_mode("").has_value());
EXPECT_FALSE(mcpp::build::parse_cache_mode("GLOBAL").has_value());
}
TEST(BuildProfile, CacheModeNameRoundTrips) {
using mcpp::build::CacheMode;
for (auto m : {CacheMode::Global, CacheMode::Local, CacheMode::Off})
EXPECT_EQ(mcpp::build::parse_cache_mode(mcpp::build::cache_mode_name(m)), m);
}
// ── cache-mode resolution ───────────────────────────────────────────────────
// Same shape as resolve_profile_name and for the same reason: the fast paths
// skip prepare_build, so they must settle the mode from one shared pure rule.
// Without that, a graph generated under `global` (which contains stage_file
// edges reading the cache) got replayed for a request that asked for `local` —
// and ruling the cache out is `local`'s entire purpose.
TEST(BuildProfile, CacheModeOverrideBeatsManifest) {
auto m = base();
m.buildConfig.cacheMode = "local";
EXPECT_EQ(mcpp::build::resolve_cache_mode(m, "global"),
mcpp::build::CacheMode::Global);
}
TEST(BuildProfile, CacheModeManifestBeatsDefault) {
auto m = base();
m.buildConfig.cacheMode = "off";
EXPECT_EQ(mcpp::build::resolve_cache_mode(m, ""), mcpp::build::CacheMode::Off);
}
TEST(BuildProfile, CacheModeDefaultsToGlobal) {
EXPECT_EQ(mcpp::build::resolve_cache_mode(base(), ""),
mcpp::build::CacheMode::Global);
}
// An unparseable value must not silently mean "global" at THIS level either: it
// falls through to the next source, and prepare_build reports it separately.
TEST(BuildProfile, UnknownManifestCacheModeFallsThroughToDefault) {
auto m = base();
m.buildConfig.cacheMode = "bogus";
EXPECT_EQ(mcpp::build::resolve_cache_mode(m, ""),
mcpp::build::CacheMode::Global);
// ...and an unparseable override does not shadow a valid manifest value.
m.buildConfig.cacheMode = "local";
EXPECT_EQ(mcpp::build::resolve_cache_mode(m, "bogus"),
mcpp::build::CacheMode::Local);
}
// ── #649 E9: the override the command line states, one rule for every verb ───
//
// `build` preferred `--profile` over the shorthands and `run` preferred the
// shorthands, so one command line built two profiles. Every verb now reads this.
TEST(BuildProfile, ProfileOptionBeatsTheShorthands) {
EXPECT_EQ(mcpp::build::profile_override_from_flags("dev", true, false), "dev");
EXPECT_EQ(mcpp::build::profile_override_from_flags("release", false, true), "release");
}
TEST(BuildProfile, ShorthandsNameTheirProfile) {
EXPECT_EQ(mcpp::build::profile_override_from_flags("", true, false), "release");
EXPECT_EQ(mcpp::build::profile_override_from_flags("", false, true), "dev");
EXPECT_EQ(mcpp::build::profile_override_from_flags("", false, false), "");
}