• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

thetic / mutiny / 24045017610

06 Apr 2026 06:33PM UTC coverage: 98.946% (-0.03%) from 98.971%
24045017610

Pull #40

github

web-flow
Merge 2c55441dc into 97995326b
Pull Request #40: Replace type-specific *_EQUAL macros with typed CHECK_EQUAL

40 of 40 new or added lines in 7 files covered. (100.0%)

1 existing line in 1 file now uncovered.

5538 of 5597 relevant lines covered (98.95%)

3438.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.36
/src/test/Shell.cpp
1
#include "mutiny/test/Shell.hpp"
2

3
#include "mutiny/test/ConsoleOutput.hpp"
4
#include "mutiny/test/Failure.hpp"
5
#include "mutiny/test/Plugin.hpp"
6
#include "mutiny/test/Registry.hpp"
7
#include "mutiny/test/Result.hpp"
8
#include "mutiny/test/Test.hpp"
9
#include "mutiny/test/jump_buffer.hpp"
10

11
#include "mutiny/String.hpp"
12
#include "mutiny/math.hpp"
13

14
#include <math.h>
15
#include <stdlib.h>
16

17
namespace mu {
18
namespace tiny {
19
namespace test {
20

21
namespace {
22

23
/* Sometimes stubs use the mutiny assertions.
24
 * Its not correct to do so, but this small helper class will prevent a
25
 * segmentation fault and instead will give an error message and also the
26
 * file/line of the check that was executed outside the tests.
27
 */
28
class OutsideTestRunnerUTest : public Shell
29
{
30
public:
31
  static OutsideTestRunnerUTest& instance();
32
  Result& get_result() { return default_test_result_; }
69✔
33
  ~OutsideTestRunnerUTest() override = default;
46✔
34

35
private:
36
  OutsideTestRunnerUTest()
46✔
37
    : Shell(
46✔
38
          "\n\t NOTE: Assertion happened without being in a test run "
39
          "(perhaps in main?)",
40
          "\n\t       Something is very wrong. Check this assertion and fix",
41
          "unknown file",
42
          0
43
      )
44
    , default_test_result_(default_output_)
46✔
45
  {
46
  }
46✔
47
  ConsoleOutput default_output_;
48
  Result default_test_result_;
49
};
50

51
OutsideTestRunnerUTest& OutsideTestRunnerUTest::instance()
138✔
52
{
53
  static OutsideTestRunnerUTest instance;
138✔
54
  return instance;
138✔
55
}
56

57
/*
58
 * Below helpers are used for the PlatformSpecificSetJmp and LongJmp. They pass
59
 * a method for what needs to happen after the jump, so that the stack stays
60
 * right.
61
 *
62
 */
63

64
class HelperTestRunInfo
65
{
66
public:
67
  HelperTestRunInfo(Shell* s, Plugin* p, Result* r)
1,187✔
68
    : shell(s)
1,187✔
69
    , plugin(p)
1,187✔
70
    , result(r)
1,187✔
71
  {
72
  }
1,187✔
73

74
  Shell* shell;
75
  Plugin* plugin;
76
  Result* result;
77
};
78

79
void helper_do_run_one_test_in_current_process(void* data)
1,187✔
80
{
81
  auto* run_info = static_cast<HelperTestRunInfo*>(data);
1,187✔
82

83
  Shell* shell = run_info->shell;
1,187✔
84
  Plugin* plugin = run_info->plugin;
1,187✔
85
  Result* result = run_info->result;
1,187✔
86

87
  shell->run_one_test_in_current_process(plugin, *result);
1,187✔
88
}
1,183✔
89

90
const NormalTerminator normal_test_terminator = NormalTerminator();
91
const CrashingTerminator crashing_test_terminator = CrashingTerminator();
92
const TerminatorWithoutExceptions normal_test_terminator_without_exceptions =
93
    TerminatorWithoutExceptions();
94
const CrashingTerminatorWithoutExceptions
95
    crashing_test_terminator_without_exceptions =
96
        CrashingTerminatorWithoutExceptions();
97

98
void (*please_crash_me_right_now)() = abort;
99
} // namespace
100

101
bool approx_equal(double d1, double d2, double threshold)
65✔
102
{
103
  if (is_nan(d1) || is_nan(d2) || is_nan(threshold))
65✔
104
    return false;
3✔
105

106
  if (is_inf(d1) && is_inf(d2)) {
62✔
107
    return true;
2✔
108
  }
109

110
  return fabs(d1 - d2) <= threshold;
60✔
111
}
112

113
const Terminator* Shell::current_test_terminator_ = &normal_test_terminator;
114
const Terminator* Shell::current_test_terminator_without_exceptions_ =
115
    &normal_test_terminator_without_exceptions;
116

117
bool Shell::rethrow_exceptions_ = false;
118

119
Shell::Shell() noexcept
31,802✔
120
  : group_("UndefinedTestGroup")
31,802✔
121
  , name_("UndefinedTest")
31,802✔
122
  , file_("UndefinedFile")
31,802✔
123
  , line_number_(0)
31,802✔
124
  , next_(nullptr)
31,802✔
125
  , has_failed_(false)
31,802✔
126
{
127
}
31,802✔
128

129
Shell::Shell(
537✔
130
    const char* group_name,
131
    const char* test_name,
132
    const char* file_name,
133
    size_t line_number
134
) noexcept
537✔
135
  : group_(group_name)
537✔
136
  , name_(test_name)
537✔
137
  , file_(file_name)
537✔
138
  , line_number_(line_number)
537✔
139
  , next_(nullptr)
537✔
140
  , has_failed_(false)
537✔
141
{
142
}
537✔
143

144
void Shell::set_crash_method(void (*crashme)())
11✔
145
{
146
  please_crash_me_right_now = crashme;
11✔
147
}
11✔
148

149
void Shell::reset_crash_method()
11✔
150
{
151
  please_crash_me_right_now = abort;
11✔
152
}
11✔
153

154
void Shell::crash()
6✔
155
{
156
  please_crash_me_right_now();
6✔
157
}
6✔
158

159
void Shell::run_one_test(Plugin* plugin, Result& result)
1,187✔
160
{
161
  has_failed_ = false;
1,187✔
162
  result.count_run();
1,187✔
163
  HelperTestRunInfo run_info(this, plugin, &result);
1,187✔
164
  set_jump(helper_do_run_one_test_in_current_process, &run_info);
1,187✔
165
}
1,183✔
166

167
Test* Shell::create_test()
16✔
168
{
169
  return new Test();
16✔
170
}
171

172
void Shell::destroy_test(Test* test)
1,188✔
173
{
174
  delete test;
1,188✔
175
}
1,188✔
176

177
void Shell::run_one_test_in_current_process(Plugin* plugin, Result& result)
1,188✔
178
{
179
  result.print_very_verbose("\n-- before runAllPreTestAction: ");
1,188✔
180
  plugin->run_all_pre_test_action(*this, result);
1,188✔
181
  result.print_very_verbose("\n-- after runAllPreTestAction: ");
1,188✔
182

183
  // save test context, so that test class can be tested
184
  Shell* saved_test = Shell::get_current();
1,188✔
185
  Result* saved_result = Shell::get_test_result();
1,188✔
186

187
  Shell::set_test_result(&result);
1,188✔
188
  Shell::set_current_test(this);
1,188✔
189

190
  Test* test_to_run = nullptr;
1,188✔
191

192
#if MUTINY_HAVE_EXCEPTIONS
193
  try {
194
#endif
195
    result.print_very_verbose("\n---- before createTest: ");
1,188✔
196
    test_to_run = create_test();
1,188✔
197
    result.print_very_verbose("\n---- after createTest: ");
1,188✔
198

199
    result.print_very_verbose("\n------ before runTest: ");
1,188✔
200
    test_to_run->run();
1,188✔
201
    result.print_very_verbose("\n------ after runTest: ");
1,184✔
202

203
    Shell::set_current_test(saved_test);
1,184✔
204
    Shell::set_test_result(saved_result);
1,184✔
205
#if MUTINY_HAVE_EXCEPTIONS
206
  } catch (...) {
4✔
207
    destroy_test(test_to_run);
4✔
208
    throw;
4✔
209
  }
4✔
210
#endif
211

212
  result.print_very_verbose("\n---- before destroyTest: ");
1,184✔
213
  destroy_test(test_to_run);
1,184✔
214
  result.print_very_verbose("\n---- after destroyTest: ");
1,184✔
215

216
  result.print_very_verbose("\n-- before runAllPostTestAction: ");
1,184✔
217
  plugin->run_all_post_test_action(*this, result);
1,184✔
218
  result.print_very_verbose("\n-- after runAllPostTestAction: ");
1,184✔
219
}
1,184✔
220

221
Shell* Shell::get_next() const
125,859✔
222
{
223
  return next_;
125,859✔
224
}
225

226
Shell* Shell::add_test(Shell* test)
32,475✔
227
{
228
  next_ = test;
32,475✔
229
  return this;
32,475✔
230
}
231

232
size_t Shell::count_tests()
33✔
233
{
234
  return next_ ? next_->count_tests() + 1 : 1;
33✔
235
}
236

237
String Shell::get_macro_name() const
1,382✔
238
{
239
  return "TEST";
1,382✔
240
}
241

242
const char* Shell::get_name() const
1,521✔
243
{
244
  return name_;
1,521✔
245
}
246

247
const char* Shell::get_group() const
62,423✔
248
{
249
  return group_;
62,423✔
250
}
251

252
String Shell::get_formatted_name() const
1,466✔
253
{
254
  String formatted_name(get_macro_name());
1,466✔
255
  formatted_name += "(";
1,466✔
256
  formatted_name += group_;
1,466✔
257
  formatted_name += ", ";
1,466✔
258
  formatted_name += name_;
1,466✔
259
  formatted_name += ")";
1,466✔
260

261
  return formatted_name;
1,466✔
262
}
×
263

264
bool Shell::has_failed() const
21✔
265
{
266
  return has_failed_;
21✔
267
}
268

269
void Shell::count_check()
946✔
270
{
271
  get_test_result()->count_check();
946✔
272
}
946✔
273

274
bool Shell::will_run() const
1,249✔
275
{
276
  return true;
1,249✔
277
}
278

279
bool Shell::is_ordered() const
2✔
280
{
281
  return false;
2✔
282
}
283

284
void Shell::set_run_ignored() {}
1✔
285

286
void Shell::set_file_name(const char* file_name)
31,739✔
287
{
288
  file_ = file_name;
31,739✔
289
}
31,739✔
290

291
void Shell::set_line_number(size_t line_number)
31,739✔
292
{
293
  line_number_ = line_number;
31,739✔
294
}
31,739✔
295

296
void Shell::set_group_name(const char* group_name)
31,751✔
297
{
298
  group_ = group_name;
31,751✔
299
}
31,751✔
300

301
void Shell::set_test_name(const char* test_name)
31,747✔
302
{
303
  name_ = test_name;
31,747✔
304
}
31,747✔
305

306
const char* Shell::get_file() const
1,674✔
307
{
308
  return file_;
1,674✔
309
}
310

311
size_t Shell::get_line_number() const
1,674✔
312
{
313
  return line_number_;
1,674✔
314
}
315

316
bool Shell::match(const char* target, const Filter* filters) const
32,051✔
317
{
318
  if (filters == nullptr)
32,051✔
319
    return true;
1,382✔
320

321
  for (; filters != nullptr; filters = filters->get_next())
60,284✔
322
    if (filters->match(target))
30,669✔
323
      return true;
1,054✔
324

325
  return false;
29,615✔
326
}
327

328
bool Shell::should_run(
30,832✔
329
    const Filter* group_filters,
330
    const Filter* name_filters
331
) const
332
{
333
  return match(group_, group_filters) && match(name_, name_filters);
30,832✔
334
}
335

336
void Shell::add_failure(const Failure& failure)
128✔
337
{
338
  has_failed_ = true;
128✔
339
  get_test_result()->add_failure(failure);
128✔
340
}
128✔
341

342
void Shell::add_test_property(const char* name, const char* value)
1✔
343
{
344
  get_test_result()->add_test_property(name, value);
1✔
345
}
1✔
346

347
void Shell::exit_test(const Terminator& terminator)
5✔
348
{
349
  terminator.exit_current_test();
5✔
350
}
×
351

352
void Shell::assert_true(
561✔
353
    bool condition,
354
    const char* check_string,
355
    const char* condition_string,
356
    const char* text,
357
    const char* file_name,
358
    size_t line_number,
359
    const Terminator& test_terminator
360
)
361
{
362
  get_test_result()->count_check();
561✔
363
  if (!condition) {
561✔
364
    add_failure(CheckFailure(
8✔
365
        this, file_name, line_number, check_string, condition_string, text
366
    ));
367
    test_terminator.exit_current_test();
8✔
368
  }
369
}
553✔
370

371
void Shell::fail(
26✔
372
    const char* text,
373
    const char* file_name,
374
    size_t line_number,
375
    const Terminator& test_terminator
376
)
377
{
378
  get_test_result()->count_check();
26✔
379
  add_failure(FailFailure(this, file_name, line_number, text));
26✔
380
  test_terminator.exit_current_test();
26✔
381
}
×
382

383
void Shell::assert_cstr_equal(
728✔
384
    const char* expected,
385
    const char* actual,
386
    const char* text,
387
    const char* file_name,
388
    size_t line_number,
389
    const Terminator& test_terminator
390
)
391
{
392
  get_test_result()->count_check();
728✔
393
  if (actual == nullptr && expected == nullptr)
728✔
394
    return;
1✔
395
  if (actual == nullptr || expected == nullptr) {
727✔
396
    add_failure(
2✔
397
        StringEqualFailure(this, file_name, line_number, expected, actual, text)
4✔
398
    );
399
    test_terminator.exit_current_test();
2✔
400
  }
401
  if (strcmp(expected, actual) != 0) {
725✔
402
    add_failure(
4✔
403
        StringEqualFailure(this, file_name, line_number, expected, actual, text)
8✔
404
    );
405
    test_terminator.exit_current_test();
4✔
406
  }
407
}
408

409
void Shell::assert_cstr_n_equal(
15✔
410
    const char* expected,
411
    const char* actual,
412
    size_t length,
413
    const char* text,
414
    const char* file_name,
415
    size_t line_number,
416
    const Terminator& test_terminator
417
)
418
{
419
  get_test_result()->count_check();
15✔
420
  if (actual == nullptr && expected == nullptr)
15✔
421
    return;
1✔
422
  if (actual == nullptr || expected == nullptr) {
14✔
423
    add_failure(
2✔
424
        StringEqualFailure(this, file_name, line_number, expected, actual, text)
4✔
425
    );
426
    test_terminator.exit_current_test();
2✔
427
  }
428
  if (strncmp(expected, actual, length) != 0) {
12✔
429
    add_failure(
6✔
430
        StringEqualFailure(this, file_name, line_number, expected, actual, text)
12✔
431
    );
432
    test_terminator.exit_current_test();
6✔
433
  }
434
}
435

436
void Shell::assert_cstr_contains(
252✔
437
    const char* expected,
438
    const char* actual,
439
    const char* text,
440
    const char* file_name,
441
    size_t line_number
442
)
443
{
444
  get_test_result()->count_check();
252✔
445
  if (actual == nullptr && expected == nullptr)
252✔
446
    return;
1✔
447
  if (actual == nullptr || expected == nullptr) {
251✔
448
    add_failure(ContainsFailure(
4✔
449
        this,
450
        file_name,
451
        line_number,
452
        string_from_or_null(expected),
4✔
453
        string_from_or_null(actual),
4✔
454
        text ? text : ""
455
    ));
456
    exit_test(get_current_test_terminator());
2✔
457
  } else if (!string_contains(actual, expected)) {
249✔
458
    add_failure(ContainsFailure(
2✔
459
        this, file_name, line_number, expected, actual, text ? text : ""
460
    ));
461
    exit_test(get_current_test_terminator());
2✔
462
  }
463
}
464

465
void Shell::assert_intmax_equal(
12✔
466
    intmax_t expected,
467
    intmax_t actual,
468
    const char* text,
469
    const char* file_name,
470
    size_t line_number,
471
    const Terminator& test_terminator
472
)
473
{
474
  get_test_result()->count_check();
12✔
475
  if (expected != actual) {
12✔
476
    add_failure(
6✔
477
        IntMaxEqualFailure(this, file_name, line_number, expected, actual, text)
12✔
478
    );
479
    test_terminator.exit_current_test();
6✔
480
  }
481
}
6✔
482

483
void Shell::assert_uintmax_equal(
12✔
484
    uintmax_t expected,
485
    uintmax_t actual,
486
    const char* text,
487
    const char* file_name,
488
    size_t line_number,
489
    const Terminator& test_terminator
490
)
491
{
492
  get_test_result()->count_check();
12✔
493
  if (expected != actual) {
12✔
494
    add_failure(UintMaxEqualFailure(
6✔
495
        this, file_name, line_number, expected, actual, text
496
    ));
497
    test_terminator.exit_current_test();
6✔
498
  }
499
}
6✔
500

501
void Shell::assert_pointers_equal(
99✔
502
    const void* expected,
503
    const void* actual,
504
    const char* text,
505
    const char* file_name,
506
    size_t line_number,
507
    const Terminator& test_terminator
508
)
509
{
510
  get_test_result()->count_check();
99✔
511
  if (expected != actual) {
99✔
512
    add_failure(EqualsFailure(
8✔
513
        this,
514
        file_name,
515
        line_number,
516
        string_from(expected),
8✔
517
        string_from(actual),
8✔
518
        text
519
    ));
520
    test_terminator.exit_current_test();
4✔
521
  }
522
}
95✔
523

524
void Shell::assert_function_pointers_equal(
18✔
525
    void (*expected)(),
526
    void (*actual)(),
527
    const char* text,
528
    const char* file_name,
529
    size_t line_number,
530
    const Terminator& test_terminator
531
)
532
{
533
  get_test_result()->count_check();
18✔
534
  if (expected != actual) {
18✔
535
    add_failure(EqualsFailure(
4✔
536
        this,
537
        file_name,
538
        line_number,
539
        string_from(expected),
4✔
540
        string_from(actual),
4✔
541
        text
542
    ));
543
    test_terminator.exit_current_test();
2✔
544
  }
545
}
16✔
546

547
void Shell::assert_approx_equal(
6✔
548
    double expected,
549
    double actual,
550
    double threshold,
551
    const char* text,
552
    const char* file_name,
553
    size_t line_number,
554
    const Terminator& test_terminator
555
)
556
{
557
  add_failure(ApproxEqualFailure(
6✔
558
      this, file_name, line_number, expected, actual, threshold, text
559
  ));
560
  test_terminator.exit_current_test();
6✔
UNCOV
561
}
×
562

563
void Shell::assert_binary_equal(
14✔
564
    const void* expected,
565
    const void* actual,
566
    size_t length,
567
    const char* text,
568
    const char* file_name,
569
    size_t line_number,
570
    const Terminator& test_terminator
571
)
572
{
573
  get_test_result()->count_check();
14✔
574
  if (length == 0)
14✔
575
    return;
3✔
576
  if (actual == nullptr && expected == nullptr)
11✔
577
    return;
1✔
578
  if (actual == nullptr || expected == nullptr) {
10✔
579
    add_failure(BinaryEqualFailure(
2✔
580
        this,
581
        file_name,
582
        line_number,
583
        static_cast<const unsigned char*>(expected),
584
        static_cast<const unsigned char*>(actual),
585
        length,
586
        text
587
    ));
588
    test_terminator.exit_current_test();
2✔
589
  }
590
  if (memcmp(expected, actual, length) != 0) {
8✔
591
    add_failure(BinaryEqualFailure(
4✔
592
        this,
593
        file_name,
594
        line_number,
595
        static_cast<const unsigned char*>(expected),
596
        static_cast<const unsigned char*>(actual),
597
        length,
598
        text
599
    ));
600
    test_terminator.exit_current_test();
4✔
601
  }
602
}
603

604
void Shell::assert_equals(
22✔
605
    bool failed,
606
    const char* expected,
607
    const char* actual,
608
    const char* text,
609
    const char* file,
610
    size_t line,
611
    const Terminator& test_terminator
612
)
613
{
614
  get_test_result()->count_check();
22✔
615
  if (failed) {
22✔
616
    add_failure(CheckEqualFailure(this, file, line, expected, actual, text));
18✔
617
    test_terminator.exit_current_test();
18✔
618
  }
619
}
4✔
620

621
void Shell::assert_equals(
12✔
622
    bool failed,
623
    String expected,
624
    String actual,
625
    const char* text,
626
    const char* file,
627
    size_t line,
628
    const Terminator& test_terminator
629
)
630
{
631
  get_test_result()->count_check();
12✔
632
  if (failed) {
12✔
633
    add_failure(CheckEqualFailure(
6✔
634
        this, file, line, expected.c_str(), actual.c_str(), text
635
    ));
636
    expected.clear();
6✔
637
    actual.clear();
6✔
638
    test_terminator.exit_current_test();
6✔
639
  }
640
}
6✔
641

642
void Shell::assert_compare(
2✔
643
    bool comparison,
644
    const char* check_string,
645
    const char* comparison_string,
646
    const char* text,
647
    const char* file_name,
648
    size_t line_number,
649
    const Terminator& test_terminator
650
)
651
{
652
  get_test_result()->count_check();
2✔
653
  if (!comparison) {
2✔
654
    add_failure(ComparisonFailure(
2✔
655
        this, file_name, line_number, check_string, comparison_string, text
656
    ));
657
    test_terminator.exit_current_test();
2✔
658
  }
659
}
×
660

661
void Shell::print_very_verbose(const char* text)
7,031✔
662
{
663
  get_test_result()->print_very_verbose(text);
7,031✔
664
}
7,031✔
665

666
Result* Shell::test_result_ = nullptr;
667
Shell* Shell::current_test_ = nullptr;
668

669
void Shell::set_test_result(Result* result)
2,372✔
670
{
671
  test_result_ = result;
2,372✔
672
}
2,372✔
673

674
void Shell::set_current_test(Shell* test)
2,372✔
675
{
676
  current_test_ = test;
2,372✔
677
}
2,372✔
678

679
Result* Shell::get_test_result()
11,067✔
680
{
681
  if (test_result_ == nullptr)
11,067✔
682
    return &OutsideTestRunnerUTest::instance().get_result();
69✔
683
  return test_result_;
10,998✔
684
}
685

686
Shell* Shell::get_current()
5,271✔
687
{
688
  if (current_test_ == nullptr)
5,271✔
689
    return &OutsideTestRunnerUTest::instance();
69✔
690
  return current_test_;
5,202✔
691
}
692

693
const Terminator& Shell::get_current_test_terminator()
1,406✔
694
{
695
  return *current_test_terminator_;
1,406✔
696
}
697

698
const Terminator& Shell::get_current_test_terminator_without_exceptions()
138✔
699
{
700
  return *current_test_terminator_without_exceptions_;
138✔
701
}
702

703
void Shell::set_crash_on_fail()
5✔
704
{
705
  current_test_terminator_ = &crashing_test_terminator;
5✔
706
  current_test_terminator_without_exceptions_ =
5✔
707
      &crashing_test_terminator_without_exceptions;
708
}
5✔
709

710
void Shell::restore_default_test_terminator()
5✔
711
{
712
  current_test_terminator_ = &normal_test_terminator;
5✔
713
  current_test_terminator_without_exceptions_ =
5✔
714
      &normal_test_terminator_without_exceptions;
715
}
5✔
716

717
void Shell::set_rethrow_exceptions(bool rethrow_exceptions)
80✔
718
{
719
  rethrow_exceptions_ = rethrow_exceptions;
80✔
720
}
80✔
721

722
bool Shell::is_rethrowing_exceptions()
17✔
723
{
724
  return rethrow_exceptions_;
17✔
725
}
726

727
} // namespace test
728
} // namespace tiny
729
} // namespace mu
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc