-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathassert_example.cpp
More file actions
329 lines (264 loc) · 10.8 KB
/
Copy pathassert_example.cpp
File metadata and controls
329 lines (264 loc) · 10.8 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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
// -----------------------------------------------------------------------------
// Copyright (c) 2026 @DMsuDev. Licensed under the MIT License.
// See LICENSE file in the project root for full license text.
// -----------------------------------------------------------------------------
#include "vigil/vigil.h"
#include <filesystem>
#include <iostream>
#include <cstring>
#include <vector>
// Demonstrates Vigil's assertion macros: VIGIL_ASSERT, VIGIL_VERIFY,
// VIGIL_ASSERT_NOT_NULL, VIGIL_ASSERT_IN_RANGE, and VIGIL_UNREACHABLE_ASSERT.
//
// Safe cases run by default; failure cases must be requested explicitly and
// will abort the process by design — do not combine them with other flags.
// ============================================================================
// Safe demos
// ============================================================================
static void Demo_BasicAssert();
static void Demo_Verify();
static void Demo_NullCheck();
static void Demo_RangeCheck();
static void Demo_Unreachable();
// ============================================================================
// Intentional failure cases — these abort the process
// ============================================================================
static void Fail_BasicAssert();
static void Fail_NullCheck();
static void Fail_RangeCheck();
static void Fail_Unreachable();
// ============================================================================
// Helpers
// ============================================================================
static void PrintUsage(const char* program);
// ============================================================================
// Entry point
// ============================================================================
int main(int argc, char* argv[])
{
if (!vigil::EnableUTF8Console())
{
std::fprintf(stderr,
"[Vigil] Failed to enable UTF-8 console support. "
"Unicode output may not display correctly.\n");
}
vigil::LogSystem::Init({
.Name = "AssertExample",
.LogDir = "logs/asserts",
.ConsoleLevel = vigil::LogLevel::Trace
});
vigil::Info("Vigil Assertion Example v{}.{}.{}",
VIGIL_VERSION_MAJOR, VIGIL_VERSION_MINOR, VIGIL_VERSION_PATCH);
#if !defined(VIGIL_ENABLE_ASSERTS)
vigil::Warn("Assertions are DISABLED in this build.");
vigil::Warn("Rebuild with -DVIGIL_ENABLE_ASSERTS=ON to activate them.");
#endif
vigil::Info("");
const std::string appName = std::filesystem::path(argv[0]).filename().string();
const std::vector<const char*> args(argv + 1, argv + argc);
// -------------------------------------------------------------------------
// Help
// -------------------------------------------------------------------------
if (args.size() == 1 &&
(std::strcmp(args[0], "--help") == 0 || std::strcmp(args[0], "-h") == 0))
{
PrintUsage(appName.c_str());
vigil::LogSystem::Shutdown();
return 0;
}
// -------------------------------------------------------------------------
// Dispatch table
// -------------------------------------------------------------------------
using Fn = void(*)();
struct Entry
{
const char* flag;
Fn fn;
bool terminal; // true = aborts the process by design
};
const Entry entries[] = {
{ "--basic", Demo_BasicAssert, false },
{ "--verify", Demo_Verify, false },
{ "--null", Demo_NullCheck, false },
{ "--range", Demo_RangeCheck, false },
{ "--unreachable", Demo_Unreachable, false },
{ "--fail-basic", Fail_BasicAssert, true },
{ "--fail-null", Fail_NullCheck, true },
{ "--fail-range", Fail_RangeCheck, true },
{ "--fail-unreachable", Fail_Unreachable, true },
};
// -------------------------------------------------------------------------
// Default: run all safe cases
// -------------------------------------------------------------------------
if (args.empty() || (args.size() == 1 && std::strcmp(args[0], "--all") == 0))
{
vigil::Info("Running all safe cases...");
vigil::Info("");
for (const auto& e : entries)
{
if (!e.terminal)
{
e.fn();
vigil::Info("");
}
}
vigil::Info("All safe cases completed successfully.");
vigil::LogSystem::Shutdown();
return 0;
}
// -------------------------------------------------------------------------
// Explicit flags
// -------------------------------------------------------------------------
// Validate all flags before executing any, so the user gets a clean error
// rather than a partial run followed by an unknown-option message.
for (const char* arg : args)
{
bool known = false;
for (const auto& e : entries)
if (std::strcmp(arg, e.flag) == 0) { known = true; break; }
if (!known)
{
vigil::Error("Unknown option: '{}'.", arg);
vigil::Info("");
PrintUsage(appName.c_str());
vigil::LogSystem::Shutdown();
return 1;
}
}
// Warn if the user combined a terminal case with other flags — it will
// abort before the rest can run.
bool hasTerminal = false;
for (const char* arg : args)
for (const auto& e : entries)
if (std::strcmp(arg, e.flag) == 0 && e.terminal) { hasTerminal = true; break; }
if (hasTerminal && args.size() > 1)
{
vigil::Warn("A failure case was combined with other flags.");
vigil::Warn("The process will abort on the first failure — subsequent flags will not run.");
vigil::Info("");
}
for (const char* arg : args)
{
for (const auto& e : entries)
{
if (std::strcmp(arg, e.flag) == 0)
{
e.fn();
if (!e.terminal) vigil::Info("");
break;
}
}
}
vigil::LogSystem::Shutdown();
return 0;
}
// ============================================================================
// Safe demos
// ============================================================================
static void Demo_BasicAssert()
{
vigil::Info("== Basic assertions =========================================");
VIGIL_ASSERT_MSG(true, "Unconditional pass.");
int x = 42;
VIGIL_ASSERT_MSG(x == 42, "Expected x == 42, got {}", x);
VIGIL_ASSERT(x > 0);
vigil::Info(" All basic assertions passed (x = {}).", x);
}
static void Demo_Verify()
{
vigil::Info("== VIGIL_VERIFY =============================================");
vigil::Info(" Unlike VIGIL_ASSERT, the expression is ALWAYS evaluated,");
vigil::Info(" even when assertions are compiled out.");
int counter = 0;
auto increment = [&counter]() { ++counter; return true; };
VIGIL_VERIFY_MSG(increment(), "Side effect must execute.");
VIGIL_ASSERT_MSG(counter == 1,
"counter should be 1 after VIGIL_VERIFY, got {}", counter);
vigil::Info(" Side effect confirmed: counter = {}.", counter);
}
static void Demo_NullCheck()
{
vigil::Info("== Null pointer checks ======================================");
int value = 100;
int* valid = &value;
int* null_p = nullptr;
VIGIL_ASSERT_NOT_NULL(valid);
VIGIL_ASSERT_MSG(*valid == 100,
"Dereferenced value should be 100, got {}", *valid);
// Confirming the null is null (passing case — no abort).
VIGIL_ASSERT_MSG(null_p == nullptr, "Null pointer correctly identified.");
vigil::Info(" Pointer checks passed (value = {}).", *valid);
}
static void Demo_RangeCheck()
{
vigil::Info("== Range validation =========================================");
int age = 25;
double temp = 22.5;
int index = 5;
VIGIL_ASSERT_IN_RANGE(age, 0, 120);
VIGIL_ASSERT_IN_RANGE(temp, -50.0, 50.0);
VIGIL_ASSERT_IN_RANGE(index, 0, 9);
vigil::Info(" All ranges valid (age={}, temp={:.1f}, index={}).",
age, temp, index);
}
static void Demo_Unreachable()
{
vigil::Info("== Unreachable code detection ================================");
vigil::Info(" VIGIL_UNREACHABLE_ASSERT() guards switch default branches.");
vigil::Info(" Adding a new enum value without a case triggers it at runtime.");
enum class State { Starting, Running, Stopped };
const State state = State::Running;
switch (state)
{
case State::Starting: vigil::Info(" State: Starting."); break;
case State::Running: vigil::Info(" State: Running."); break;
case State::Stopped: vigil::Info(" State: Stopped."); break;
// default: VIGIL_UNREACHABLE_ASSERT();
}
vigil::Info(" No unreachable paths hit for State::Running.");
}
// ============================================================================
// Intentional failure cases (abort by design)
// ============================================================================
static void Fail_BasicAssert()
{
vigil::Warn("Triggering intentional failure: basic assertion.");
int x = 42;
VIGIL_ASSERT_MSG(x == 0, "Expected x == 0, but x = {}.", x);
}
static void Fail_NullCheck()
{
vigil::Warn("Triggering intentional failure: null pointer check.");
int* p = nullptr;
VIGIL_ASSERT_NOT_NULL(p);
}
static void Fail_RangeCheck()
{
vigil::Warn("Triggering intentional failure: range validation.");
int value = 150;
VIGIL_ASSERT_IN_RANGE(value, 0, 100);
}
static void Fail_Unreachable()
{
vigil::Warn("Triggering intentional failure: unreachable code path.");
VIGIL_UNREACHABLE_ASSERT();
}
// ============================================================================
// Usage
// ============================================================================
static void PrintUsage(const char* program)
{
std::cout << "Usage: " << program << " [option...]\n\n";
std::cout << "Safe cases (combinable):\n";
std::cout << " (none) / --all Run all safe cases (default).\n";
std::cout << " --basic VIGIL_ASSERT / VIGIL_ASSERT_MSG.\n";
std::cout << " --verify VIGIL_VERIFY side-effect semantics.\n";
std::cout << " --null VIGIL_ASSERT_NOT_NULL.\n";
std::cout << " --range VIGIL_ASSERT_IN_RANGE.\n";
std::cout << " --unreachable VIGIL_UNREACHABLE_ASSERT (safe path).\n\n";
std::cout << "Failure cases (abort the process — do not combine):\n";
std::cout << " --fail-basic Failing VIGIL_ASSERT_MSG.\n";
std::cout << " --fail-null Failing VIGIL_ASSERT_NOT_NULL.\n";
std::cout << " --fail-range Failing VIGIL_ASSERT_IN_RANGE.\n";
std::cout << " --fail-unreachable VIGIL_UNREACHABLE_ASSERT triggered.\n";
}