Skip to content

Commit 7895bef

Browse files
committed
Add support for semihosted platforms
1 parent 6a5eaf6 commit 7895bef

File tree

4 files changed

+80
-14
lines changed

4 files changed

+80
-14
lines changed

include/argparse.hpp

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
#pragma once
22

3-
#include <argparse/argparse.hpp>
4-
#include <fstream>
53
#include <string>
64
#include <string_view>
75

6+
#ifdef CPPSPEC_SEMIHOSTED
7+
#include <sys/stat.h>
8+
#include <cstring>
9+
#else
10+
#include <argparse/argparse.hpp>
11+
#include <filesystem>
12+
#include <fstream>
13+
#endif
14+
815
#include "formatters/junit_xml.hpp"
916
#include "formatters/progress.hpp"
1017
#include "formatters/tap.hpp"
@@ -24,6 +31,31 @@ inline std::string file_name(std::string_view path) {
2431
}
2532

2633
inline Runner parse(int argc, char** const argv) {
34+
#ifdef CPPSPEC_SEMIHOSTED
35+
int i = 0;
36+
for (; i < argc; ++i) {
37+
if (strcmp(argv[i], "-f") == 0) {
38+
break;
39+
}
40+
}
41+
if (i == argc) {
42+
return Runner{std::make_shared<Formatters::Progress>()};
43+
std::exit(-1);
44+
}
45+
std::string format_string = argv[i + 1];
46+
if (format_string == "d" || format_string == "detail") {
47+
return Runner{std::make_shared<Formatters::Verbose>()};
48+
} else if (format_string == "p" || format_string == "progress") {
49+
return Runner{std::make_shared<Formatters::Progress>()};
50+
} else if (format_string == "t" || format_string == "tap") {
51+
return Runner{std::make_shared<Formatters::TAP>()};
52+
} else if (format_string == "j" || format_string == "junit") {
53+
return Runner{std::make_shared<Formatters::JUnitXML>()};
54+
} else {
55+
std::cerr << "Unrecognized format type" << std::endl;
56+
std::exit(-1);
57+
}
58+
#else
2759
std::filesystem::path executable_path = argv[0];
2860
std::string executable_name = executable_path.filename().string();
2961
argparse::ArgumentParser program{executable_name};
@@ -71,7 +103,7 @@ inline Runner parse(int argc, char** const argv) {
71103
auto junit_output = std::make_shared<Formatters::JUnitXML>(*file_stream, false);
72104
return Runner{formatter, junit_output};
73105
}
74-
75106
return Runner{formatter};
107+
#endif
76108
}
77109
} // namespace CppSpec

include/cppspec.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,22 @@
3333
#define after_each self.after_each
3434
#define let(name, body) auto(name) = self.let(body);
3535

36+
#ifdef CPPSPEC_SEMIHOSTED
3637
#define CPPSPEC_MAIN(spec) \
3738
int main(int argc, char** const argv) { \
3839
return CppSpec::parse(argc, argv).add_spec(spec).exec().is_success() ? EXIT_SUCCESS : EXIT_FAILURE; \
40+
} \
41+
extern "C" int _getentropy(void* buf, size_t buflen) { \
42+
return -1; \
3943
}
4044

45+
#else
46+
#define CPPSPEC_MAIN(spec) \
47+
int main(int argc, char** const argv) { \
48+
return CppSpec::parse(argc, argv).add_spec(spec).exec().is_success() ? EXIT_SUCCESS : EXIT_FAILURE; \
49+
}
50+
#endif
51+
4152
#define CPPSPEC_SPEC(spec_name) \
4253
int spec_name##_spec(int argc, char** const argv) { \
4354
return CppSpec::parse(argc, argv).add_spec(spec_name).exec().is_success() ? EXIT_SUCCESS : EXIT_FAILURE; \

include/formatters/junit_xml.hpp

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
#pragma once
22
#include <algorithm>
3-
#include <atomic>
43
#include <chrono>
5-
#include <filesystem>
64
#include <numeric>
75
#include <string>
86

7+
#ifndef CPPSPEC_SEMIHOSTED
8+
#include <filesystem>
9+
#endif
10+
911
#include "formatters_base.hpp"
1012
#include "it_base.hpp"
1113

@@ -116,7 +118,7 @@ struct TestSuite {
116118

117119
[[nodiscard]] std::string to_xml() const {
118120
std::string timestamp_str;
119-
#ifdef __APPLE__
121+
#if defined(__APPLE__) || defined(CPPSPEC_SEMIHOSTED)
120122
// Cludge because macOS doesn't have std::chrono::current_zone() or std::chrono::zoned_time()
121123
std::time_t time_t_timestamp = std::chrono::system_clock::to_time_t(timestamp);
122124
std::tm localtime = *std::localtime(&time_t_timestamp);
@@ -142,7 +144,7 @@ struct TestSuite {
142144
}
143145

144146
static size_t get_next_id() {
145-
static std::atomic_size_t id_counter = 0;
147+
static std::size_t id_counter = 0;
146148
return id_counter++;
147149
}
148150
};
@@ -198,8 +200,25 @@ class JUnitXML : public BaseFormatter {
198200

199201
void format(const Description& description) override {
200202
if (test_suites.name.empty()) {
203+
#ifdef CPPSPEC_SEMIHOSTED
204+
std::string file_path = description.get_location().file_name();
205+
// remove leading folders
206+
auto pos = file_path.find_last_of("/");
207+
if (pos != std::string::npos) {
208+
file_path = file_path.substr(pos + 1);
209+
}
210+
211+
// remove extension
212+
pos = file_path.find_last_of('.');
213+
if (pos != std::string::npos) {
214+
file_path = file_path.substr(0, pos);
215+
}
216+
217+
test_suites.name = file_path;
218+
#else
201219
std::filesystem::path file_path = description.get_location().file_name();
202220
test_suites.name = file_path.stem().string();
221+
#endif
203222
}
204223
if (description.has_parent()) {
205224
return;
@@ -213,7 +232,7 @@ class JUnitXML : public BaseFormatter {
213232
std::forward_list<std::string> descriptions;
214233

215234
descriptions.push_front(it.get_description());
216-
for (const Description* parent = it.get_parent_as<Description>(); parent->has_parent();
235+
for (const auto* parent = it.get_parent_as<Description>(); parent->has_parent();
217236
parent = parent->get_parent_as<Description>()) {
218237
descriptions.push_front(parent->get_description());
219238
}

include/formatters/progress.hpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,17 @@ inline void Progress::format(const ItBase& it) {
107107
}
108108

109109
inline void Progress::format_failure_messages() {
110-
if (!baked_failure_messages.empty()) { // If we have any failures to format
111-
for (const std::string& message : baked_failure_messages) {
112-
out_stream << std::endl;
113-
out_stream << message; // separated by a blank line
114-
}
115-
baked_failure_messages.clear(); // Finally, clear the failures list.
110+
if (baked_failure_messages.empty()) {
111+
out_stream << std::endl; // If we don't have any failures, just print a blank line.
112+
return;
113+
}
114+
115+
// If we have any failures to format
116+
for (const std::string& message : baked_failure_messages) {
117+
out_stream << std::endl;
118+
out_stream << message; // separated by a blank line
116119
}
120+
baked_failure_messages.clear(); // Finally, clear the failures list.
117121
}
118122

119123
static Progress progress;

0 commit comments

Comments
 (0)