Skip to content

Commit 803c153

Browse files
committed
Working argparse
1 parent cf02040 commit 803c153

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+412
-414
lines changed

CMakeLists.txt

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
cmake_minimum_required(VERSION 3.27 FATAL_ERROR)
22

3-
if(IWYU)
4-
find_program(iwyu_path NAMES include-what-you-use iwyu)
5-
endif(IWYU)
6-
73
project(c++spec)
84

95
set(CMAKE_COLOR_DIAGNOSTICS ON)
@@ -14,7 +10,7 @@ include(FetchContent)
1410

1511
FetchContent_Declare(argparse
1612
GIT_REPOSITORY https://github.com/p-ranav/argparse/
17-
GIT_TAG v2.9
13+
GIT_TAG v3.0
1814
)
1915
FetchContent_MakeAvailable(argparse)
2016

@@ -43,23 +39,43 @@ target_precompile_headers(c++spec INTERFACE
4339
${c++spec_headers}
4440
)
4541

46-
option(BUILD_TESTS "Build tests." ON)
42+
# HELPERS
43+
44+
# Add spec
45+
function(add_spec source_file)
46+
cmake_path(GET source_file STEM spec_name)
47+
add_executable(${spec_name} ${source_file})
48+
target_link_libraries(${spec_name} c++spec)
49+
50+
set_target_properties(${spec_name} PROPERTIES
51+
CXX_STANDARD 20
52+
CXX_STANDARD_REQUIRED YES
53+
)
54+
add_test(NAME ${spec_name} COMMAND ${spec_name} --verbose)
55+
endfunction(add_spec)
56+
57+
# Discover Specs
58+
function(discover_specs spec_folder)
59+
file(GLOB_RECURSE specs ${spec_folder}/*_spec.cpp)
60+
61+
foreach(spec IN LISTS specs)
62+
add_spec(${spec})
63+
endforeach()
64+
endfunction(discover_specs)
65+
66+
option(BUILD_TESTS "Build tests" ON)
4767

4868
if(BUILD_TESTS)
49-
# enable_testing()
69+
enable_testing()
5070

5171
# Tests
52-
add_subdirectory(spec)
72+
discover_specs(spec)
5373
endif(BUILD_TESTS)
5474

55-
option(BUILD_EXAMPLES "Build examples." ON)
75+
option(BUILD_EXAMPLES "Build examples" ON)
5676

5777
if(BUILD_EXAMPLES)
5878
add_subdirectory(examples)
59-
60-
if(iwyu_path)
61-
set_property(TARGET cppspec_sample PROPERTY CXX_INCLUDE_WHAT_YOU_USE ${iwyu_path})
62-
endif()
6379
endif(BUILD_EXAMPLES)
6480

6581
# ##### Documentation generation #######

examples/sample/example_spec.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,13 @@ describe list_spec("A list spec", $ {
192192
});
193193

194194
/* Here is the declaration of fabs description defined in an other file (fabs_spec.c in this sample)*/
195-
int main(){
196-
return CppSpec::Runner()
195+
int main(int argc, char **argv){
196+
return CppSpec::parse(argc, argv)
197197
.add_spec(bool_spec)
198198
.add_spec(abs_spec)
199199
.add_spec(strcmp_spec)
200200
.add_spec(vector_spec)
201201
.add_spec(let_spec)
202202
.add_spec(list_spec)
203-
.exec<CppSpec::Formatters::Verbose>() ? EXIT_SUCCESS : EXIT_FAILURE;
204-
}
203+
.exec() ? EXIT_SUCCESS : EXIT_FAILURE;
204+
}

examples/sample/jasmine_intro.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ auto to_include_matcher = describe("to contain", $ {
255255
});
256256

257257
int main(int argc, char** argv) {
258-
return CppSpec::Runner()
258+
return CppSpec::parse(argc, argv)
259259
.add_spec(a_suite)
260260
.add_spec(suite_object)
261261
.add_spec(to_be_compare)
@@ -266,5 +266,5 @@ int main(int argc, char** argv) {
266266
.add_spec(a_spec_before_each)
267267
.add_spec(a_spec_nesting)
268268
.add_spec(to_include_matcher)
269-
.exec<CppSpec::Formatters::Verbose>() ? EXIT_SUCCESS : EXIT_FAILURE;
269+
.exec() ? EXIT_SUCCESS : EXIT_FAILURE;
270270
}

include/argparse.hpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <argparse/argparse.hpp>
44
#include <string_view>
5+
#include "runner.hpp"
56

67
#include "formatters/progress.hpp"
78
#include "formatters/tap.hpp"
@@ -22,14 +23,15 @@ constexpr std::string file_name(std::string_view path) {
2223

2324
struct RuntimeOpts {
2425
bool verbose = false;
25-
std::unique_ptr<Formatters::BaseFormatter> formatter = nullptr;
26+
std::shared_ptr<Formatters::BaseFormatter> formatter = nullptr;
2627
};
2728

28-
inline RuntimeOpts parse(int argc, char** argv) {
29-
argparse::ArgumentParser program(file_name(__FILE__));
29+
inline Runner parse(int argc, char** argv) {
30+
argparse::ArgumentParser program{file_name(argv[0])};
3031

3132
program.add_argument("-f", "--format")
3233
.default_value(std::string{"p"})
34+
.choices("progress", "p", "tap", "t", "detail", "d")
3335
.required()
3436
.help("set the output format");
3537

@@ -48,22 +50,18 @@ inline RuntimeOpts parse(int argc, char** argv) {
4850

4951
RuntimeOpts opts;
5052

51-
if (program["--verbose"] == true) {
52-
opts.verbose = true;
53-
}
54-
5553
auto format_string = program.get<std::string>("--format");
56-
if (format_string == "p" || format_string == "progress") {
54+
if (format_string == "d" || format_string == "detail" || program["--verbose"] == true) {
55+
opts.formatter = std::make_unique<Formatters::Verbose>();
56+
} else if (format_string == "p" || format_string == "progress") {
5757
opts.formatter = std::make_unique<Formatters::Progress>();
5858
} else if (format_string == "t" || format_string == "tap") {
5959
opts.formatter = std::make_unique<Formatters::TAP>();
60-
} else if (format_string == "d" || format_string == "detail") {
61-
opts.formatter = std::make_unique<Formatters::Verbose>();
6260
} else {
6361
std::cerr << "Unrecognized format type" << std::endl;
6462
std::exit(-1);
6563
}
6664

67-
return opts;
65+
return Runner{opts.formatter};
6866
}
6967
} // namespace CppSpec

include/child.hpp

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ class Child {
8080

8181
/** @brief Check to see if the Child has a parent. */
8282
const bool has_parent() noexcept { return parent != nullptr; }
83-
const bool has_parent() const noexcept { return parent != nullptr; }
83+
[[nodiscard]] const bool has_parent() const noexcept { return parent != nullptr; }
8484

8585
// TODO: Look in to making these references instead of pointer returns
8686
/** @brief Get the Child's parent. */
87-
Child *get_parent() const noexcept { return parent; }
87+
[[nodiscard]] Child *get_parent() const noexcept { return parent; }
8888

8989
template <class C>
9090
C get_parent_as() const noexcept {
@@ -103,23 +103,23 @@ class Child {
103103

104104
/*--------- Formatter helper functions -----------*/
105105
// Check to see if the tree has a printer
106-
const bool has_formatter() const noexcept;
106+
[[nodiscard]] bool has_formatter() const noexcept;
107107

108108
// Get the printer from the tree
109-
Formatters::BaseFormatter &get_formatter() const noexcept;
109+
[[nodiscard]] Formatters::BaseFormatter &get_formatter() const noexcept;
110110

111-
void set_formatter(const Formatters::BaseFormatter &formatter) {
112-
this->formatter = &const_cast<Formatters::BaseFormatter &>(formatter);
111+
void set_formatter(Formatters::BaseFormatter &formatter) {
112+
this->formatter = &formatter;
113113
}
114114

115115
/*--------- Primary member functions -------------*/
116116

117117
/** @brief Get the status of the object (success/failure) */
118-
const bool get_status() const noexcept { return this->status; }
118+
[[nodiscard]] bool get_status() const noexcept { return this->status; }
119119
void failed() noexcept; // Report failure to the object.
120120

121121
// Calculate the padding for printing this object
122-
std::string padding() const noexcept;
122+
[[nodiscard]] std::string padding() const noexcept;
123123
};
124124

125125
/*>>>>>>>>>>>>>>>>>>>> Child <<<<<<<<<<<<<<<<<<<<<<<<<*/
@@ -133,7 +133,8 @@ class Child {
133133
inline void Child::failed() noexcept {
134134
this->status = false;
135135
// propogates the failure up the tree
136-
if (this->has_parent()) this->get_parent()->failed();
136+
if (this->has_parent()) { this->get_parent()->failed();
137+
}
137138
}
138139

139140
/**
@@ -144,15 +145,19 @@ inline std::string Child::padding() const noexcept {
144145
return this->has_parent() ? this->get_parent()->padding() + " " : "";
145146
}
146147

147-
inline const bool Child::has_formatter() const noexcept {
148-
if (this->formatter != nullptr) return true;
149-
if (!this->has_parent()) return false; // base case;
148+
inline bool Child::has_formatter() const noexcept {
149+
if (this->formatter != nullptr) { return true;
150+
}
151+
if (!this->has_parent()) { return false; // base case;
152+
}
150153
return parent->has_formatter();
151154
}
152155

153156
inline Formatters::BaseFormatter &Child::get_formatter() const noexcept {
154-
if (this->formatter) return *formatter;
155-
if (!this->has_parent()) std::terminate();
157+
if (this->formatter != nullptr) { return *formatter;
158+
}
159+
if (!this->has_parent()) { std::terminate();
160+
}
156161
return parent->get_formatter();
157162
}
158163

include/class_description.hpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
#include "description.hpp"
88

9-
109
namespace CppSpec {
1110

1211
/**
@@ -25,7 +24,7 @@ class ClassDescription : public Description {
2524
using Block = std::function<void(ClassDescription<T> &)>;
2625

2726
Block block;
28-
std::string type = "";
27+
std::string type;
2928

3029
public:
3130
const bool has_subject = true;
@@ -83,7 +82,7 @@ class ClassDescription : public Description {
8382
/** @brief an alias for it */
8483
Result specify(std::function<void(ItCD<T> &)> block) { return it(block); }
8584

86-
template <class U=std::nullptr_t>
85+
template <class U = std::nullptr_t>
8786
Result context(std::string description,
8887
std::function<void(ClassDescription<T> &)> block);
8988

@@ -100,7 +99,9 @@ class ClassDescription : public Description {
10099

101100
Result run(Formatters::BaseFormatter &printer) override;
102101

103-
std::string get_subject_type() const noexcept override { return type; }
102+
[[nodiscard]] std::string get_subject_type() const noexcept override {
103+
return type;
104+
}
104105
};
105106

106107
template <class T>
@@ -244,11 +245,17 @@ Result ClassDescription<T>::it(std::function<void(ItCD<T> &)> block) {
244245

245246
template <class T>
246247
Result ClassDescription<T>::run(Formatters::BaseFormatter &printer) {
247-
if (not this->has_formatter()) this->set_formatter(printer);
248+
if (not this->has_formatter()) {
249+
this->set_formatter(printer);
250+
}
248251
printer.format(*this);
249252
this->block(*this);
250-
for (const auto &a : after_alls) a();
251-
if (this->get_parent() == nullptr) printer.flush();
253+
for (const auto &a : after_alls) {
254+
a();
255+
}
256+
if (this->get_parent() == nullptr) {
257+
printer.flush();
258+
}
252259
return this->get_status() ? Result::success() : Result::failure();
253260
}
254261

include/cppspec.hpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
#define CPPSPEC_HPP
77
#pragma once
88

9-
#include "runner.hpp"
9+
#include "argparse.hpp"
1010

11+
#ifndef CPPSPEC_MACROLESS
1112
/*>>>>>>>>>>>>>>>>>>>> MACROS <<<<<<<<<<<<<<<<<<<<<<*/
1213

1314
// For *some* reason, MSVC++ refuses to correctly deduce the types of
@@ -18,7 +19,9 @@
1819

1920
#define it self.it
2021
#define specify it
21-
#ifdef _MSC_VER // Apparently MSVC++ doesn't conform to C++14 14.2/4. Annoying.
22+
23+
// Apparently MSVC++ doesn't conform to C++14 14.2/4. Annoying.
24+
#if defined(_MSC_VER) && !defined(__clang__)
2225
#define context self.context
2326
#define expect self.expect
2427
#else
@@ -34,8 +37,15 @@
3437
#define before_each self.before_each
3538
#define after_all self.after_all
3639
#define after_each self.after_each
37-
#define let(name, body) auto name = self.let(body);
40+
#define let(name, body) auto (name) = self.let(body);
41+
42+
#define CPPSPEC_MAIN(spec) \
43+
int main(int argc, char **argv) { \
44+
return CppSpec::parse(argc, argv).add_spec(spec).exec() ? EXIT_SUCCESS \
45+
: EXIT_FAILURE; \
46+
}
3847

48+
#endif
3949
/*>>>>>>>>>>>>>>>>>>> TYPEDEFS <<<<<<<<<<<<<<<<<<<<<*/
4050

4151
using describe = CppSpec::Description;

0 commit comments

Comments
 (0)