Skip to content

Commit ac56443

Browse files
committed
Migrate from std::string parameter to const char* due to ambiguity
1 parent 3de732c commit ac56443

File tree

10 files changed

+88
-93
lines changed

10 files changed

+88
-93
lines changed

CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
cmake_minimum_required(VERSION 3.27 FATAL_ERROR)
22

3-
project(c++spec)
3+
project(c++spec
4+
VERSION 1.2.0
5+
DESCRIPTION "BDD testing for C++"
6+
LANGUAGES CXX
7+
)
48

59
set(CMAKE_COLOR_DIAGNOSTICS ON)
610

@@ -77,6 +81,7 @@ option(CPPSPEC_BUILD_DOCS "Build C++Spec documentation")
7781

7882
if(CPPSPEC_BUILD_TESTS)
7983
enable_testing()
84+
include(CTest)
8085

8186
# Tests
8287
add_subdirectory(spec)

examples/sample/example_spec.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ describe bool_spec("Some Tests", $ {
6868
});
6969

7070

71-
explain <std::list<int>> ({1,2,3}, _ {
71+
explain(std::list<int>{1,2,3}, _ {
7272
it(_ { is_expected().to_contain(1); });
7373

7474
it("includes [1,2,3]", _ {
75-
expect<std::list<int>>({1,2,3}).to_contain({1,2,3});
75+
expect(std::list<int>{1,2,3}).to_contain({1,2,3});
7676
});
7777

7878
it( _ { is_expected().not_().to_contain(4); });
@@ -185,7 +185,7 @@ describe let_spec("let", $ {
185185
// });
186186

187187
describe list_spec("A list spec", $ {
188-
explain <std::list<int>> ({1,2,3,4}, _ {
188+
explain(std::list<int>{1,2,3,4}, _ {
189189
it( _ { is_expected().to_contain(8); });
190190
it( _ { is_expected().to_start_with({1,2,3}); });
191191
});

include/class_description.hpp

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ class ClassDescription : public Description {
3636
this->description = Pretty::to_word(subject);
3737
}
3838

39-
ClassDescription(std::string description, Block block) : Description(description), block(block), subject(T()) {}
39+
ClassDescription(const char* description, Block block) : Description(description), block(block), subject(T()) {}
4040

4141
ClassDescription(T subject, Block block)
4242
: Description(Pretty::to_word(subject)),
4343
block(block),
4444
type(" : " + Util::demangle(typeid(T).name())),
4545
subject(subject) {}
4646

47-
ClassDescription(std::string description, T subject, Block block)
47+
ClassDescription(const char* description, T subject, Block block)
4848
: Description(description), block(block), subject(subject) {}
4949

5050
ClassDescription(T &subject, Block block)
@@ -60,27 +60,25 @@ class ClassDescription : public Description {
6060
}
6161

6262
template <typename U>
63-
ClassDescription(std::string description, std::initializer_list<U> init_list, Block block)
63+
ClassDescription(const char* description, std::initializer_list<U> init_list, Block block)
6464
: Description(description), block(block), subject(T(init_list)) {}
6565

66-
Result it(std::string description, std::function<void(ItCD<T> &)> block);
66+
Result it(const char* description, std::function<void(ItCD<T> &)> block);
6767
Result it(std::function<void(ItCD<T> &)> block);
6868
/** @brief an alias for it */
69-
Result specify(std::string description, std::function<void(ItCD<T> &)> block) { return it(description, block); }
69+
Result specify(const char* description, std::function<void(ItCD<T> &)> block) { return it(description, block); }
7070
/** @brief an alias for it */
7171
Result specify(std::function<void(ItCD<T> &)> block) { return it(block); }
7272

73-
template <class U = std::nullptr_t>
74-
Result context(std::string description, std::function<void(ClassDescription<T> &)> block);
73+
template <class U = std::nullptr_t, class B>
74+
Result context(const char* description, B block);
7575

76-
template <class U>
77-
Result context(std::string description, U subject, std::function<void(ClassDescription<U> &)> block);
78-
template <class U>
79-
Result context(std::string description, U &subject, std::function<void(ClassDescription<U> &)> block);
80-
template <class U>
81-
Result context(U subject, std::function<void(ClassDescription<U> &)> block);
82-
template <class U>
83-
Result context(U &subject, std::function<void(ClassDescription<U> &)> block);
76+
template <class U, class B>
77+
Result context(const char* description, U subject, B block);
78+
template <class U, class B>
79+
Result context(const char* description, U &subject, B block);
80+
template <class U, class B>
81+
Result context(U subject, B block);
8482

8583
Result run(Formatters::BaseFormatter &printer) override;
8684

@@ -91,9 +89,9 @@ template <class T>
9189
using ClassContext = ClassDescription<T>;
9290

9391
template <class T>
94-
template <class U>
95-
Result ClassDescription<T>::context(std::string description, U subject,
96-
std::function<void(ClassDescription<U> &)> block) {
92+
template <class U, class B>
93+
Result ClassDescription<T>::context(const char* description, U subject,
94+
B block) {
9795
ClassContext<U> context(description, subject, block);
9896
context.set_parent(this);
9997
context.ClassContext<U>::before_eaches = this->before_eaches;
@@ -102,15 +100,15 @@ Result ClassDescription<T>::context(std::string description, U subject,
102100
}
103101

104102
template <class T>
105-
template <class U>
106-
Result ClassDescription<T>::context(U subject, std::function<void(ClassDescription<U> &)> block) {
103+
template <class U, class B>
104+
Result ClassDescription<T>::context(U subject, B block) {
107105
return this->context("", std::forward<U>(subject), block);
108106
}
109107

110108
template <class T>
111-
template <class U>
112-
Result ClassDescription<T>::context(std::string description, U &subject,
113-
std::function<void(ClassDescription<U> &)> block) {
109+
template <class U, class B>
110+
Result ClassDescription<T>::context(const char* description, U &subject,
111+
B block) {
114112
ClassContext<U> context(description, subject, block);
115113
context.set_parent(this);
116114
context.ClassContext<U>::before_eaches = this->before_eaches;
@@ -119,28 +117,23 @@ Result ClassDescription<T>::context(std::string description, U &subject,
119117
}
120118

121119
template <class T>
122-
template <class U>
123-
Result ClassDescription<T>::context(U &subject, std::function<void(ClassDescription<U> &)> block) {
124-
return this->context("", std::forward<U>(subject), block);
125-
}
126-
127-
template <class T>
128-
template <class U>
129-
Result ClassDescription<T>::context(std::string description, std::function<void(ClassDescription<T> &)> block) {
120+
template <class U, class B>
121+
Result ClassDescription<T>::context(const char* description, B block) {
130122
ClassContext<T> context(description, this->subject, block);
131123
context.set_parent(this);
132124
context.before_eaches = this->before_eaches;
133125
context.after_eaches = this->after_eaches;
134126
return context.run(this->get_formatter());
135127
}
136128

137-
template <class T>
138-
Result Description::context(T subject, std::function<void(ClassDescription<T> &)> block) {
129+
template <class T, class B>
130+
requires (!std::is_same_v<T, const char*>)
131+
Result Description::context(T subject, B block) {
139132
return this->context("", subject, block);
140133
}
141134

142-
template <class T>
143-
Result Description::context(std::string description, T subject, std::function<void(ClassDescription<T> &)> block) {
135+
template <class T, class B>
136+
Result Description::context(const char* description, T subject, B block) {
144137
ClassContext<T> context(description, subject, block);
145138
context.set_parent(this);
146139
context.before_eaches = this->before_eaches;
@@ -179,7 +172,7 @@ Result Description::context(std::initializer_list<U> init_list, std::function<vo
179172
* @return the result of the test
180173
*/
181174
template <class T>
182-
Result ClassDescription<T>::it(std::string name, std::function<void(ItCD<T> &)> block) {
175+
Result ClassDescription<T>::it(const char* name, std::function<void(ItCD<T> &)> block) {
183176
ItCD<T> it(*this, this->subject, name, block);
184177
Result result = it.run(this->get_formatter());
185178
exec_after_eaches();

include/description.hpp

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

77
#include <deque>
88
#include <forward_list>
9-
#include <queue>
109
#include <string>
1110
#include <utility>
1211

@@ -40,10 +39,11 @@ class Description : public Runnable {
4039
// field initialized. They should only be used by subclasses
4140
// of Description.
4241
Description() = default;
43-
explicit Description(std::string description) noexcept : description(std::move(description)) {}
42+
explicit Description(std::string&& description) noexcept : description(std::move(description)) {}
43+
explicit Description(const char* description) noexcept : description(description) {}
4444

45-
Description(const Child &parent, std::string description, Block block) noexcept
46-
: Runnable(parent), block(std::move(block)), description(std::move(description)) {}
45+
Description(const Child &parent, const char* description, Block block) noexcept
46+
: Runnable(parent), block(std::move(block)), description(description) {}
4747

4848
void exec_before_eaches();
4949
void exec_after_eaches();
@@ -54,24 +54,25 @@ class Description : public Runnable {
5454
Description(Description &&copy) = default;
5555

5656
// Primary constructor. Entry of all specs.
57-
Description(std::string description, Block block) noexcept
57+
Description(const char* description, Block block) noexcept
5858
: block(std::move(block)), description(std::move(description)) {}
5959

6060
/********* Specify/It *********/
6161

62-
Result it(std::string description, ItD::Block body);
62+
Result it(const char* description, ItD::Block body);
6363
Result it(ItD::Block body);
6464

6565
/********* Context ***********/
6666

6767
template <class T = std::nullptr_t>
68-
Result context(std::string name, Block body);
68+
Result context(const char* name, Block body);
6969

70-
template <class T>
71-
Result context(T subject, std::function<void(ClassDescription<T> &)> block);
70+
template <class T, class B>
71+
requires (!std::is_same_v<T, const char*>)
72+
Result context(T subject, B block);
7273

73-
template <class T>
74-
Result context(std::string description, T subject, std::function<void(ClassDescription<T> &)> block);
74+
template <class T, class B>
75+
Result context(const char* description, T subject, B block);
7576

7677
template <class T, typename U>
7778
Result context(std::initializer_list<U> init_list, std::function<void(ClassDescription<T> &)> block);
@@ -108,7 +109,7 @@ using Context = Description;
108109

109110
/*========= Description::it =========*/
110111

111-
inline Result Description::it(std::string description, ItD::Block block) {
112+
inline Result Description::it(const char* description, ItD::Block block) {
112113
ItD it(*this, description, block);
113114
Result result = it.run(this->get_formatter());
114115
exec_after_eaches();
@@ -127,7 +128,7 @@ inline Result Description::it(ItD::Block block) {
127128
/*========= Description::context =========*/
128129

129130
template <class T>
130-
inline Result Description::context(std::string description, Block body) {
131+
inline Result Description::context(const char* description, Block body) {
131132
Context context(*this, description, body);
132133
context.before_eaches = this->before_eaches;
133134
context.after_eaches = this->after_eaches;

include/formatters/tap.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ inline void TAP::format(const Description &description) {
3434
}
3535

3636
inline void TAP::format(const ItBase &it) {
37-
std::string description = it.get_description();
37+
std::string description{it.get_description()};
3838

3939
// Build up the description for the test by ascending the
4040
// execution tree and chaining the individual descriptions together
4141

4242
for (const auto *parent = it.get_parent_as<const Description *>(); parent != nullptr;
4343
parent = parent->get_parent_as<const Description *>()) {
44-
description = parent->get_description() + " " + description;
44+
description = std::string(parent->get_description()) + " " + description;
4545
}
4646

4747
if (color_output) {

include/it.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ class ItD : public ItBase {
4848
*
4949
* @return the constructed ItD object
5050
*/
51-
ItD(const Child &parent, std::string description, Block block)
52-
: ItBase(parent, std::move(description)), block(std::move(block)) {}
51+
ItD(const Child &parent, const char* description, Block block)
52+
: ItBase(parent, description), block(std::move(block)) {}
5353

5454
/**
5555
* @brief The anonymous ItD constructor
@@ -104,7 +104,7 @@ class ItCD : public ItBase {
104104
T &subject;
105105

106106
// This is only ever instantiated by ClassDescription<T>
107-
ItCD(const Child &parent, T &subject, std::string description, Block block)
107+
ItCD(const Child &parent, T &subject, const char* description, Block block)
108108
: ItBase(parent, description), block(block), subject(subject) {}
109109

110110
ItCD(const Child &parent, T &subject, Block block) : ItBase(parent), block(block), subject(subject) {}

include/it_base.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class ItBase : public Runnable {
4848
* @param description the documentation string of the `it` statement
4949
* @return the constructed BaseIt
5050
*/
51-
explicit ItBase(const Child &parent, std::string description) noexcept
51+
explicit ItBase(const Child &parent, const char* description) noexcept
5252
: Runnable(parent), description(std::move(description)) {}
5353

5454
/**
@@ -61,14 +61,13 @@ class ItBase : public Runnable {
6161
* @brief Get the description string for the `it` statement
6262
* @return the description string
6363
*/
64-
std::string get_description() noexcept { return description; }
6564
[[nodiscard]] std::string get_description() const noexcept { return description; }
6665

6766
/**
6867
* @brief Set the description string
6968
* @return a reference to the modified ItBase
7069
*/
71-
ItBase &set_description(const std::string &description) noexcept {
70+
ItBase &set_description(std::string_view description) noexcept {
7271
this->description = description;
7372
return *this;
7473
}

spec/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
add_compile_options(-Wno-unused-parameter -Wno-missing-template-arg-list-after-template-kw)
1+
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
2+
add_compile_options(-Wno-unused-parameter -Wno-missing-template-arg-list-after-template-kw -Wno-missing-template-keyword -Wno-unknown-warning-option)
3+
endif()
4+
25
discover_specs(${CMAKE_CURRENT_SOURCE_DIR})

spec/describe_a_spec.cpp

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,34 @@ struct TestClass {
1313
: field1(field1), field2(field2){};
1414
};
1515

16-
describe_a<TestClass> describe_a_implicit_spec(
17-
"Implicit subjects", $ {
18-
it(
19-
"Default constructor should be called", _ {
20-
expect(subject.field1).to_equal("foo");
21-
expect(subject.field2).to_equal("bar");
22-
});
16+
// clang-format off
17+
describe_a<TestClass> describe_a_implicit_spec("Implicit subjects", $ {
18+
it("Default constructor should be called", _ {
19+
expect(subject.field1).to_equal("foo");
20+
expect(subject.field2).to_equal("bar");
2321
});
22+
});
2423

25-
describe_a<TestClass> describe_a_explicit_spec(
26-
"Explicit subjects", TestClass("bar", "baz"), $ {
27-
it(
28-
"Specified constructor should be called", _ {
29-
expect(subject.field1).to_equal("bar");
30-
expect(subject.field2).to_equal("baz");
31-
});
24+
describe_a<TestClass> describe_a_explicit_spec("Explicit subjects", TestClass("bar", "baz"), $ {
25+
it("Specified constructor should be called", _ {
26+
expect(subject.field1).to_equal("bar");
27+
expect(subject.field2).to_equal("baz");
3228
});
29+
});
3330

34-
describe_a<std::true_type> describe_a_syntax_spec(
35-
"describe_a syntax", $ {
36-
context(
37-
"A nested context with no given subject", _ {
38-
it(
39-
"should inherit the subject",
40-
_ { expect(subject).to_equal(true); });
41-
});
42-
43-
context<int>(
44-
"A nested context with a given subject", 1, _ {
45-
it(
46-
"should not have the same subject as the parent",
47-
_ { is_expected().to_equal(1); });
48-
});
31+
describe_a<std::true_type> describe_a_syntax_spec("describe_a syntax", $ {
32+
context("A nested context with no given subject", _ {
33+
it("should inherit the subject", _ {
34+
expect(subject).to_equal(true);
4935
});
36+
});
37+
38+
context("A nested context with a given subject", 1, _ {
39+
it("should not have the same subject as the parent", _ {
40+
is_expected().to_equal(1);
41+
});
42+
});
43+
});
5044

5145
int main(int argc, char **argv) {
5246
return CppSpec ::parse(argc, argv)

spec/describe_spec.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ using namespace CppSpec;
44

55
describe describe_spec("Description", $ {
66
it("responds to it", _ { });
7-
context<int>("can create ClassContexts", 1, _{});
7+
context("can create ClassContexts", 1, _{});
88
});
99

1010

11-
CPPSPEC_MAIN(describe_spec);
11+
CPPSPEC_MAIN(describe_spec);

0 commit comments

Comments
 (0)