Skip to content

Commit

Permalink
🎨 🆕 📚 [example] Parameterized tests with language syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
kris-jusiak authored and krzysztof-jusiak committed Dec 27, 2019
1 parent c1447ce commit 429db0a
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 55 deletions.
122 changes: 73 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ All tests passed (2 asserts in 1 tests)
```cpp
int main() {
for (const auto& i : std::vector{1, 2, 3}) {
for (auto i : std::vector{1, 2, 3}) {
test("parameterized " + std::to_string(i)) = [i] { // 3 tests
expect(that % i > 0); // 3 asserts
};
Expand Down Expand Up @@ -622,14 +622,14 @@ All tests passed (4 asserts in 1 tests)
<p>

```cpp
for (const auto& i : std::vector{1, 2, 3}) {
for (auto i : std::vector{1, 2, 3}) {
test("parameterized " + std::to_string(i)) = [i] {
expect(that % i > 0);
};
}

"args"_test =
[](const auto& arg) {
[](auto arg) {
expect(arg >= 1_i);
}
| std::vector{1, 2, 3};
Expand All @@ -641,7 +641,7 @@ for (const auto& i : std::vector{1, 2, 3}) {
| std::tuple<bool, int>{};

"args and types"_test =
[]<class TArg>(const TArg& arg) {
[]<class TArg>(TArg arg) {
!expect(std::is_integral_v<TArg>);
expect(42_i == arg or true_b == arg);
expect(type<TArg> == type<int> or type<TArg> == type<bool>);
Expand Down Expand Up @@ -1279,38 +1279,10 @@ namespace boost::ut::inline v1_1_4 {
</details>

<a name="faq"></a>
<a name="cpp-20"></a>
<a name="how-it-works"></a>
<a name="macro"></a>
<details open><summary>FAQ</summary>
<p>

<details open><summary>&nbsp;&nbsp;&nbsp;&nbsp;C++20 features?</summary>
<p>

* API

* [Source Location](https://eel.is/c++draft/support.srcloc#source.location.syn)
* Assertions - `expect(false)` - ` __FILE__:__LINE__:FAILED [false]`

* [Designated initializers](https://eel.is/c++draft/dcl.init#nt:designated-initializer-list)
* Configuration - `cfg<override> = {.filter = "test"}`

* [Non-Type Template Parameter](https://eel.is/c++draft/temp.arg.nontype)
* Constant matchers - `constant<42_i == 42>`

* [Template Parameter List for generic lambdas](https://eel.is/c++draft/expr.prim.lambda)
* Parameterized tests - `"types"_test = []<class T>() {};`

* [Concepts](https://eel.is/c++draft/concepts.lang)
* Operators - `Operator @ Operator`

* [Modules](https://eel.is/c++draft/module)
* `import boost.ut;`

</p>
</details>

<a name="how-it-works"></a>
<details open><summary>&nbsp;&nbsp;&nbsp;&nbsp;How does it work?</summary>
<p>

Expand Down Expand Up @@ -1457,6 +1429,74 @@ namespace boost::ut::inline v1_1_4 {
</p>
</details>
<a name="cpp-20"></a>
<details open><summary>&nbsp;&nbsp;&nbsp;&nbsp;C++20 features?</summary>
<p>
* API
* [Source Location](https://eel.is/c++draft/support.srcloc#source.location.syn)
* Assertions - `expect(false)` - ` __FILE__:__LINE__:FAILED [false]`
* [Designated initializers](https://eel.is/c++draft/dcl.init#nt:designated-initializer-list)
* Configuration - `cfg<override> = {.filter = "test"}`
* [Non-Type Template Parameter](https://eel.is/c++draft/temp.arg.nontype)
* Constant matchers - `constant<42_i == 42>`
* [Template Parameter List for generic lambdas](https://eel.is/c++draft/expr.prim.lambda)
* Parameterized tests - `"types"_test = []<class T>() {};`
* [Concepts](https://eel.is/c++draft/concepts.lang)
* Operators - `Operator @ Operator`
* [Modules](https://eel.is/c++draft/module)
* `import boost.ut;`
</p>
</details>
<a name="cpp-2x"></a>
<details open><summary>&nbsp;&nbsp;&nbsp;&nbsp;C++2X integration?</summary>
<p>
> Parameterized tests with Expansion statements (http://wg21.link/P1306r1)
```cpp
template for (auto arg : std::tuple<int, double>{}) {
test("types " + std::to_string(arg)) = [arg] {
expect(type(arg) == type<int> or type(arg) == type<double>);
};
}
```

```
All tests passed (2 asserts in 2 tests)
```

> https://cppx.godbolt.org/z/dMmqmM
</p>
</details>

<a name="std"></a>
<details open><summary>&nbsp;&nbsp;&nbsp;&nbsp;Is standardization an option?</summary>
<p>

> Personally, I believe that C++ standard could benefit from common testing primitives (`expect`, `""_test`) because
* It lowers the entry-level to the language (no need for third-party libraries)
* It improves the education aspect (one standard way of doing it)
* It makes the language more coherent/stable (consistent design with other features, stable API)
* It makes the testing a first class citizen (shows that the community cares about this aspect of the language)
* It allows to publish tests for the Standard Library (STL) in the standard way (coherency, easier to extend)
* It allows to act as additional documentation as a way to verify whether a particular implementation is conforming (quality, self-verification)
* It helps with establishing standard vocabulary for testing (common across STL and other projects)

</p>
</details>

<a name="macros"></a>
<details open><summary>&nbsp;&nbsp;&nbsp;&nbsp;Can I still use macros?</summary>
<p>

Expand Down Expand Up @@ -1500,22 +1540,6 @@ All tests passed (4 asserts in 3 tests)
</p>
</details>

<details open><summary>&nbsp;&nbsp;&nbsp;&nbsp;Is standardization an option?</summary>
<p>

> Personally, I believe that C++ standard could benefit from common testing primitives (`expect`, `""_test`) because
* It lowers the entry-level to the language (no need for third-party libraries)
* It improves the education aspect (one standard way of doing it)
* It makes the language more coherent/stable (consistent design with other features, stable API)
* It makes the testing a first class citizen (shows that the community cares about this aspect of the language)
* It allows to publish tests for the Standard Library (STL) in the standard way (coherency, easier to extend)
* It allows to act as additional documentation as a way to verify whether a particular implementation is conforming (quality, self-verification)
* It helps with establishing standard vocabulary for testing (common across STL and other projects)

</p>
</details>

<details open><summary>&nbsp;&nbsp;&nbsp;&nbsp;What about Mocks/Stubs/Fakes?</summary>
<p>

Expand Down
29 changes: 24 additions & 5 deletions example/parameterized.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,48 @@
// http://www.boost.org/LICENSE_1_0.txt)
//
#include <boost/ut.hpp>
#include <string>
#include <tuple>
#include <type_traits>
#include <vector>

int main() {
using namespace boost::ut;

for (const auto& i : std::vector{1, 2, 3}) {
test("parameterized " + std::to_string(i)) = [i] { // 3 tests
expect(that % i > 0); // 3 asserts
/// Language syntax
for (auto i : std::vector{1, 2, 3}) {
test("args / " + std::to_string(i)) = [i] { // 3 tests
expect(that % i > 0); // 3 asserts
};
}

"args"_test = [](const auto& arg) {
/// Alternative syntax
"args"_test = [](auto arg) {
expect(arg > 0_i) << "all values greater than 0";
} | std::vector{1, 2, 3};

/// Alternative syntax
"types"_test = []<class T>() {
expect(std::is_integral_v<T>) << "all types are integrals";
}
| std::tuple<bool, int>{};

"args and types"_test = []<class TArg>(const TArg& arg) {
/// Language syntax
std::apply(
[](auto... args) {
((test("args and types / " + std::to_string(args)) =
[&] {
using TArgs = decltype(args);
!expect(std::is_integral_v<TArgs>);
expect(42_i == static_cast<int>(args) or args);
expect(type<TArgs> == type<int> or type<TArgs> == type<bool>);
}),
...);
},
std::tuple{42, true});

/// Alternative syntax
"args and types"_test = []<class TArg>(TArg arg) {
!expect(std::is_integral_v<TArg>);
expect(42_i == static_cast<int>(arg) or arg);
expect(type<TArg> == type<int> or type<TArg> == type<bool>);
Expand Down
2 changes: 1 addition & 1 deletion include/boost/ut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1509,7 +1509,7 @@ struct test {
.location = test.location,
.arg = none{},
.run = test.test});
return test;
return test.test;
}

template <class Test,
Expand Down

0 comments on commit 429db0a

Please sign in to comment.