Hello libcode-validation
This commit is contained in:
commit
2601654936
17
.editorconfig
Normal file
17
.editorconfig
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
indent_size = 4
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.yaml]
|
||||||
|
indent_size = 2
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
* text=auto
|
20
.gitea/workflows/on-push.yaml
Normal file
20
.gitea/workflows/on-push.yaml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
name: on-push
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-test:
|
||||||
|
runs-on: linux
|
||||||
|
container: code.helloryan.se/infra/buildenv/cxx-amd64-fedora-40:latest
|
||||||
|
volumes:
|
||||||
|
- /build
|
||||||
|
steps:
|
||||||
|
- name: Clone repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Initialize
|
||||||
|
run: |
|
||||||
|
bpkg create -d /build cc config.cc.coptions="-Wall -Werror"
|
||||||
|
bdep init -A /build
|
||||||
|
- name: Build
|
||||||
|
run: b
|
||||||
|
- name: Test
|
||||||
|
run: b test
|
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.bdep/
|
||||||
|
|
||||||
|
# Local default options files.
|
||||||
|
#
|
||||||
|
.build2/local/
|
||||||
|
|
||||||
|
# Compiler/linker output.
|
||||||
|
#
|
||||||
|
*.d
|
||||||
|
*.t
|
||||||
|
*.i
|
||||||
|
*.i.*
|
||||||
|
*.ii
|
||||||
|
*.ii.*
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.gcm
|
||||||
|
*.pcm
|
||||||
|
*.ifc
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
*.exp
|
||||||
|
*.pdb
|
||||||
|
*.ilk
|
||||||
|
*.exe
|
||||||
|
*.exe.dlls/
|
||||||
|
*.exe.manifest
|
||||||
|
*.pc
|
31
LICENSE
Normal file
31
LICENSE
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
Copyright © 2024 Ryan. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. All advertising materials mentioning features or use of this software must
|
||||||
|
display the following acknowledgement:
|
||||||
|
|
||||||
|
This product includes software developed by Ryan, http://helloryan.se/.
|
||||||
|
|
||||||
|
4. Neither the name(s) of the copyright holder(s) nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from this
|
||||||
|
software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||||
|
NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
21
README.md
Normal file
21
README.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# libcode-validation
|
||||||
|
|
||||||
|
![Build status](https://code.helloryan.se/code/libcode-validation/actions/workflows/on-push.yaml/badge.svg)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
None, other than a modern C++-compiler.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
See the wiki, https://code.helloryan.se/code/wiki/wiki/Build-Instructions, for
|
||||||
|
build instructions.
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
|
||||||
|
Please report bugs and issues by sending an e-mail to: ryan@helloryan.se.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Please send an e-mail to ryan@helloryan.se to request an account and
|
||||||
|
write-access to the libcode-validation repository.
|
4
build/.gitignore
vendored
Normal file
4
build/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/config.build
|
||||||
|
/root/
|
||||||
|
/bootstrap/
|
||||||
|
build/
|
7
build/bootstrap.build
Normal file
7
build/bootstrap.build
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
project = libcode-validation
|
||||||
|
|
||||||
|
using version
|
||||||
|
using config
|
||||||
|
using test
|
||||||
|
using install
|
||||||
|
using dist
|
6
build/export.build
Normal file
6
build/export.build
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
$out_root/
|
||||||
|
{
|
||||||
|
include code/validation/
|
||||||
|
}
|
||||||
|
|
||||||
|
export $out_root/code/validation/$import.target
|
16
build/root.build
Normal file
16
build/root.build
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Uncomment to suppress warnings coming from external libraries.
|
||||||
|
#
|
||||||
|
#cxx.internal.scope = current
|
||||||
|
|
||||||
|
cxx.std = latest
|
||||||
|
|
||||||
|
using cxx
|
||||||
|
|
||||||
|
hxx{*}: extension = hxx
|
||||||
|
ixx{*}: extension = ixx
|
||||||
|
txx{*}: extension = txx
|
||||||
|
cxx{*}: extension = cxx
|
||||||
|
|
||||||
|
# The test target for cross-testing (running tests under Wine, etc).
|
||||||
|
#
|
||||||
|
test.target = $cxx.target
|
5
buildfile
Normal file
5
buildfile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
./: {code/ tests/} doc{README.md} legal{LICENSE} manifest
|
||||||
|
|
||||||
|
# Don't install tests.
|
||||||
|
#
|
||||||
|
tests/: install = false
|
9
code/validation/.gitignore
vendored
Normal file
9
code/validation/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Generated version header.
|
||||||
|
#
|
||||||
|
version.hxx
|
||||||
|
|
||||||
|
# Unit test executables and Testscript output directories
|
||||||
|
# (can be symlinks).
|
||||||
|
#
|
||||||
|
*.test
|
||||||
|
test-*.test
|
51
code/validation/assert.hxx
Normal file
51
code/validation/assert.hxx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef code__validation__assert_hxx_
|
||||||
|
#define code__validation__assert_hxx_
|
||||||
|
|
||||||
|
#include <code/validation/except.hxx>
|
||||||
|
#include <code/validation/traits.hxx>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <source_location>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace code::validation::Assert
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void
|
||||||
|
assert_true(T const&,
|
||||||
|
std::string,
|
||||||
|
std::source_location const& = std::source_location::current());
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void
|
||||||
|
assert_false(T const&,
|
||||||
|
std::string,
|
||||||
|
std::source_location const& = std::source_location::current());
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void
|
||||||
|
assert_null(T const&,
|
||||||
|
std::string,
|
||||||
|
std::source_location const& = std::source_location::current());
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void
|
||||||
|
assert_not_null(T const&,
|
||||||
|
std::string,
|
||||||
|
std::source_location const& = std::source_location::current());
|
||||||
|
|
||||||
|
template<typename T1, typename T2 = T1>
|
||||||
|
void
|
||||||
|
assert_equal(T1 const&,
|
||||||
|
T2 const&,
|
||||||
|
std::string,
|
||||||
|
std::string,
|
||||||
|
std::source_location const& = std::source_location::current());
|
||||||
|
|
||||||
|
} // namespace code::validation::Assert
|
||||||
|
|
||||||
|
#include <code/validation/assert.txx>
|
||||||
|
|
||||||
|
#endif
|
210
code/validation/assert.txx
Normal file
210
code/validation/assert.txx
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
namespace code::validation::Assert
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
class Unary_expression_failure
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Unary_expression_failure(std::string message,
|
||||||
|
std::string file,
|
||||||
|
std::uint32_t line,
|
||||||
|
std::string expr,
|
||||||
|
std::string val)
|
||||||
|
: message_{std::move(message)},
|
||||||
|
file_{std::move(file)},
|
||||||
|
line_{line},
|
||||||
|
expr_{std::move(expr)},
|
||||||
|
val_{std::move(val)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
print(std::ostream& o) const
|
||||||
|
{
|
||||||
|
o << " " << message_ << '\n';
|
||||||
|
o << " source: " << file_ << ':' << line_ << ":\n";
|
||||||
|
o << " expression: " << expr_ << '\n';
|
||||||
|
o << " value : " << val_ << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string message_;
|
||||||
|
std::string file_;
|
||||||
|
std::uint32_t line_;
|
||||||
|
std::string expr_;
|
||||||
|
std::string val_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Binary_expression_failure
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Binary_expression_failure(std::string message,
|
||||||
|
std::string file,
|
||||||
|
std::uint32_t line,
|
||||||
|
std::string lhs_expr,
|
||||||
|
std::string lhs_val,
|
||||||
|
std::string rhs_expr,
|
||||||
|
std::string rhs_val)
|
||||||
|
: message_{std::move(message)},
|
||||||
|
file_{std::move(file)},
|
||||||
|
line_{line},
|
||||||
|
lhs_expr_{std::move(lhs_expr)},
|
||||||
|
lhs_val_{std::move(lhs_val)},
|
||||||
|
rhs_expr_{std::move(rhs_expr)},
|
||||||
|
rhs_val_{std::move(rhs_val)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
print(std::ostream& o) const
|
||||||
|
{
|
||||||
|
o << " " << message_ << '\n';
|
||||||
|
o << " source: " << file_ << ':' << line_ << ":\n";
|
||||||
|
o << " left-hand expression : " << lhs_expr_ << '\n';
|
||||||
|
o << " left-hand value : " << lhs_val_ << '\n';
|
||||||
|
o << " right-hand expression: " << rhs_expr_ << '\n';
|
||||||
|
o << " right-hand value : " << rhs_val_ << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string message_;
|
||||||
|
std::string file_;
|
||||||
|
std::uint32_t line_;
|
||||||
|
std::string lhs_expr_;
|
||||||
|
std::string lhs_val_;
|
||||||
|
std::string rhs_expr_;
|
||||||
|
std::string rhs_val_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void
|
||||||
|
assert_true(T const& value,
|
||||||
|
std::string expr,
|
||||||
|
std::source_location const& source)
|
||||||
|
{
|
||||||
|
if (value == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string expr_str;
|
||||||
|
|
||||||
|
if constexpr (has_output_operator<T>) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << value;
|
||||||
|
expr_str = str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Fail{
|
||||||
|
Unary_expression_failure{
|
||||||
|
"expected expression to be true; was false",
|
||||||
|
source.file_name(),
|
||||||
|
source.line(),
|
||||||
|
std::move(expr),
|
||||||
|
std::move(expr_str)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void
|
||||||
|
assert_false(T const& value,
|
||||||
|
std::string expr,
|
||||||
|
std::source_location const& source)
|
||||||
|
{
|
||||||
|
if (value == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string expr_str;
|
||||||
|
|
||||||
|
if constexpr (has_output_operator<T>) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << value;
|
||||||
|
expr_str = str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Fail{
|
||||||
|
Unary_expression_failure{
|
||||||
|
"expected expression to be false; was true",
|
||||||
|
source.file_name(),
|
||||||
|
source.line(),
|
||||||
|
std::move(expr),
|
||||||
|
std::move(expr_str)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void
|
||||||
|
assert_null(T const& value,
|
||||||
|
std::string expr,
|
||||||
|
std::source_location const& source)
|
||||||
|
{
|
||||||
|
if (value == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string expr_str;
|
||||||
|
|
||||||
|
if constexpr (has_output_operator<T>) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << value;
|
||||||
|
expr_str = str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Fail{
|
||||||
|
Unary_expression_failure{
|
||||||
|
"expected expression to be nullptr; was not",
|
||||||
|
source.file_name(),
|
||||||
|
source.line(),
|
||||||
|
std::move(expr),
|
||||||
|
std::move(expr_str)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
void
|
||||||
|
assert_equal(T1 const& lhs,
|
||||||
|
T2 const& rhs,
|
||||||
|
std::string lhs_expr,
|
||||||
|
std::string rhs_expr,
|
||||||
|
std::source_location const& source)
|
||||||
|
{
|
||||||
|
if (lhs == rhs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string lhs_val;
|
||||||
|
std::string rhs_val;
|
||||||
|
|
||||||
|
if constexpr (has_output_operator<T1>) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << lhs;
|
||||||
|
lhs_val = str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (has_output_operator<T2>) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << rhs;
|
||||||
|
rhs_val = str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Fail{
|
||||||
|
Binary_expression_failure{
|
||||||
|
"expected lhs to equal rhs; they did not",
|
||||||
|
source.file_name(),
|
||||||
|
source.line(),
|
||||||
|
std::move(lhs_expr),
|
||||||
|
std::move(lhs_val),
|
||||||
|
std::move(rhs_expr),
|
||||||
|
std::move(rhs_val)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace code::validation::Assert
|
62
code/validation/buildfile
Normal file
62
code/validation/buildfile
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
intf_libs = # Interface dependencies.
|
||||||
|
impl_libs = # Implementation dependencies.
|
||||||
|
|
||||||
|
./: lib{code-validation}: libul{code-validation}
|
||||||
|
|
||||||
|
libul{code-validation}: {hxx ixx txx cxx}{** -**.test... -version} \
|
||||||
|
{hxx }{ version}
|
||||||
|
|
||||||
|
libul{code-validation}: $impl_libs $intf_libs
|
||||||
|
|
||||||
|
# Unit tests.
|
||||||
|
#
|
||||||
|
exe{*.test}:
|
||||||
|
{
|
||||||
|
test = true
|
||||||
|
install = false
|
||||||
|
}
|
||||||
|
|
||||||
|
for t: cxx{**.test...}
|
||||||
|
{
|
||||||
|
d = $directory($t)
|
||||||
|
n = $name($t)...
|
||||||
|
|
||||||
|
./: $d/exe{$n}: $t $d/{hxx ixx txx}{+$n} $d/testscript{+$n}
|
||||||
|
$d/exe{$n}: libul{code-validation}: bin.whole = false
|
||||||
|
}
|
||||||
|
|
||||||
|
hxx{version}: in{version} $src_root/manifest
|
||||||
|
{
|
||||||
|
dist = true
|
||||||
|
clean = ($src_root != $out_root)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build options.
|
||||||
|
#
|
||||||
|
cxx.poptions =+ "-I$out_root" "-I$src_root"
|
||||||
|
|
||||||
|
# Export options.
|
||||||
|
#
|
||||||
|
lib{code-validation}:
|
||||||
|
{
|
||||||
|
cxx.export.poptions = "-I$out_root" "-I$src_root"
|
||||||
|
cxx.export.libs = $intf_libs
|
||||||
|
}
|
||||||
|
|
||||||
|
# For pre-releases use the complete version to make sure they cannot
|
||||||
|
# be used in place of another pre-release or the final version. See
|
||||||
|
# the version module for details on the version.* variable values.
|
||||||
|
#
|
||||||
|
if $version.pre_release
|
||||||
|
lib{code-validation}: bin.lib.version = "-$version.project_id"
|
||||||
|
else
|
||||||
|
lib{code-validation}: bin.lib.version = "-$version.major.$version.minor"
|
||||||
|
|
||||||
|
# Install into the code/validation/ subdirectory of, say, /usr/include/
|
||||||
|
# recreating subdirectories.
|
||||||
|
#
|
||||||
|
{hxx ixx txx}{*}:
|
||||||
|
{
|
||||||
|
install = include/code/validation/
|
||||||
|
install.subdirs = true
|
||||||
|
}
|
29
code/validation/except.hxx
Normal file
29
code/validation/except.hxx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef code__validation__except_hxx_
|
||||||
|
#define code__validation__except_hxx_
|
||||||
|
|
||||||
|
#include <code/validation/test-fail-extras.hxx>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
class Fail
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Fail(Test_fail_extras extras)
|
||||||
|
: extras_{std::move(extras)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
Test_fail_extras const&
|
||||||
|
extras() const
|
||||||
|
{
|
||||||
|
return extras_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Test_fail_extras extras_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace code::validation
|
||||||
|
|
||||||
|
#endif
|
118
code/validation/exec.cxx
Normal file
118
code/validation/exec.cxx
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#include <code/validation/exec.hxx>
|
||||||
|
|
||||||
|
#include <code/validation/except.hxx>
|
||||||
|
#include <code/validation/setup.hxx>
|
||||||
|
#include <code/validation/teardown.hxx>
|
||||||
|
#include <code/validation/test-case.hxx>
|
||||||
|
#include <code/validation/test-result.hxx>
|
||||||
|
#include <code/validation/utility.hxx>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
exec_setup()
|
||||||
|
{
|
||||||
|
auto current = Setup::first();
|
||||||
|
|
||||||
|
if (!current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
// fixme: report setup exceptions. fail entire unit test on exception.
|
||||||
|
//
|
||||||
|
current->run();
|
||||||
|
current = current->next();
|
||||||
|
} while (current && current != Setup::first());
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
exec_teardown()
|
||||||
|
{
|
||||||
|
auto current = Teardown::first();
|
||||||
|
|
||||||
|
if (!current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
// fixme: report teardown exceptions. fail entire unit test on exception.
|
||||||
|
//
|
||||||
|
current->run();
|
||||||
|
current = current->next();
|
||||||
|
} while (current && current != Teardown::first());
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool
|
||||||
|
exec_test_case(Test_summary& summary, Test_case& test_case)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Utility::Current<Test_case> current{&test_case};
|
||||||
|
|
||||||
|
exec_setup();
|
||||||
|
|
||||||
|
try {
|
||||||
|
test_case.run();
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
exec_teardown();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
exec_teardown();
|
||||||
|
|
||||||
|
summary.append({
|
||||||
|
test_case.description(),
|
||||||
|
test_case.file(),
|
||||||
|
test_case.line(),
|
||||||
|
"passed"
|
||||||
|
});
|
||||||
|
|
||||||
|
summary.inc_pass();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Fail const& fail) {
|
||||||
|
summary.append({
|
||||||
|
test_case.description(),
|
||||||
|
test_case.file(),
|
||||||
|
test_case.line(),
|
||||||
|
"failed",
|
||||||
|
fail.extras()
|
||||||
|
});
|
||||||
|
|
||||||
|
summary.inc_fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
exec(Test_summary& summary)
|
||||||
|
{
|
||||||
|
auto current = &Test_case::first();
|
||||||
|
|
||||||
|
if (!current) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool all_passed{true};
|
||||||
|
|
||||||
|
do {
|
||||||
|
bool passed = exec_test_case(summary, *current);
|
||||||
|
|
||||||
|
if (!passed) {
|
||||||
|
all_passed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = ¤t->next();
|
||||||
|
} while (current != &Test_case::first());
|
||||||
|
|
||||||
|
return all_passed;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace code::validation
|
16
code/validation/exec.hxx
Normal file
16
code/validation/exec.hxx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef code__validation__exec_hxx_
|
||||||
|
#define code__validation__exec_hxx_
|
||||||
|
|
||||||
|
#include <code/validation/test-summary.hxx>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
bool
|
||||||
|
exec(Test_summary& summary);
|
||||||
|
|
||||||
|
} // namespace code::validation
|
||||||
|
|
||||||
|
#endif
|
54
code/validation/macros.hxx
Normal file
54
code/validation/macros.hxx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef code__validation__macros_hxx_
|
||||||
|
#define code__validation__macros_hxx_
|
||||||
|
|
||||||
|
#include <code/validation/assert.hxx>
|
||||||
|
#include <code/validation/setup.hxx>
|
||||||
|
#include <code/validation/teardown.hxx>
|
||||||
|
#include <code/validation/test-case.hxx>
|
||||||
|
|
||||||
|
#define VALIDATION_TEST_SETUP_2(file, line) \
|
||||||
|
static void test_setup_func_##line(); \
|
||||||
|
code::validation::Setup test_setup_##line(file, line, &test_setup_func_##line); \
|
||||||
|
void test_setup_func_##line()
|
||||||
|
|
||||||
|
#define VALIDATION_TEST_SETUP_1(file, line) \
|
||||||
|
VALIDATION_TEST_SETUP_2(file, line)
|
||||||
|
|
||||||
|
#define VALIDATION_TEST_SETUP \
|
||||||
|
VALIDATION_TEST_SETUP_1(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
#define VALIDATION_TEST_TEARDOWN_2(file, line) \
|
||||||
|
static void test_teardown_func_##line(); \
|
||||||
|
code::validation::Teardown test_teardown_##line(file, line, &test_teardown_func_##line); \
|
||||||
|
void test_teardown_func_##line()
|
||||||
|
|
||||||
|
#define VALIDATION_TEST_TEARDOWN_1(file, line) \
|
||||||
|
VALIDATION_TEST_TEARDOWN_2(file, line)
|
||||||
|
|
||||||
|
#define VALIDATION_TEST_TEARDOWN \
|
||||||
|
VALIDATION_TEST_TEARDOWN_1(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
#define VALIDATION_TEST_2(name, file, line) \
|
||||||
|
void test_func_##line(); \
|
||||||
|
code::validation::Test_case test_##line(#name, (file), (line), &test_func_##line); \
|
||||||
|
void test_func_##line()
|
||||||
|
|
||||||
|
#define VALIDATION_TEST_1(name, file, line) \
|
||||||
|
VALIDATION_TEST_2(name, file, line)
|
||||||
|
|
||||||
|
#define VALIDATION_TEST(name) \
|
||||||
|
VALIDATION_TEST_1(name, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
#define VALIDATION_ASSERT_TRUE(expr) \
|
||||||
|
::code::validation::Assert::assert_true((expr), #expr)
|
||||||
|
|
||||||
|
#define VALIDATION_ASSERT_FALSE(expr) \
|
||||||
|
::code::validation::Assert::assert_false((expr), #expr)
|
||||||
|
|
||||||
|
#define VALIDATION_ASSERT_NULL(expr) \
|
||||||
|
::code::validation::Assert::assert_null((expr), #expr)
|
||||||
|
|
||||||
|
#define VALIDATION_ASSERT_EQUAL(lhs, rhs) \
|
||||||
|
::code::validation::Assert::assert_equal((lhs), (rhs), #lhs, #rhs)
|
||||||
|
|
||||||
|
#endif
|
43
code/validation/main.cxx
Normal file
43
code/validation/main.cxx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include <code/validation/main.hxx>
|
||||||
|
|
||||||
|
#include <code/validation/exec.hxx>
|
||||||
|
#include <code/validation/test-summary.hxx>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int verbosity{0};
|
||||||
|
bool print_stats{false};
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
if (strcmp(argv[i], "--verbose") == 0) {
|
||||||
|
++verbosity;
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[i], "-v") == 0) {
|
||||||
|
++verbosity;
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[i], "--stats") == 0) {
|
||||||
|
print_stats = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Test_summary summary;
|
||||||
|
|
||||||
|
bool success = exec(summary);
|
||||||
|
|
||||||
|
bool print_summary = verbosity > 0;
|
||||||
|
bool print_extras = verbosity > 1;
|
||||||
|
|
||||||
|
if (print_summary) {
|
||||||
|
summary.print(std::cout, print_extras, print_stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace code::validation
|
15
code/validation/main.hxx
Normal file
15
code/validation/main.hxx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef code__validation__main_hxx_
|
||||||
|
#define code__validation__main_hxx_
|
||||||
|
|
||||||
|
#include <code/validation/macros.hxx>
|
||||||
|
#include <code/validation/assert.hxx>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char* argv[]);
|
||||||
|
|
||||||
|
} // namespace code::validation
|
||||||
|
|
||||||
|
#endif
|
60
code/validation/setup.cxx
Normal file
60
code/validation/setup.cxx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#include <code/validation/setup.hxx>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
Setup::
|
||||||
|
Setup(std::string file, int line, std::function<void()> function)
|
||||||
|
: file_{std::move(file)}, line_{line}, function_{function}
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
Setup::
|
||||||
|
file() const
|
||||||
|
{
|
||||||
|
return file_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Setup::
|
||||||
|
line() const
|
||||||
|
{
|
||||||
|
return line_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Setup*
|
||||||
|
Setup::
|
||||||
|
next()
|
||||||
|
{
|
||||||
|
return Utility::Intrusive_list<Setup>::next();
|
||||||
|
}
|
||||||
|
|
||||||
|
Setup*
|
||||||
|
Setup::
|
||||||
|
previous()
|
||||||
|
{
|
||||||
|
return Utility::Intrusive_list<Setup>::previous();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Setup::
|
||||||
|
run()
|
||||||
|
{
|
||||||
|
function_();
|
||||||
|
}
|
||||||
|
|
||||||
|
Setup*
|
||||||
|
Setup::
|
||||||
|
first()
|
||||||
|
{
|
||||||
|
return Utility::Intrusive_list<Setup>::first();
|
||||||
|
}
|
||||||
|
|
||||||
|
Setup*
|
||||||
|
Setup::
|
||||||
|
last()
|
||||||
|
{
|
||||||
|
return Utility::Intrusive_list<Setup>::last();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace code::validation
|
54
code/validation/setup.hxx
Normal file
54
code/validation/setup.hxx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef code__validation__setup_hxx_
|
||||||
|
#define code__validation__setup_hxx_
|
||||||
|
|
||||||
|
#include <code/validation/utility.hxx>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <source_location>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
class Setup
|
||||||
|
: Utility::Intrusive_list<Setup>
|
||||||
|
{
|
||||||
|
friend Utility::Intrusive_list<Setup>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Setup(std::string, int, std::function<void()> function);
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
file() const;
|
||||||
|
|
||||||
|
int
|
||||||
|
line() const;
|
||||||
|
|
||||||
|
Setup*
|
||||||
|
next();
|
||||||
|
|
||||||
|
Setup*
|
||||||
|
previous();
|
||||||
|
|
||||||
|
void
|
||||||
|
run();
|
||||||
|
|
||||||
|
static
|
||||||
|
Setup*
|
||||||
|
first();
|
||||||
|
|
||||||
|
static
|
||||||
|
Setup*
|
||||||
|
last();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string file_;
|
||||||
|
int line_;
|
||||||
|
std::function<void()> function_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace code::validation
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
60
code/validation/teardown.cxx
Normal file
60
code/validation/teardown.cxx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#include <code/validation/teardown.hxx>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
Teardown::
|
||||||
|
Teardown(std::string file, int line, std::function<void()> function)
|
||||||
|
: file_{std::move(file)}, line_{line}, function_{function}
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
Teardown::
|
||||||
|
file() const
|
||||||
|
{
|
||||||
|
return file_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Teardown::
|
||||||
|
line() const
|
||||||
|
{
|
||||||
|
return line_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Teardown*
|
||||||
|
Teardown::
|
||||||
|
next()
|
||||||
|
{
|
||||||
|
return Utility::Intrusive_list<Teardown>::next();
|
||||||
|
}
|
||||||
|
|
||||||
|
Teardown*
|
||||||
|
Teardown::
|
||||||
|
previous()
|
||||||
|
{
|
||||||
|
return Utility::Intrusive_list<Teardown>::previous();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Teardown::
|
||||||
|
run()
|
||||||
|
{
|
||||||
|
function_();
|
||||||
|
}
|
||||||
|
|
||||||
|
Teardown*
|
||||||
|
Teardown::
|
||||||
|
first()
|
||||||
|
{
|
||||||
|
return Utility::Intrusive_list<Teardown>::first();
|
||||||
|
}
|
||||||
|
|
||||||
|
Teardown*
|
||||||
|
Teardown::
|
||||||
|
last()
|
||||||
|
{
|
||||||
|
return Utility::Intrusive_list<Teardown>::last();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace code::validation
|
54
code/validation/teardown.hxx
Normal file
54
code/validation/teardown.hxx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef code__validation__teardown_hxx_
|
||||||
|
#define code__validation__teardown_hxx_
|
||||||
|
|
||||||
|
#include <code/validation/utility.hxx>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <source_location>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
class Teardown
|
||||||
|
: Utility::Intrusive_list<Teardown>
|
||||||
|
{
|
||||||
|
friend Utility::Intrusive_list<Teardown>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Teardown(std::string, int, std::function<void()> function);
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
file() const;
|
||||||
|
|
||||||
|
int
|
||||||
|
line() const;
|
||||||
|
|
||||||
|
Teardown*
|
||||||
|
next();
|
||||||
|
|
||||||
|
Teardown*
|
||||||
|
previous();
|
||||||
|
|
||||||
|
void
|
||||||
|
run();
|
||||||
|
|
||||||
|
static
|
||||||
|
Teardown*
|
||||||
|
first();
|
||||||
|
|
||||||
|
static
|
||||||
|
Teardown*
|
||||||
|
last();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string file_;
|
||||||
|
int line_;
|
||||||
|
std::function<void()> function_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace code::validation
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
73
code/validation/test-case.cxx
Normal file
73
code/validation/test-case.cxx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include <code/validation/test-case.hxx>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
Test_case::
|
||||||
|
Test_case(std::string description,
|
||||||
|
std::string file,
|
||||||
|
int line,
|
||||||
|
std::function<void()> function)
|
||||||
|
: description_{std::move(description)},
|
||||||
|
file_{std::move(file)},
|
||||||
|
line_{line},
|
||||||
|
function_{function}
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
Test_case::
|
||||||
|
description() const
|
||||||
|
{
|
||||||
|
return description_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
Test_case::
|
||||||
|
file() const
|
||||||
|
{
|
||||||
|
return file_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Test_case::
|
||||||
|
line() const
|
||||||
|
{
|
||||||
|
return line_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Test_case&
|
||||||
|
Test_case::
|
||||||
|
next()
|
||||||
|
{
|
||||||
|
return *Utility::Intrusive_list<Test_case>::next();
|
||||||
|
}
|
||||||
|
|
||||||
|
Test_case&
|
||||||
|
Test_case::
|
||||||
|
previous()
|
||||||
|
{
|
||||||
|
return *Utility::Intrusive_list<Test_case>::previous();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Test_case::
|
||||||
|
run()
|
||||||
|
{
|
||||||
|
function_();
|
||||||
|
}
|
||||||
|
|
||||||
|
Test_case&
|
||||||
|
Test_case::
|
||||||
|
first()
|
||||||
|
{
|
||||||
|
return *Utility::Intrusive_list<Test_case>::first();
|
||||||
|
}
|
||||||
|
|
||||||
|
Test_case&
|
||||||
|
Test_case::
|
||||||
|
last()
|
||||||
|
{
|
||||||
|
return *Utility::Intrusive_list<Test_case>::last();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace code::validation
|
57
code/validation/test-case.hxx
Normal file
57
code/validation/test-case.hxx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#ifndef code__validation__test_case_hxx_
|
||||||
|
#define code__validation__test_case_hxx_
|
||||||
|
|
||||||
|
#include <code/validation/utility.hxx>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <source_location>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
class Test_case
|
||||||
|
: Utility::Intrusive_list<Test_case>
|
||||||
|
{
|
||||||
|
friend Utility::Intrusive_list<Test_case>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Test_case(std::string, std::string, int, std::function<void()> function);
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
description() const;
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
file() const;
|
||||||
|
|
||||||
|
int
|
||||||
|
line() const;
|
||||||
|
|
||||||
|
Test_case&
|
||||||
|
next();
|
||||||
|
|
||||||
|
Test_case&
|
||||||
|
previous();
|
||||||
|
|
||||||
|
void
|
||||||
|
run();
|
||||||
|
|
||||||
|
static
|
||||||
|
Test_case&
|
||||||
|
first();
|
||||||
|
|
||||||
|
static
|
||||||
|
Test_case&
|
||||||
|
last();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string description_;
|
||||||
|
std::string file_;
|
||||||
|
int line_;
|
||||||
|
std::function<void()> function_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace code::validation
|
||||||
|
|
||||||
|
#endif
|
13
code/validation/test-fail-extras.cxx
Normal file
13
code/validation/test-fail-extras.cxx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include <code/validation/test-result.hxx>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
void
|
||||||
|
Test_fail_extras::
|
||||||
|
print(std::ostream& o) const
|
||||||
|
{
|
||||||
|
extras_->do_print(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
58
code/validation/test-fail-extras.hxx
Normal file
58
code/validation/test-fail-extras.hxx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#ifndef code__validation__test_fail_extras_hxx_
|
||||||
|
#define code__validation__test_fail_extras_hxx_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
class Test_fail_extras
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
Test_fail_extras(T extras)
|
||||||
|
: extras_{std::make_shared<Wrapper<T>>(std::move(extras))}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
print(std::ostream&) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Abstraction
|
||||||
|
{
|
||||||
|
virtual
|
||||||
|
~Abstraction() noexcept = default;
|
||||||
|
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
do_print(std::ostream&) const = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Wrapper
|
||||||
|
: Abstraction
|
||||||
|
{
|
||||||
|
template<typename... Args>
|
||||||
|
Wrapper(Args&&... args)
|
||||||
|
: extras{std::forward<Args>(args)...}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
do_print(std::ostream& o) const override
|
||||||
|
{
|
||||||
|
extras.print(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
T extras;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<Abstraction const> extras_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace code::validation
|
||||||
|
|
||||||
|
#endif
|
69
code/validation/test-result.cxx
Normal file
69
code/validation/test-result.cxx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#include <code/validation/test-result.hxx>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
Test_result::
|
||||||
|
Test_result(std::string description,
|
||||||
|
std::string file,
|
||||||
|
int line,
|
||||||
|
std::string message)
|
||||||
|
: description_{std::move(description)},
|
||||||
|
file_{std::move(file)},
|
||||||
|
line_{line_},
|
||||||
|
message_{std::move(message)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
Test_result::
|
||||||
|
Test_result(std::string description,
|
||||||
|
std::string file,
|
||||||
|
int line,
|
||||||
|
std::string message,
|
||||||
|
Test_fail_extras extras)
|
||||||
|
: description_{std::move(description)},
|
||||||
|
file_{std::move(file)},
|
||||||
|
line_{line_},
|
||||||
|
message_{std::move(message)},
|
||||||
|
extras_{extras}
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
Test_result::
|
||||||
|
description() const
|
||||||
|
{
|
||||||
|
return description_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
Test_result::
|
||||||
|
file() const
|
||||||
|
{
|
||||||
|
return file_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Test_result::
|
||||||
|
line() const
|
||||||
|
{
|
||||||
|
return line_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
Test_result::
|
||||||
|
message() const
|
||||||
|
{
|
||||||
|
return message_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Test_result::
|
||||||
|
print(std::ostream& o, bool print_extras) const
|
||||||
|
{
|
||||||
|
o << "test: " << description() << ": " << message() << '\n';
|
||||||
|
|
||||||
|
if (print_extras && extras_) {
|
||||||
|
extras_->print(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace code::validation
|
45
code/validation/test-result.hxx
Normal file
45
code/validation/test-result.hxx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef code__validation__test_result_hxx_
|
||||||
|
#define code__validation__test_result_hxx_
|
||||||
|
|
||||||
|
#include <code/validation/test-fail-extras.hxx>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
class Test_result
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Test_result(std::string, std::string, int, std::string);
|
||||||
|
|
||||||
|
Test_result(std::string, std::string, int, std::string, Test_fail_extras);
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
description() const;
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
file() const;
|
||||||
|
|
||||||
|
int
|
||||||
|
line() const;
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
message() const;
|
||||||
|
|
||||||
|
void
|
||||||
|
print(std::ostream&, bool) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string description_;
|
||||||
|
std::string file_;
|
||||||
|
int line_;
|
||||||
|
std::string message_;
|
||||||
|
std::optional<Test_fail_extras> extras_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace code::validation
|
||||||
|
|
||||||
|
#endif
|
48
code/validation/test-summary.cxx
Normal file
48
code/validation/test-summary.cxx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include <code/validation/test-summary.hxx>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
void
|
||||||
|
Test_summary::
|
||||||
|
append(Test_result result)
|
||||||
|
{
|
||||||
|
results_.emplace_back(std::move(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Test_summary::
|
||||||
|
inc_pass()
|
||||||
|
{
|
||||||
|
++pass_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Test_summary::
|
||||||
|
inc_fail()
|
||||||
|
{
|
||||||
|
++fail_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Test_summary::
|
||||||
|
print(std::ostream& o, bool print_extras, bool stats) const
|
||||||
|
{
|
||||||
|
for (auto const& j : results_) {
|
||||||
|
j.print(o, print_extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats) {
|
||||||
|
auto total = pass_ + fail_;
|
||||||
|
|
||||||
|
o << "test statistics:\n"
|
||||||
|
<< "tests : " << total << '\n'
|
||||||
|
<< "tests passed: " << pass_ << '\n'
|
||||||
|
<< "tests failed: " << fail_ << '\n'
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace code::validation
|
38
code/validation/test-summary.hxx
Normal file
38
code/validation/test-summary.hxx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef code__validation__test_summary_hxx_
|
||||||
|
#define code__validation__test_summary_hxx_
|
||||||
|
|
||||||
|
#include <code/validation/test-result.hxx>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
class Test_summary
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Test_summary() = default;
|
||||||
|
|
||||||
|
void
|
||||||
|
append(Test_result);
|
||||||
|
|
||||||
|
void
|
||||||
|
inc_pass();
|
||||||
|
|
||||||
|
void
|
||||||
|
inc_fail();
|
||||||
|
|
||||||
|
void
|
||||||
|
print(std::ostream&, bool, bool) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Test_result> results_;
|
||||||
|
int pass_{};
|
||||||
|
int fail_{};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace code::validation
|
||||||
|
|
||||||
|
#endif
|
23
code/validation/traits.hxx
Normal file
23
code/validation/traits.hxx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef code__validation__traits_hxx_
|
||||||
|
#define code__validation__traits_hxx_
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace code::validation
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept has_output_operator = requires(std::ostream& o, T const& value)
|
||||||
|
{
|
||||||
|
// check if T can be written to an std::ostream.
|
||||||
|
//
|
||||||
|
{
|
||||||
|
o << value
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace code::validation
|
||||||
|
|
||||||
|
#endif
|
138
code/validation/utility.hxx
Normal file
138
code/validation/utility.hxx
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
#ifndef code__validation__utility_hxx_
|
||||||
|
#define code__validation__utility_hxx_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace code::validation::Utility
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Intrusive_list
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
Intrusive_list()
|
||||||
|
{
|
||||||
|
if (!first_ || !last_) {
|
||||||
|
first_ = this;
|
||||||
|
last_ = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
first_->prev_ = this;
|
||||||
|
last_->next_ = this;
|
||||||
|
|
||||||
|
prev_ = last_;
|
||||||
|
next_ = first_;
|
||||||
|
|
||||||
|
last_ = this;
|
||||||
|
|
||||||
|
++counter_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Intrusive_list(Intrusive_list const&) = delete;
|
||||||
|
Intrusive_list(Intrusive_list&&) = delete;
|
||||||
|
|
||||||
|
~Intrusive_list() noexcept
|
||||||
|
{
|
||||||
|
if (first_ == this) {
|
||||||
|
first_ = next_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_ == this) {
|
||||||
|
last_ = prev_;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_->next_ = next_;
|
||||||
|
next_->prev_ = prev_;
|
||||||
|
|
||||||
|
--counter_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Intrusive_list& operator=(Intrusive_list const&) = delete;
|
||||||
|
Intrusive_list& operator=(Intrusive_list&&) = delete;
|
||||||
|
|
||||||
|
T*
|
||||||
|
previous()
|
||||||
|
{
|
||||||
|
return static_cast<T*>(prev_);
|
||||||
|
}
|
||||||
|
|
||||||
|
T*
|
||||||
|
next()
|
||||||
|
{
|
||||||
|
return static_cast<T*>(next_);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
T*
|
||||||
|
first()
|
||||||
|
{
|
||||||
|
return static_cast<T*>(first_);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
T*
|
||||||
|
last()
|
||||||
|
{
|
||||||
|
return static_cast<T*>(last_);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
std::size_t
|
||||||
|
count()
|
||||||
|
{
|
||||||
|
return counter_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Intrusive_list<T>* prev_{nullptr};
|
||||||
|
Intrusive_list<T>* next_{nullptr};
|
||||||
|
|
||||||
|
static Intrusive_list<T>* first_;
|
||||||
|
static Intrusive_list<T>* last_;
|
||||||
|
|
||||||
|
static std::size_t counter_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Intrusive_list<T>* Intrusive_list<T>::first_{nullptr};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Intrusive_list<T>* Intrusive_list<T>::last_{nullptr};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::size_t Intrusive_list<T>::counter_{0};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Current
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit
|
||||||
|
Current(T* current)
|
||||||
|
{
|
||||||
|
current_ = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Current() noexcept
|
||||||
|
{
|
||||||
|
current_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
T*
|
||||||
|
get()
|
||||||
|
{
|
||||||
|
return current_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static T* current_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* Current<T>::current_{nullptr};
|
||||||
|
|
||||||
|
} // namespace code::validation::Utility
|
||||||
|
|
||||||
|
#endif
|
8
code/validation/validate.hxx
Normal file
8
code/validation/validate.hxx
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef code__validation__validation_hxx_
|
||||||
|
#define code__validation__validation_hxx_
|
||||||
|
|
||||||
|
#include <code/validation/exec.hxx>
|
||||||
|
#include <code/validation/macros.hxx>
|
||||||
|
#include <code/validation/main.hxx>
|
||||||
|
|
||||||
|
#endif
|
37
code/validation/version.hxx.in
Normal file
37
code/validation/version.hxx.in
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef code__validation___version_hxx_
|
||||||
|
#define code__validation___version_hxx_
|
||||||
|
|
||||||
|
// The numeric version format is AAAAABBBBBCCCCCDDDE where:
|
||||||
|
//
|
||||||
|
// AAAAA - major version number
|
||||||
|
// BBBBB - minor version number
|
||||||
|
// CCCCC - bugfix version number
|
||||||
|
// DDD - alpha / beta (DDD + 500) version number
|
||||||
|
// E - final (0) / snapshot (1)
|
||||||
|
//
|
||||||
|
// When DDDE is not 0, 1 is subtracted from AAAAABBBBBCCCCC. For example:
|
||||||
|
//
|
||||||
|
// Version AAAAABBBBBCCCCCDDDE
|
||||||
|
//
|
||||||
|
// 0.1.0 0000000001000000000
|
||||||
|
// 0.1.2 0000000001000020000
|
||||||
|
// 1.2.3 0000100002000030000
|
||||||
|
// 2.2.0-a.1 0000200001999990010
|
||||||
|
// 3.0.0-b.2 0000299999999995020
|
||||||
|
// 2.2.0-a.1.z 0000200001999990011
|
||||||
|
//
|
||||||
|
#define LIBCODE_VALIDATION_VERSION $libcode_validation.version.project_number$ULL
|
||||||
|
#define LIBCODE_VALIDATION_VERSION_STR "$libcode_validation.version.project$"
|
||||||
|
#define LIBCODE_VALIDATION_VERSION_ID "$libcode_validation.version.project_id$"
|
||||||
|
#define LIBCODE_VALIDATION_VERSION_FULL "$libcode_validation.version$"
|
||||||
|
|
||||||
|
#define LIBCODE_VALIDATION_VERSION_MAJOR $libcode_validation.version.major$
|
||||||
|
#define LIBCODE_VALIDATION_VERSION_MINOR $libcode_validation.version.minor$
|
||||||
|
#define LIBCODE_VALIDATION_VERSION_PATCH $libcode_validation.version.patch$
|
||||||
|
|
||||||
|
#define LIBCODE_VALIDATION_PRE_RELEASE $libcode_validation.version.pre_release$
|
||||||
|
|
||||||
|
#define LIBCODE_VALIDATION_SNAPSHOT_SN $libcode_validation.version.snapshot_sn$ULL
|
||||||
|
#define LIBCODE_VALIDATION_SNAPSHOT_ID "$libcode_validation.version.snapshot_id$"
|
||||||
|
|
||||||
|
#endif
|
11
manifest
Normal file
11
manifest
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
: 1
|
||||||
|
name: libcode-validation
|
||||||
|
version: 0.1.0-a.0.z
|
||||||
|
language: c++
|
||||||
|
summary: libcode-validation C++ library
|
||||||
|
license: BSD-4-Clause
|
||||||
|
description-file: README.md
|
||||||
|
url: https://helloryan.se/code/
|
||||||
|
email: ryan@helloryan.se
|
||||||
|
depends: * build2 >= 0.17.0
|
||||||
|
depends: * bpkg >= 0.17.0
|
2
repositories.manifest
Normal file
2
repositories.manifest
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
: 1
|
||||||
|
summary: libcode-validation project repository
|
8
tests/.gitignore
vendored
Normal file
8
tests/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Test executables.
|
||||||
|
#
|
||||||
|
driver
|
||||||
|
|
||||||
|
# Testscript output directories (can be symlinks).
|
||||||
|
#
|
||||||
|
test
|
||||||
|
test-*
|
1
tests/basics/.gitignore
vendored
Normal file
1
tests/basics/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
basics
|
31
tests/basics/basics.cxx
Normal file
31
tests/basics/basics.cxx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include <code/validation/main.hxx>
|
||||||
|
|
||||||
|
VALIDATION_TEST_SETUP
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VALIDATION_TEST_TEARDOWN
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VALIDATION_TEST(test_true)
|
||||||
|
{
|
||||||
|
VALIDATION_ASSERT_TRUE(true == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALIDATION_TEST(test_false)
|
||||||
|
{
|
||||||
|
VALIDATION_ASSERT_FALSE(true == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALIDATION_TEST(test_null)
|
||||||
|
{
|
||||||
|
int* ptr{nullptr};
|
||||||
|
VALIDATION_ASSERT_NULL(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
return code::validation::main(argc, argv);
|
||||||
|
}
|
4
tests/basics/buildfile
Normal file
4
tests/basics/buildfile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import libs = libcode-validation%lib{code-validation}
|
||||||
|
|
||||||
|
exe{basics}: {hxx ixx txx cxx}{**} $libs testscript{**}
|
||||||
|
exe{basics}: test.options = -v -v
|
4
tests/build/.gitignore
vendored
Normal file
4
tests/build/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/config.build
|
||||||
|
/root/
|
||||||
|
/bootstrap/
|
||||||
|
build/
|
5
tests/build/bootstrap.build
Normal file
5
tests/build/bootstrap.build
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
project = # Unnamed tests subproject.
|
||||||
|
|
||||||
|
using config
|
||||||
|
using test
|
||||||
|
using dist
|
16
tests/build/root.build
Normal file
16
tests/build/root.build
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
cxx.std = latest
|
||||||
|
|
||||||
|
using cxx
|
||||||
|
|
||||||
|
hxx{*}: extension = hxx
|
||||||
|
ixx{*}: extension = ixx
|
||||||
|
txx{*}: extension = txx
|
||||||
|
cxx{*}: extension = cxx
|
||||||
|
|
||||||
|
# Every exe{} in this subproject is by default a test.
|
||||||
|
#
|
||||||
|
exe{*}: test = true
|
||||||
|
|
||||||
|
# The test target for cross-testing (running tests under Wine, etc).
|
||||||
|
#
|
||||||
|
test.target = $cxx.target
|
1
tests/buildfile
Normal file
1
tests/buildfile
Normal file
@ -0,0 +1 @@
|
|||||||
|
./: {*/ -build/}
|
Loading…
x
Reference in New Issue
Block a user