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

thetic / mu.tiny / 24637976892

19 Apr 2026 08:06PM UTC coverage: 98.879% (+0.008%) from 98.871%
24637976892

push

github

web-flow
Merge pull request #78 from thetic/feat/70-tap-output

Add TapOutputPlugin for TAP version 13 output

129 of 130 new or added lines in 4 files covered. (99.23%)

5206 of 5265 relevant lines covered (98.88%)

3393.47 hits per line

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

99.08
/src/test/TapOutput.cpp
1
#include "mu/tiny/test/TapOutput.hpp"
2

3
#include "mu/tiny/test/Failure.hpp"
4
#include "mu/tiny/test/Output.hpp"
5
#include "mu/tiny/test/Result.hpp"
6
#include "mu/tiny/test/Shell.hpp"
7

8
namespace mu {
9
namespace tiny {
10
namespace test {
11

12
namespace {
13

14
String yaml_escape(const String& text)
7✔
15
{
16
  String result;
7✔
17
  for (const char* p = text.c_str(); *p; ++p) {
145✔
18
    switch (*p) {
138✔
19
      case '\\':
1✔
20
        result += "\\\\";
1✔
21
        break;
1✔
22
      case '"':
2✔
23
        result += "\\\"";
2✔
24
        break;
2✔
25
      case '\n':
1✔
26
        result += "\\n";
1✔
27
        break;
1✔
28
      case '\r':
1✔
29
        result += "\\r";
1✔
30
        break;
1✔
31
      case '\t':
1✔
32
        result += "\\t";
1✔
33
        break;
1✔
34
      default:
132✔
35
        result += *p;
132✔
36
        break;
132✔
37
    }
38
  }
39
  return result;
7✔
NEW
40
}
×
41

42
} // namespace
43

44
class TapTestResultNode
45
{
46
public:
47
  TapTestResultNode() = default;
21✔
48

49
  String group;
50
  String name;
51
  bool skipped{ false };
52
  String skip_message;
53
  Failure* failure{ nullptr };
54
  bool failure_is_error{ false };
55
  TapTestResultNode* next{ nullptr };
56
};
57

58
class TapOutputImpl
59
{
60
public:
61
  TapOutputImpl() = default;
21✔
62

63
  size_t test_count{ 0 };
64
  TapTestResultNode* head{ nullptr };
65
  TapTestResultNode* tail{ nullptr };
66
};
67

68
TapOutput::TapOutput()
21✔
69
  : impl_(new TapOutputImpl)
21✔
70
{
71
}
21✔
72

73
TapOutput::~TapOutput()
42✔
74
{
75
  clear_nodes();
21✔
76
  delete impl_;
21✔
77
}
42✔
78

79
void TapOutput::clear_nodes()
38✔
80
{
81
  TapTestResultNode* cur = impl_->head;
38✔
82
  while (cur) {
59✔
83
    TapTestResultNode* tmp = cur->next;
21✔
84
    delete cur->failure;
21✔
85
    delete cur;
21✔
86
    cur = tmp;
21✔
87
  }
88
  impl_->head = nullptr;
38✔
89
  impl_->tail = nullptr;
38✔
90
}
38✔
91

92
void TapOutput::print_tests_started()
17✔
93
{
94
  impl_->test_count = 0;
17✔
95
  clear_nodes();
17✔
96
}
17✔
97

98
void TapOutput::print_current_group_started(const Shell& /*test*/) {}
18✔
99
void TapOutput::print_current_group_ended(const Result& /*res*/) {}
18✔
100

101
void TapOutput::print_current_test_started(const Shell& test)
21✔
102
{
103
  impl_->test_count++;
21✔
104

105
  if (impl_->tail == nullptr) {
21✔
106
    impl_->head = impl_->tail = new TapTestResultNode;
17✔
107
  } else {
108
    impl_->tail->next = new TapTestResultNode;
4✔
109
    impl_->tail = impl_->tail->next;
4✔
110
  }
111
  impl_->tail->group = test.get_group();
21✔
112
  impl_->tail->name = test.get_name();
21✔
113

114
  if (!test.will_run()) {
21✔
115
    impl_->tail->skipped = true;
1✔
116
    impl_->tail->skip_message = test.get_macro_name();
1✔
117
  }
118
}
21✔
119

120
void TapOutput::print_current_test_ended(const Result& /*res*/) {}
21✔
121

122
void TapOutput::print_tests_ended(const Result& /*result*/)
17✔
123
{
124
  String header = string_from_format(
125
      "TAP version 13\n1..%d\n", static_cast<int>(impl_->test_count)
17✔
126
  );
17✔
127
  fputs_(header.c_str(), stdout_);
17✔
128

129
  size_t n = 0;
17✔
130
  for (TapTestResultNode* cur = impl_->head; cur; cur = cur->next) {
38✔
131
    ++n;
21✔
132
    String test_id = cur->group;
21✔
133
    test_id += ".";
21✔
134
    test_id += cur->name;
21✔
135

136
    if (cur->failure) {
21✔
137
      String line = string_from_format(
138
          "not ok %d - %s\n", static_cast<int>(n), test_id.c_str()
139
      );
7✔
140
      line += "  ---\n";
7✔
141
      line += string_from_format(
14✔
142
          "  message: \"%s\"\n",
143
          yaml_escape(cur->failure->get_message()).c_str()
14✔
144
      );
7✔
145
      line += cur->failure_is_error ? "  severity: comment\n"
7✔
146
                                    : "  severity: fail\n";
7✔
147
      line += "  at:\n";
7✔
148
      line += string_from_format(
14✔
149
          "    file: %s\n", cur->failure->get_file_name().c_str()
7✔
150
      );
7✔
151
      line += string_from_format(
7✔
152
          "    line: %d\n",
153
          static_cast<int>(cur->failure->get_failure_line_number())
7✔
154
      );
7✔
155
      line += "  ...\n";
7✔
156
      fputs_(line.c_str(), stdout_);
7✔
157
    } else if (cur->skipped) {
21✔
158
      String line = string_from_format(
159
          "ok %d - %s # SKIP %s\n",
160
          static_cast<int>(n),
161
          test_id.c_str(),
162
          cur->skip_message.c_str()
163
      );
2✔
164
      fputs_(line.c_str(), stdout_);
2✔
165
    } else {
2✔
166
      String line = string_from_format(
167
          "ok %d - %s\n", static_cast<int>(n), test_id.c_str()
168
      );
12✔
169
      fputs_(line.c_str(), stdout_);
12✔
170
    }
12✔
171
  }
21✔
172
}
17✔
173

174
void TapOutput::print_buffer(const char*) {}
1✔
175

176
void TapOutput::print_failure(const Failure& failure)
7✔
177
{
178
  if (impl_->tail != nullptr && impl_->tail->failure == nullptr) {
7✔
179
    impl_->tail->failure_is_error = failure.is_error();
7✔
180
    impl_->tail->failure = new Failure(failure);
7✔
181
  }
182
}
7✔
183

184
void TapOutput::print_skipped(const char* message)
1✔
185
{
186
  if (impl_->tail != nullptr) {
1✔
187
    impl_->tail->skipped = true;
1✔
188
    impl_->tail->skip_message = message;
1✔
189
  }
190
}
1✔
191

192
} // namespace test
193
} // namespace tiny
194
} // 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