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

thetic / mutiny / 24374861549

14 Apr 2026 12:51AM UTC coverage: 98.944%. Remained the same
24374861549

Pull #51

github

web-flow
Merge 6b6f27964 into 18e0cc9d5
Pull Request #51: Templatize ApproxEqualFailure and assert_approx_equal

14 of 15 new or added lines in 2 files covered. (93.33%)

2 existing lines in 2 files now uncovered.

5530 of 5589 relevant lines covered (98.94%)

3444.32 hits per line

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

98.08
/src/test/Failure.cpp
1
#include "mutiny/test/Failure.hpp"
2

3
#include "mutiny/test/Output.hpp"
4
#include "mutiny/test/Shell.hpp"
5

6
#include "mutiny/String.hpp"
7

8
#if MUTINY_USE_STD_CPP_LIB
9
#include <typeinfo>
10
#if defined(__GNUC__)
11
#include <memory>
12

13
#include <cxxabi.h>
14
#endif
15
#endif
16

17
namespace mu {
18
namespace tiny {
19
namespace test {
20
namespace {
21
bool is_control_with_short_escape_sequence(char ch)
970✔
22
{
23
  return '\a' <= ch && '\r' >= ch;
970✔
24
}
25

26
void pad_strings_to_same_length(String& str1, String& str2, char pad_character)
18✔
27
{
28
  if (str1.size() > str2.size()) {
18✔
29
    pad_strings_to_same_length(str2, str1, pad_character);
1✔
30
    return;
1✔
31
  }
32

33
  str1 = String(str2.size() - str1.size(), pad_character) + str1;
17✔
34
}
35

36
size_t get_printable_size(String const& str)
114✔
37
{
38
  size_t str_size = str.size();
114✔
39
  size_t printable_str_size = str_size;
114✔
40

41
  for (size_t i = 0; i < str_size; i++) {
599✔
42
    char c = str.c_str()[i];
485✔
43
    if (is_control_with_short_escape_sequence(c)) {
485✔
44
      printable_str_size += 1;
6✔
45
    } else if (iscntrl(c)) {
479✔
46
      printable_str_size += 3;
2✔
47
    }
48
  }
49

50
  return printable_str_size;
114✔
51
}
52

53
String printable(String const& str)
114✔
54
{
55
  static const char* short_escape_codes[] = { "\\a", "\\b", "\\t", "\\n",
56
                                              "\\v", "\\f", "\\r" };
57

58
  String result;
114✔
59
  result.reserve(get_printable_size(str));
114✔
60

61
  size_t str_size = str.size();
114✔
62
  for (size_t i = 0; i < str_size; i++) {
599✔
63
    char c = str.c_str()[i];
485✔
64
    if (is_control_with_short_escape_sequence(c)) {
485✔
65
      result += short_escape_codes[static_cast<unsigned char>(c - '\a')];
6✔
66
    } else if (iscntrl(c)) {
479✔
67
      result += string_from_format("\\x%02X ", c);
2✔
68
    } else {
69
      result += c;
477✔
70
    }
71
  }
72

73
  return result;
114✔
74
}
×
75

76
String printable_string_from_or_null(const char* expected)
122✔
77
{
78
  return (expected) ? printable(string_from(expected)) : string_from("(null)");
244✔
79
}
80
} // namespace
81

82
Failure::Failure(
82✔
83
    Shell* test,
84
    const char* file_name,
85
    size_t line_number,
86
    const String& the_message
87
)
82✔
88
  : test_name_(test->get_formatted_name())
82✔
89
  , test_name_only_(test->get_name())
82✔
90
  , file_name_(file_name)
82✔
91
  , line_number_(line_number)
82✔
92
  , test_file_name_(test->get_file())
82✔
93
  , test_line_number_(test->get_line_number())
82✔
94
  , message_(the_message)
164✔
95
{
96
}
82✔
97

98
Failure::Failure(Shell* test, const String& the_message)
158✔
99
  : test_name_(test->get_formatted_name())
158✔
100
  , test_name_only_(test->get_name())
158✔
101
  , file_name_(test->get_file())
158✔
102
  , line_number_(test->get_line_number())
158✔
103
  , test_file_name_(test->get_file())
158✔
104
  , test_line_number_(test->get_line_number())
158✔
105
  , message_(the_message)
316✔
106
{
107
}
158✔
108

109
Failure::Failure(Shell* test, const char* file_name, size_t line_num)
157✔
110
  : test_name_(test->get_formatted_name())
157✔
111
  , test_name_only_(test->get_name())
157✔
112
  , file_name_(file_name)
157✔
113
  , line_number_(line_num)
157✔
114
  , test_file_name_(test->get_file())
157✔
115
  , test_line_number_(test->get_line_number())
157✔
116
  , message_("no message")
314✔
117
{
118
}
157✔
119

120
Failure::Failure(Failure&& f) noexcept
168✔
121
  : test_name_(static_cast<String&&>(f.test_name_))
168✔
122
  , test_name_only_(static_cast<String&&>(f.test_name_only_))
168✔
123
  , file_name_(static_cast<String&&>(f.file_name_))
168✔
124
  , line_number_(f.line_number_)
168✔
125
  , test_file_name_(static_cast<String&&>(f.test_file_name_))
168✔
126
  , test_line_number_(f.test_line_number_)
168✔
127
  , message_(static_cast<String&&>(f.message_))
336✔
128
{
129
}
168✔
130

131
const String& Failure::get_file_name() const
162✔
132
{
133
  return file_name_;
162✔
134
}
135

136
const String& Failure::get_test_file_name() const
110✔
137
{
138
  return test_file_name_;
110✔
139
}
140

141
const String& Failure::get_test_name() const
136✔
142
{
143
  return test_name_;
136✔
144
}
145

146
const String& Failure::get_test_name_only() const
×
147
{
148
  return test_name_only_;
×
149
}
150

151
size_t Failure::get_failure_line_number() const
162✔
152
{
153
  return line_number_;
162✔
154
}
155

156
size_t Failure::get_test_line_number() const
110✔
157
{
158
  return test_line_number_;
110✔
159
}
160

161
const String& Failure::get_message() const
337✔
162
{
163
  return message_;
337✔
164
}
165

166
bool Failure::is_outside_test_file() const
136✔
167
{
168
  return test_file_name_ != file_name_;
136✔
169
}
170

171
bool Failure::is_in_helper_function() const
28✔
172
{
173
  return line_number_ < test_line_number_;
28✔
174
}
175

176
String Failure::create_but_was_string(
115✔
177
    const String& expected,
178
    const String& actual
179
)
180
{
181
  return string_from_format(
182
      "expected <%s>\n\tbut was  <%s>", expected.c_str(), actual.c_str()
183
  );
115✔
184
}
185

186
String Failure::create_difference_at_pos_string(
63✔
187
    const String& actual,
188
    size_t offset,
189
    size_t reported_position
190
)
191
{
192
  String result;
63✔
193
  const size_t extra_characters_window = 20;
63✔
194
  const size_t half_of_extra_characters_window = extra_characters_window / 2;
63✔
195

196
  String padding_for_preventing_out_of_bounds(
197
      half_of_extra_characters_window, ' '
198
  );
63✔
199
  String actual_string = padding_for_preventing_out_of_bounds + actual +
126✔
200
                         padding_for_preventing_out_of_bounds;
63✔
201
  String different_string = string_from_format(
202
      "difference starts at position %lu at: <",
203
      static_cast<unsigned long>(reported_position)
204
  );
63✔
205

206
  result += "\n";
63✔
207
  result += string_from_format(
126✔
208
      "\t%s%s>\n",
209
      different_string.c_str(),
210
      actual_string.substr(offset, extra_characters_window).c_str()
126✔
211
  );
63✔
212

213
  result += string_from_format(
126✔
214
      "\t%s^",
215
      String(different_string.size() + half_of_extra_characters_window, ' ')
126✔
216
          .c_str()
217
  );
63✔
218
  return result;
126✔
219
}
63✔
220

221
String Failure::create_user_text(const String& text)
128✔
222
{
223
  String user_message = "";
128✔
224
  if (!text.empty()) {
128✔
225
    user_message += "Message: ";
39✔
226
    user_message += text;
39✔
227
    user_message += "\n\t";
39✔
228
  }
229
  return user_message;
128✔
230
}
×
231

232
EqualsFailure::EqualsFailure(
4✔
233
    Shell* test,
234
    const char* file_name,
235
    size_t line_number,
236
    const char* expected,
237
    const char* actual,
238
    const String& text
239
)
4✔
240
  : Failure(test, file_name, line_number)
4✔
241
{
242
  message_ = create_user_text(text);
4✔
243

244
  message_ += create_but_was_string(
8✔
245
      string_from_or_null(expected), string_from_or_null(actual)
8✔
246
  );
4✔
247
}
4✔
248

249
EqualsFailure::EqualsFailure(
2✔
250
    Shell* test,
251
    const char* file_name,
252
    size_t line_number,
253
    const String& expected,
254
    const String& actual,
255
    const String& text
256
)
2✔
257
  : Failure(test, file_name, line_number)
2✔
258
{
259
  message_ = create_user_text(text);
2✔
260

261
  message_ += create_but_was_string(expected, actual);
2✔
262
}
2✔
263

264

265
CheckEqualFailure::CheckEqualFailure(
33✔
266
    Shell* test,
267
    const char* file_name,
268
    size_t line_number,
269
    const String& expected,
270
    const String& actual,
271
    const String& text
272
)
33✔
273
  : Failure(test, file_name, line_number)
33✔
274
{
275
  message_ = create_user_text(text);
33✔
276

277
  String printable_expected = printable_string_from_or_null(expected.c_str());
33✔
278
  String printable_actual = printable_string_from_or_null(actual.c_str());
33✔
279

280
  message_ += create_but_was_string(printable_expected, printable_actual);
33✔
281

282
  size_t fail_start;
283
  for (fail_start = 0; actual[fail_start] == expected[fail_start]; fail_start++)
52✔
284
    ;
285
  size_t fail_start_printable;
286
  for (fail_start_printable = 0; printable_actual[fail_start_printable] ==
53✔
287
                                 printable_expected[fail_start_printable];
53✔
288
       fail_start_printable++)
289
    ;
290
  message_ += create_difference_at_pos_string(
66✔
291
      printable_actual, fail_start_printable, fail_start
292
  );
33✔
293
}
33✔
294

295
ComparisonFailure::ComparisonFailure(
2✔
296
    Shell* test,
297
    const char* file_name,
298
    size_t line_number,
299
    const String& check_string,
300
    const String& comparison_string,
301
    const String& text
302
)
2✔
303
  : Failure(test, file_name, line_number)
2✔
304
{
305
  message_ = create_user_text(text);
2✔
306
  message_ += check_string;
2✔
307
  message_ += "(";
2✔
308
  message_ += comparison_string;
2✔
309
  message_ += ") failed";
2✔
310
}
2✔
311

312
ContainsFailure::ContainsFailure(
4✔
313
    Shell* test,
314
    const char* file_name,
315
    size_t line_number,
316
    const String& expected,
317
    const String& actual,
318
    const String& text
319
)
4✔
320
  : Failure(test, file_name, line_number)
4✔
321
{
322
  message_ = create_user_text(text);
4✔
323

324
  message_ += string_from_format(
8✔
325
      "actual <%s>\n\tdid not contain  <%s>", actual.c_str(), expected.c_str()
326
  );
4✔
327
}
4✔
328

329
CheckFailure::CheckFailure(
6✔
330
    Shell* test,
331
    const char* file_name,
332
    size_t line_number,
333
    const String& check_string,
334
    const String& condition_string,
335
    const String& text
336
)
6✔
337
  : Failure(test, file_name, line_number)
6✔
338
{
339
  message_ = create_user_text(text);
6✔
340

341
  message_ += check_string;
6✔
342
  message_ += "(";
6✔
343
  message_ += condition_string;
6✔
344
  message_ += ") failed";
6✔
345
}
6✔
346

347
FailFailure::FailFailure(
28✔
348
    Shell* test,
349
    const char* file_name,
350
    size_t line_number,
351
    const String& message
352
)
28✔
353
  : Failure(test, file_name, line_number)
28✔
354
{
355
  message_ = message;
28✔
356
}
28✔
357

358
IntMaxEqualFailure::IntMaxEqualFailure(
10✔
359
    Shell* test,
360
    const char* file_name,
361
    size_t line_number,
362
    long long expected,
363
    long long actual,
364
    const String& text
365
)
10✔
366
  : Failure(test, file_name, line_number)
10✔
367
{
368
  message_ = create_user_text(text);
10✔
369

370
  String a_decimal = string_from(actual);
10✔
371
  String e_decimal = string_from(expected);
10✔
372

373
  pad_strings_to_same_length(a_decimal, e_decimal, ' ');
10✔
374

375
  String actual_reported =
376
      a_decimal + " " + brackets_formatted_hex_string_from(actual);
10✔
377
  String expected_reported =
378
      e_decimal + " " + brackets_formatted_hex_string_from(expected);
10✔
379
  message_ += create_but_was_string(expected_reported, actual_reported);
10✔
380
}
10✔
381

382
UintMaxEqualFailure::UintMaxEqualFailure(
7✔
383
    Shell* test,
384
    const char* file_name,
385
    size_t line_number,
386
    unsigned long long expected,
387
    unsigned long long actual,
388
    const String& text
389
)
7✔
390
  : Failure(test, file_name, line_number)
7✔
391
{
392
  message_ = create_user_text(text);
7✔
393

394
  String a_decimal = string_from(actual);
7✔
395
  String e_decimal = string_from(expected);
7✔
396

397
  pad_strings_to_same_length(a_decimal, e_decimal, ' ');
7✔
398

399
  String actual_reported =
400
      a_decimal + " " + brackets_formatted_hex_string_from(actual);
7✔
401
  String expected_reported =
402
      e_decimal + " " + brackets_formatted_hex_string_from(expected);
7✔
403
  message_ += create_but_was_string(expected_reported, actual_reported);
7✔
404
}
7✔
405

406
StringEqualFailure::StringEqualFailure(
23✔
407
    Shell* test,
408
    const char* file_name,
409
    size_t line_number,
410
    const char* expected,
411
    const char* actual,
412
    const String& text
413
)
23✔
414
  : Failure(test, file_name, line_number)
23✔
415
{
416
  message_ = create_user_text(text);
23✔
417

418
  String printable_expected = printable_string_from_or_null(expected);
23✔
419
  String printable_actual = printable_string_from_or_null(actual);
23✔
420

421
  message_ += create_but_was_string(printable_expected, printable_actual);
23✔
422
  if ((expected) && (actual)) {
23✔
423
    size_t fail_start;
424
    for (fail_start = 0; actual[fail_start] == expected[fail_start];
85✔
425
         fail_start++)
426
      ;
427
    size_t fail_start_printable;
428
    for (fail_start_printable = 0; printable_actual[fail_start_printable] ==
87✔
429
                                   printable_expected[fail_start_printable];
87✔
430
         fail_start_printable++)
431
      ;
432
    message_ += create_difference_at_pos_string(
34✔
433
        printable_actual, fail_start_printable, fail_start
434
    );
17✔
435
  }
436
}
23✔
437

438
StringEqualNoCaseFailure::StringEqualNoCaseFailure(
5✔
439
    Shell* test,
440
    const char* file_name,
441
    size_t line_number,
442
    const char* expected,
443
    const char* actual,
444
    const String& text
445
)
5✔
446
  : Failure(test, file_name, line_number)
5✔
447
{
448
  message_ = create_user_text(text);
5✔
449

450
  String printable_expected = printable_string_from_or_null(expected);
5✔
451
  String printable_actual = printable_string_from_or_null(actual);
5✔
452

453
  message_ += create_but_was_string(printable_expected, printable_actual);
5✔
454
  if ((expected) && (actual)) {
5✔
455
    size_t fail_start;
456
    for (fail_start = 0;
8✔
457
         tolower(actual[fail_start]) == tolower(expected[fail_start]);
8✔
458
         fail_start++)
459
      ;
460
    size_t fail_start_printable;
461
    for (fail_start_printable = 0;
8✔
462
         tolower(printable_actual[fail_start_printable]) ==
8✔
463
         tolower(printable_expected[fail_start_printable]);
8✔
464
         fail_start_printable++)
465
      ;
466
    message_ += create_difference_at_pos_string(
6✔
467
        printable_actual, fail_start_printable, fail_start
468
    );
3✔
469
  }
470
}
5✔
471

472
BinaryEqualFailure::BinaryEqualFailure(
14✔
473
    Shell* test,
474
    const char* file_name,
475
    size_t line_number,
476
    const unsigned char* expected,
477
    const unsigned char* actual,
478
    size_t size,
479
    const String& text
480
)
14✔
481
  : Failure(test, file_name, line_number)
14✔
482
{
483
  message_ = create_user_text(text);
14✔
484

485
  String actual_hex = string_from_binary_or_null(actual, size);
14✔
486

487
  message_ += create_but_was_string(
28✔
488
      string_from_binary_or_null(expected, size), actual_hex
28✔
489
  );
14✔
490
  if ((expected) && (actual)) {
14✔
491
    size_t fail_start;
492
    for (fail_start = 0; actual[fail_start] == expected[fail_start];
25✔
493
         fail_start++)
494
      ;
495
    message_ += create_difference_at_pos_string(
10✔
496
        actual_hex, (fail_start * 3 + 1), fail_start
10✔
497
    );
10✔
498
  }
499
}
14✔
500

501
FeatureUnsupportedFailure::FeatureUnsupportedFailure(
1✔
502
    Shell* test,
503
    const char* file_name,
504
    size_t line_number,
505
    const String& feature_name,
506
    const String& text
507
)
1✔
508
  : Failure(test, file_name, line_number)
1✔
509
{
510
  message_ = create_user_text(text);
1✔
511

512
  message_ += string_from_format(
2✔
513
      "The feature \"%s\" is not supported in this environment or with the "
514
      "feature set selected when building the library.",
515
      feature_name.c_str()
516
  );
1✔
517
}
1✔
518

519
#if MUTINY_HAVE_EXCEPTIONS
520
UnexpectedExceptionFailure::UnexpectedExceptionFailure(Shell* test)
9✔
521
  : Failure(test, "Unexpected exception of unknown type was thrown.")
9✔
522
{
523
}
9✔
524

525
#if MUTINY_USE_STD_CPP_LIB
526
#if MUTINY_HAVE_RTTI
527
namespace {
528
String get_exception_type_name(const std::exception& e)
5✔
529
{
530
  const char* name = typeid(e).name();
5✔
531
#if defined(__GNUC__)
532
  int status = -1;
5✔
533

534
  std::unique_ptr<char, void (*)(void*)> demangled_name(
UNCOV
535
      abi::__cxa_demangle(name, nullptr, nullptr, &status), free
×
536
  );
5✔
537

538
  return (status == 0) ? demangled_name.get() : name;
10✔
539
#else
540
  return name;
541
#endif
542
}
5✔
543
} // namespace
544
#endif // MUTINY_HAVE_RTTI
545

546
UnexpectedExceptionFailure::UnexpectedExceptionFailure(
5✔
547
    Shell* test,
548
    const std::exception& e
549
)
5✔
550
  : Failure(
551
        test,
552
#if MUTINY_HAVE_RTTI
553
        string_from_format(
10✔
554
            "Unexpected exception of type '%s' was thrown: %s",
555
            get_exception_type_name(e).c_str(),
10✔
556
            e.what()
5✔
557
        )
558
#else
559
        "Unexpected exception of unknown type was thrown."
560
#endif
561
    )
10✔
562
{
563
  (void)e;
564
}
5✔
565
#endif // MUTINY_USE_STD_CPP_LIB
566
#endif // MUTINY_HAVE_EXCEPTIONS
567

568
} // namespace test
569
} // namespace tiny
570
} // 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