mirror of
https://github.com/wiiu-env/WiiUPluginSystem.git
synced 2024-11-15 23:35:15 +01:00
Add storage_test_plugin
This commit is contained in:
parent
58a2d3f734
commit
c66d73efe4
3
.github/workflows/pr.yml
vendored
3
.github/workflows/pr.yml
vendored
@ -30,6 +30,7 @@ jobs:
|
|||||||
- name: clang-format
|
- name: clang-format
|
||||||
run: |
|
run: |
|
||||||
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./plugins/example_plugin/src
|
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./plugins/example_plugin/src
|
||||||
|
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./plugins/storage_test_plugin/src --exclude ./plugins/storage_test_plugin/src/catch2
|
||||||
build-examples:
|
build-examples:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
needs: clang-format-examples
|
needs: clang-format-examples
|
||||||
@ -39,6 +40,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
docker build . -f Dockerfile.buildexamples -t builder
|
docker build . -f Dockerfile.buildexamples -t builder
|
||||||
cd ./plugins/example_plugin
|
cd ./plugins/example_plugin
|
||||||
|
docker run --rm -v ${PWD}:/project builder make
|
||||||
|
cd ../storage_test_plugin
|
||||||
docker run --rm -v ${PWD}:/project builder make
|
docker run --rm -v ${PWD}:/project builder make
|
||||||
- uses: actions/upload-artifact@master
|
- uses: actions/upload-artifact@master
|
||||||
with:
|
with:
|
||||||
|
4
.github/workflows/push_image.yml
vendored
4
.github/workflows/push_image.yml
vendored
@ -31,7 +31,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: clang-format
|
- name: clang-format
|
||||||
run: |
|
run: |
|
||||||
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./plugins/example_plugin/src
|
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./plugins/storage_test_plugin/src --exclude ./plugins/storage_test_plugin/src/catch2
|
||||||
build-examples:
|
build-examples:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
needs: clang-format-examples
|
needs: clang-format-examples
|
||||||
@ -41,6 +41,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
docker build . -f Dockerfile.buildexamples -t builder
|
docker build . -f Dockerfile.buildexamples -t builder
|
||||||
cd ./plugins/example_plugin
|
cd ./plugins/example_plugin
|
||||||
|
docker run --rm -v ${PWD}:/project builder make
|
||||||
|
cd ../storage_test_plugin
|
||||||
docker run --rm -v ${PWD}:/project builder make
|
docker run --rm -v ${PWD}:/project builder make
|
||||||
build-and-push-image:
|
build-and-push-image:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -28,4 +28,4 @@ It's highly recommended to pin the version to the **latest date** instead of usi
|
|||||||
|
|
||||||
## Format the code via docker
|
## Format the code via docker
|
||||||
|
|
||||||
`docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./include ./libraries ./plugins/example_plugin/src -i`
|
`docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./include ./libraries ./plugins/example_plugin/src ./plugins/storage_test_plugin/src --exclude ./plugins/storage_test_plugin/src/catch2 -i`
|
||||||
|
67
plugins/storage_test_plugin/.clang-format
Normal file
67
plugins/storage_test_plugin/.clang-format
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# Generated from CLion C/C++ Code Style settings
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: Consecutive
|
||||||
|
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
|
||||||
|
AlignOperands: Align
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: Always
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: Always
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
ColumnLimit: 0
|
||||||
|
CompactNamespaces: false
|
||||||
|
ContinuationIndentWidth: 8
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 4
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MaxEmptyLinesToKeep: 2
|
||||||
|
NamespaceIndentation: All
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: false
|
||||||
|
SpaceAfterCStyleCast: true
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
5
plugins/storage_test_plugin/Dockerfile
Normal file
5
plugins/storage_test_plugin/Dockerfile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
FROM ghcr.io/wiiu-env/devkitppc:20230218
|
||||||
|
|
||||||
|
COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:20230215 /artifacts $DEVKITPRO
|
||||||
|
|
||||||
|
WORKDIR project
|
143
plugins/storage_test_plugin/Makefile
Normal file
143
plugins/storage_test_plugin/Makefile
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||||
|
endif
|
||||||
|
|
||||||
|
TOPDIR ?= $(CURDIR)
|
||||||
|
|
||||||
|
include $(DEVKITPRO)/wups/share/wups_rules
|
||||||
|
|
||||||
|
WUT_ROOT := $(DEVKITPRO)/wut
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# TARGET is the name of the output
|
||||||
|
# BUILD is the directory where object files & intermediate files will be placed
|
||||||
|
# SOURCES is a list of directories containing source code
|
||||||
|
# DATA is a list of directories containing data files
|
||||||
|
# INCLUDES is a list of directories containing header files
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
TARGET := StorageTestPlugin
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := src src/utils \
|
||||||
|
src/catch2 \
|
||||||
|
src/catch2/benchmark \
|
||||||
|
src/catch2/generators \
|
||||||
|
src/catch2/interfaces \
|
||||||
|
src/catch2/internal \
|
||||||
|
src/catch2/matchers \
|
||||||
|
src/catch2/matchers/internal \
|
||||||
|
src/catch2/reporters \
|
||||||
|
DATA := data
|
||||||
|
INCLUDES := src
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||||
|
$(MACHDEP)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS)
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) $(WUPSSPECS)
|
||||||
|
|
||||||
|
LIBS := -lwups -lwut
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level
|
||||||
|
# containing include and lib
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(PORTLIBS) $(WUPS_ROOT) $(WUT_ROOT)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||||
|
export TOPDIR := $(CURDIR)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||||
|
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||||
|
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean all
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
all: $(BUILD)
|
||||||
|
|
||||||
|
$(BUILD):
|
||||||
|
@$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(TARGET).wps $(TARGET).elf
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
all : $(OUTPUT).wps
|
||||||
|
|
||||||
|
$(OUTPUT).wps : $(OUTPUT).elf
|
||||||
|
$(OUTPUT).elf : $(OFILES)
|
||||||
|
|
||||||
|
$(OFILES_SRC) : $(HFILES_BIN)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
%.bin.o %_bin.h : %.bin
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#-------------------------------------------------------------------------------
|
55
plugins/storage_test_plugin/README.md
Normal file
55
plugins/storage_test_plugin/README.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Storage test plugin
|
||||||
|
|
||||||
|
This plugin implements several tests of StorageAPI. Results are be printed to the OSConsole ([USBSerialLoggingModule](https://github.com/wiiu-env/USBSerialLoggingModule))
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
(`[ENVIRONMENT]` is a placeholder for the actual environment name.)
|
||||||
|
|
||||||
|
1. Requires the [WiiUPluginLoaderBackend](https://github.com/wiiu-env/WiiUPluginLoaderBackend) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
||||||
|
|
||||||
|
It's recommended to [wiiload](https://github.com/wiiu-env/wiiload_plugin) this plugin whenever you want to run the test.
|
||||||
|
|
||||||
|
This plugin uses [Catch2](https://github.com/catchorg/Catch2) to run tests.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
For building you need:
|
||||||
|
|
||||||
|
- [wups](https://github.com/Maschell/WiiUPluginSystem)
|
||||||
|
- [wut](https://github.com/devkitpro/wut)
|
||||||
|
|
||||||
|
Install them (in this order) according to their README's. Don't forget the dependencies of the libs itself.
|
||||||
|
|
||||||
|
Then you should be able to compile via `make` (with no logging) or `make DEBUG=1` (with logging).
|
||||||
|
|
||||||
|
## Buildflags
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
|
||||||
|
Building via `make` only logs errors (via OSReport). To enable logging via the [LoggingModule](https://github.com/wiiu-env/LoggingModule) set `DEBUG` to `1` or `VERBOSE`.
|
||||||
|
|
||||||
|
`make` Logs errors only (via OSReport).
|
||||||
|
`make DEBUG=1` Enables information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
|
||||||
|
`make DEBUG=VERBOSE` Enables verbose information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
|
||||||
|
|
||||||
|
If the [LoggingModule](https://github.com/wiiu-env/LoggingModule) isn't present, it will fall back to UDP (port 4405) and [CafeOS](https://github.com/wiiu-env/USBSerialLoggingModule) logging.
|
||||||
|
|
||||||
|
## Building using the Dockerfile
|
||||||
|
|
||||||
|
It's possible to use a docker image for building. This way you don't need anything installed on your host system.
|
||||||
|
|
||||||
|
```
|
||||||
|
# Build docker image (only needed once)
|
||||||
|
docker build . -t storage-test-plugin-builder
|
||||||
|
|
||||||
|
# make
|
||||||
|
docker run -it --rm -v ${PWD}:/project storage-test-plugin-builder make DEBUG=1
|
||||||
|
|
||||||
|
# make clean
|
||||||
|
docker run -it --rm -v ${PWD}:/project storage-test-plugin-builder make clean
|
||||||
|
```
|
||||||
|
|
||||||
|
## Format the code via docker
|
||||||
|
|
||||||
|
`docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./src --exclude ./src/catch2 -i`
|
@ -0,0 +1,148 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_BENCHMARK_HPP_INCLUDED
|
||||||
|
#define CATCH_BENCHMARK_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/catch_user_config.hpp>
|
||||||
|
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||||
|
#include <catch2/internal/catch_context.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
#include <catch2/internal/catch_test_failure_exception.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_name.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_benchmark_stats.hpp>
|
||||||
|
#include <catch2/benchmark/catch_clock.hpp>
|
||||||
|
#include <catch2/benchmark/catch_environment.hpp>
|
||||||
|
#include <catch2/benchmark/catch_execution_plan.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_estimate_clock.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_analyse.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
#include <exception>
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
struct Benchmark {
|
||||||
|
Benchmark(std::string&& benchmarkName)
|
||||||
|
: name(CATCH_MOVE(benchmarkName)) {}
|
||||||
|
|
||||||
|
template <class FUN>
|
||||||
|
Benchmark(std::string&& benchmarkName , FUN &&func)
|
||||||
|
: fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {}
|
||||||
|
|
||||||
|
template <typename Clock>
|
||||||
|
ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
|
||||||
|
auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
|
||||||
|
auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
|
||||||
|
auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);
|
||||||
|
int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
|
||||||
|
return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Clock = default_clock>
|
||||||
|
void run() {
|
||||||
|
auto const* cfg = getCurrentContext().getConfig();
|
||||||
|
|
||||||
|
auto env = Detail::measure_environment<Clock>();
|
||||||
|
|
||||||
|
getResultCapture().benchmarkPreparing(name);
|
||||||
|
CATCH_TRY{
|
||||||
|
auto plan = user_code([&] {
|
||||||
|
return prepare<Clock>(*cfg, env);
|
||||||
|
});
|
||||||
|
|
||||||
|
BenchmarkInfo info {
|
||||||
|
CATCH_MOVE(name),
|
||||||
|
plan.estimated_duration.count(),
|
||||||
|
plan.iterations_per_sample,
|
||||||
|
cfg->benchmarkSamples(),
|
||||||
|
cfg->benchmarkResamples(),
|
||||||
|
env.clock_resolution.mean.count(),
|
||||||
|
env.clock_cost.mean.count()
|
||||||
|
};
|
||||||
|
|
||||||
|
getResultCapture().benchmarkStarting(info);
|
||||||
|
|
||||||
|
auto samples = user_code([&] {
|
||||||
|
return plan.template run<Clock>(*cfg, env);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
|
||||||
|
BenchmarkStats<FloatDuration<Clock>> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
|
||||||
|
getResultCapture().benchmarkEnded(stats);
|
||||||
|
} CATCH_CATCH_ANON (TestFailureException const&) {
|
||||||
|
getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr);
|
||||||
|
} CATCH_CATCH_ALL{
|
||||||
|
getResultCapture().benchmarkFailed(translateActiveException());
|
||||||
|
// We let the exception go further up so that the
|
||||||
|
// test case is marked as failed.
|
||||||
|
std::rethrow_exception(std::current_exception());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sets lambda to be used in fun *and* executes benchmark!
|
||||||
|
template <typename Fun, std::enable_if_t<!Detail::is_related<Fun, Benchmark>::value, int> = 0>
|
||||||
|
Benchmark & operator=(Fun func) {
|
||||||
|
auto const* cfg = getCurrentContext().getConfig();
|
||||||
|
if (!cfg->skipBenchmarks()) {
|
||||||
|
fun = Detail::BenchmarkFunction(func);
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Detail::BenchmarkFunction fun;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
|
||||||
|
#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
|
||||||
|
|
||||||
|
#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
|
||||||
|
if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
|
||||||
|
BenchmarkName = [&](int benchmarkIndex)
|
||||||
|
|
||||||
|
#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
|
||||||
|
if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
|
||||||
|
BenchmarkName = [&]
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_PREFIX_ALL)
|
||||||
|
|
||||||
|
#define CATCH_BENCHMARK(...) \
|
||||||
|
INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
|
||||||
|
#define CATCH_BENCHMARK_ADVANCED(name) \
|
||||||
|
INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define BENCHMARK(...) \
|
||||||
|
INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
|
||||||
|
#define BENCHMARK_ADVANCED(name) \
|
||||||
|
INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CATCH_BENCHMARK_HPP_INCLUDED
|
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
/** \file
|
||||||
|
* This is a convenience header for Catch2's benchmarking. It includes
|
||||||
|
* **all** of Catch2 headers related to benchmarking.
|
||||||
|
*
|
||||||
|
* Generally the Catch2 users should use specific includes they need,
|
||||||
|
* but this header can be used instead for ease-of-experimentation, or
|
||||||
|
* just plain convenience, at the cost of (significantly) increased
|
||||||
|
* compilation times.
|
||||||
|
*
|
||||||
|
* When a new header is added to either the `benchmark` folder, or to
|
||||||
|
* the corresponding internal (detail) subfolder, it should be added here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CATCH_BENCHMARK_ALL_HPP_INCLUDED
|
||||||
|
#define CATCH_BENCHMARK_ALL_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||||
|
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||||
|
#include <catch2/benchmark/catch_clock.hpp>
|
||||||
|
#include <catch2/benchmark/catch_constructor.hpp>
|
||||||
|
#include <catch2/benchmark/catch_environment.hpp>
|
||||||
|
#include <catch2/benchmark/catch_estimate.hpp>
|
||||||
|
#include <catch2/benchmark/catch_execution_plan.hpp>
|
||||||
|
#include <catch2/benchmark/catch_optimizer.hpp>
|
||||||
|
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||||
|
#include <catch2/benchmark/catch_sample_analysis.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_analyse.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_benchmark_stats.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_estimate_clock.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_measure.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_repeat.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_stats.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_timing.hpp>
|
||||||
|
|
||||||
|
#endif // CATCH_BENCHMARK_ALL_HPP_INCLUDED
|
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
ChronometerConcept::~ChronometerConcept() = default;
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_CHRONOMETER_HPP_INCLUDED
|
||||||
|
#define CATCH_CHRONOMETER_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/benchmark/catch_clock.hpp>
|
||||||
|
#include <catch2/benchmark/catch_optimizer.hpp>
|
||||||
|
#include <catch2/internal/catch_meta.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
struct ChronometerConcept {
|
||||||
|
virtual void start() = 0;
|
||||||
|
virtual void finish() = 0;
|
||||||
|
virtual ~ChronometerConcept(); // = default;
|
||||||
|
|
||||||
|
ChronometerConcept() = default;
|
||||||
|
ChronometerConcept(ChronometerConcept const&) = default;
|
||||||
|
ChronometerConcept& operator=(ChronometerConcept const&) = default;
|
||||||
|
};
|
||||||
|
template <typename Clock>
|
||||||
|
struct ChronometerModel final : public ChronometerConcept {
|
||||||
|
void start() override { started = Clock::now(); }
|
||||||
|
void finish() override { finished = Clock::now(); }
|
||||||
|
|
||||||
|
ClockDuration<Clock> elapsed() const { return finished - started; }
|
||||||
|
|
||||||
|
TimePoint<Clock> started;
|
||||||
|
TimePoint<Clock> finished;
|
||||||
|
};
|
||||||
|
} // namespace Detail
|
||||||
|
|
||||||
|
struct Chronometer {
|
||||||
|
public:
|
||||||
|
template <typename Fun>
|
||||||
|
void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable<Fun(int)>()); }
|
||||||
|
|
||||||
|
int runs() const { return repeats; }
|
||||||
|
|
||||||
|
Chronometer(Detail::ChronometerConcept& meter, int repeats_)
|
||||||
|
: impl(&meter)
|
||||||
|
, repeats(repeats_) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename Fun>
|
||||||
|
void measure(Fun&& fun, std::false_type) {
|
||||||
|
measure([&fun](int) { return fun(); }, std::true_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Fun>
|
||||||
|
void measure(Fun&& fun, std::true_type) {
|
||||||
|
Detail::optimizer_barrier();
|
||||||
|
impl->start();
|
||||||
|
for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i);
|
||||||
|
impl->finish();
|
||||||
|
Detail::optimizer_barrier();
|
||||||
|
}
|
||||||
|
|
||||||
|
Detail::ChronometerConcept* impl;
|
||||||
|
int repeats;
|
||||||
|
};
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_CHRONOMETER_HPP_INCLUDED
|
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_CLOCK_HPP_INCLUDED
|
||||||
|
#define CATCH_CLOCK_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <ratio>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
template <typename Clock>
|
||||||
|
using ClockDuration = typename Clock::duration;
|
||||||
|
template <typename Clock>
|
||||||
|
using FloatDuration = std::chrono::duration<double, typename Clock::period>;
|
||||||
|
|
||||||
|
template <typename Clock>
|
||||||
|
using TimePoint = typename Clock::time_point;
|
||||||
|
|
||||||
|
using default_clock = std::chrono::steady_clock;
|
||||||
|
|
||||||
|
template <typename Clock>
|
||||||
|
struct now {
|
||||||
|
TimePoint<Clock> operator()() const {
|
||||||
|
return Clock::now();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using fp_seconds = std::chrono::duration<double, std::ratio<1>>;
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_CLOCK_HPP_INCLUDED
|
@ -0,0 +1,82 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_CONSTRUCTOR_HPP_INCLUDED
|
||||||
|
#define CATCH_CONSTRUCTOR_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
template <typename T, bool Destruct>
|
||||||
|
struct ObjectStorage
|
||||||
|
{
|
||||||
|
ObjectStorage() = default;
|
||||||
|
|
||||||
|
ObjectStorage(const ObjectStorage& other)
|
||||||
|
{
|
||||||
|
new(&data) T(other.stored_object());
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectStorage(ObjectStorage&& other)
|
||||||
|
{
|
||||||
|
new(data) T(CATCH_MOVE(other.stored_object()));
|
||||||
|
}
|
||||||
|
|
||||||
|
~ObjectStorage() { destruct_on_exit<T>(); }
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void construct(Args&&... args)
|
||||||
|
{
|
||||||
|
new (data) T(CATCH_FORWARD(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool AllowManualDestruction = !Destruct>
|
||||||
|
std::enable_if_t<AllowManualDestruction> destruct()
|
||||||
|
{
|
||||||
|
stored_object().~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// If this is a constructor benchmark, destruct the underlying object
|
||||||
|
template <typename U>
|
||||||
|
void destruct_on_exit(std::enable_if_t<Destruct, U>* = nullptr) { destruct<true>(); }
|
||||||
|
// Otherwise, don't
|
||||||
|
template <typename U>
|
||||||
|
void destruct_on_exit(std::enable_if_t<!Destruct, U>* = nullptr) { }
|
||||||
|
|
||||||
|
#if defined( __GNUC__ ) && __GNUC__ <= 6
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||||
|
#endif
|
||||||
|
T& stored_object() { return *reinterpret_cast<T*>( data ); }
|
||||||
|
|
||||||
|
T const& stored_object() const {
|
||||||
|
return *reinterpret_cast<T const*>( data );
|
||||||
|
}
|
||||||
|
#if defined( __GNUC__ ) && __GNUC__ <= 6
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
alignas( T ) unsigned char data[sizeof( T )]{};
|
||||||
|
};
|
||||||
|
} // namespace Detail
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using storage_for = Detail::ObjectStorage<T, true>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using destructable_object = Detail::ObjectStorage<T, false>;
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_CONSTRUCTOR_HPP_INCLUDED
|
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED
|
||||||
|
#define CATCH_ENVIRONMENT_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/benchmark/catch_clock.hpp>
|
||||||
|
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
template <typename Duration>
|
||||||
|
struct EnvironmentEstimate {
|
||||||
|
Duration mean;
|
||||||
|
OutlierClassification outliers;
|
||||||
|
|
||||||
|
template <typename Duration2>
|
||||||
|
operator EnvironmentEstimate<Duration2>() const {
|
||||||
|
return { mean, outliers };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <typename Clock>
|
||||||
|
struct Environment {
|
||||||
|
using clock_type = Clock;
|
||||||
|
EnvironmentEstimate<FloatDuration<Clock>> clock_resolution;
|
||||||
|
EnvironmentEstimate<FloatDuration<Clock>> clock_cost;
|
||||||
|
};
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_ENVIRONMENT_HPP_INCLUDED
|
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_ESTIMATE_HPP_INCLUDED
|
||||||
|
#define CATCH_ESTIMATE_HPP_INCLUDED
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
template <typename Duration>
|
||||||
|
struct Estimate {
|
||||||
|
Duration point;
|
||||||
|
Duration lower_bound;
|
||||||
|
Duration upper_bound;
|
||||||
|
double confidence_interval;
|
||||||
|
|
||||||
|
template <typename Duration2>
|
||||||
|
operator Estimate<Duration2>() const {
|
||||||
|
return { point, lower_bound, upper_bound, confidence_interval };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_ESTIMATE_HPP_INCLUDED
|
@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED
|
||||||
|
#define CATCH_EXECUTION_PLAN_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||||
|
#include <catch2/benchmark/catch_clock.hpp>
|
||||||
|
#include <catch2/benchmark/catch_environment.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_repeat.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
template <typename Duration>
|
||||||
|
struct ExecutionPlan {
|
||||||
|
int iterations_per_sample;
|
||||||
|
Duration estimated_duration;
|
||||||
|
Detail::BenchmarkFunction benchmark;
|
||||||
|
Duration warmup_time;
|
||||||
|
int warmup_iterations;
|
||||||
|
|
||||||
|
template <typename Duration2>
|
||||||
|
operator ExecutionPlan<Duration2>() const {
|
||||||
|
return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Clock>
|
||||||
|
std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
|
||||||
|
// warmup a bit
|
||||||
|
Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{}));
|
||||||
|
|
||||||
|
std::vector<FloatDuration<Clock>> times;
|
||||||
|
const auto num_samples = cfg.benchmarkSamples();
|
||||||
|
times.reserve( num_samples );
|
||||||
|
for ( size_t i = 0; i < num_samples; ++i ) {
|
||||||
|
Detail::ChronometerModel<Clock> model;
|
||||||
|
this->benchmark( Chronometer( model, iterations_per_sample ) );
|
||||||
|
auto sample_time = model.elapsed() - env.clock_cost.mean;
|
||||||
|
if ( sample_time < FloatDuration<Clock>::zero() ) {
|
||||||
|
sample_time = FloatDuration<Clock>::zero();
|
||||||
|
}
|
||||||
|
times.push_back(sample_time / iterations_per_sample);
|
||||||
|
}
|
||||||
|
return times;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_EXECUTION_PLAN_HPP_INCLUDED
|
@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_OPTIMIZER_HPP_INCLUDED
|
||||||
|
#define CATCH_OPTIMIZER_HPP_INCLUDED
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__)
|
||||||
|
# include <atomic> // atomic_thread_fence
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
template <typename T>
|
||||||
|
inline void keep_memory(T* p) {
|
||||||
|
asm volatile("" : : "g"(p) : "memory");
|
||||||
|
}
|
||||||
|
inline void keep_memory() {
|
||||||
|
asm volatile("" : : : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
inline void optimizer_barrier() { keep_memory(); }
|
||||||
|
} // namespace Detail
|
||||||
|
#elif defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__)
|
||||||
|
|
||||||
|
#if defined(_MSVC_VER)
|
||||||
|
#pragma optimize("", off)
|
||||||
|
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||||
|
// For IAR the pragma only affects the following function
|
||||||
|
#pragma optimize=disable
|
||||||
|
#endif
|
||||||
|
template <typename T>
|
||||||
|
inline void keep_memory(T* p) {
|
||||||
|
// thanks @milleniumbug
|
||||||
|
*reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
|
||||||
|
}
|
||||||
|
// TODO equivalent keep_memory()
|
||||||
|
#if defined(_MSVC_VER)
|
||||||
|
#pragma optimize("", on)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
inline void optimizer_barrier() {
|
||||||
|
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||||
|
}
|
||||||
|
} // namespace Detail
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void deoptimize_value(T&& x) {
|
||||||
|
keep_memory(&x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Fn, typename... Args>
|
||||||
|
inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t<!std::is_same<void, decltype(fn(args...))>::value> {
|
||||||
|
deoptimize_value(CATCH_FORWARD(fn) (CATCH_FORWARD(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Fn, typename... Args>
|
||||||
|
inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t<std::is_same<void, decltype(fn(args...))>::value> {
|
||||||
|
CATCH_FORWARD(fn) (CATCH_FORWARD(args)...);
|
||||||
|
}
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_OPTIMIZER_HPP_INCLUDED
|
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED
|
||||||
|
#define CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
struct OutlierClassification {
|
||||||
|
int samples_seen = 0;
|
||||||
|
int low_severe = 0; // more than 3 times IQR below Q1
|
||||||
|
int low_mild = 0; // 1.5 to 3 times IQR below Q1
|
||||||
|
int high_mild = 0; // 1.5 to 3 times IQR above Q3
|
||||||
|
int high_severe = 0; // more than 3 times IQR above Q3
|
||||||
|
|
||||||
|
int total() const {
|
||||||
|
return low_severe + low_mild + high_mild + high_severe;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED
|
@ -0,0 +1,48 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
|
||||||
|
#define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/benchmark/catch_estimate.hpp>
|
||||||
|
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
template <typename Duration>
|
||||||
|
struct SampleAnalysis {
|
||||||
|
std::vector<Duration> samples;
|
||||||
|
Estimate<Duration> mean;
|
||||||
|
Estimate<Duration> standard_deviation;
|
||||||
|
OutlierClassification outliers;
|
||||||
|
double outlier_variance;
|
||||||
|
|
||||||
|
template <typename Duration2>
|
||||||
|
operator SampleAnalysis<Duration2>() const {
|
||||||
|
std::vector<Duration2> samples2;
|
||||||
|
samples2.reserve(samples.size());
|
||||||
|
for (auto const& d : samples) {
|
||||||
|
samples2.push_back(Duration2(d));
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
CATCH_MOVE(samples2),
|
||||||
|
mean,
|
||||||
|
standard_deviation,
|
||||||
|
outliers,
|
||||||
|
outlier_variance,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
|
@ -0,0 +1,82 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_ANALYSE_HPP_INCLUDED
|
||||||
|
#define CATCH_ANALYSE_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/benchmark/catch_environment.hpp>
|
||||||
|
#include <catch2/benchmark/catch_sample_analysis.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_stats.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
template <typename Duration, typename Iterator>
|
||||||
|
SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) {
|
||||||
|
if (!cfg.benchmarkNoAnalysis()) {
|
||||||
|
std::vector<double> samples;
|
||||||
|
samples.reserve(static_cast<size_t>(last - first));
|
||||||
|
for (auto current = first; current != last; ++current) {
|
||||||
|
samples.push_back( current->count() );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end());
|
||||||
|
auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end());
|
||||||
|
|
||||||
|
auto wrap_estimate = [](Estimate<double> e) {
|
||||||
|
return Estimate<Duration> {
|
||||||
|
Duration(e.point),
|
||||||
|
Duration(e.lower_bound),
|
||||||
|
Duration(e.upper_bound),
|
||||||
|
e.confidence_interval,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
std::vector<Duration> samples2;
|
||||||
|
samples2.reserve(samples.size());
|
||||||
|
for (auto s : samples) {
|
||||||
|
samples2.push_back( Duration( s ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
CATCH_MOVE(samples2),
|
||||||
|
wrap_estimate(analysis.mean),
|
||||||
|
wrap_estimate(analysis.standard_deviation),
|
||||||
|
outliers,
|
||||||
|
analysis.outlier_variance,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
std::vector<Duration> samples;
|
||||||
|
samples.reserve(static_cast<size_t>(last - first));
|
||||||
|
|
||||||
|
Duration mean = Duration(0);
|
||||||
|
int i = 0;
|
||||||
|
for (auto it = first; it < last; ++it, ++i) {
|
||||||
|
samples.push_back(Duration(*it));
|
||||||
|
mean += Duration(*it);
|
||||||
|
}
|
||||||
|
mean /= i;
|
||||||
|
|
||||||
|
return {
|
||||||
|
CATCH_MOVE(samples),
|
||||||
|
Estimate<Duration>{mean, mean, mean, 0.0},
|
||||||
|
Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0},
|
||||||
|
OutlierClassification{},
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_ANALYSE_HPP_INCLUDED
|
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
BenchmarkFunction::callable::~callable() = default;
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
|
||||||
|
#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||||
|
#include <catch2/internal/catch_meta.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
template <typename T, typename U>
|
||||||
|
struct is_related
|
||||||
|
: std::is_same<std::decay_t<T>, std::decay_t<U>> {};
|
||||||
|
|
||||||
|
/// We need to reinvent std::function because every piece of code that might add overhead
|
||||||
|
/// in a measurement context needs to have consistent performance characteristics so that we
|
||||||
|
/// can account for it in the measurement.
|
||||||
|
/// Implementations of std::function with optimizations that aren't always applicable, like
|
||||||
|
/// small buffer optimizations, are not uncommon.
|
||||||
|
/// This is effectively an implementation of std::function without any such optimizations;
|
||||||
|
/// it may be slow, but it is consistently slow.
|
||||||
|
struct BenchmarkFunction {
|
||||||
|
private:
|
||||||
|
struct callable {
|
||||||
|
virtual void call(Chronometer meter) const = 0;
|
||||||
|
virtual Catch::Detail::unique_ptr<callable> clone() const = 0;
|
||||||
|
virtual ~callable(); // = default;
|
||||||
|
|
||||||
|
callable() = default;
|
||||||
|
callable(callable const&) = default;
|
||||||
|
callable& operator=(callable const&) = default;
|
||||||
|
};
|
||||||
|
template <typename Fun>
|
||||||
|
struct model : public callable {
|
||||||
|
model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {}
|
||||||
|
model(Fun const& fun_) : fun(fun_) {}
|
||||||
|
|
||||||
|
Catch::Detail::unique_ptr<callable> clone() const override {
|
||||||
|
return Catch::Detail::make_unique<model<Fun>>( *this );
|
||||||
|
}
|
||||||
|
|
||||||
|
void call(Chronometer meter) const override {
|
||||||
|
call(meter, is_callable<Fun(Chronometer)>());
|
||||||
|
}
|
||||||
|
void call(Chronometer meter, std::true_type) const {
|
||||||
|
fun(meter);
|
||||||
|
}
|
||||||
|
void call(Chronometer meter, std::false_type) const {
|
||||||
|
meter.measure(fun);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fun fun;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct do_nothing { void operator()() const {} };
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
BenchmarkFunction(model<T>* c) : f(c) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
BenchmarkFunction()
|
||||||
|
: f(new model<do_nothing>{ {} }) {}
|
||||||
|
|
||||||
|
template <typename Fun,
|
||||||
|
std::enable_if_t<!is_related<Fun, BenchmarkFunction>::value, int> = 0>
|
||||||
|
BenchmarkFunction(Fun&& fun)
|
||||||
|
: f(new model<std::decay_t<Fun>>(CATCH_FORWARD(fun))) {}
|
||||||
|
|
||||||
|
BenchmarkFunction( BenchmarkFunction&& that ) noexcept:
|
||||||
|
f( CATCH_MOVE( that.f ) ) {}
|
||||||
|
|
||||||
|
BenchmarkFunction(BenchmarkFunction const& that)
|
||||||
|
: f(that.f->clone()) {}
|
||||||
|
|
||||||
|
BenchmarkFunction&
|
||||||
|
operator=( BenchmarkFunction&& that ) noexcept {
|
||||||
|
f = CATCH_MOVE( that.f );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BenchmarkFunction& operator=(BenchmarkFunction const& that) {
|
||||||
|
f = that.f->clone();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(Chronometer meter) const { f->call(meter); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Catch::Detail::unique_ptr<callable> f;
|
||||||
|
};
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
|
@ -0,0 +1,64 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_BENCHMARK_STATS_HPP_INCLUDED
|
||||||
|
#define CATCH_BENCHMARK_STATS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
#include <catch2/benchmark/catch_estimate.hpp>
|
||||||
|
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||||
|
// The fwd decl & default specialization needs to be seen by VS2017 before
|
||||||
|
// BenchmarkStats itself, or VS2017 will report compilation error.
|
||||||
|
#include <catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct BenchmarkInfo {
|
||||||
|
std::string name;
|
||||||
|
double estimatedDuration;
|
||||||
|
int iterations;
|
||||||
|
unsigned int samples;
|
||||||
|
unsigned int resamples;
|
||||||
|
double clockResolution;
|
||||||
|
double clockCost;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Duration>
|
||||||
|
struct BenchmarkStats {
|
||||||
|
BenchmarkInfo info;
|
||||||
|
|
||||||
|
std::vector<Duration> samples;
|
||||||
|
Benchmark::Estimate<Duration> mean;
|
||||||
|
Benchmark::Estimate<Duration> standardDeviation;
|
||||||
|
Benchmark::OutlierClassification outliers;
|
||||||
|
double outlierVariance;
|
||||||
|
|
||||||
|
template <typename Duration2>
|
||||||
|
operator BenchmarkStats<Duration2>() const {
|
||||||
|
std::vector<Duration2> samples2;
|
||||||
|
samples2.reserve(samples.size());
|
||||||
|
for (auto const& sample : samples) {
|
||||||
|
samples2.push_back(Duration2(sample));
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
info,
|
||||||
|
CATCH_MOVE(samples2),
|
||||||
|
mean,
|
||||||
|
standardDeviation,
|
||||||
|
outliers,
|
||||||
|
outlierVariance,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_BENCHMARK_STATS_HPP_INCLUDED
|
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
|
||||||
|
#define CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
// We cannot forward declare the type with default template argument
|
||||||
|
// multiple times, so it is split out into a separate header so that
|
||||||
|
// we can prevent multiple declarations in dependees
|
||||||
|
template <typename Duration = std::chrono::duration<double, std::nano>>
|
||||||
|
struct BenchmarkStats;
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
|
@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED
|
||||||
|
#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_meta.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
template <typename T>
|
||||||
|
struct CompleteType { using type = T; };
|
||||||
|
template <>
|
||||||
|
struct CompleteType<void> { struct type {}; };
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using CompleteType_t = typename CompleteType<T>::type;
|
||||||
|
|
||||||
|
template <typename Result>
|
||||||
|
struct CompleteInvoker {
|
||||||
|
template <typename Fun, typename... Args>
|
||||||
|
static Result invoke(Fun&& fun, Args&&... args) {
|
||||||
|
return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct CompleteInvoker<void> {
|
||||||
|
template <typename Fun, typename... Args>
|
||||||
|
static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {
|
||||||
|
CATCH_FORWARD(fun)(CATCH_FORWARD(args)...);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// invoke and not return void :(
|
||||||
|
template <typename Fun, typename... Args>
|
||||||
|
CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {
|
||||||
|
return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Detail
|
||||||
|
|
||||||
|
template <typename Fun>
|
||||||
|
Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {
|
||||||
|
return Detail::complete_invoke(CATCH_FORWARD(fun));
|
||||||
|
}
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED
|
@ -0,0 +1,125 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
|
||||||
|
#define CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/benchmark/catch_clock.hpp>
|
||||||
|
#include <catch2/benchmark/catch_environment.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_stats.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_measure.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||||
|
#include <catch2/benchmark/catch_clock.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
template <typename Clock>
|
||||||
|
std::vector<double> resolution(int k) {
|
||||||
|
std::vector<TimePoint<Clock>> times;
|
||||||
|
times.reserve(static_cast<size_t>(k + 1));
|
||||||
|
for ( int i = 0; i < k + 1; ++i ) {
|
||||||
|
times.push_back( Clock::now() );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> deltas;
|
||||||
|
deltas.reserve(static_cast<size_t>(k));
|
||||||
|
for ( size_t idx = 1; idx < times.size(); ++idx ) {
|
||||||
|
deltas.push_back( static_cast<double>(
|
||||||
|
( times[idx] - times[idx - 1] ).count() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return deltas;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto warmup_iterations = 10000;
|
||||||
|
constexpr auto warmup_time = std::chrono::milliseconds(100);
|
||||||
|
constexpr auto minimum_ticks = 1000;
|
||||||
|
constexpr auto warmup_seed = 10000;
|
||||||
|
constexpr auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
|
||||||
|
constexpr auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
|
||||||
|
constexpr auto clock_cost_estimation_tick_limit = 100000;
|
||||||
|
constexpr auto clock_cost_estimation_time = std::chrono::milliseconds(10);
|
||||||
|
constexpr auto clock_cost_estimation_iterations = 10000;
|
||||||
|
|
||||||
|
template <typename Clock>
|
||||||
|
int warmup() {
|
||||||
|
return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>)
|
||||||
|
.iterations;
|
||||||
|
}
|
||||||
|
template <typename Clock>
|
||||||
|
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) {
|
||||||
|
auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>)
|
||||||
|
.result;
|
||||||
|
return {
|
||||||
|
FloatDuration<Clock>(mean(r.begin(), r.end())),
|
||||||
|
classify_outliers(r.begin(), r.end()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
template <typename Clock>
|
||||||
|
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
|
||||||
|
auto time_limit = (std::min)(
|
||||||
|
resolution * clock_cost_estimation_tick_limit,
|
||||||
|
FloatDuration<Clock>(clock_cost_estimation_time_limit));
|
||||||
|
auto time_clock = [](int k) {
|
||||||
|
return Detail::measure<Clock>([k] {
|
||||||
|
for (int i = 0; i < k; ++i) {
|
||||||
|
volatile auto ignored = Clock::now();
|
||||||
|
(void)ignored;
|
||||||
|
}
|
||||||
|
}).elapsed;
|
||||||
|
};
|
||||||
|
time_clock(1);
|
||||||
|
int iters = clock_cost_estimation_iterations;
|
||||||
|
auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock);
|
||||||
|
std::vector<double> times;
|
||||||
|
int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
|
||||||
|
times.reserve(static_cast<size_t>(nsamples));
|
||||||
|
for ( int s = 0; s < nsamples; ++s ) {
|
||||||
|
times.push_back( static_cast<double>(
|
||||||
|
( time_clock( r.iterations ) / r.iterations )
|
||||||
|
.count() ) );
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
FloatDuration<Clock>(mean(times.begin(), times.end())),
|
||||||
|
classify_outliers(times.begin(), times.end()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Clock>
|
||||||
|
Environment<FloatDuration<Clock>> measure_environment() {
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||||
|
#endif
|
||||||
|
static Catch::Detail::unique_ptr<Environment<FloatDuration<Clock>>> env;
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
if (env) {
|
||||||
|
return *env;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto iters = Detail::warmup<Clock>();
|
||||||
|
auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
|
||||||
|
auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
|
||||||
|
|
||||||
|
env = Catch::Detail::make_unique<Environment<FloatDuration<Clock>>>( Environment<FloatDuration<Clock>>{resolution, cost} );
|
||||||
|
return *env;
|
||||||
|
}
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
|
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_MEASURE_HPP_INCLUDED
|
||||||
|
#define CATCH_MEASURE_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_timing.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
template <typename Clock, typename Fun, typename... Args>
|
||||||
|
TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) {
|
||||||
|
auto start = Clock::now();
|
||||||
|
auto&& r = Detail::complete_invoke(fun, CATCH_FORWARD(args)...);
|
||||||
|
auto end = Clock::now();
|
||||||
|
auto delta = end - start;
|
||||||
|
return { delta, CATCH_FORWARD(r), 1 };
|
||||||
|
}
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_MEASURE_HPP_INCLUDED
|
@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_REPEAT_HPP_INCLUDED
|
||||||
|
#define CATCH_REPEAT_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
template <typename Fun>
|
||||||
|
struct repeater {
|
||||||
|
void operator()(int k) const {
|
||||||
|
for (int i = 0; i < k; ++i) {
|
||||||
|
fun();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Fun fun;
|
||||||
|
};
|
||||||
|
template <typename Fun>
|
||||||
|
repeater<std::decay_t<Fun>> repeat(Fun&& fun) {
|
||||||
|
return { CATCH_FORWARD(fun) };
|
||||||
|
}
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_REPEAT_HPP_INCLUDED
|
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||||
|
#include <catch2/internal/catch_enforce.hpp>
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
struct optimized_away_error : std::exception {
|
||||||
|
const char* what() const noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* optimized_away_error::what() const noexcept {
|
||||||
|
return "could not measure benchmark, maybe it was optimized away";
|
||||||
|
}
|
||||||
|
|
||||||
|
void throw_optimized_away_error() {
|
||||||
|
Catch::throw_exception(optimized_away_error{});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
@ -0,0 +1,65 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
|
||||||
|
#define CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/benchmark/catch_clock.hpp>
|
||||||
|
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_measure.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_timing.hpp>
|
||||||
|
#include <catch2/internal/catch_meta.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
template <typename Clock, typename Fun>
|
||||||
|
TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {
|
||||||
|
return Detail::measure<Clock>(fun, iters);
|
||||||
|
}
|
||||||
|
template <typename Clock, typename Fun>
|
||||||
|
TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {
|
||||||
|
Detail::ChronometerModel<Clock> meter;
|
||||||
|
auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
|
||||||
|
|
||||||
|
return { meter.elapsed(), CATCH_MOVE(result), iters };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Clock, typename Fun>
|
||||||
|
using run_for_at_least_argument_t = std::conditional_t<is_callable<Fun(Chronometer)>::value, Chronometer, int>;
|
||||||
|
|
||||||
|
|
||||||
|
[[noreturn]]
|
||||||
|
void throw_optimized_away_error();
|
||||||
|
|
||||||
|
template <typename Clock, typename Fun>
|
||||||
|
TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>>
|
||||||
|
run_for_at_least(ClockDuration<Clock> how_long,
|
||||||
|
const int initial_iterations,
|
||||||
|
Fun&& fun) {
|
||||||
|
auto iters = initial_iterations;
|
||||||
|
while (iters < (1 << 30)) {
|
||||||
|
auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
|
||||||
|
|
||||||
|
if (Timing.elapsed >= how_long) {
|
||||||
|
return { Timing.elapsed, CATCH_MOVE(Timing.result), iters };
|
||||||
|
}
|
||||||
|
iters *= 2;
|
||||||
|
}
|
||||||
|
throw_optimized_away_error();
|
||||||
|
}
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
|
@ -0,0 +1,330 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#include <catch2/benchmark/detail/catch_stats.hpp>
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <numeric>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_USE_ASYNC)
|
||||||
|
#include <future>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <typename URng, typename Estimator>
|
||||||
|
static sample
|
||||||
|
resample( URng& rng,
|
||||||
|
unsigned int resamples,
|
||||||
|
std::vector<double>::const_iterator first,
|
||||||
|
std::vector<double>::const_iterator last,
|
||||||
|
Estimator& estimator ) {
|
||||||
|
auto n = static_cast<size_t>( last - first );
|
||||||
|
std::uniform_int_distribution<decltype( n )> dist( 0,
|
||||||
|
n - 1 );
|
||||||
|
|
||||||
|
sample out;
|
||||||
|
out.reserve( resamples );
|
||||||
|
// We allocate the vector outside the loop to avoid realloc
|
||||||
|
// per resample
|
||||||
|
std::vector<double> resampled;
|
||||||
|
resampled.reserve( n );
|
||||||
|
for ( size_t i = 0; i < resamples; ++i ) {
|
||||||
|
resampled.clear();
|
||||||
|
for ( size_t s = 0; s < n; ++s ) {
|
||||||
|
resampled.push_back(
|
||||||
|
first[static_cast<std::ptrdiff_t>(
|
||||||
|
dist( rng ) )] );
|
||||||
|
}
|
||||||
|
const auto estimate =
|
||||||
|
estimator( resampled.begin(), resampled.end() );
|
||||||
|
out.push_back( estimate );
|
||||||
|
}
|
||||||
|
std::sort( out.begin(), out.end() );
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double outlier_variance( Estimate<double> mean,
|
||||||
|
Estimate<double> stddev,
|
||||||
|
int n ) {
|
||||||
|
double sb = stddev.point;
|
||||||
|
double mn = mean.point / n;
|
||||||
|
double mg_min = mn / 2.;
|
||||||
|
double sg = (std::min)( mg_min / 4., sb / std::sqrt( n ) );
|
||||||
|
double sg2 = sg * sg;
|
||||||
|
double sb2 = sb * sb;
|
||||||
|
|
||||||
|
auto c_max = [n, mn, sb2, sg2]( double x ) -> double {
|
||||||
|
double k = mn - x;
|
||||||
|
double d = k * k;
|
||||||
|
double nd = n * d;
|
||||||
|
double k0 = -n * nd;
|
||||||
|
double k1 = sb2 - n * sg2 + nd;
|
||||||
|
double det = k1 * k1 - 4 * sg2 * k0;
|
||||||
|
return static_cast<int>( -2. * k0 /
|
||||||
|
( k1 + std::sqrt( det ) ) );
|
||||||
|
};
|
||||||
|
|
||||||
|
auto var_out = [n, sb2, sg2]( double c ) {
|
||||||
|
double nc = n - c;
|
||||||
|
return ( nc / n ) * ( sb2 - nc * sg2 );
|
||||||
|
};
|
||||||
|
|
||||||
|
return (std::min)( var_out( 1 ),
|
||||||
|
var_out(
|
||||||
|
(std::min)( c_max( 0. ),
|
||||||
|
c_max( mg_min ) ) ) ) /
|
||||||
|
sb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double erf_inv( double x ) {
|
||||||
|
// Code accompanying the article "Approximating the erfinv
|
||||||
|
// function" in GPU Computing Gems, Volume 2
|
||||||
|
double w, p;
|
||||||
|
|
||||||
|
w = -log( ( 1.0 - x ) * ( 1.0 + x ) );
|
||||||
|
|
||||||
|
if ( w < 6.250000 ) {
|
||||||
|
w = w - 3.125000;
|
||||||
|
p = -3.6444120640178196996e-21;
|
||||||
|
p = -1.685059138182016589e-19 + p * w;
|
||||||
|
p = 1.2858480715256400167e-18 + p * w;
|
||||||
|
p = 1.115787767802518096e-17 + p * w;
|
||||||
|
p = -1.333171662854620906e-16 + p * w;
|
||||||
|
p = 2.0972767875968561637e-17 + p * w;
|
||||||
|
p = 6.6376381343583238325e-15 + p * w;
|
||||||
|
p = -4.0545662729752068639e-14 + p * w;
|
||||||
|
p = -8.1519341976054721522e-14 + p * w;
|
||||||
|
p = 2.6335093153082322977e-12 + p * w;
|
||||||
|
p = -1.2975133253453532498e-11 + p * w;
|
||||||
|
p = -5.4154120542946279317e-11 + p * w;
|
||||||
|
p = 1.051212273321532285e-09 + p * w;
|
||||||
|
p = -4.1126339803469836976e-09 + p * w;
|
||||||
|
p = -2.9070369957882005086e-08 + p * w;
|
||||||
|
p = 4.2347877827932403518e-07 + p * w;
|
||||||
|
p = -1.3654692000834678645e-06 + p * w;
|
||||||
|
p = -1.3882523362786468719e-05 + p * w;
|
||||||
|
p = 0.0001867342080340571352 + p * w;
|
||||||
|
p = -0.00074070253416626697512 + p * w;
|
||||||
|
p = -0.0060336708714301490533 + p * w;
|
||||||
|
p = 0.24015818242558961693 + p * w;
|
||||||
|
p = 1.6536545626831027356 + p * w;
|
||||||
|
} else if ( w < 16.000000 ) {
|
||||||
|
w = sqrt( w ) - 3.250000;
|
||||||
|
p = 2.2137376921775787049e-09;
|
||||||
|
p = 9.0756561938885390979e-08 + p * w;
|
||||||
|
p = -2.7517406297064545428e-07 + p * w;
|
||||||
|
p = 1.8239629214389227755e-08 + p * w;
|
||||||
|
p = 1.5027403968909827627e-06 + p * w;
|
||||||
|
p = -4.013867526981545969e-06 + p * w;
|
||||||
|
p = 2.9234449089955446044e-06 + p * w;
|
||||||
|
p = 1.2475304481671778723e-05 + p * w;
|
||||||
|
p = -4.7318229009055733981e-05 + p * w;
|
||||||
|
p = 6.8284851459573175448e-05 + p * w;
|
||||||
|
p = 2.4031110387097893999e-05 + p * w;
|
||||||
|
p = -0.0003550375203628474796 + p * w;
|
||||||
|
p = 0.00095328937973738049703 + p * w;
|
||||||
|
p = -0.0016882755560235047313 + p * w;
|
||||||
|
p = 0.0024914420961078508066 + p * w;
|
||||||
|
p = -0.0037512085075692412107 + p * w;
|
||||||
|
p = 0.005370914553590063617 + p * w;
|
||||||
|
p = 1.0052589676941592334 + p * w;
|
||||||
|
p = 3.0838856104922207635 + p * w;
|
||||||
|
} else {
|
||||||
|
w = sqrt( w ) - 5.000000;
|
||||||
|
p = -2.7109920616438573243e-11;
|
||||||
|
p = -2.5556418169965252055e-10 + p * w;
|
||||||
|
p = 1.5076572693500548083e-09 + p * w;
|
||||||
|
p = -3.7894654401267369937e-09 + p * w;
|
||||||
|
p = 7.6157012080783393804e-09 + p * w;
|
||||||
|
p = -1.4960026627149240478e-08 + p * w;
|
||||||
|
p = 2.9147953450901080826e-08 + p * w;
|
||||||
|
p = -6.7711997758452339498e-08 + p * w;
|
||||||
|
p = 2.2900482228026654717e-07 + p * w;
|
||||||
|
p = -9.9298272942317002539e-07 + p * w;
|
||||||
|
p = 4.5260625972231537039e-06 + p * w;
|
||||||
|
p = -1.9681778105531670567e-05 + p * w;
|
||||||
|
p = 7.5995277030017761139e-05 + p * w;
|
||||||
|
p = -0.00021503011930044477347 + p * w;
|
||||||
|
p = -0.00013871931833623122026 + p * w;
|
||||||
|
p = 1.0103004648645343977 + p * w;
|
||||||
|
p = 4.8499064014085844221 + p * w;
|
||||||
|
}
|
||||||
|
return p * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
standard_deviation( std::vector<double>::const_iterator first,
|
||||||
|
std::vector<double>::const_iterator last ) {
|
||||||
|
auto m = Catch::Benchmark::Detail::mean( first, last );
|
||||||
|
double variance =
|
||||||
|
std::accumulate( first,
|
||||||
|
last,
|
||||||
|
0.,
|
||||||
|
[m]( double a, double b ) {
|
||||||
|
double diff = b - m;
|
||||||
|
return a + diff * diff;
|
||||||
|
} ) /
|
||||||
|
( last - first );
|
||||||
|
return std::sqrt( variance );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
|
||||||
|
#if defined( __GNUC__ ) || defined( __clang__ )
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||||
|
#endif
|
||||||
|
bool directCompare( double lhs, double rhs ) { return lhs == rhs; }
|
||||||
|
#if defined( __GNUC__ ) || defined( __clang__ )
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) {
|
||||||
|
auto count = last - first;
|
||||||
|
double idx = (count - 1) * k / static_cast<double>(q);
|
||||||
|
int j = static_cast<int>(idx);
|
||||||
|
double g = idx - j;
|
||||||
|
std::nth_element(first, first + j, last);
|
||||||
|
auto xj = first[j];
|
||||||
|
if ( directCompare( g, 0 ) ) {
|
||||||
|
return xj;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto xj1 = *std::min_element(first + (j + 1), last);
|
||||||
|
return xj + g * (xj1 - xj);
|
||||||
|
}
|
||||||
|
|
||||||
|
OutlierClassification
|
||||||
|
classify_outliers( std::vector<double>::const_iterator first,
|
||||||
|
std::vector<double>::const_iterator last ) {
|
||||||
|
std::vector<double> copy( first, last );
|
||||||
|
|
||||||
|
auto q1 = weighted_average_quantile( 1, 4, copy.begin(), copy.end() );
|
||||||
|
auto q3 = weighted_average_quantile( 3, 4, copy.begin(), copy.end() );
|
||||||
|
auto iqr = q3 - q1;
|
||||||
|
auto los = q1 - ( iqr * 3. );
|
||||||
|
auto lom = q1 - ( iqr * 1.5 );
|
||||||
|
auto him = q3 + ( iqr * 1.5 );
|
||||||
|
auto his = q3 + ( iqr * 3. );
|
||||||
|
|
||||||
|
OutlierClassification o;
|
||||||
|
for ( ; first != last; ++first ) {
|
||||||
|
const double t = *first;
|
||||||
|
if ( t < los ) {
|
||||||
|
++o.low_severe;
|
||||||
|
} else if ( t < lom ) {
|
||||||
|
++o.low_mild;
|
||||||
|
} else if ( t > his ) {
|
||||||
|
++o.high_severe;
|
||||||
|
} else if ( t > him ) {
|
||||||
|
++o.high_mild;
|
||||||
|
}
|
||||||
|
++o.samples_seen;
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
double mean( std::vector<double>::const_iterator first,
|
||||||
|
std::vector<double>::const_iterator last ) {
|
||||||
|
auto count = last - first;
|
||||||
|
double sum = 0.;
|
||||||
|
while (first != last) {
|
||||||
|
sum += *first;
|
||||||
|
++first;
|
||||||
|
}
|
||||||
|
return sum / static_cast<double>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double erfc_inv(double x) {
|
||||||
|
return erf_inv(1.0 - x);
|
||||||
|
}
|
||||||
|
|
||||||
|
double normal_quantile(double p) {
|
||||||
|
static const double ROOT_TWO = std::sqrt(2.0);
|
||||||
|
|
||||||
|
double result = 0.0;
|
||||||
|
assert(p >= 0 && p <= 1);
|
||||||
|
if (p < 0 || p > 1) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = -erfc_inv(2.0 * p);
|
||||||
|
// result *= normal distribution standard deviation (1.0) * sqrt(2)
|
||||||
|
result *= /*sd * */ ROOT_TWO;
|
||||||
|
// result += normal disttribution mean (0)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrap_analysis analyse_samples(double confidence_level,
|
||||||
|
unsigned int n_resamples,
|
||||||
|
std::vector<double>::iterator first,
|
||||||
|
std::vector<double>::iterator last) {
|
||||||
|
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
|
||||||
|
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||||
|
static std::random_device entropy;
|
||||||
|
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||||
|
|
||||||
|
auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
|
||||||
|
|
||||||
|
auto mean = &Detail::mean;
|
||||||
|
auto stddev = &standard_deviation;
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_USE_ASYNC)
|
||||||
|
auto Estimate = [=](double(*f)(std::vector<double>::const_iterator,
|
||||||
|
std::vector<double>::const_iterator)) {
|
||||||
|
auto seed = entropy();
|
||||||
|
return std::async(std::launch::async, [=] {
|
||||||
|
std::mt19937 rng(seed);
|
||||||
|
auto resampled = resample(rng, n_resamples, first, last, f);
|
||||||
|
return bootstrap(confidence_level, first, last, resampled, f);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
auto mean_future = Estimate(mean);
|
||||||
|
auto stddev_future = Estimate(stddev);
|
||||||
|
|
||||||
|
auto mean_estimate = mean_future.get();
|
||||||
|
auto stddev_estimate = stddev_future.get();
|
||||||
|
#else
|
||||||
|
auto Estimate = [=](double(*f)(std::vector<double>::const_iterator,
|
||||||
|
std::vector<double>::const_iterator)) {
|
||||||
|
auto seed = entropy();
|
||||||
|
std::mt19937 rng(seed);
|
||||||
|
auto resampled = resample(rng, n_resamples, first, last, f);
|
||||||
|
return bootstrap(confidence_level, first, last, resampled, f);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto mean_estimate = Estimate(mean);
|
||||||
|
auto stddev_estimate = Estimate(stddev);
|
||||||
|
#endif // CATCH_USE_ASYNC
|
||||||
|
|
||||||
|
double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
|
||||||
|
|
||||||
|
return { mean_estimate, stddev_estimate, outlier_variance };
|
||||||
|
}
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
@ -0,0 +1,125 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_STATS_HPP_INCLUDED
|
||||||
|
#define CATCH_STATS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/benchmark/catch_estimate.hpp>
|
||||||
|
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
namespace Detail {
|
||||||
|
using sample = std::vector<double>;
|
||||||
|
|
||||||
|
// Used when we know we want == comparison of two doubles
|
||||||
|
// to centralize warning suppression
|
||||||
|
bool directCompare( double lhs, double rhs );
|
||||||
|
|
||||||
|
double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);
|
||||||
|
|
||||||
|
OutlierClassification
|
||||||
|
classify_outliers( std::vector<double>::const_iterator first,
|
||||||
|
std::vector<double>::const_iterator last );
|
||||||
|
|
||||||
|
double mean( std::vector<double>::const_iterator first,
|
||||||
|
std::vector<double>::const_iterator last );
|
||||||
|
|
||||||
|
template <typename Estimator>
|
||||||
|
sample jackknife(Estimator&& estimator,
|
||||||
|
std::vector<double>::iterator first,
|
||||||
|
std::vector<double>::iterator last) {
|
||||||
|
auto n = static_cast<size_t>(last - first);
|
||||||
|
auto second = first;
|
||||||
|
++second;
|
||||||
|
sample results;
|
||||||
|
results.reserve(n);
|
||||||
|
|
||||||
|
for (auto it = first; it != last; ++it) {
|
||||||
|
std::iter_swap(it, first);
|
||||||
|
results.push_back(estimator(second, last));
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double normal_cdf(double x) {
|
||||||
|
return std::erfc(-x / std::sqrt(2.0)) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double erfc_inv(double x);
|
||||||
|
|
||||||
|
double normal_quantile(double p);
|
||||||
|
|
||||||
|
template <typename Estimator>
|
||||||
|
Estimate<double> bootstrap( double confidence_level,
|
||||||
|
std::vector<double>::iterator first,
|
||||||
|
std::vector<double>::iterator last,
|
||||||
|
sample const& resample,
|
||||||
|
Estimator&& estimator ) {
|
||||||
|
auto n_samples = last - first;
|
||||||
|
|
||||||
|
double point = estimator(first, last);
|
||||||
|
// Degenerate case with a single sample
|
||||||
|
if (n_samples == 1) return { point, point, point, confidence_level };
|
||||||
|
|
||||||
|
sample jack = jackknife(estimator, first, last);
|
||||||
|
double jack_mean = mean(jack.begin(), jack.end());
|
||||||
|
double sum_squares = 0, sum_cubes = 0;
|
||||||
|
for (double x : jack) {
|
||||||
|
auto difference = jack_mean - x;
|
||||||
|
auto square = difference * difference;
|
||||||
|
auto cube = square * difference;
|
||||||
|
sum_squares += square; sum_cubes += cube;
|
||||||
|
}
|
||||||
|
|
||||||
|
double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));
|
||||||
|
long n = static_cast<long>(resample.size());
|
||||||
|
double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / static_cast<double>(n);
|
||||||
|
// degenerate case with uniform samples
|
||||||
|
if ( directCompare( prob_n, 0. ) ) {
|
||||||
|
return { point, point, point, confidence_level };
|
||||||
|
}
|
||||||
|
|
||||||
|
double bias = normal_quantile(prob_n);
|
||||||
|
double z1 = normal_quantile((1. - confidence_level) / 2.);
|
||||||
|
|
||||||
|
auto cumn = [n]( double x ) -> long {
|
||||||
|
return std::lround( normal_cdf( x ) * static_cast<double>(n) );
|
||||||
|
};
|
||||||
|
auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); };
|
||||||
|
double b1 = bias + z1;
|
||||||
|
double b2 = bias - z1;
|
||||||
|
double a1 = a(b1);
|
||||||
|
double a2 = a(b2);
|
||||||
|
auto lo = static_cast<size_t>((std::max)(cumn(a1), 0l));
|
||||||
|
auto hi = static_cast<size_t>((std::min)(cumn(a2), n - 1));
|
||||||
|
|
||||||
|
return { point, resample[lo], resample[hi], confidence_level };
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bootstrap_analysis {
|
||||||
|
Estimate<double> mean;
|
||||||
|
Estimate<double> standard_deviation;
|
||||||
|
double outlier_variance;
|
||||||
|
};
|
||||||
|
|
||||||
|
bootstrap_analysis analyse_samples(double confidence_level,
|
||||||
|
unsigned int n_resamples,
|
||||||
|
std::vector<double>::iterator first,
|
||||||
|
std::vector<double>::iterator last);
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_STATS_HPP_INCLUDED
|
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
// Adapted from donated nonius code.
|
||||||
|
|
||||||
|
#ifndef CATCH_TIMING_HPP_INCLUDED
|
||||||
|
#define CATCH_TIMING_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/benchmark/catch_clock.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Benchmark {
|
||||||
|
template <typename Duration, typename Result>
|
||||||
|
struct Timing {
|
||||||
|
Duration elapsed;
|
||||||
|
Result result;
|
||||||
|
int iterations;
|
||||||
|
};
|
||||||
|
template <typename Clock, typename Func, typename... Args>
|
||||||
|
using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;
|
||||||
|
} // namespace Benchmark
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_TIMING_HPP_INCLUDED
|
129
plugins/storage_test_plugin/src/catch2/catch_all.hpp
Normal file
129
plugins/storage_test_plugin/src/catch2/catch_all.hpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
/** \file
|
||||||
|
* This is a convenience header for Catch2. It includes **all** of Catch2 headers.
|
||||||
|
*
|
||||||
|
* Generally the Catch2 users should use specific includes they need,
|
||||||
|
* but this header can be used instead for ease-of-experimentation, or
|
||||||
|
* just plain convenience, at the cost of (significantly) increased
|
||||||
|
* compilation times.
|
||||||
|
*
|
||||||
|
* When a new header is added to either the top level folder, or to the
|
||||||
|
* corresponding internal subfolder, it should be added here. Headers
|
||||||
|
* added to the various subparts (e.g. matchers, generators, etc...),
|
||||||
|
* should go their respective catch-all headers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CATCH_ALL_HPP_INCLUDED
|
||||||
|
#define CATCH_ALL_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/benchmark/catch_benchmark_all.hpp>
|
||||||
|
#include <catch2/catch_approx.hpp>
|
||||||
|
#include <catch2/catch_assertion_info.hpp>
|
||||||
|
#include <catch2/catch_assertion_result.hpp>
|
||||||
|
#include <catch2/catch_config.hpp>
|
||||||
|
#include <catch2/catch_get_random_seed.hpp>
|
||||||
|
#include <catch2/catch_message.hpp>
|
||||||
|
#include <catch2/catch_section_info.hpp>
|
||||||
|
#include <catch2/catch_session.hpp>
|
||||||
|
#include <catch2/catch_tag_alias.hpp>
|
||||||
|
#include <catch2/catch_tag_alias_autoregistrar.hpp>
|
||||||
|
#include <catch2/catch_template_test_macros.hpp>
|
||||||
|
#include <catch2/catch_test_case_info.hpp>
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <catch2/catch_test_spec.hpp>
|
||||||
|
#include <catch2/catch_timer.hpp>
|
||||||
|
#include <catch2/catch_tostring.hpp>
|
||||||
|
#include <catch2/catch_totals.hpp>
|
||||||
|
#include <catch2/catch_translate_exception.hpp>
|
||||||
|
#include <catch2/catch_version.hpp>
|
||||||
|
#include <catch2/catch_version_macros.hpp>
|
||||||
|
#include <catch2/generators/catch_generators_all.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_all.hpp>
|
||||||
|
#include <catch2/internal/catch_assertion_handler.hpp>
|
||||||
|
#include <catch2/internal/catch_case_insensitive_comparisons.hpp>
|
||||||
|
#include <catch2/internal/catch_case_sensitive.hpp>
|
||||||
|
#include <catch2/internal/catch_clara.hpp>
|
||||||
|
#include <catch2/internal/catch_commandline.hpp>
|
||||||
|
#include <catch2/internal/catch_compare_traits.hpp>
|
||||||
|
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||||
|
#include <catch2/internal/catch_config_android_logwrite.hpp>
|
||||||
|
#include <catch2/internal/catch_config_counter.hpp>
|
||||||
|
#include <catch2/internal/catch_config_static_analysis_support.hpp>
|
||||||
|
#include <catch2/internal/catch_config_uncaught_exceptions.hpp>
|
||||||
|
#include <catch2/internal/catch_config_wchar.hpp>
|
||||||
|
#include <catch2/internal/catch_console_colour.hpp>
|
||||||
|
#include <catch2/internal/catch_console_width.hpp>
|
||||||
|
#include <catch2/internal/catch_container_nonmembers.hpp>
|
||||||
|
#include <catch2/internal/catch_context.hpp>
|
||||||
|
#include <catch2/internal/catch_debug_console.hpp>
|
||||||
|
#include <catch2/internal/catch_debugger.hpp>
|
||||||
|
#include <catch2/internal/catch_decomposer.hpp>
|
||||||
|
#include <catch2/internal/catch_enforce.hpp>
|
||||||
|
#include <catch2/internal/catch_enum_values_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_errno_guard.hpp>
|
||||||
|
#include <catch2/internal/catch_exception_translator_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_fatal_condition_handler.hpp>
|
||||||
|
#include <catch2/internal/catch_floating_point_helpers.hpp>
|
||||||
|
#include <catch2/internal/catch_getenv.hpp>
|
||||||
|
#include <catch2/internal/catch_is_permutation.hpp>
|
||||||
|
#include <catch2/internal/catch_istream.hpp>
|
||||||
|
#include <catch2/internal/catch_lazy_expr.hpp>
|
||||||
|
#include <catch2/internal/catch_leak_detector.hpp>
|
||||||
|
#include <catch2/internal/catch_list.hpp>
|
||||||
|
#include <catch2/internal/catch_logical_traits.hpp>
|
||||||
|
#include <catch2/internal/catch_message_info.hpp>
|
||||||
|
#include <catch2/internal/catch_meta.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
#include <catch2/internal/catch_noncopyable.hpp>
|
||||||
|
#include <catch2/internal/catch_optional.hpp>
|
||||||
|
#include <catch2/internal/catch_output_redirect.hpp>
|
||||||
|
#include <catch2/internal/catch_parse_numbers.hpp>
|
||||||
|
#include <catch2/internal/catch_platform.hpp>
|
||||||
|
#include <catch2/internal/catch_polyfills.hpp>
|
||||||
|
#include <catch2/internal/catch_preprocessor.hpp>
|
||||||
|
#include <catch2/internal/catch_preprocessor_internal_stringify.hpp>
|
||||||
|
#include <catch2/internal/catch_preprocessor_remove_parens.hpp>
|
||||||
|
#include <catch2/internal/catch_random_number_generator.hpp>
|
||||||
|
#include <catch2/internal/catch_random_seed_generation.hpp>
|
||||||
|
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_reporter_spec_parser.hpp>
|
||||||
|
#include <catch2/internal/catch_result_type.hpp>
|
||||||
|
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||||
|
#include <catch2/internal/catch_run_context.hpp>
|
||||||
|
#include <catch2/internal/catch_section.hpp>
|
||||||
|
#include <catch2/internal/catch_sharding.hpp>
|
||||||
|
#include <catch2/internal/catch_singletons.hpp>
|
||||||
|
#include <catch2/internal/catch_source_line_info.hpp>
|
||||||
|
#include <catch2/internal/catch_startup_exception_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_stdstreams.hpp>
|
||||||
|
#include <catch2/internal/catch_stream_end_stop.hpp>
|
||||||
|
#include <catch2/internal/catch_string_manip.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
#include <catch2/internal/catch_tag_alias_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_template_test_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_test_case_info_hasher.hpp>
|
||||||
|
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||||
|
#include <catch2/internal/catch_test_case_tracker.hpp>
|
||||||
|
#include <catch2/internal/catch_test_failure_exception.hpp>
|
||||||
|
#include <catch2/internal/catch_test_macro_impl.hpp>
|
||||||
|
#include <catch2/internal/catch_test_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_test_run_info.hpp>
|
||||||
|
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||||
|
#include <catch2/internal/catch_textflow.hpp>
|
||||||
|
#include <catch2/internal/catch_to_string.hpp>
|
||||||
|
#include <catch2/internal/catch_uncaught_exceptions.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_name.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
#include <catch2/internal/catch_void_type.hpp>
|
||||||
|
#include <catch2/internal/catch_wildcard_pattern.hpp>
|
||||||
|
#include <catch2/internal/catch_xmlwriter.hpp>
|
||||||
|
#include <catch2/matchers/catch_matchers_all.hpp>
|
||||||
|
#include <catch2/reporters/catch_reporters_all.hpp>
|
||||||
|
|
||||||
|
#endif // CATCH_ALL_HPP_INCLUDED
|
85
plugins/storage_test_plugin/src/catch2/catch_approx.cpp
Normal file
85
plugins/storage_test_plugin/src/catch2/catch_approx.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/catch_approx.hpp>
|
||||||
|
#include <catch2/internal/catch_enforce.hpp>
|
||||||
|
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
||||||
|
// But without the subtraction to allow for INFINITY in comparison
|
||||||
|
bool marginComparison(double lhs, double rhs, double margin) {
|
||||||
|
return (lhs + margin >= rhs) && (rhs + margin >= lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
Approx::Approx ( double value )
|
||||||
|
: m_epsilon( std::numeric_limits<float>::epsilon()*100. ),
|
||||||
|
m_margin( 0.0 ),
|
||||||
|
m_scale( 0.0 ),
|
||||||
|
m_value( value )
|
||||||
|
{}
|
||||||
|
|
||||||
|
Approx Approx::custom() {
|
||||||
|
return Approx( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
Approx Approx::operator-() const {
|
||||||
|
auto temp(*this);
|
||||||
|
temp.m_value = -temp.m_value;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string Approx::toString() const {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Approx::equalityComparisonImpl(const double other) const {
|
||||||
|
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
|
||||||
|
// Thanks to Richard Harris for his help refining the scaled margin value
|
||||||
|
return marginComparison(m_value, other, m_margin)
|
||||||
|
|| marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Approx::setMargin(double newMargin) {
|
||||||
|
CATCH_ENFORCE(newMargin >= 0,
|
||||||
|
"Invalid Approx::margin: " << newMargin << '.'
|
||||||
|
<< " Approx::Margin has to be non-negative.");
|
||||||
|
m_margin = newMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Approx::setEpsilon(double newEpsilon) {
|
||||||
|
CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
|
||||||
|
"Invalid Approx::epsilon: " << newEpsilon << '.'
|
||||||
|
<< " Approx::epsilon has to be in [0, 1]");
|
||||||
|
m_epsilon = newEpsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace literals {
|
||||||
|
Approx operator "" _a(long double val) {
|
||||||
|
return Approx(val);
|
||||||
|
}
|
||||||
|
Approx operator "" _a(unsigned long long val) {
|
||||||
|
return Approx(val);
|
||||||
|
}
|
||||||
|
} // end namespace literals
|
||||||
|
|
||||||
|
std::string StringMaker<Catch::Approx>::convert(Catch::Approx const& value) {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace Catch
|
128
plugins/storage_test_plugin/src/catch2/catch_approx.hpp
Normal file
128
plugins/storage_test_plugin/src/catch2/catch_approx.hpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_APPROX_HPP_INCLUDED
|
||||||
|
#define CATCH_APPROX_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/catch_tostring.hpp>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
class Approx {
|
||||||
|
private:
|
||||||
|
bool equalityComparisonImpl(double other) const;
|
||||||
|
// Sets and validates the new margin (margin >= 0)
|
||||||
|
void setMargin(double margin);
|
||||||
|
// Sets and validates the new epsilon (0 < epsilon < 1)
|
||||||
|
void setEpsilon(double epsilon);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Approx ( double value );
|
||||||
|
|
||||||
|
static Approx custom();
|
||||||
|
|
||||||
|
Approx operator-() const;
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
Approx operator()( T const& value ) const {
|
||||||
|
Approx approx( static_cast<double>(value) );
|
||||||
|
approx.m_epsilon = m_epsilon;
|
||||||
|
approx.m_margin = m_margin;
|
||||||
|
approx.m_scale = m_scale;
|
||||||
|
return approx;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
explicit Approx( T const& value ): Approx(static_cast<double>(value))
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
friend bool operator == ( const T& lhs, Approx const& rhs ) {
|
||||||
|
auto lhs_v = static_cast<double>(lhs);
|
||||||
|
return rhs.equalityComparisonImpl(lhs_v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
friend bool operator == ( Approx const& lhs, const T& rhs ) {
|
||||||
|
return operator==( rhs, lhs );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
friend bool operator != ( T const& lhs, Approx const& rhs ) {
|
||||||
|
return !operator==( lhs, rhs );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
friend bool operator != ( Approx const& lhs, T const& rhs ) {
|
||||||
|
return !operator==( rhs, lhs );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
friend bool operator <= ( T const& lhs, Approx const& rhs ) {
|
||||||
|
return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
friend bool operator <= ( Approx const& lhs, T const& rhs ) {
|
||||||
|
return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
friend bool operator >= ( T const& lhs, Approx const& rhs ) {
|
||||||
|
return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
friend bool operator >= ( Approx const& lhs, T const& rhs ) {
|
||||||
|
return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
Approx& epsilon( T const& newEpsilon ) {
|
||||||
|
const auto epsilonAsDouble = static_cast<double>(newEpsilon);
|
||||||
|
setEpsilon(epsilonAsDouble);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
Approx& margin( T const& newMargin ) {
|
||||||
|
const auto marginAsDouble = static_cast<double>(newMargin);
|
||||||
|
setMargin(marginAsDouble);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||||
|
Approx& scale( T const& newScale ) {
|
||||||
|
m_scale = static_cast<double>(newScale);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string toString() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
double m_epsilon;
|
||||||
|
double m_margin;
|
||||||
|
double m_scale;
|
||||||
|
double m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace literals {
|
||||||
|
Approx operator ""_a(long double val);
|
||||||
|
Approx operator ""_a(unsigned long long val);
|
||||||
|
} // end namespace literals
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct StringMaker<Catch::Approx> {
|
||||||
|
static std::string convert(Catch::Approx const& value);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_APPROX_HPP_INCLUDED
|
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED
|
||||||
|
#define CATCH_ASSERTION_INFO_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_result_type.hpp>
|
||||||
|
#include <catch2/internal/catch_source_line_info.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct AssertionInfo {
|
||||||
|
// AssertionInfo() = delete;
|
||||||
|
|
||||||
|
StringRef macroName;
|
||||||
|
SourceLineInfo lineInfo;
|
||||||
|
StringRef capturedExpression;
|
||||||
|
ResultDisposition::Flags resultDisposition;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED
|
@ -0,0 +1,105 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/catch_assertion_result.hpp>
|
||||||
|
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression):
|
||||||
|
lazyExpression(_lazyExpression),
|
||||||
|
resultType(_resultType) {}
|
||||||
|
|
||||||
|
std::string AssertionResultData::reconstructExpression() const {
|
||||||
|
|
||||||
|
if( reconstructedExpression.empty() ) {
|
||||||
|
if( lazyExpression ) {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << lazyExpression;
|
||||||
|
reconstructedExpression = rss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reconstructedExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData&& data )
|
||||||
|
: m_info( info ),
|
||||||
|
m_resultData( CATCH_MOVE(data) )
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Result was a success
|
||||||
|
bool AssertionResult::succeeded() const {
|
||||||
|
return Catch::isOk( m_resultData.resultType );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result was a success, or failure is suppressed
|
||||||
|
bool AssertionResult::isOk() const {
|
||||||
|
return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultWas::OfType AssertionResult::getResultType() const {
|
||||||
|
return m_resultData.resultType;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssertionResult::hasExpression() const {
|
||||||
|
return !m_info.capturedExpression.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssertionResult::hasMessage() const {
|
||||||
|
return !m_resultData.message.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AssertionResult::getExpression() const {
|
||||||
|
// Possibly overallocating by 3 characters should be basically free
|
||||||
|
std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
|
||||||
|
if (isFalseTest(m_info.resultDisposition)) {
|
||||||
|
expr += "!(";
|
||||||
|
}
|
||||||
|
expr += m_info.capturedExpression;
|
||||||
|
if (isFalseTest(m_info.resultDisposition)) {
|
||||||
|
expr += ')';
|
||||||
|
}
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AssertionResult::getExpressionInMacro() const {
|
||||||
|
if ( m_info.macroName.empty() ) {
|
||||||
|
return static_cast<std::string>( m_info.capturedExpression );
|
||||||
|
}
|
||||||
|
std::string expr;
|
||||||
|
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
|
||||||
|
expr += m_info.macroName;
|
||||||
|
expr += "( ";
|
||||||
|
expr += m_info.capturedExpression;
|
||||||
|
expr += " )";
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssertionResult::hasExpandedExpression() const {
|
||||||
|
return hasExpression() && getExpandedExpression() != getExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AssertionResult::getExpandedExpression() const {
|
||||||
|
std::string expr = m_resultData.reconstructExpression();
|
||||||
|
return expr.empty()
|
||||||
|
? getExpression()
|
||||||
|
: expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringRef AssertionResult::getMessage() const {
|
||||||
|
return m_resultData.message;
|
||||||
|
}
|
||||||
|
SourceLineInfo AssertionResult::getSourceInfo() const {
|
||||||
|
return m_info.lineInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringRef AssertionResult::getTestMacroName() const {
|
||||||
|
return m_info.macroName;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace Catch
|
@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED
|
||||||
|
#define CATCH_ASSERTION_RESULT_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/catch_assertion_info.hpp>
|
||||||
|
#include <catch2/internal/catch_result_type.hpp>
|
||||||
|
#include <catch2/internal/catch_source_line_info.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
#include <catch2/internal/catch_lazy_expr.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct AssertionResultData
|
||||||
|
{
|
||||||
|
AssertionResultData() = delete;
|
||||||
|
|
||||||
|
AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );
|
||||||
|
|
||||||
|
std::string message;
|
||||||
|
mutable std::string reconstructedExpression;
|
||||||
|
LazyExpression lazyExpression;
|
||||||
|
ResultWas::OfType resultType;
|
||||||
|
|
||||||
|
std::string reconstructExpression() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AssertionResult {
|
||||||
|
public:
|
||||||
|
AssertionResult() = delete;
|
||||||
|
AssertionResult( AssertionInfo const& info, AssertionResultData&& data );
|
||||||
|
|
||||||
|
bool isOk() const;
|
||||||
|
bool succeeded() const;
|
||||||
|
ResultWas::OfType getResultType() const;
|
||||||
|
bool hasExpression() const;
|
||||||
|
bool hasMessage() const;
|
||||||
|
std::string getExpression() const;
|
||||||
|
std::string getExpressionInMacro() const;
|
||||||
|
bool hasExpandedExpression() const;
|
||||||
|
std::string getExpandedExpression() const;
|
||||||
|
StringRef getMessage() const;
|
||||||
|
SourceLineInfo getSourceInfo() const;
|
||||||
|
StringRef getTestMacroName() const;
|
||||||
|
|
||||||
|
//protected:
|
||||||
|
AssertionInfo m_info;
|
||||||
|
AssertionResultData m_resultData;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED
|
247
plugins/storage_test_plugin/src/catch2/catch_config.cpp
Normal file
247
plugins/storage_test_plugin/src/catch2/catch_config.cpp
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/catch_config.hpp>
|
||||||
|
#include <catch2/catch_user_config.hpp>
|
||||||
|
#include <catch2/internal/catch_enforce.hpp>
|
||||||
|
#include <catch2/internal/catch_parse_numbers.hpp>
|
||||||
|
#include <catch2/internal/catch_stdstreams.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
#include <catch2/internal/catch_string_manip.hpp>
|
||||||
|
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_tag_alias_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_getenv.hpp>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static bool enableBazelEnvSupport() {
|
||||||
|
#if defined( CATCH_CONFIG_BAZEL_SUPPORT )
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return Detail::getEnv( "BAZEL_TEST" ) != nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bazelShardingOptions {
|
||||||
|
unsigned int shardIndex, shardCount;
|
||||||
|
std::string shardFilePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Optional<bazelShardingOptions> readBazelShardingOptions() {
|
||||||
|
const auto bazelShardIndex = Detail::getEnv( "TEST_SHARD_INDEX" );
|
||||||
|
const auto bazelShardTotal = Detail::getEnv( "TEST_TOTAL_SHARDS" );
|
||||||
|
const auto bazelShardInfoFile = Detail::getEnv( "TEST_SHARD_STATUS_FILE" );
|
||||||
|
|
||||||
|
|
||||||
|
const bool has_all =
|
||||||
|
bazelShardIndex && bazelShardTotal && bazelShardInfoFile;
|
||||||
|
if ( !has_all ) {
|
||||||
|
// We provide nice warning message if the input is
|
||||||
|
// misconfigured.
|
||||||
|
auto warn = []( const char* env_var ) {
|
||||||
|
Catch::cerr()
|
||||||
|
<< "Warning: Bazel shard configuration is missing '"
|
||||||
|
<< env_var << "'. Shard configuration is skipped.\n";
|
||||||
|
};
|
||||||
|
if ( !bazelShardIndex ) {
|
||||||
|
warn( "TEST_SHARD_INDEX" );
|
||||||
|
}
|
||||||
|
if ( !bazelShardTotal ) {
|
||||||
|
warn( "TEST_TOTAL_SHARDS" );
|
||||||
|
}
|
||||||
|
if ( !bazelShardInfoFile ) {
|
||||||
|
warn( "TEST_SHARD_STATUS_FILE" );
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto shardIndex = parseUInt( bazelShardIndex );
|
||||||
|
if ( !shardIndex ) {
|
||||||
|
Catch::cerr()
|
||||||
|
<< "Warning: could not parse 'TEST_SHARD_INDEX' ('" << bazelShardIndex
|
||||||
|
<< "') as unsigned int.\n";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto shardTotal = parseUInt( bazelShardTotal );
|
||||||
|
if ( !shardTotal ) {
|
||||||
|
Catch::cerr()
|
||||||
|
<< "Warning: could not parse 'TEST_TOTAL_SHARD' ('"
|
||||||
|
<< bazelShardTotal << "') as unsigned int.\n";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return bazelShardingOptions{
|
||||||
|
*shardIndex, *shardTotal, bazelShardInfoFile };
|
||||||
|
|
||||||
|
}
|
||||||
|
} // end namespace
|
||||||
|
|
||||||
|
|
||||||
|
bool operator==( ProcessedReporterSpec const& lhs,
|
||||||
|
ProcessedReporterSpec const& rhs ) {
|
||||||
|
return lhs.name == rhs.name &&
|
||||||
|
lhs.outputFilename == rhs.outputFilename &&
|
||||||
|
lhs.colourMode == rhs.colourMode &&
|
||||||
|
lhs.customOptions == rhs.customOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::Config( ConfigData const& data ):
|
||||||
|
m_data( data ) {
|
||||||
|
// We need to trim filter specs to avoid trouble with superfluous
|
||||||
|
// whitespace (esp. important for bdd macros, as those are manually
|
||||||
|
// aligned with whitespace).
|
||||||
|
|
||||||
|
for (auto& elem : m_data.testsOrTags) {
|
||||||
|
elem = trim(elem);
|
||||||
|
}
|
||||||
|
for (auto& elem : m_data.sectionsToRun) {
|
||||||
|
elem = trim(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the default reporter if user hasn't asked for a specific one
|
||||||
|
if ( m_data.reporterSpecifications.empty() ) {
|
||||||
|
m_data.reporterSpecifications.push_back( {
|
||||||
|
#if defined( CATCH_CONFIG_DEFAULT_REPORTER )
|
||||||
|
CATCH_CONFIG_DEFAULT_REPORTER,
|
||||||
|
#else
|
||||||
|
"console",
|
||||||
|
#endif
|
||||||
|
{}, {}, {}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( enableBazelEnvSupport() ) {
|
||||||
|
readBazelEnvVars();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bazel support can modify the test specs, so parsing has to happen
|
||||||
|
// after reading Bazel env vars.
|
||||||
|
TestSpecParser parser( ITagAliasRegistry::get() );
|
||||||
|
if ( !m_data.testsOrTags.empty() ) {
|
||||||
|
m_hasTestFilters = true;
|
||||||
|
for ( auto const& testOrTags : m_data.testsOrTags ) {
|
||||||
|
parser.parse( testOrTags );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_testSpec = parser.testSpec();
|
||||||
|
|
||||||
|
|
||||||
|
// We now fixup the reporter specs to handle default output spec,
|
||||||
|
// default colour spec, etc
|
||||||
|
bool defaultOutputUsed = false;
|
||||||
|
for ( auto const& reporterSpec : m_data.reporterSpecifications ) {
|
||||||
|
// We do the default-output check separately, while always
|
||||||
|
// using the default output below to make the code simpler
|
||||||
|
// and avoid superfluous copies.
|
||||||
|
if ( reporterSpec.outputFile().none() ) {
|
||||||
|
CATCH_ENFORCE( !defaultOutputUsed,
|
||||||
|
"Internal error: cannot use default output for "
|
||||||
|
"multiple reporters" );
|
||||||
|
defaultOutputUsed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_processedReporterSpecs.push_back( ProcessedReporterSpec{
|
||||||
|
reporterSpec.name(),
|
||||||
|
reporterSpec.outputFile() ? *reporterSpec.outputFile()
|
||||||
|
: data.defaultOutputFilename,
|
||||||
|
reporterSpec.colourMode().valueOr( data.defaultColourMode ),
|
||||||
|
reporterSpec.customOptions() } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::~Config() = default;
|
||||||
|
|
||||||
|
|
||||||
|
bool Config::listTests() const { return m_data.listTests; }
|
||||||
|
bool Config::listTags() const { return m_data.listTags; }
|
||||||
|
bool Config::listReporters() const { return m_data.listReporters; }
|
||||||
|
bool Config::listListeners() const { return m_data.listListeners; }
|
||||||
|
|
||||||
|
std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
|
||||||
|
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
|
||||||
|
|
||||||
|
std::vector<ReporterSpec> const& Config::getReporterSpecs() const {
|
||||||
|
return m_data.reporterSpecifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ProcessedReporterSpec> const&
|
||||||
|
Config::getProcessedReporterSpecs() const {
|
||||||
|
return m_processedReporterSpecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestSpec const& Config::testSpec() const { return m_testSpec; }
|
||||||
|
bool Config::hasTestFilters() const { return m_hasTestFilters; }
|
||||||
|
|
||||||
|
bool Config::showHelp() const { return m_data.showHelp; }
|
||||||
|
|
||||||
|
// IConfig interface
|
||||||
|
bool Config::allowThrows() const { return !m_data.noThrow; }
|
||||||
|
StringRef Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
||||||
|
bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
|
||||||
|
bool Config::warnAboutMissingAssertions() const {
|
||||||
|
return !!( m_data.warnings & WarnAbout::NoAssertions );
|
||||||
|
}
|
||||||
|
bool Config::warnAboutUnmatchedTestSpecs() const {
|
||||||
|
return !!( m_data.warnings & WarnAbout::UnmatchedTestSpec );
|
||||||
|
}
|
||||||
|
bool Config::zeroTestsCountAsSuccess() const { return m_data.allowZeroTests; }
|
||||||
|
ShowDurations Config::showDurations() const { return m_data.showDurations; }
|
||||||
|
double Config::minDuration() const { return m_data.minDuration; }
|
||||||
|
TestRunOrder Config::runOrder() const { return m_data.runOrder; }
|
||||||
|
uint32_t Config::rngSeed() const { return m_data.rngSeed; }
|
||||||
|
unsigned int Config::shardCount() const { return m_data.shardCount; }
|
||||||
|
unsigned int Config::shardIndex() const { return m_data.shardIndex; }
|
||||||
|
ColourMode Config::defaultColourMode() const { return m_data.defaultColourMode; }
|
||||||
|
bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
|
||||||
|
int Config::abortAfter() const { return m_data.abortAfter; }
|
||||||
|
bool Config::showInvisibles() const { return m_data.showInvisibles; }
|
||||||
|
Verbosity Config::verbosity() const { return m_data.verbosity; }
|
||||||
|
|
||||||
|
bool Config::skipBenchmarks() const { return m_data.skipBenchmarks; }
|
||||||
|
bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
|
||||||
|
unsigned int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
|
||||||
|
double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
|
||||||
|
unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
|
||||||
|
std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
|
||||||
|
|
||||||
|
void Config::readBazelEnvVars() {
|
||||||
|
// Register a JUnit reporter for Bazel. Bazel sets an environment
|
||||||
|
// variable with the path to XML output. If this file is written to
|
||||||
|
// during test, Bazel will not generate a default XML output.
|
||||||
|
// This allows the XML output file to contain higher level of detail
|
||||||
|
// than what is possible otherwise.
|
||||||
|
const auto bazelOutputFile = Detail::getEnv( "XML_OUTPUT_FILE" );
|
||||||
|
|
||||||
|
if ( bazelOutputFile ) {
|
||||||
|
m_data.reporterSpecifications.push_back(
|
||||||
|
{ "junit", std::string( bazelOutputFile ), {}, {} } );
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto bazelTestSpec = Detail::getEnv( "TESTBRIDGE_TEST_ONLY" );
|
||||||
|
if ( bazelTestSpec ) {
|
||||||
|
// Presumably the test spec from environment should overwrite
|
||||||
|
// the one we got from CLI (if we got any)
|
||||||
|
m_data.testsOrTags.clear();
|
||||||
|
m_data.testsOrTags.push_back( bazelTestSpec );
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto bazelShardOptions = readBazelShardingOptions();
|
||||||
|
if ( bazelShardOptions ) {
|
||||||
|
std::ofstream f( bazelShardOptions->shardFilePath,
|
||||||
|
std::ios_base::out | std::ios_base::trunc );
|
||||||
|
if ( f.is_open() ) {
|
||||||
|
f << "";
|
||||||
|
m_data.shardIndex = bazelShardOptions->shardIndex;
|
||||||
|
m_data.shardCount = bazelShardOptions->shardCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace Catch
|
153
plugins/storage_test_plugin/src/catch2/catch_config.hpp
Normal file
153
plugins/storage_test_plugin/src/catch2/catch_config.hpp
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_CONFIG_HPP_INCLUDED
|
||||||
|
#define CATCH_CONFIG_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/catch_test_spec.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
#include <catch2/internal/catch_optional.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
#include <catch2/internal/catch_random_seed_generation.hpp>
|
||||||
|
#include <catch2/internal/catch_reporter_spec_parser.hpp>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
class IStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `ReporterSpec` but with the defaults filled in.
|
||||||
|
*
|
||||||
|
* Like `ReporterSpec`, the semantics are unchecked.
|
||||||
|
*/
|
||||||
|
struct ProcessedReporterSpec {
|
||||||
|
std::string name;
|
||||||
|
std::string outputFilename;
|
||||||
|
ColourMode colourMode;
|
||||||
|
std::map<std::string, std::string> customOptions;
|
||||||
|
friend bool operator==( ProcessedReporterSpec const& lhs,
|
||||||
|
ProcessedReporterSpec const& rhs );
|
||||||
|
friend bool operator!=( ProcessedReporterSpec const& lhs,
|
||||||
|
ProcessedReporterSpec const& rhs ) {
|
||||||
|
return !( lhs == rhs );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConfigData {
|
||||||
|
|
||||||
|
bool listTests = false;
|
||||||
|
bool listTags = false;
|
||||||
|
bool listReporters = false;
|
||||||
|
bool listListeners = false;
|
||||||
|
|
||||||
|
bool showSuccessfulTests = false;
|
||||||
|
bool shouldDebugBreak = false;
|
||||||
|
bool noThrow = false;
|
||||||
|
bool showHelp = false;
|
||||||
|
bool showInvisibles = false;
|
||||||
|
bool filenamesAsTags = false;
|
||||||
|
bool libIdentify = false;
|
||||||
|
bool allowZeroTests = false;
|
||||||
|
|
||||||
|
int abortAfter = -1;
|
||||||
|
uint32_t rngSeed = generateRandomSeed(GenerateFrom::Default);
|
||||||
|
|
||||||
|
unsigned int shardCount = 1;
|
||||||
|
unsigned int shardIndex = 0;
|
||||||
|
|
||||||
|
bool skipBenchmarks = false;
|
||||||
|
bool benchmarkNoAnalysis = false;
|
||||||
|
unsigned int benchmarkSamples = 100;
|
||||||
|
double benchmarkConfidenceInterval = 0.95;
|
||||||
|
unsigned int benchmarkResamples = 100000;
|
||||||
|
std::chrono::milliseconds::rep benchmarkWarmupTime = 100;
|
||||||
|
|
||||||
|
Verbosity verbosity = Verbosity::Normal;
|
||||||
|
WarnAbout::What warnings = WarnAbout::Nothing;
|
||||||
|
ShowDurations showDurations = ShowDurations::DefaultForReporter;
|
||||||
|
double minDuration = -1;
|
||||||
|
TestRunOrder runOrder = TestRunOrder::Declared;
|
||||||
|
ColourMode defaultColourMode = ColourMode::PlatformDefault;
|
||||||
|
WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
|
||||||
|
|
||||||
|
std::string defaultOutputFilename;
|
||||||
|
std::string name;
|
||||||
|
std::string processName;
|
||||||
|
std::vector<ReporterSpec> reporterSpecifications;
|
||||||
|
|
||||||
|
std::vector<std::string> testsOrTags;
|
||||||
|
std::vector<std::string> sectionsToRun;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Config : public IConfig {
|
||||||
|
public:
|
||||||
|
|
||||||
|
Config() = default;
|
||||||
|
Config( ConfigData const& data );
|
||||||
|
~Config() override; // = default in the cpp file
|
||||||
|
|
||||||
|
bool listTests() const;
|
||||||
|
bool listTags() const;
|
||||||
|
bool listReporters() const;
|
||||||
|
bool listListeners() const;
|
||||||
|
|
||||||
|
std::vector<ReporterSpec> const& getReporterSpecs() const;
|
||||||
|
std::vector<ProcessedReporterSpec> const&
|
||||||
|
getProcessedReporterSpecs() const;
|
||||||
|
|
||||||
|
std::vector<std::string> const& getTestsOrTags() const override;
|
||||||
|
std::vector<std::string> const& getSectionsToRun() const override;
|
||||||
|
|
||||||
|
TestSpec const& testSpec() const override;
|
||||||
|
bool hasTestFilters() const override;
|
||||||
|
|
||||||
|
bool showHelp() const;
|
||||||
|
|
||||||
|
// IConfig interface
|
||||||
|
bool allowThrows() const override;
|
||||||
|
StringRef name() const override;
|
||||||
|
bool includeSuccessfulResults() const override;
|
||||||
|
bool warnAboutMissingAssertions() const override;
|
||||||
|
bool warnAboutUnmatchedTestSpecs() const override;
|
||||||
|
bool zeroTestsCountAsSuccess() const override;
|
||||||
|
ShowDurations showDurations() const override;
|
||||||
|
double minDuration() const override;
|
||||||
|
TestRunOrder runOrder() const override;
|
||||||
|
uint32_t rngSeed() const override;
|
||||||
|
unsigned int shardCount() const override;
|
||||||
|
unsigned int shardIndex() const override;
|
||||||
|
ColourMode defaultColourMode() const override;
|
||||||
|
bool shouldDebugBreak() const override;
|
||||||
|
int abortAfter() const override;
|
||||||
|
bool showInvisibles() const override;
|
||||||
|
Verbosity verbosity() const override;
|
||||||
|
bool skipBenchmarks() const override;
|
||||||
|
bool benchmarkNoAnalysis() const override;
|
||||||
|
unsigned int benchmarkSamples() const override;
|
||||||
|
double benchmarkConfidenceInterval() const override;
|
||||||
|
unsigned int benchmarkResamples() const override;
|
||||||
|
std::chrono::milliseconds benchmarkWarmupTime() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Reads Bazel env vars and applies them to the config
|
||||||
|
void readBazelEnvVars();
|
||||||
|
|
||||||
|
ConfigData m_data;
|
||||||
|
std::vector<ProcessedReporterSpec> m_processedReporterSpecs;
|
||||||
|
TestSpec m_testSpec;
|
||||||
|
bool m_hasTestFilters = false;
|
||||||
|
};
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_CONFIG_HPP_INCLUDED
|
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/catch_get_random_seed.hpp>
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_context.hpp>
|
||||||
|
#include <catch2/catch_config.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
std::uint32_t getSeed() {
|
||||||
|
return getCurrentContext().getConfig()->rngSeed();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_GET_RANDOM_SEED_HPP_INCLUDED
|
||||||
|
#define CATCH_GET_RANDOM_SEED_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
//! Returns Catch2's current RNG seed.
|
||||||
|
std::uint32_t getSeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CATCH_GET_RANDOM_SEED_HPP_INCLUDED
|
116
plugins/storage_test_plugin/src/catch2/catch_message.cpp
Normal file
116
plugins/storage_test_plugin/src/catch2/catch_message.cpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/catch_message.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||||
|
#include <catch2/internal/catch_uncaught_exceptions.hpp>
|
||||||
|
#include <catch2/internal/catch_enforce.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
ScopedMessage::ScopedMessage( MessageBuilder&& builder ):
|
||||||
|
m_info( CATCH_MOVE(builder.m_info) ) {
|
||||||
|
m_info.message = builder.m_stream.str();
|
||||||
|
getResultCapture().pushScopedMessage( m_info );
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
|
||||||
|
m_info( CATCH_MOVE( old.m_info ) ) {
|
||||||
|
old.m_moved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedMessage::~ScopedMessage() {
|
||||||
|
if ( !uncaught_exceptions() && !m_moved ){
|
||||||
|
getResultCapture().popScopedMessage(m_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Capturer::Capturer( StringRef macroName,
|
||||||
|
SourceLineInfo const& lineInfo,
|
||||||
|
ResultWas::OfType resultType,
|
||||||
|
StringRef names ):
|
||||||
|
m_resultCapture( getResultCapture() ) {
|
||||||
|
auto trimmed = [&] (size_t start, size_t end) {
|
||||||
|
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
|
||||||
|
++start;
|
||||||
|
}
|
||||||
|
while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
|
||||||
|
--end;
|
||||||
|
}
|
||||||
|
return names.substr(start, end - start + 1);
|
||||||
|
};
|
||||||
|
auto skipq = [&] (size_t start, char quote) {
|
||||||
|
for (auto i = start + 1; i < names.size() ; ++i) {
|
||||||
|
if (names[i] == quote)
|
||||||
|
return i;
|
||||||
|
if (names[i] == '\\')
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t start = 0;
|
||||||
|
std::stack<char> openings;
|
||||||
|
for (size_t pos = 0; pos < names.size(); ++pos) {
|
||||||
|
char c = names[pos];
|
||||||
|
switch (c) {
|
||||||
|
case '[':
|
||||||
|
case '{':
|
||||||
|
case '(':
|
||||||
|
// It is basically impossible to disambiguate between
|
||||||
|
// comparison and start of template args in this context
|
||||||
|
// case '<':
|
||||||
|
openings.push(c);
|
||||||
|
break;
|
||||||
|
case ']':
|
||||||
|
case '}':
|
||||||
|
case ')':
|
||||||
|
// case '>':
|
||||||
|
openings.pop();
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
pos = skipq(pos, c);
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
if (start != pos && openings.empty()) {
|
||||||
|
m_messages.emplace_back(macroName, lineInfo, resultType);
|
||||||
|
m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
|
||||||
|
m_messages.back().message += " := ";
|
||||||
|
start = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(openings.empty() && "Mismatched openings");
|
||||||
|
m_messages.emplace_back(macroName, lineInfo, resultType);
|
||||||
|
m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
|
||||||
|
m_messages.back().message += " := ";
|
||||||
|
}
|
||||||
|
Capturer::~Capturer() {
|
||||||
|
if ( !uncaught_exceptions() ){
|
||||||
|
assert( m_captured == m_messages.size() );
|
||||||
|
for( size_t i = 0; i < m_captured; ++i )
|
||||||
|
m_resultCapture.popScopedMessage( m_messages[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Capturer::captureValue( size_t index, std::string const& value ) {
|
||||||
|
assert( index < m_messages.size() );
|
||||||
|
m_messages[index].message += value;
|
||||||
|
m_resultCapture.pushScopedMessage( m_messages[index] );
|
||||||
|
m_captured++;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace Catch
|
148
plugins/storage_test_plugin/src/catch2/catch_message.hpp
Normal file
148
plugins/storage_test_plugin/src/catch2/catch_message.hpp
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_MESSAGE_HPP_INCLUDED
|
||||||
|
#define CATCH_MESSAGE_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_result_type.hpp>
|
||||||
|
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||||
|
#include <catch2/internal/catch_stream_end_stop.hpp>
|
||||||
|
#include <catch2/internal/catch_message_info.hpp>
|
||||||
|
#include <catch2/catch_tostring.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct SourceLineInfo;
|
||||||
|
class IResultCapture;
|
||||||
|
|
||||||
|
struct MessageStream {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
MessageStream& operator << ( T const& value ) {
|
||||||
|
m_stream << value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReusableStringStream m_stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MessageBuilder : MessageStream {
|
||||||
|
MessageBuilder( StringRef macroName,
|
||||||
|
SourceLineInfo const& lineInfo,
|
||||||
|
ResultWas::OfType type ):
|
||||||
|
m_info(macroName, lineInfo, type) {}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
MessageBuilder&& operator << ( T const& value ) && {
|
||||||
|
m_stream << value;
|
||||||
|
return CATCH_MOVE(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageInfo m_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScopedMessage {
|
||||||
|
public:
|
||||||
|
explicit ScopedMessage( MessageBuilder&& builder );
|
||||||
|
ScopedMessage( ScopedMessage& duplicate ) = delete;
|
||||||
|
ScopedMessage( ScopedMessage&& old ) noexcept;
|
||||||
|
~ScopedMessage();
|
||||||
|
|
||||||
|
MessageInfo m_info;
|
||||||
|
bool m_moved = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Capturer {
|
||||||
|
std::vector<MessageInfo> m_messages;
|
||||||
|
IResultCapture& m_resultCapture;
|
||||||
|
size_t m_captured = 0;
|
||||||
|
public:
|
||||||
|
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
|
||||||
|
|
||||||
|
Capturer(Capturer const&) = delete;
|
||||||
|
Capturer& operator=(Capturer const&) = delete;
|
||||||
|
|
||||||
|
~Capturer();
|
||||||
|
|
||||||
|
void captureValue( size_t index, std::string const& value );
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void captureValues( size_t index, T const& value ) {
|
||||||
|
captureValue( index, Catch::Detail::stringify( value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename... Ts>
|
||||||
|
void captureValues( size_t index, T const& value, Ts const&... values ) {
|
||||||
|
captureValue( index, Catch::Detail::stringify(value) );
|
||||||
|
captureValues( index+1, values... );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
|
||||||
|
do { \
|
||||||
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
|
||||||
|
catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
|
||||||
|
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||||
|
} while( false )
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
|
||||||
|
Catch::Capturer varName( macroName##_catch_sr, \
|
||||||
|
CATCH_INTERNAL_LINEINFO, \
|
||||||
|
Catch::ResultWas::Info, \
|
||||||
|
#__VA_ARGS__##_catch_sr ); \
|
||||||
|
varName.captureValues( 0, __VA_ARGS__ )
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define INTERNAL_CATCH_INFO( macroName, log ) \
|
||||||
|
const Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
|
||||||
|
Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
|
||||||
|
|
||||||
|
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
|
||||||
|
#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
|
||||||
|
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||||
|
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", __VA_ARGS__ )
|
||||||
|
|
||||||
|
#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
|
||||||
|
|
||||||
|
#define CATCH_INFO( msg ) (void)(0)
|
||||||
|
#define CATCH_UNSCOPED_INFO( msg ) (void)(0)
|
||||||
|
#define CATCH_WARN( msg ) (void)(0)
|
||||||
|
#define CATCH_CAPTURE( ... ) (void)(0)
|
||||||
|
|
||||||
|
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
|
||||||
|
|
||||||
|
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
||||||
|
#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
|
||||||
|
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||||
|
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", __VA_ARGS__ )
|
||||||
|
|
||||||
|
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
|
||||||
|
|
||||||
|
#define INFO( msg ) (void)(0)
|
||||||
|
#define UNSCOPED_INFO( msg ) (void)(0)
|
||||||
|
#define WARN( msg ) (void)(0)
|
||||||
|
#define CAPTURE( ... ) (void)(0)
|
||||||
|
|
||||||
|
#endif // end of user facing macro declarations
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CATCH_MESSAGE_HPP_INCLUDED
|
107
plugins/storage_test_plugin/src/catch2/catch_registry_hub.cpp
Normal file
107
plugins/storage_test_plugin/src/catch2/catch_registry_hub.cpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_context.hpp>
|
||||||
|
#include <catch2/internal/catch_enforce.hpp>
|
||||||
|
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||||
|
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_exception_translator_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_tag_alias_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_startup_exception_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_singletons.hpp>
|
||||||
|
#include <catch2/internal/catch_enum_values_registry.hpp>
|
||||||
|
#include <catch2/catch_test_case_info.hpp>
|
||||||
|
#include <catch2/internal/catch_noncopyable.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class RegistryHub : public IRegistryHub,
|
||||||
|
public IMutableRegistryHub,
|
||||||
|
private Detail::NonCopyable {
|
||||||
|
|
||||||
|
public: // IRegistryHub
|
||||||
|
RegistryHub() = default;
|
||||||
|
ReporterRegistry const& getReporterRegistry() const override {
|
||||||
|
return m_reporterRegistry;
|
||||||
|
}
|
||||||
|
ITestCaseRegistry const& getTestCaseRegistry() const override {
|
||||||
|
return m_testCaseRegistry;
|
||||||
|
}
|
||||||
|
IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
|
||||||
|
return m_exceptionTranslatorRegistry;
|
||||||
|
}
|
||||||
|
ITagAliasRegistry const& getTagAliasRegistry() const override {
|
||||||
|
return m_tagAliasRegistry;
|
||||||
|
}
|
||||||
|
StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
|
||||||
|
return m_exceptionRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public: // IMutableRegistryHub
|
||||||
|
void registerReporter( std::string const& name, IReporterFactoryPtr factory ) override {
|
||||||
|
m_reporterRegistry.registerReporter( name, CATCH_MOVE(factory) );
|
||||||
|
}
|
||||||
|
void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) override {
|
||||||
|
m_reporterRegistry.registerListener( CATCH_MOVE(factory) );
|
||||||
|
}
|
||||||
|
void registerTest( Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker ) override {
|
||||||
|
m_testCaseRegistry.registerTest( CATCH_MOVE(testInfo), CATCH_MOVE(invoker) );
|
||||||
|
}
|
||||||
|
void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) override {
|
||||||
|
m_exceptionTranslatorRegistry.registerTranslator( CATCH_MOVE(translator) );
|
||||||
|
}
|
||||||
|
void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
|
||||||
|
m_tagAliasRegistry.add( alias, tag, lineInfo );
|
||||||
|
}
|
||||||
|
void registerStartupException() noexcept override {
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
m_exceptionRegistry.add(std::current_exception());
|
||||||
|
#else
|
||||||
|
CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
|
||||||
|
return m_enumValuesRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TestRegistry m_testCaseRegistry;
|
||||||
|
ReporterRegistry m_reporterRegistry;
|
||||||
|
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
|
||||||
|
TagAliasRegistry m_tagAliasRegistry;
|
||||||
|
StartupExceptionRegistry m_exceptionRegistry;
|
||||||
|
Detail::EnumValuesRegistry m_enumValuesRegistry;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
|
||||||
|
|
||||||
|
IRegistryHub const& getRegistryHub() {
|
||||||
|
return RegistryHubSingleton::get();
|
||||||
|
}
|
||||||
|
IMutableRegistryHub& getMutableRegistryHub() {
|
||||||
|
return RegistryHubSingleton::getMutable();
|
||||||
|
}
|
||||||
|
void cleanUp() {
|
||||||
|
cleanupSingletons();
|
||||||
|
cleanUpContext();
|
||||||
|
}
|
||||||
|
std::string translateActiveException() {
|
||||||
|
return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // end namespace Catch
|
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_SECTION_INFO_HPP_INCLUDED
|
||||||
|
#define CATCH_SECTION_INFO_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
#include <catch2/internal/catch_source_line_info.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
#include <catch2/catch_totals.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct SectionInfo {
|
||||||
|
// The last argument is ignored, so that people can write
|
||||||
|
// SECTION("ShortName", "Proper description that is long") and
|
||||||
|
// still use the `-c` flag comfortably.
|
||||||
|
SectionInfo( SourceLineInfo const& _lineInfo, std::string _name,
|
||||||
|
const char* const = nullptr ):
|
||||||
|
name(CATCH_MOVE(_name)),
|
||||||
|
lineInfo(_lineInfo)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
SourceLineInfo lineInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SectionEndInfo {
|
||||||
|
SectionInfo sectionInfo;
|
||||||
|
Counts prevAssertions;
|
||||||
|
double durationInSeconds;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_SECTION_INFO_HPP_INCLUDED
|
364
plugins/storage_test_plugin/src/catch2/catch_session.cpp
Normal file
364
plugins/storage_test_plugin/src/catch2/catch_session.cpp
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/catch_session.hpp>
|
||||||
|
#include <catch2/internal/catch_console_colour.hpp>
|
||||||
|
#include <catch2/internal/catch_enforce.hpp>
|
||||||
|
#include <catch2/internal/catch_list.hpp>
|
||||||
|
#include <catch2/internal/catch_context.hpp>
|
||||||
|
#include <catch2/internal/catch_run_context.hpp>
|
||||||
|
#include <catch2/catch_test_spec.hpp>
|
||||||
|
#include <catch2/catch_version.hpp>
|
||||||
|
#include <catch2/internal/catch_startup_exception_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_sharding.hpp>
|
||||||
|
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||||
|
#include <catch2/internal/catch_textflow.hpp>
|
||||||
|
#include <catch2/internal/catch_windows_h_proxy.hpp>
|
||||||
|
#include <catch2/reporters/catch_reporter_multi.hpp>
|
||||||
|
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
#include <catch2/internal/catch_stdstreams.hpp>
|
||||||
|
#include <catch2/internal/catch_istream.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <exception>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const int MaxExitCode = 255;
|
||||||
|
|
||||||
|
IEventListenerPtr createReporter(std::string const& reporterName, ReporterConfig&& config) {
|
||||||
|
auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, CATCH_MOVE(config));
|
||||||
|
CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << '\'');
|
||||||
|
|
||||||
|
return reporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEventListenerPtr prepareReporters(Config const* config) {
|
||||||
|
if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()
|
||||||
|
&& config->getProcessedReporterSpecs().size() == 1) {
|
||||||
|
auto const& spec = config->getProcessedReporterSpecs()[0];
|
||||||
|
return createReporter(
|
||||||
|
spec.name,
|
||||||
|
ReporterConfig( config,
|
||||||
|
makeStream( spec.outputFilename ),
|
||||||
|
spec.colourMode,
|
||||||
|
spec.customOptions ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto multi = Detail::make_unique<MultiReporter>(config);
|
||||||
|
|
||||||
|
auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
|
||||||
|
for (auto const& listener : listeners) {
|
||||||
|
multi->addListener(listener->create(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto const& reporterSpec : config->getProcessedReporterSpecs() ) {
|
||||||
|
multi->addReporter( createReporter(
|
||||||
|
reporterSpec.name,
|
||||||
|
ReporterConfig( config,
|
||||||
|
makeStream( reporterSpec.outputFilename ),
|
||||||
|
reporterSpec.colourMode,
|
||||||
|
reporterSpec.customOptions ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return multi;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestGroup {
|
||||||
|
public:
|
||||||
|
explicit TestGroup(IEventListenerPtr&& reporter, Config const* config):
|
||||||
|
m_reporter(reporter.get()),
|
||||||
|
m_config{config},
|
||||||
|
m_context{config, CATCH_MOVE(reporter)} {
|
||||||
|
|
||||||
|
assert( m_config->testSpec().getInvalidSpecs().empty() &&
|
||||||
|
"Invalid test specs should be handled before running tests" );
|
||||||
|
|
||||||
|
auto const& allTestCases = getAllTestCasesSorted(*m_config);
|
||||||
|
auto const& testSpec = m_config->testSpec();
|
||||||
|
if ( !testSpec.hasFilters() ) {
|
||||||
|
for ( auto const& test : allTestCases ) {
|
||||||
|
if ( !test.getTestCaseInfo().isHidden() ) {
|
||||||
|
m_tests.emplace( &test );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_matches =
|
||||||
|
testSpec.matchesByFilter( allTestCases, *m_config );
|
||||||
|
for ( auto const& match : m_matches ) {
|
||||||
|
m_tests.insert( match.tests.begin(),
|
||||||
|
match.tests.end() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_tests = createShard(m_tests, m_config->shardCount(), m_config->shardIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
Totals execute() {
|
||||||
|
Totals totals;
|
||||||
|
for (auto const& testCase : m_tests) {
|
||||||
|
if (!m_context.aborting())
|
||||||
|
totals += m_context.runTest(*testCase);
|
||||||
|
else
|
||||||
|
m_reporter->skipTest(testCase->getTestCaseInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& match : m_matches) {
|
||||||
|
if (match.tests.empty()) {
|
||||||
|
m_unmatchedTestSpecs = true;
|
||||||
|
m_reporter->noMatchingTestCases( match.name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return totals;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hadUnmatchedTestSpecs() const {
|
||||||
|
return m_unmatchedTestSpecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
IEventListener* m_reporter;
|
||||||
|
Config const* m_config;
|
||||||
|
RunContext m_context;
|
||||||
|
std::set<TestCaseHandle const*> m_tests;
|
||||||
|
TestSpec::Matches m_matches;
|
||||||
|
bool m_unmatchedTestSpecs = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
void applyFilenamesAsTags() {
|
||||||
|
for (auto const& testInfo : getRegistryHub().getTestCaseRegistry().getAllInfos()) {
|
||||||
|
testInfo->addFilenameTag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anon namespace
|
||||||
|
|
||||||
|
Session::Session() {
|
||||||
|
static bool alreadyInstantiated = false;
|
||||||
|
if( alreadyInstantiated ) {
|
||||||
|
CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
|
||||||
|
CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// There cannot be exceptions at startup in no-exception mode.
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
|
||||||
|
if ( !exceptions.empty() ) {
|
||||||
|
config();
|
||||||
|
getCurrentMutableContext().setConfig(m_config.get());
|
||||||
|
|
||||||
|
m_startupExceptions = true;
|
||||||
|
auto errStream = makeStream( "%stderr" );
|
||||||
|
auto colourImpl = makeColourImpl(
|
||||||
|
ColourMode::PlatformDefault, errStream.get() );
|
||||||
|
auto guard = colourImpl->guardColour( Colour::Red );
|
||||||
|
errStream->stream() << "Errors occurred during startup!" << '\n';
|
||||||
|
// iterate over all exceptions and notify user
|
||||||
|
for ( const auto& ex_ptr : exceptions ) {
|
||||||
|
try {
|
||||||
|
std::rethrow_exception(ex_ptr);
|
||||||
|
} catch ( std::exception const& ex ) {
|
||||||
|
errStream->stream() << TextFlow::Column( ex.what() ).indent(2) << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
alreadyInstantiated = true;
|
||||||
|
m_cli = makeCommandLineParser( m_configData );
|
||||||
|
}
|
||||||
|
Session::~Session() {
|
||||||
|
Catch::cleanUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::showHelp() const {
|
||||||
|
Catch::cout()
|
||||||
|
<< "\nCatch2 v" << libraryVersion() << '\n'
|
||||||
|
<< m_cli << '\n'
|
||||||
|
<< "For more detailed usage please see the project docs\n\n" << std::flush;
|
||||||
|
}
|
||||||
|
void Session::libIdentify() {
|
||||||
|
Catch::cout()
|
||||||
|
<< std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
|
||||||
|
<< std::left << std::setw(16) << "category: " << "testframework\n"
|
||||||
|
<< std::left << std::setw(16) << "framework: " << "Catch2\n"
|
||||||
|
<< std::left << std::setw(16) << "version: " << libraryVersion() << '\n' << std::flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Session::applyCommandLine( int argc, char const * const * argv ) {
|
||||||
|
if( m_startupExceptions )
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
auto result = m_cli.parse( Clara::Args( argc, argv ) );
|
||||||
|
|
||||||
|
if( !result ) {
|
||||||
|
config();
|
||||||
|
getCurrentMutableContext().setConfig(m_config.get());
|
||||||
|
auto errStream = makeStream( "%stderr" );
|
||||||
|
auto colour = makeColourImpl( ColourMode::PlatformDefault, errStream.get() );
|
||||||
|
|
||||||
|
errStream->stream()
|
||||||
|
<< colour->guardColour( Colour::Red )
|
||||||
|
<< "\nError(s) in input:\n"
|
||||||
|
<< TextFlow::Column( result.errorMessage() ).indent( 2 )
|
||||||
|
<< "\n\n";
|
||||||
|
errStream->stream() << "Run with -? for usage\n\n" << std::flush;
|
||||||
|
return MaxExitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_configData.showHelp )
|
||||||
|
showHelp();
|
||||||
|
if( m_configData.libIdentify )
|
||||||
|
libIdentify();
|
||||||
|
|
||||||
|
m_config.reset();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
|
||||||
|
int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
|
||||||
|
|
||||||
|
char **utf8Argv = new char *[ argc ];
|
||||||
|
|
||||||
|
for ( int i = 0; i < argc; ++i ) {
|
||||||
|
int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
|
||||||
|
|
||||||
|
utf8Argv[ i ] = new char[ bufSize ];
|
||||||
|
|
||||||
|
WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
int returnCode = applyCommandLine( argc, utf8Argv );
|
||||||
|
|
||||||
|
for ( int i = 0; i < argc; ++i )
|
||||||
|
delete [] utf8Argv[ i ];
|
||||||
|
|
||||||
|
delete [] utf8Argv;
|
||||||
|
|
||||||
|
return returnCode;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Session::useConfigData( ConfigData const& configData ) {
|
||||||
|
m_configData = configData;
|
||||||
|
m_config.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Session::run() {
|
||||||
|
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
|
||||||
|
Catch::cout() << "...waiting for enter/ return before starting\n" << std::flush;
|
||||||
|
static_cast<void>(std::getchar());
|
||||||
|
}
|
||||||
|
int exitCode = runInternal();
|
||||||
|
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
|
||||||
|
Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << '\n' << std::flush;
|
||||||
|
static_cast<void>(std::getchar());
|
||||||
|
}
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clara::Parser const& Session::cli() const {
|
||||||
|
return m_cli;
|
||||||
|
}
|
||||||
|
void Session::cli( Clara::Parser const& newParser ) {
|
||||||
|
m_cli = newParser;
|
||||||
|
}
|
||||||
|
ConfigData& Session::configData() {
|
||||||
|
return m_configData;
|
||||||
|
}
|
||||||
|
Config& Session::config() {
|
||||||
|
if( !m_config )
|
||||||
|
m_config = Detail::make_unique<Config>( m_configData );
|
||||||
|
return *m_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Session::runInternal() {
|
||||||
|
if( m_startupExceptions )
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (m_configData.showHelp || m_configData.libIdentify) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m_configData.shardIndex >= m_configData.shardCount ) {
|
||||||
|
Catch::cerr() << "The shard count (" << m_configData.shardCount
|
||||||
|
<< ") must be greater than the shard index ("
|
||||||
|
<< m_configData.shardIndex << ")\n"
|
||||||
|
<< std::flush;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CATCH_TRY {
|
||||||
|
config(); // Force config to be constructed
|
||||||
|
|
||||||
|
seedRng( *m_config );
|
||||||
|
|
||||||
|
if (m_configData.filenamesAsTags) {
|
||||||
|
applyFilenamesAsTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up global config instance before we start calling into other functions
|
||||||
|
getCurrentMutableContext().setConfig(m_config.get());
|
||||||
|
|
||||||
|
// Create reporter(s) so we can route listings through them
|
||||||
|
auto reporter = prepareReporters(m_config.get());
|
||||||
|
|
||||||
|
auto const& invalidSpecs = m_config->testSpec().getInvalidSpecs();
|
||||||
|
if ( !invalidSpecs.empty() ) {
|
||||||
|
for ( auto const& spec : invalidSpecs ) {
|
||||||
|
reporter->reportInvalidTestSpec( spec );
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Handle list request
|
||||||
|
if (list(*reporter, *m_config)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestGroup tests { CATCH_MOVE(reporter), m_config.get() };
|
||||||
|
auto const totals = tests.execute();
|
||||||
|
|
||||||
|
if ( tests.hadUnmatchedTestSpecs()
|
||||||
|
&& m_config->warnAboutUnmatchedTestSpecs() ) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( totals.testCases.total() == 0
|
||||||
|
&& !m_config->zeroTestsCountAsSuccess() ) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( totals.testCases.total() > 0 &&
|
||||||
|
totals.testCases.total() == totals.testCases.skipped
|
||||||
|
&& !m_config->zeroTestsCountAsSuccess() ) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that on unices only the lower 8 bits are usually used, clamping
|
||||||
|
// the return value to 255 prevents false negative when some multiple
|
||||||
|
// of 256 tests has failed
|
||||||
|
return (std::min) (MaxExitCode, static_cast<int>(totals.assertions.failed));
|
||||||
|
}
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
catch( std::exception& ex ) {
|
||||||
|
Catch::cerr() << ex.what() << '\n' << std::flush;
|
||||||
|
return MaxExitCode;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace Catch
|
62
plugins/storage_test_plugin/src/catch2/catch_session.hpp
Normal file
62
plugins/storage_test_plugin/src/catch2/catch_session.hpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_SESSION_HPP_INCLUDED
|
||||||
|
#define CATCH_SESSION_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_commandline.hpp>
|
||||||
|
#include <catch2/internal/catch_noncopyable.hpp>
|
||||||
|
#include <catch2/catch_config.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
#include <catch2/internal/catch_config_wchar.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
class Session : Detail::NonCopyable {
|
||||||
|
public:
|
||||||
|
|
||||||
|
Session();
|
||||||
|
~Session();
|
||||||
|
|
||||||
|
void showHelp() const;
|
||||||
|
void libIdentify();
|
||||||
|
|
||||||
|
int applyCommandLine( int argc, char const * const * argv );
|
||||||
|
#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
|
||||||
|
int applyCommandLine( int argc, wchar_t const * const * argv );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void useConfigData( ConfigData const& configData );
|
||||||
|
|
||||||
|
template<typename CharT>
|
||||||
|
int run(int argc, CharT const * const argv[]) {
|
||||||
|
if (m_startupExceptions)
|
||||||
|
return 1;
|
||||||
|
int returnCode = applyCommandLine(argc, argv);
|
||||||
|
if (returnCode == 0)
|
||||||
|
returnCode = run();
|
||||||
|
return returnCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
int run();
|
||||||
|
|
||||||
|
Clara::Parser const& cli() const;
|
||||||
|
void cli( Clara::Parser const& newParser );
|
||||||
|
ConfigData& configData();
|
||||||
|
Config& config();
|
||||||
|
private:
|
||||||
|
int runInternal();
|
||||||
|
|
||||||
|
Clara::Parser m_cli;
|
||||||
|
ConfigData m_configData;
|
||||||
|
Detail::unique_ptr<Config> m_config;
|
||||||
|
bool m_startupExceptions = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_SESSION_HPP_INCLUDED
|
29
plugins/storage_test_plugin/src/catch2/catch_tag_alias.hpp
Normal file
29
plugins/storage_test_plugin/src/catch2/catch_tag_alias.hpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_TAG_ALIAS_HPP_INCLUDED
|
||||||
|
#define CATCH_TAG_ALIAS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_source_line_info.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct TagAlias {
|
||||||
|
TagAlias(std::string const& _tag, SourceLineInfo _lineInfo):
|
||||||
|
tag(_tag),
|
||||||
|
lineInfo(_lineInfo)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string tag;
|
||||||
|
SourceLineInfo lineInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_TAG_ALIAS_HPP_INCLUDED
|
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/catch_tag_alias_autoregistrar.hpp>
|
||||||
|
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {
|
||||||
|
CATCH_TRY {
|
||||||
|
getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);
|
||||||
|
} CATCH_CATCH_ALL {
|
||||||
|
// Do not throw when constructing global objects, instead register the exception to be processed later
|
||||||
|
getMutableRegistryHub().registerStartupException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
|
||||||
|
#define CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_name.hpp>
|
||||||
|
#include <catch2/internal/catch_source_line_info.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct RegistrarForTagAliases {
|
||||||
|
RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
|
||||||
|
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||||
|
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||||
|
namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
|
||||||
|
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||||
|
|
||||||
|
#endif // CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
|
@ -0,0 +1,124 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
|
||||||
|
#define CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
|
||||||
|
|
||||||
|
// We need this suppression to leak, because it took until GCC 10
|
||||||
|
// for the front end to handle local suppression via _Pragma properly
|
||||||
|
// inside templates (so `TEMPLATE_TEST_CASE` and co).
|
||||||
|
// **THIS IS DIFFERENT FOR STANDARD TESTS, WHERE GCC 9 IS SUFFICIENT**
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ < 10
|
||||||
|
#pragma GCC diagnostic ignored "-Wparentheses"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <catch2/internal/catch_template_test_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_preprocessor.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
|
||||||
|
|
||||||
|
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
|
||||||
|
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
|
||||||
|
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
|
||||||
|
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
|
||||||
|
#define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
|
||||||
|
#define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
#else
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
|
||||||
|
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
|
||||||
|
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
|
||||||
|
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||||
|
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
|
||||||
|
#define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
|
||||||
|
#define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
|
||||||
|
|
||||||
|
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
|
||||||
|
#else
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
|
||||||
|
#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// When disabled, these can be shared between proper preprocessor and MSVC preprocessor
|
||||||
|
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||||
|
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||||
|
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
#define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE(__VA_ARGS__)
|
||||||
|
#define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
|
||||||
|
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
|
||||||
|
|
||||||
|
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||||
|
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||||
|
#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
|
||||||
|
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
|
||||||
|
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
|
||||||
|
#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
|
||||||
|
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
|
||||||
|
#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
|
||||||
|
#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
#else
|
||||||
|
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
|
||||||
|
#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
|
||||||
|
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||||
|
#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
|
||||||
|
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
|
||||||
|
#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
|
||||||
|
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||||
|
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
|
||||||
|
#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
|
||||||
|
#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
|
||||||
|
|
||||||
|
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||||
|
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
|
||||||
|
#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
|
||||||
|
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
|
||||||
|
#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
|
||||||
|
#else
|
||||||
|
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
|
||||||
|
#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
|
||||||
|
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
|
||||||
|
#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// When disabled, these can be shared between proper preprocessor and MSVC preprocessor
|
||||||
|
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||||
|
#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||||
|
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
#define TEMPLATE_LIST_TEST_CASE( ... ) TEMPLATE_TEST_CASE(__VA_ARGS__)
|
||||||
|
#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
|
||||||
|
#endif // end of user facing macro declarations
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
|
263
plugins/storage_test_plugin/src/catch2/catch_test_case_info.cpp
Normal file
263
plugins/storage_test_plugin/src/catch2/catch_test_case_info.cpp
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/catch_test_case_info.hpp>
|
||||||
|
#include <catch2/internal/catch_enforce.hpp>
|
||||||
|
#include <catch2/internal/catch_string_manip.hpp>
|
||||||
|
#include <catch2/internal/catch_case_insensitive_comparisons.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cctype>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
using TCP_underlying_type = uint8_t;
|
||||||
|
static_assert(sizeof(TestCaseProperties) == sizeof(TCP_underlying_type),
|
||||||
|
"The size of the TestCaseProperties is different from the assumed size");
|
||||||
|
|
||||||
|
TestCaseProperties operator|(TestCaseProperties lhs, TestCaseProperties rhs) {
|
||||||
|
return static_cast<TestCaseProperties>(
|
||||||
|
static_cast<TCP_underlying_type>(lhs) | static_cast<TCP_underlying_type>(rhs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCaseProperties& operator|=(TestCaseProperties& lhs, TestCaseProperties rhs) {
|
||||||
|
lhs = static_cast<TestCaseProperties>(
|
||||||
|
static_cast<TCP_underlying_type>(lhs) | static_cast<TCP_underlying_type>(rhs)
|
||||||
|
);
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCaseProperties operator&(TestCaseProperties lhs, TestCaseProperties rhs) {
|
||||||
|
return static_cast<TestCaseProperties>(
|
||||||
|
static_cast<TCP_underlying_type>(lhs) & static_cast<TCP_underlying_type>(rhs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool applies(TestCaseProperties tcp) {
|
||||||
|
static_assert(static_cast<TCP_underlying_type>(TestCaseProperties::None) == 0,
|
||||||
|
"TestCaseProperties::None must be equal to 0");
|
||||||
|
return tcp != TestCaseProperties::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCaseProperties parseSpecialTag( StringRef tag ) {
|
||||||
|
if( !tag.empty() && tag[0] == '.' )
|
||||||
|
return TestCaseProperties::IsHidden;
|
||||||
|
else if( tag == "!throws"_sr )
|
||||||
|
return TestCaseProperties::Throws;
|
||||||
|
else if( tag == "!shouldfail"_sr )
|
||||||
|
return TestCaseProperties::ShouldFail;
|
||||||
|
else if( tag == "!mayfail"_sr )
|
||||||
|
return TestCaseProperties::MayFail;
|
||||||
|
else if( tag == "!nonportable"_sr )
|
||||||
|
return TestCaseProperties::NonPortable;
|
||||||
|
else if( tag == "!benchmark"_sr )
|
||||||
|
return TestCaseProperties::Benchmark | TestCaseProperties::IsHidden;
|
||||||
|
else
|
||||||
|
return TestCaseProperties::None;
|
||||||
|
}
|
||||||
|
bool isReservedTag( StringRef tag ) {
|
||||||
|
return parseSpecialTag( tag ) == TestCaseProperties::None
|
||||||
|
&& tag.size() > 0
|
||||||
|
&& !std::isalnum( static_cast<unsigned char>(tag[0]) );
|
||||||
|
}
|
||||||
|
void enforceNotReservedTag( StringRef tag, SourceLineInfo const& _lineInfo ) {
|
||||||
|
CATCH_ENFORCE( !isReservedTag(tag),
|
||||||
|
"Tag name: [" << tag << "] is not allowed.\n"
|
||||||
|
<< "Tag names starting with non alphanumeric characters are reserved\n"
|
||||||
|
<< _lineInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string makeDefaultName() {
|
||||||
|
static size_t counter = 0;
|
||||||
|
return "Anonymous test case " + std::to_string(++counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringRef extractFilenamePart(StringRef filename) {
|
||||||
|
size_t lastDot = filename.size();
|
||||||
|
while (lastDot > 0 && filename[lastDot - 1] != '.') {
|
||||||
|
--lastDot;
|
||||||
|
}
|
||||||
|
--lastDot;
|
||||||
|
|
||||||
|
size_t nameStart = lastDot;
|
||||||
|
while (nameStart > 0 && filename[nameStart - 1] != '/' && filename[nameStart - 1] != '\\') {
|
||||||
|
--nameStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filename.substr(nameStart, lastDot - nameStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the upper bound on size of extra tags ([#file]+[.])
|
||||||
|
size_t sizeOfExtraTags(StringRef filepath) {
|
||||||
|
// [.] is 3, [#] is another 3
|
||||||
|
const size_t extras = 3 + 3;
|
||||||
|
return extractFilenamePart(filepath).size() + extras;
|
||||||
|
}
|
||||||
|
} // end unnamed namespace
|
||||||
|
|
||||||
|
bool operator<( Tag const& lhs, Tag const& rhs ) {
|
||||||
|
Detail::CaseInsensitiveLess cmp;
|
||||||
|
return cmp( lhs.original, rhs.original );
|
||||||
|
}
|
||||||
|
bool operator==( Tag const& lhs, Tag const& rhs ) {
|
||||||
|
Detail::CaseInsensitiveEqualTo cmp;
|
||||||
|
return cmp( lhs.original, rhs.original );
|
||||||
|
}
|
||||||
|
|
||||||
|
Detail::unique_ptr<TestCaseInfo>
|
||||||
|
makeTestCaseInfo(StringRef _className,
|
||||||
|
NameAndTags const& nameAndTags,
|
||||||
|
SourceLineInfo const& _lineInfo ) {
|
||||||
|
return Detail::make_unique<TestCaseInfo>(_className, nameAndTags, _lineInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCaseInfo::TestCaseInfo(StringRef _className,
|
||||||
|
NameAndTags const& _nameAndTags,
|
||||||
|
SourceLineInfo const& _lineInfo):
|
||||||
|
name( _nameAndTags.name.empty() ? makeDefaultName() : _nameAndTags.name ),
|
||||||
|
className( _className ),
|
||||||
|
lineInfo( _lineInfo )
|
||||||
|
{
|
||||||
|
StringRef originalTags = _nameAndTags.tags;
|
||||||
|
// We need to reserve enough space to store all of the tags
|
||||||
|
// (including optional hidden tag and filename tag)
|
||||||
|
auto requiredSize = originalTags.size() + sizeOfExtraTags(_lineInfo.file);
|
||||||
|
backingTags.reserve(requiredSize);
|
||||||
|
|
||||||
|
// We cannot copy the tags directly, as we need to normalize
|
||||||
|
// some tags, so that [.foo] is copied as [.][foo].
|
||||||
|
size_t tagStart = 0;
|
||||||
|
size_t tagEnd = 0;
|
||||||
|
bool inTag = false;
|
||||||
|
for (size_t idx = 0; idx < originalTags.size(); ++idx) {
|
||||||
|
auto c = originalTags[idx];
|
||||||
|
if (c == '[') {
|
||||||
|
CATCH_ENFORCE(
|
||||||
|
!inTag,
|
||||||
|
"Found '[' inside a tag while registering test case '"
|
||||||
|
<< _nameAndTags.name << "' at " << _lineInfo );
|
||||||
|
|
||||||
|
inTag = true;
|
||||||
|
tagStart = idx;
|
||||||
|
}
|
||||||
|
if (c == ']') {
|
||||||
|
CATCH_ENFORCE(
|
||||||
|
inTag,
|
||||||
|
"Found unmatched ']' while registering test case '"
|
||||||
|
<< _nameAndTags.name << "' at " << _lineInfo );
|
||||||
|
|
||||||
|
inTag = false;
|
||||||
|
tagEnd = idx;
|
||||||
|
assert(tagStart < tagEnd);
|
||||||
|
|
||||||
|
// We need to check the tag for special meanings, copy
|
||||||
|
// it over to backing storage and actually reference the
|
||||||
|
// backing storage in the saved tags
|
||||||
|
StringRef tagStr = originalTags.substr(tagStart+1, tagEnd - tagStart - 1);
|
||||||
|
CATCH_ENFORCE( !tagStr.empty(),
|
||||||
|
"Found an empty tag while registering test case '"
|
||||||
|
<< _nameAndTags.name << "' at "
|
||||||
|
<< _lineInfo );
|
||||||
|
|
||||||
|
enforceNotReservedTag(tagStr, lineInfo);
|
||||||
|
properties |= parseSpecialTag(tagStr);
|
||||||
|
// When copying a tag to the backing storage, we need to
|
||||||
|
// check if it is a merged hide tag, such as [.foo], and
|
||||||
|
// if it is, we need to handle it as if it was [foo].
|
||||||
|
if (tagStr.size() > 1 && tagStr[0] == '.') {
|
||||||
|
tagStr = tagStr.substr(1, tagStr.size() - 1);
|
||||||
|
}
|
||||||
|
// We skip over dealing with the [.] tag, as we will add
|
||||||
|
// it later unconditionally and then sort and unique all
|
||||||
|
// the tags.
|
||||||
|
internalAppendTag(tagStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CATCH_ENFORCE( !inTag,
|
||||||
|
"Found an unclosed tag while registering test case '"
|
||||||
|
<< _nameAndTags.name << "' at " << _lineInfo );
|
||||||
|
|
||||||
|
|
||||||
|
// Add [.] if relevant
|
||||||
|
if (isHidden()) {
|
||||||
|
internalAppendTag("."_sr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort and prepare tags
|
||||||
|
std::sort(begin(tags), end(tags));
|
||||||
|
tags.erase(std::unique(begin(tags), end(tags)),
|
||||||
|
end(tags));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestCaseInfo::isHidden() const {
|
||||||
|
return applies( properties & TestCaseProperties::IsHidden );
|
||||||
|
}
|
||||||
|
bool TestCaseInfo::throws() const {
|
||||||
|
return applies( properties & TestCaseProperties::Throws );
|
||||||
|
}
|
||||||
|
bool TestCaseInfo::okToFail() const {
|
||||||
|
return applies( properties & (TestCaseProperties::ShouldFail | TestCaseProperties::MayFail ) );
|
||||||
|
}
|
||||||
|
bool TestCaseInfo::expectedToFail() const {
|
||||||
|
return applies( properties & (TestCaseProperties::ShouldFail) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestCaseInfo::addFilenameTag() {
|
||||||
|
std::string combined("#");
|
||||||
|
combined += extractFilenamePart(lineInfo.file);
|
||||||
|
internalAppendTag(combined);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TestCaseInfo::tagsAsString() const {
|
||||||
|
std::string ret;
|
||||||
|
// '[' and ']' per tag
|
||||||
|
std::size_t full_size = 2 * tags.size();
|
||||||
|
for (const auto& tag : tags) {
|
||||||
|
full_size += tag.original.size();
|
||||||
|
}
|
||||||
|
ret.reserve(full_size);
|
||||||
|
for (const auto& tag : tags) {
|
||||||
|
ret.push_back('[');
|
||||||
|
ret += tag.original;
|
||||||
|
ret.push_back(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestCaseInfo::internalAppendTag(StringRef tagStr) {
|
||||||
|
backingTags += '[';
|
||||||
|
const auto backingStart = backingTags.size();
|
||||||
|
backingTags += tagStr;
|
||||||
|
const auto backingEnd = backingTags.size();
|
||||||
|
backingTags += ']';
|
||||||
|
tags.emplace_back(StringRef(backingTags.c_str() + backingStart, backingEnd - backingStart));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<( TestCaseInfo const& lhs, TestCaseInfo const& rhs ) {
|
||||||
|
// We want to avoid redoing the string comparisons multiple times,
|
||||||
|
// so we store the result of a three-way comparison before using
|
||||||
|
// it in the actual comparison logic.
|
||||||
|
const auto cmpName = lhs.name.compare( rhs.name );
|
||||||
|
if ( cmpName != 0 ) {
|
||||||
|
return cmpName < 0;
|
||||||
|
}
|
||||||
|
const auto cmpClassName = lhs.className.compare( rhs.className );
|
||||||
|
if ( cmpClassName != 0 ) {
|
||||||
|
return cmpClassName < 0;
|
||||||
|
}
|
||||||
|
return lhs.tags < rhs.tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCaseInfo const& TestCaseHandle::getTestCaseInfo() const {
|
||||||
|
return *m_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace Catch
|
131
plugins/storage_test_plugin/src/catch2/catch_test_case_info.hpp
Normal file
131
plugins/storage_test_plugin/src/catch2/catch_test_case_info.hpp
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_TEST_CASE_INFO_HPP_INCLUDED
|
||||||
|
#define CATCH_TEST_CASE_INFO_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_source_line_info.hpp>
|
||||||
|
#include <catch2/internal/catch_noncopyable.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
#include <catch2/internal/catch_test_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wpadded"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A **view** of a tag string that provides case insensitive comparisons
|
||||||
|
*
|
||||||
|
* Note that in Catch2 internals, the square brackets around tags are
|
||||||
|
* not a part of tag's representation, so e.g. "[cool-tag]" is represented
|
||||||
|
* as "cool-tag" internally.
|
||||||
|
*/
|
||||||
|
struct Tag {
|
||||||
|
constexpr Tag(StringRef original_):
|
||||||
|
original(original_)
|
||||||
|
{}
|
||||||
|
StringRef original;
|
||||||
|
|
||||||
|
friend bool operator< ( Tag const& lhs, Tag const& rhs );
|
||||||
|
friend bool operator==( Tag const& lhs, Tag const& rhs );
|
||||||
|
};
|
||||||
|
|
||||||
|
class ITestInvoker;
|
||||||
|
|
||||||
|
enum class TestCaseProperties : uint8_t {
|
||||||
|
None = 0,
|
||||||
|
IsHidden = 1 << 1,
|
||||||
|
ShouldFail = 1 << 2,
|
||||||
|
MayFail = 1 << 3,
|
||||||
|
Throws = 1 << 4,
|
||||||
|
NonPortable = 1 << 5,
|
||||||
|
Benchmark = 1 << 6
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various metadata about the test case.
|
||||||
|
*
|
||||||
|
* A test case is uniquely identified by its (class)name and tags
|
||||||
|
* combination, with source location being ignored, and other properties
|
||||||
|
* being determined from tags.
|
||||||
|
*
|
||||||
|
* Tags are kept sorted.
|
||||||
|
*/
|
||||||
|
struct TestCaseInfo : Detail::NonCopyable {
|
||||||
|
|
||||||
|
TestCaseInfo(StringRef _className,
|
||||||
|
NameAndTags const& _tags,
|
||||||
|
SourceLineInfo const& _lineInfo);
|
||||||
|
|
||||||
|
bool isHidden() const;
|
||||||
|
bool throws() const;
|
||||||
|
bool okToFail() const;
|
||||||
|
bool expectedToFail() const;
|
||||||
|
|
||||||
|
// Adds the tag(s) with test's filename (for the -# flag)
|
||||||
|
void addFilenameTag();
|
||||||
|
|
||||||
|
//! Orders by name, classname and tags
|
||||||
|
friend bool operator<( TestCaseInfo const& lhs,
|
||||||
|
TestCaseInfo const& rhs );
|
||||||
|
|
||||||
|
|
||||||
|
std::string tagsAsString() const;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
StringRef className;
|
||||||
|
private:
|
||||||
|
std::string backingTags;
|
||||||
|
// Internally we copy tags to the backing storage and then add
|
||||||
|
// refs to this storage to the tags vector.
|
||||||
|
void internalAppendTag(StringRef tagString);
|
||||||
|
public:
|
||||||
|
std::vector<Tag> tags;
|
||||||
|
SourceLineInfo lineInfo;
|
||||||
|
TestCaseProperties properties = TestCaseProperties::None;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper over the test case information and the test case invoker
|
||||||
|
*
|
||||||
|
* Does not own either, and is specifically made to be cheap
|
||||||
|
* to copy around.
|
||||||
|
*/
|
||||||
|
class TestCaseHandle {
|
||||||
|
TestCaseInfo* m_info;
|
||||||
|
ITestInvoker* m_invoker;
|
||||||
|
public:
|
||||||
|
TestCaseHandle(TestCaseInfo* info, ITestInvoker* invoker) :
|
||||||
|
m_info(info), m_invoker(invoker) {}
|
||||||
|
|
||||||
|
void invoke() const {
|
||||||
|
m_invoker->invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCaseInfo const& getTestCaseInfo() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
Detail::unique_ptr<TestCaseInfo>
|
||||||
|
makeTestCaseInfo( StringRef className,
|
||||||
|
NameAndTags const& nameAndTags,
|
||||||
|
SourceLineInfo const& lineInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CATCH_TEST_CASE_INFO_HPP_INCLUDED
|
226
plugins/storage_test_plugin/src/catch2/catch_test_macros.hpp
Normal file
226
plugins/storage_test_plugin/src/catch2/catch_test_macros.hpp
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_TEST_MACROS_HPP_INCLUDED
|
||||||
|
#define CATCH_TEST_MACROS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_test_macro_impl.hpp>
|
||||||
|
#include <catch2/catch_message.hpp>
|
||||||
|
#include <catch2/catch_user_config.hpp>
|
||||||
|
#include <catch2/internal/catch_section.hpp>
|
||||||
|
#include <catch2/internal/catch_test_registry.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_name.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
// All of our user-facing macros support configuration toggle, that
|
||||||
|
// forces them to be defined prefixed with CATCH_. We also like to
|
||||||
|
// support another toggle that can minimize (disable) their implementation.
|
||||||
|
// Given this, we have 4 different configuration options below
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
|
||||||
|
|
||||||
|
#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
|
#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||||
|
|
||||||
|
#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
|
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
|
||||||
|
#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
|
|
||||||
|
#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
|
#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||||
|
#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||||
|
#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||||
|
#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||||
|
|
||||||
|
#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
|
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||||
|
#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
|
|
||||||
|
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||||
|
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||||
|
#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||||
|
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||||
|
#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
|
||||||
|
#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
|
#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
|
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
|
#define CATCH_SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
|
||||||
|
#define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
|
||||||
|
#define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
|
||||||
|
#define CATCH_STATIC_CHECK( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
|
||||||
|
#define CATCH_STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
|
||||||
|
#else
|
||||||
|
#define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ )
|
||||||
|
#define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )
|
||||||
|
#define CATCH_STATIC_CHECK( ... ) CATCH_CHECK( __VA_ARGS__ )
|
||||||
|
#define CATCH_STATIC_CHECK_FALSE( ... ) CATCH_CHECK_FALSE( __VA_ARGS__ )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// "BDD-style" convenience wrappers
|
||||||
|
#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
|
||||||
|
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
||||||
|
#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
|
||||||
|
#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
|
||||||
|
#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
|
||||||
|
#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
|
||||||
|
#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
|
||||||
|
#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
|
||||||
|
|
||||||
|
#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, implemented | vv prefixed, disabled
|
||||||
|
|
||||||
|
#define CATCH_REQUIRE( ... ) (void)(0)
|
||||||
|
#define CATCH_REQUIRE_FALSE( ... ) (void)(0)
|
||||||
|
|
||||||
|
#define CATCH_REQUIRE_THROWS( ... ) (void)(0)
|
||||||
|
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
|
||||||
|
#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0)
|
||||||
|
|
||||||
|
#define CATCH_CHECK( ... ) (void)(0)
|
||||||
|
#define CATCH_CHECK_FALSE( ... ) (void)(0)
|
||||||
|
#define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__)
|
||||||
|
#define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
|
||||||
|
#define CATCH_CHECK_NOFAIL( ... ) (void)(0)
|
||||||
|
|
||||||
|
#define CATCH_CHECK_THROWS( ... ) (void)(0)
|
||||||
|
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
|
||||||
|
#define CATCH_CHECK_NOTHROW( ... ) (void)(0)
|
||||||
|
|
||||||
|
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||||
|
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||||
|
#define CATCH_METHOD_AS_TEST_CASE( method, ... )
|
||||||
|
#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
||||||
|
#define CATCH_SECTION( ... )
|
||||||
|
#define CATCH_DYNAMIC_SECTION( ... )
|
||||||
|
#define CATCH_FAIL( ... ) (void)(0)
|
||||||
|
#define CATCH_FAIL_CHECK( ... ) (void)(0)
|
||||||
|
#define CATCH_SUCCEED( ... ) (void)(0)
|
||||||
|
#define CATCH_SKIP( ... ) (void)(0)
|
||||||
|
|
||||||
|
#define CATCH_STATIC_REQUIRE( ... ) (void)(0)
|
||||||
|
#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
|
||||||
|
#define CATCH_STATIC_CHECK( ... ) (void)(0)
|
||||||
|
#define CATCH_STATIC_CHECK_FALSE( ... ) (void)(0)
|
||||||
|
|
||||||
|
// "BDD-style" convenience wrappers
|
||||||
|
#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||||
|
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className )
|
||||||
|
#define CATCH_GIVEN( desc )
|
||||||
|
#define CATCH_AND_GIVEN( desc )
|
||||||
|
#define CATCH_WHEN( desc )
|
||||||
|
#define CATCH_AND_WHEN( desc )
|
||||||
|
#define CATCH_THEN( desc )
|
||||||
|
#define CATCH_AND_THEN( desc )
|
||||||
|
|
||||||
|
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, disabled | vv unprefixed, implemented
|
||||||
|
|
||||||
|
#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
|
#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||||
|
|
||||||
|
#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
|
#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
|
||||||
|
#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
|
|
||||||
|
#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
|
#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||||
|
#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||||
|
#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||||
|
#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||||
|
|
||||||
|
#define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
|
#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||||
|
#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
|
|
||||||
|
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||||
|
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
|
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||||
|
#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||||
|
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||||
|
#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
|
||||||
|
#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
|
#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
|
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
|
#define SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
|
||||||
|
#define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
|
||||||
|
#define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
|
||||||
|
#define STATIC_CHECK( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
|
||||||
|
#define STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
|
||||||
|
#else
|
||||||
|
#define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ )
|
||||||
|
#define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )
|
||||||
|
#define STATIC_CHECK( ... ) CHECK( __VA_ARGS__ )
|
||||||
|
#define STATIC_CHECK_FALSE( ... ) CHECK_FALSE( __VA_ARGS__ )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// "BDD-style" convenience wrappers
|
||||||
|
#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
|
||||||
|
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
||||||
|
#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
|
||||||
|
#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
|
||||||
|
#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
|
||||||
|
#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
|
||||||
|
#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
|
||||||
|
#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
|
||||||
|
|
||||||
|
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ unprefixed, implemented | vv unprefixed, disabled
|
||||||
|
|
||||||
|
#define REQUIRE( ... ) (void)(0)
|
||||||
|
#define REQUIRE_FALSE( ... ) (void)(0)
|
||||||
|
|
||||||
|
#define REQUIRE_THROWS( ... ) (void)(0)
|
||||||
|
#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
|
||||||
|
#define REQUIRE_NOTHROW( ... ) (void)(0)
|
||||||
|
|
||||||
|
#define CHECK( ... ) (void)(0)
|
||||||
|
#define CHECK_FALSE( ... ) (void)(0)
|
||||||
|
#define CHECKED_IF( ... ) if (__VA_ARGS__)
|
||||||
|
#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
|
||||||
|
#define CHECK_NOFAIL( ... ) (void)(0)
|
||||||
|
|
||||||
|
#define CHECK_THROWS( ... ) (void)(0)
|
||||||
|
#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
|
||||||
|
#define CHECK_NOTHROW( ... ) (void)(0)
|
||||||
|
|
||||||
|
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__)
|
||||||
|
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||||
|
#define METHOD_AS_TEST_CASE( method, ... )
|
||||||
|
#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
||||||
|
#define SECTION( ... )
|
||||||
|
#define DYNAMIC_SECTION( ... )
|
||||||
|
#define FAIL( ... ) (void)(0)
|
||||||
|
#define FAIL_CHECK( ... ) (void)(0)
|
||||||
|
#define SUCCEED( ... ) (void)(0)
|
||||||
|
#define SKIP( ... ) (void)(0)
|
||||||
|
|
||||||
|
#define STATIC_REQUIRE( ... ) (void)(0)
|
||||||
|
#define STATIC_REQUIRE_FALSE( ... ) (void)(0)
|
||||||
|
#define STATIC_CHECK( ... ) (void)(0)
|
||||||
|
#define STATIC_CHECK_FALSE( ... ) (void)(0)
|
||||||
|
|
||||||
|
// "BDD-style" convenience wrappers
|
||||||
|
#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ) )
|
||||||
|
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className )
|
||||||
|
|
||||||
|
#define GIVEN( desc )
|
||||||
|
#define AND_GIVEN( desc )
|
||||||
|
#define WHEN( desc )
|
||||||
|
#define AND_WHEN( desc )
|
||||||
|
#define THEN( desc )
|
||||||
|
#define AND_THEN( desc )
|
||||||
|
|
||||||
|
#endif // ^^ unprefixed, disabled
|
||||||
|
|
||||||
|
// end of user facing macros
|
||||||
|
|
||||||
|
#endif // CATCH_TEST_MACROS_HPP_INCLUDED
|
141
plugins/storage_test_plugin/src/catch2/catch_test_spec.cpp
Normal file
141
plugins/storage_test_plugin/src/catch2/catch_test_spec.cpp
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/catch_test_spec.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_testcase.hpp>
|
||||||
|
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||||
|
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||||
|
#include <catch2/internal/catch_string_manip.hpp>
|
||||||
|
#include <catch2/catch_test_case_info.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
TestSpec::Pattern::Pattern( std::string const& name )
|
||||||
|
: m_name( name )
|
||||||
|
{}
|
||||||
|
|
||||||
|
TestSpec::Pattern::~Pattern() = default;
|
||||||
|
|
||||||
|
std::string const& TestSpec::Pattern::name() const {
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
|
||||||
|
: Pattern( filterString )
|
||||||
|
, m_wildcardPattern( toLower( name ), CaseSensitive::No )
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
|
||||||
|
return m_wildcardPattern.matches( testCase.name );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSpec::NamePattern::serializeTo( std::ostream& out ) const {
|
||||||
|
out << '"' << name() << '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
|
||||||
|
: Pattern( filterString )
|
||||||
|
, m_tag( tag )
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
|
||||||
|
return std::find( begin( testCase.tags ),
|
||||||
|
end( testCase.tags ),
|
||||||
|
Tag( m_tag ) ) != end( testCase.tags );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSpec::TagPattern::serializeTo( std::ostream& out ) const {
|
||||||
|
out << name();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
|
||||||
|
bool should_use = !testCase.isHidden();
|
||||||
|
for (auto const& pattern : m_required) {
|
||||||
|
should_use = true;
|
||||||
|
if (!pattern->matches(testCase)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto const& pattern : m_forbidden) {
|
||||||
|
if (pattern->matches(testCase)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return should_use;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSpec::Filter::serializeTo( std::ostream& out ) const {
|
||||||
|
bool first = true;
|
||||||
|
for ( auto const& pattern : m_required ) {
|
||||||
|
if ( !first ) {
|
||||||
|
out << ' ';
|
||||||
|
}
|
||||||
|
out << *pattern;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
for ( auto const& pattern : m_forbidden ) {
|
||||||
|
if ( !first ) {
|
||||||
|
out << ' ';
|
||||||
|
}
|
||||||
|
out << *pattern;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string TestSpec::extractFilterName( Filter const& filter ) {
|
||||||
|
Catch::ReusableStringStream sstr;
|
||||||
|
sstr << filter;
|
||||||
|
return sstr.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestSpec::hasFilters() const {
|
||||||
|
return !m_filters.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestSpec::matches( TestCaseInfo const& testCase ) const {
|
||||||
|
return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const {
|
||||||
|
Matches matches;
|
||||||
|
matches.reserve( m_filters.size() );
|
||||||
|
for ( auto const& filter : m_filters ) {
|
||||||
|
std::vector<TestCaseHandle const*> currentMatches;
|
||||||
|
for ( auto const& test : testCases )
|
||||||
|
if ( isThrowSafe( test, config ) &&
|
||||||
|
filter.matches( test.getTestCaseInfo() ) )
|
||||||
|
currentMatches.emplace_back( &test );
|
||||||
|
matches.push_back(
|
||||||
|
FilterMatch{ extractFilterName( filter ), currentMatches } );
|
||||||
|
}
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TestSpec::vectorStrings& TestSpec::getInvalidSpecs() const {
|
||||||
|
return m_invalidSpecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSpec::serializeTo( std::ostream& out ) const {
|
||||||
|
bool first = true;
|
||||||
|
for ( auto const& filter : m_filters ) {
|
||||||
|
if ( !first ) {
|
||||||
|
out << ',';
|
||||||
|
}
|
||||||
|
out << filter;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
119
plugins/storage_test_plugin/src/catch2/catch_test_spec.hpp
Normal file
119
plugins/storage_test_plugin/src/catch2/catch_test_spec.hpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_TEST_SPEC_HPP_INCLUDED
|
||||||
|
#define CATCH_TEST_SPEC_HPP_INCLUDED
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wpadded"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
#include <catch2/internal/catch_wildcard_pattern.hpp>
|
||||||
|
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
class IConfig;
|
||||||
|
struct TestCaseInfo;
|
||||||
|
class TestCaseHandle;
|
||||||
|
|
||||||
|
class TestSpec {
|
||||||
|
|
||||||
|
class Pattern {
|
||||||
|
public:
|
||||||
|
explicit Pattern( std::string const& name );
|
||||||
|
virtual ~Pattern();
|
||||||
|
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
|
||||||
|
std::string const& name() const;
|
||||||
|
private:
|
||||||
|
virtual void serializeTo( std::ostream& out ) const = 0;
|
||||||
|
// Writes string that would be reparsed into the pattern
|
||||||
|
friend std::ostream& operator<<(std::ostream& out,
|
||||||
|
Pattern const& pattern) {
|
||||||
|
pattern.serializeTo( out );
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const m_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NamePattern : public Pattern {
|
||||||
|
public:
|
||||||
|
explicit NamePattern( std::string const& name, std::string const& filterString );
|
||||||
|
bool matches( TestCaseInfo const& testCase ) const override;
|
||||||
|
private:
|
||||||
|
void serializeTo( std::ostream& out ) const override;
|
||||||
|
|
||||||
|
WildcardPattern m_wildcardPattern;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TagPattern : public Pattern {
|
||||||
|
public:
|
||||||
|
explicit TagPattern( std::string const& tag, std::string const& filterString );
|
||||||
|
bool matches( TestCaseInfo const& testCase ) const override;
|
||||||
|
private:
|
||||||
|
void serializeTo( std::ostream& out ) const override;
|
||||||
|
|
||||||
|
std::string m_tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Filter {
|
||||||
|
std::vector<Detail::unique_ptr<Pattern>> m_required;
|
||||||
|
std::vector<Detail::unique_ptr<Pattern>> m_forbidden;
|
||||||
|
|
||||||
|
//! Serializes this filter into a string that would be parsed into
|
||||||
|
//! an equivalent filter
|
||||||
|
void serializeTo( std::ostream& out ) const;
|
||||||
|
friend std::ostream& operator<<(std::ostream& out, Filter const& f) {
|
||||||
|
f.serializeTo( out );
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches( TestCaseInfo const& testCase ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string extractFilterName( Filter const& filter );
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct FilterMatch {
|
||||||
|
std::string name;
|
||||||
|
std::vector<TestCaseHandle const*> tests;
|
||||||
|
};
|
||||||
|
using Matches = std::vector<FilterMatch>;
|
||||||
|
using vectorStrings = std::vector<std::string>;
|
||||||
|
|
||||||
|
bool hasFilters() const;
|
||||||
|
bool matches( TestCaseInfo const& testCase ) const;
|
||||||
|
Matches matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const;
|
||||||
|
const vectorStrings & getInvalidSpecs() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Filter> m_filters;
|
||||||
|
std::vector<std::string> m_invalidSpecs;
|
||||||
|
|
||||||
|
friend class TestSpecParser;
|
||||||
|
//! Serializes this test spec into a string that would be parsed into
|
||||||
|
//! equivalent test spec
|
||||||
|
void serializeTo( std::ostream& out ) const;
|
||||||
|
friend std::ostream& operator<<(std::ostream& out,
|
||||||
|
TestSpec const& spec) {
|
||||||
|
spec.serializeTo( out );
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CATCH_TEST_SPEC_HPP_INCLUDED
|
37
plugins/storage_test_plugin/src/catch2/catch_timer.cpp
Normal file
37
plugins/storage_test_plugin/src/catch2/catch_timer.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/catch_timer.hpp>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
|
||||||
|
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
} // end unnamed namespace
|
||||||
|
|
||||||
|
void Timer::start() {
|
||||||
|
m_nanoseconds = getCurrentNanosecondsSinceEpoch();
|
||||||
|
}
|
||||||
|
auto Timer::getElapsedNanoseconds() const -> uint64_t {
|
||||||
|
return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;
|
||||||
|
}
|
||||||
|
auto Timer::getElapsedMicroseconds() const -> uint64_t {
|
||||||
|
return getElapsedNanoseconds()/1000;
|
||||||
|
}
|
||||||
|
auto Timer::getElapsedMilliseconds() const -> unsigned int {
|
||||||
|
return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
|
||||||
|
}
|
||||||
|
auto Timer::getElapsedSeconds() const -> double {
|
||||||
|
return getElapsedMicroseconds()/1000000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Catch
|
27
plugins/storage_test_plugin/src/catch2/catch_timer.hpp
Normal file
27
plugins/storage_test_plugin/src/catch2/catch_timer.hpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_TIMER_HPP_INCLUDED
|
||||||
|
#define CATCH_TIMER_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
class Timer {
|
||||||
|
uint64_t m_nanoseconds = 0;
|
||||||
|
public:
|
||||||
|
void start();
|
||||||
|
auto getElapsedNanoseconds() const -> uint64_t;
|
||||||
|
auto getElapsedMicroseconds() const -> uint64_t;
|
||||||
|
auto getElapsedMilliseconds() const -> unsigned int;
|
||||||
|
auto getElapsedSeconds() const -> double;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_TIMER_HPP_INCLUDED
|
254
plugins/storage_test_plugin/src/catch2/catch_tostring.cpp
Normal file
254
plugins/storage_test_plugin/src/catch2/catch_tostring.cpp
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/catch_tostring.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||||
|
#include <catch2/internal/catch_context.hpp>
|
||||||
|
#include <catch2/internal/catch_polyfills.hpp>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const int hexThreshold = 255;
|
||||||
|
|
||||||
|
struct Endianness {
|
||||||
|
enum Arch { Big, Little };
|
||||||
|
|
||||||
|
static Arch which() {
|
||||||
|
int one = 1;
|
||||||
|
// If the lowest byte we read is non-zero, we can assume
|
||||||
|
// that little endian format is used.
|
||||||
|
auto value = *reinterpret_cast<char*>(&one);
|
||||||
|
return value ? Little : Big;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::string fpToString(T value, int precision) {
|
||||||
|
if (Catch::isnan(value)) {
|
||||||
|
return "nan";
|
||||||
|
}
|
||||||
|
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << std::setprecision(precision)
|
||||||
|
<< std::fixed
|
||||||
|
<< value;
|
||||||
|
std::string d = rss.str();
|
||||||
|
std::size_t i = d.find_last_not_of('0');
|
||||||
|
if (i != std::string::npos && i != d.size() - 1) {
|
||||||
|
if (d[i] == '.')
|
||||||
|
i++;
|
||||||
|
d = d.substr(0, i + 1);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
} // end unnamed namespace
|
||||||
|
|
||||||
|
std::string convertIntoString(StringRef string, bool escape_invisibles) {
|
||||||
|
std::string ret;
|
||||||
|
// This is enough for the "don't escape invisibles" case, and a good
|
||||||
|
// lower bound on the "escape invisibles" case.
|
||||||
|
ret.reserve(string.size() + 2);
|
||||||
|
|
||||||
|
if (!escape_invisibles) {
|
||||||
|
ret += '"';
|
||||||
|
ret += string;
|
||||||
|
ret += '"';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += '"';
|
||||||
|
for (char c : string) {
|
||||||
|
switch (c) {
|
||||||
|
case '\r':
|
||||||
|
ret.append("\\r");
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
ret.append("\\n");
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
ret.append("\\t");
|
||||||
|
break;
|
||||||
|
case '\f':
|
||||||
|
ret.append("\\f");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret.push_back(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret += '"';
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string convertIntoString(StringRef string) {
|
||||||
|
return convertIntoString(string, getCurrentContext().getConfig()->showInvisibles());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string rawMemoryToString( const void *object, std::size_t size ) {
|
||||||
|
// Reverse order for little endian architectures
|
||||||
|
int i = 0, end = static_cast<int>( size ), inc = 1;
|
||||||
|
if( Endianness::which() == Endianness::Little ) {
|
||||||
|
i = end-1;
|
||||||
|
end = inc = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char const *bytes = static_cast<unsigned char const *>(object);
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << "0x" << std::setfill('0') << std::hex;
|
||||||
|
for( ; i != end; i += inc )
|
||||||
|
rss << std::setw(2) << static_cast<unsigned>(bytes[i]);
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
} // end Detail namespace
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//// ======================================================= ////
|
||||||
|
//
|
||||||
|
// Out-of-line defs for full specialization of StringMaker
|
||||||
|
//
|
||||||
|
//// ======================================================= ////
|
||||||
|
|
||||||
|
std::string StringMaker<std::string>::convert(const std::string& str) {
|
||||||
|
return Detail::convertIntoString( str );
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
|
||||||
|
std::string StringMaker<std::string_view>::convert(std::string_view str) {
|
||||||
|
return Detail::convertIntoString( StringRef( str.data(), str.size() ) );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string StringMaker<char const*>::convert(char const* str) {
|
||||||
|
if (str) {
|
||||||
|
return Detail::convertIntoString( str );
|
||||||
|
} else {
|
||||||
|
return{ "{null string}" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::string StringMaker<char*>::convert(char* str) {
|
||||||
|
if (str) {
|
||||||
|
return Detail::convertIntoString( str );
|
||||||
|
} else {
|
||||||
|
return{ "{null string}" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CATCH_CONFIG_WCHAR
|
||||||
|
std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
|
||||||
|
std::string s;
|
||||||
|
s.reserve(wstr.size());
|
||||||
|
for (auto c : wstr) {
|
||||||
|
s += (c <= 0xff) ? static_cast<char>(c) : '?';
|
||||||
|
}
|
||||||
|
return ::Catch::Detail::stringify(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
|
||||||
|
std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {
|
||||||
|
return StringMaker<std::wstring>::convert(std::wstring(str));
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
|
||||||
|
if (str) {
|
||||||
|
return ::Catch::Detail::stringify(std::wstring{ str });
|
||||||
|
} else {
|
||||||
|
return{ "{null string}" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
|
||||||
|
if (str) {
|
||||||
|
return ::Catch::Detail::stringify(std::wstring{ str });
|
||||||
|
} else {
|
||||||
|
return{ "{null string}" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_CPP17_BYTE)
|
||||||
|
#include <cstddef>
|
||||||
|
std::string StringMaker<std::byte>::convert(std::byte value) {
|
||||||
|
return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
|
||||||
|
}
|
||||||
|
#endif // defined(CATCH_CONFIG_CPP17_BYTE)
|
||||||
|
|
||||||
|
std::string StringMaker<int>::convert(int value) {
|
||||||
|
return ::Catch::Detail::stringify(static_cast<long long>(value));
|
||||||
|
}
|
||||||
|
std::string StringMaker<long>::convert(long value) {
|
||||||
|
return ::Catch::Detail::stringify(static_cast<long long>(value));
|
||||||
|
}
|
||||||
|
std::string StringMaker<long long>::convert(long long value) {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << value;
|
||||||
|
if (value > Detail::hexThreshold) {
|
||||||
|
rss << " (0x" << std::hex << value << ')';
|
||||||
|
}
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StringMaker<unsigned int>::convert(unsigned int value) {
|
||||||
|
return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
|
||||||
|
}
|
||||||
|
std::string StringMaker<unsigned long>::convert(unsigned long value) {
|
||||||
|
return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
|
||||||
|
}
|
||||||
|
std::string StringMaker<unsigned long long>::convert(unsigned long long value) {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << value;
|
||||||
|
if (value > Detail::hexThreshold) {
|
||||||
|
rss << " (0x" << std::hex << value << ')';
|
||||||
|
}
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StringMaker<signed char>::convert(signed char value) {
|
||||||
|
if (value == '\r') {
|
||||||
|
return "'\\r'";
|
||||||
|
} else if (value == '\f') {
|
||||||
|
return "'\\f'";
|
||||||
|
} else if (value == '\n') {
|
||||||
|
return "'\\n'";
|
||||||
|
} else if (value == '\t') {
|
||||||
|
return "'\\t'";
|
||||||
|
} else if ('\0' <= value && value < ' ') {
|
||||||
|
return ::Catch::Detail::stringify(static_cast<unsigned int>(value));
|
||||||
|
} else {
|
||||||
|
char chstr[] = "' '";
|
||||||
|
chstr[1] = value;
|
||||||
|
return chstr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::string StringMaker<char>::convert(char c) {
|
||||||
|
return ::Catch::Detail::stringify(static_cast<signed char>(c));
|
||||||
|
}
|
||||||
|
std::string StringMaker<unsigned char>::convert(unsigned char c) {
|
||||||
|
return ::Catch::Detail::stringify(static_cast<char>(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
int StringMaker<float>::precision = 5;
|
||||||
|
|
||||||
|
std::string StringMaker<float>::convert(float value) {
|
||||||
|
return Detail::fpToString(value, precision) + 'f';
|
||||||
|
}
|
||||||
|
|
||||||
|
int StringMaker<double>::precision = 10;
|
||||||
|
|
||||||
|
std::string StringMaker<double>::convert(double value) {
|
||||||
|
return Detail::fpToString(value, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace Catch
|
668
plugins/storage_test_plugin/src/catch2/catch_tostring.hpp
Normal file
668
plugins/storage_test_plugin/src/catch2/catch_tostring.hpp
Normal file
@ -0,0 +1,668 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_TOSTRING_HPP_INCLUDED
|
||||||
|
#define CATCH_TOSTRING_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||||
|
#include <catch2/internal/catch_config_wchar.hpp>
|
||||||
|
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||||
|
#include <catch2/internal/catch_void_type.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_enum_values_registry.hpp>
|
||||||
|
|
||||||
|
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
|
||||||
|
#include <string_view>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// We need a dummy global operator<< so we can bring it into Catch namespace later
|
||||||
|
struct Catch_global_namespace_dummy{};
|
||||||
|
std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
// Bring in global namespace operator<< for ADL lookup in
|
||||||
|
// `IsStreamInsertable` below.
|
||||||
|
using ::operator<<;
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
|
||||||
|
inline std::size_t catch_strnlen(const char *str, std::size_t n) {
|
||||||
|
auto ret = std::char_traits<char>::find(str, n, '\0');
|
||||||
|
if (ret != nullptr) {
|
||||||
|
return static_cast<std::size_t>(ret - str);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr StringRef unprintableString = "{?}"_sr;
|
||||||
|
|
||||||
|
//! Encases `string in quotes, and optionally escapes invisibles
|
||||||
|
std::string convertIntoString( StringRef string, bool escapeInvisibles );
|
||||||
|
|
||||||
|
//! Encases `string` in quotes, and escapes invisibles if user requested
|
||||||
|
//! it via CLI
|
||||||
|
std::string convertIntoString( StringRef string );
|
||||||
|
|
||||||
|
std::string rawMemoryToString( const void *object, std::size_t size );
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::string rawMemoryToString( const T& object ) {
|
||||||
|
return rawMemoryToString( &object, sizeof(object) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class IsStreamInsertable {
|
||||||
|
template<typename Stream, typename U>
|
||||||
|
static auto test(int)
|
||||||
|
-> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type());
|
||||||
|
|
||||||
|
template<typename, typename>
|
||||||
|
static auto test(...)->std::false_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const bool value = decltype(test<std::ostream, const T&>(0))::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename E>
|
||||||
|
std::string convertUnknownEnumToString( E e );
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::enable_if_t<
|
||||||
|
!std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
|
||||||
|
std::string> convertUnstreamable( T const& ) {
|
||||||
|
return std::string(Detail::unprintableString);
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
std::enable_if_t<
|
||||||
|
!std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
|
||||||
|
std::string> convertUnstreamable(T const& ex) {
|
||||||
|
return ex.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::enable_if_t<
|
||||||
|
std::is_enum<T>::value,
|
||||||
|
std::string> convertUnstreamable( T const& value ) {
|
||||||
|
return convertUnknownEnumToString( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_MANAGED)
|
||||||
|
//! Convert a CLR string to a utf8 std::string
|
||||||
|
template<typename T>
|
||||||
|
std::string clrReferenceToString( T^ ref ) {
|
||||||
|
if (ref == nullptr)
|
||||||
|
return std::string("null");
|
||||||
|
auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
|
||||||
|
cli::pin_ptr<System::Byte> p = &bytes[0];
|
||||||
|
return std::string(reinterpret_cast<char const *>(p), bytes->Length);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Detail
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename = void>
|
||||||
|
struct StringMaker {
|
||||||
|
template <typename Fake = T>
|
||||||
|
static
|
||||||
|
std::enable_if_t<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>
|
||||||
|
convert(const Fake& value) {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
// NB: call using the function-like syntax to avoid ambiguity with
|
||||||
|
// user-defined templated operator<< under clang.
|
||||||
|
rss.operator<<(value);
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Fake = T>
|
||||||
|
static
|
||||||
|
std::enable_if_t<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>
|
||||||
|
convert( const Fake& value ) {
|
||||||
|
#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
|
||||||
|
return Detail::convertUnstreamable(value);
|
||||||
|
#else
|
||||||
|
return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
|
||||||
|
// This function dispatches all stringification requests inside of Catch.
|
||||||
|
// Should be preferably called fully qualified, like ::Catch::Detail::stringify
|
||||||
|
template <typename T>
|
||||||
|
std::string stringify(const T& e) {
|
||||||
|
return ::Catch::StringMaker<std::remove_cv_t<std::remove_reference_t<T>>>::convert(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename E>
|
||||||
|
std::string convertUnknownEnumToString( E e ) {
|
||||||
|
return ::Catch::Detail::stringify(static_cast<std::underlying_type_t<E>>(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_MANAGED)
|
||||||
|
template <typename T>
|
||||||
|
std::string stringify( T^ e ) {
|
||||||
|
return ::Catch::StringMaker<T^>::convert(e);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Detail
|
||||||
|
|
||||||
|
// Some predefined specializations
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct StringMaker<std::string> {
|
||||||
|
static std::string convert(const std::string& str);
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
|
||||||
|
template<>
|
||||||
|
struct StringMaker<std::string_view> {
|
||||||
|
static std::string convert(std::string_view str);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct StringMaker<char const *> {
|
||||||
|
static std::string convert(char const * str);
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
struct StringMaker<char *> {
|
||||||
|
static std::string convert(char * str);
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_WCHAR)
|
||||||
|
template<>
|
||||||
|
struct StringMaker<std::wstring> {
|
||||||
|
static std::string convert(const std::wstring& wstr);
|
||||||
|
};
|
||||||
|
|
||||||
|
# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
|
||||||
|
template<>
|
||||||
|
struct StringMaker<std::wstring_view> {
|
||||||
|
static std::string convert(std::wstring_view str);
|
||||||
|
};
|
||||||
|
# endif
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct StringMaker<wchar_t const *> {
|
||||||
|
static std::string convert(wchar_t const * str);
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
struct StringMaker<wchar_t *> {
|
||||||
|
static std::string convert(wchar_t * str);
|
||||||
|
};
|
||||||
|
#endif // CATCH_CONFIG_WCHAR
|
||||||
|
|
||||||
|
template<size_t SZ>
|
||||||
|
struct StringMaker<char[SZ]> {
|
||||||
|
static std::string convert(char const* str) {
|
||||||
|
return Detail::convertIntoString(
|
||||||
|
StringRef( str, Detail::catch_strnlen( str, SZ ) ) );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<size_t SZ>
|
||||||
|
struct StringMaker<signed char[SZ]> {
|
||||||
|
static std::string convert(signed char const* str) {
|
||||||
|
auto reinterpreted = reinterpret_cast<char const*>(str);
|
||||||
|
return Detail::convertIntoString(
|
||||||
|
StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<size_t SZ>
|
||||||
|
struct StringMaker<unsigned char[SZ]> {
|
||||||
|
static std::string convert(unsigned char const* str) {
|
||||||
|
auto reinterpreted = reinterpret_cast<char const*>(str);
|
||||||
|
return Detail::convertIntoString(
|
||||||
|
StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_CPP17_BYTE)
|
||||||
|
template<>
|
||||||
|
struct StringMaker<std::byte> {
|
||||||
|
static std::string convert(std::byte value);
|
||||||
|
};
|
||||||
|
#endif // defined(CATCH_CONFIG_CPP17_BYTE)
|
||||||
|
template<>
|
||||||
|
struct StringMaker<int> {
|
||||||
|
static std::string convert(int value);
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
struct StringMaker<long> {
|
||||||
|
static std::string convert(long value);
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
struct StringMaker<long long> {
|
||||||
|
static std::string convert(long long value);
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
struct StringMaker<unsigned int> {
|
||||||
|
static std::string convert(unsigned int value);
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
struct StringMaker<unsigned long> {
|
||||||
|
static std::string convert(unsigned long value);
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
struct StringMaker<unsigned long long> {
|
||||||
|
static std::string convert(unsigned long long value);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct StringMaker<bool> {
|
||||||
|
static std::string convert(bool b) {
|
||||||
|
using namespace std::string_literals;
|
||||||
|
return b ? "true"s : "false"s;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct StringMaker<char> {
|
||||||
|
static std::string convert(char c);
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
struct StringMaker<signed char> {
|
||||||
|
static std::string convert(signed char c);
|
||||||
|
};
|
||||||
|
template<>
|
||||||
|
struct StringMaker<unsigned char> {
|
||||||
|
static std::string convert(unsigned char c);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct StringMaker<std::nullptr_t> {
|
||||||
|
static std::string convert(std::nullptr_t) {
|
||||||
|
using namespace std::string_literals;
|
||||||
|
return "nullptr"s;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct StringMaker<float> {
|
||||||
|
static std::string convert(float value);
|
||||||
|
CATCH_EXPORT static int precision;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct StringMaker<double> {
|
||||||
|
static std::string convert(double value);
|
||||||
|
CATCH_EXPORT static int precision;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct StringMaker<T*> {
|
||||||
|
template <typename U>
|
||||||
|
static std::string convert(U* p) {
|
||||||
|
if (p) {
|
||||||
|
return ::Catch::Detail::rawMemoryToString(p);
|
||||||
|
} else {
|
||||||
|
return "nullptr";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename R, typename C>
|
||||||
|
struct StringMaker<R C::*> {
|
||||||
|
static std::string convert(R C::* p) {
|
||||||
|
if (p) {
|
||||||
|
return ::Catch::Detail::rawMemoryToString(p);
|
||||||
|
} else {
|
||||||
|
return "nullptr";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(_MANAGED)
|
||||||
|
template <typename T>
|
||||||
|
struct StringMaker<T^> {
|
||||||
|
static std::string convert( T^ ref ) {
|
||||||
|
return ::Catch::Detail::clrReferenceToString(ref);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
template<typename InputIterator, typename Sentinel = InputIterator>
|
||||||
|
std::string rangeToString(InputIterator first, Sentinel last) {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << "{ ";
|
||||||
|
if (first != last) {
|
||||||
|
rss << ::Catch::Detail::stringify(*first);
|
||||||
|
for (++first; first != last; ++first)
|
||||||
|
rss << ", " << ::Catch::Detail::stringify(*first);
|
||||||
|
}
|
||||||
|
rss << " }";
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// Separate std-lib types stringification, so it can be selectively enabled
|
||||||
|
// This means that we do not bring in their headers
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
|
||||||
|
# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
|
||||||
|
# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
|
||||||
|
# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
|
||||||
|
# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Separate std::pair specialization
|
||||||
|
#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
|
||||||
|
#include <utility>
|
||||||
|
namespace Catch {
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
struct StringMaker<std::pair<T1, T2> > {
|
||||||
|
static std::string convert(const std::pair<T1, T2>& pair) {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << "{ "
|
||||||
|
<< ::Catch::Detail::stringify(pair.first)
|
||||||
|
<< ", "
|
||||||
|
<< ::Catch::Detail::stringify(pair.second)
|
||||||
|
<< " }";
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
|
||||||
|
#include <optional>
|
||||||
|
namespace Catch {
|
||||||
|
template<typename T>
|
||||||
|
struct StringMaker<std::optional<T> > {
|
||||||
|
static std::string convert(const std::optional<T>& optional) {
|
||||||
|
if (optional.has_value()) {
|
||||||
|
return ::Catch::Detail::stringify(*optional);
|
||||||
|
} else {
|
||||||
|
return "{ }";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
|
||||||
|
|
||||||
|
// Separate std::tuple specialization
|
||||||
|
#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
|
||||||
|
#include <tuple>
|
||||||
|
namespace Catch {
|
||||||
|
namespace Detail {
|
||||||
|
template<
|
||||||
|
typename Tuple,
|
||||||
|
std::size_t N = 0,
|
||||||
|
bool = (N < std::tuple_size<Tuple>::value)
|
||||||
|
>
|
||||||
|
struct TupleElementPrinter {
|
||||||
|
static void print(const Tuple& tuple, std::ostream& os) {
|
||||||
|
os << (N ? ", " : " ")
|
||||||
|
<< ::Catch::Detail::stringify(std::get<N>(tuple));
|
||||||
|
TupleElementPrinter<Tuple, N + 1>::print(tuple, os);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename Tuple,
|
||||||
|
std::size_t N
|
||||||
|
>
|
||||||
|
struct TupleElementPrinter<Tuple, N, false> {
|
||||||
|
static void print(const Tuple&, std::ostream&) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ...Types>
|
||||||
|
struct StringMaker<std::tuple<Types...>> {
|
||||||
|
static std::string convert(const std::tuple<Types...>& tuple) {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << '{';
|
||||||
|
Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());
|
||||||
|
rss << " }";
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
|
||||||
|
#include <variant>
|
||||||
|
namespace Catch {
|
||||||
|
template<>
|
||||||
|
struct StringMaker<std::monostate> {
|
||||||
|
static std::string convert(const std::monostate&) {
|
||||||
|
return "{ }";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Elements>
|
||||||
|
struct StringMaker<std::variant<Elements...>> {
|
||||||
|
static std::string convert(const std::variant<Elements...>& variant) {
|
||||||
|
if (variant.valueless_by_exception()) {
|
||||||
|
return "{valueless variant}";
|
||||||
|
} else {
|
||||||
|
return std::visit(
|
||||||
|
[](const auto& value) {
|
||||||
|
return ::Catch::Detail::stringify(value);
|
||||||
|
},
|
||||||
|
variant
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
// Import begin/ end from std here
|
||||||
|
using std::begin;
|
||||||
|
using std::end;
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
template <typename T, typename = void>
|
||||||
|
struct is_range_impl : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_range_impl<T, void_t<decltype(begin(std::declval<T>()))>> : std::true_type {};
|
||||||
|
} // namespace Detail
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_range : Detail::is_range_impl<T> {};
|
||||||
|
|
||||||
|
#if defined(_MANAGED) // Managed types are never ranges
|
||||||
|
template <typename T>
|
||||||
|
struct is_range<T^> {
|
||||||
|
static const bool value = false;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename Range>
|
||||||
|
std::string rangeToString( Range const& range ) {
|
||||||
|
return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle vector<bool> specially
|
||||||
|
template<typename Allocator>
|
||||||
|
std::string rangeToString( std::vector<bool, Allocator> const& v ) {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << "{ ";
|
||||||
|
bool first = true;
|
||||||
|
for( bool b : v ) {
|
||||||
|
if( first )
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
rss << ", ";
|
||||||
|
rss << ::Catch::Detail::stringify( b );
|
||||||
|
}
|
||||||
|
rss << " }";
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename R>
|
||||||
|
struct StringMaker<R, std::enable_if_t<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>> {
|
||||||
|
static std::string convert( R const& range ) {
|
||||||
|
return rangeToString( range );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, size_t SZ>
|
||||||
|
struct StringMaker<T[SZ]> {
|
||||||
|
static std::string convert(T const(&arr)[SZ]) {
|
||||||
|
return rangeToString(arr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
// Separate std::chrono::duration specialization
|
||||||
|
#include <ctime>
|
||||||
|
#include <ratio>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
template <class Ratio>
|
||||||
|
struct ratio_string {
|
||||||
|
static std::string symbol() {
|
||||||
|
Catch::ReusableStringStream rss;
|
||||||
|
rss << '[' << Ratio::num << '/'
|
||||||
|
<< Ratio::den << ']';
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ratio_string<std::atto> {
|
||||||
|
static char symbol() { return 'a'; }
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct ratio_string<std::femto> {
|
||||||
|
static char symbol() { return 'f'; }
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct ratio_string<std::pico> {
|
||||||
|
static char symbol() { return 'p'; }
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct ratio_string<std::nano> {
|
||||||
|
static char symbol() { return 'n'; }
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct ratio_string<std::micro> {
|
||||||
|
static char symbol() { return 'u'; }
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct ratio_string<std::milli> {
|
||||||
|
static char symbol() { return 'm'; }
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////
|
||||||
|
// std::chrono::duration specializations
|
||||||
|
template<typename Value, typename Ratio>
|
||||||
|
struct StringMaker<std::chrono::duration<Value, Ratio>> {
|
||||||
|
static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<typename Value>
|
||||||
|
struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
|
||||||
|
static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << duration.count() << " s";
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<typename Value>
|
||||||
|
struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
|
||||||
|
static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << duration.count() << " m";
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<typename Value>
|
||||||
|
struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
|
||||||
|
static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
|
||||||
|
ReusableStringStream rss;
|
||||||
|
rss << duration.count() << " h";
|
||||||
|
return rss.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////
|
||||||
|
// std::chrono::time_point specialization
|
||||||
|
// Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>
|
||||||
|
template<typename Clock, typename Duration>
|
||||||
|
struct StringMaker<std::chrono::time_point<Clock, Duration>> {
|
||||||
|
static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {
|
||||||
|
return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// std::chrono::time_point<system_clock> specialization
|
||||||
|
template<typename Duration>
|
||||||
|
struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
||||||
|
static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
|
||||||
|
auto converted = std::chrono::system_clock::to_time_t(time_point);
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
std::tm timeInfo = {};
|
||||||
|
gmtime_s(&timeInfo, &converted);
|
||||||
|
#else
|
||||||
|
std::tm* timeInfo = std::gmtime(&converted);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
|
||||||
|
char timeStamp[timeStampSize];
|
||||||
|
const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
|
||||||
|
#else
|
||||||
|
std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
|
||||||
|
#endif
|
||||||
|
return std::string(timeStamp, timeStampSize - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||||
|
|
||||||
|
#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
|
||||||
|
namespace Catch { \
|
||||||
|
template<> struct StringMaker<enumName> { \
|
||||||
|
static std::string convert( enumName value ) { \
|
||||||
|
static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
|
||||||
|
return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CATCH_TOSTRING_HPP_INCLUDED
|
65
plugins/storage_test_plugin/src/catch2/catch_totals.cpp
Normal file
65
plugins/storage_test_plugin/src/catch2/catch_totals.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/catch_totals.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
Counts Counts::operator - ( Counts const& other ) const {
|
||||||
|
Counts diff;
|
||||||
|
diff.passed = passed - other.passed;
|
||||||
|
diff.failed = failed - other.failed;
|
||||||
|
diff.failedButOk = failedButOk - other.failedButOk;
|
||||||
|
diff.skipped = skipped - other.skipped;
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
Counts& Counts::operator += ( Counts const& other ) {
|
||||||
|
passed += other.passed;
|
||||||
|
failed += other.failed;
|
||||||
|
failedButOk += other.failedButOk;
|
||||||
|
skipped += other.skipped;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint64_t Counts::total() const {
|
||||||
|
return passed + failed + failedButOk + skipped;
|
||||||
|
}
|
||||||
|
bool Counts::allPassed() const {
|
||||||
|
return failed == 0 && failedButOk == 0 && skipped == 0;
|
||||||
|
}
|
||||||
|
bool Counts::allOk() const {
|
||||||
|
return failed == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Totals Totals::operator - ( Totals const& other ) const {
|
||||||
|
Totals diff;
|
||||||
|
diff.assertions = assertions - other.assertions;
|
||||||
|
diff.testCases = testCases - other.testCases;
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
Totals& Totals::operator += ( Totals const& other ) {
|
||||||
|
assertions += other.assertions;
|
||||||
|
testCases += other.testCases;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Totals Totals::delta( Totals const& prevTotals ) const {
|
||||||
|
Totals diff = *this - prevTotals;
|
||||||
|
if( diff.assertions.failed > 0 )
|
||||||
|
++diff.testCases.failed;
|
||||||
|
else if( diff.assertions.failedButOk > 0 )
|
||||||
|
++diff.testCases.failedButOk;
|
||||||
|
else if ( diff.assertions.skipped > 0 )
|
||||||
|
++ diff.testCases.skipped;
|
||||||
|
else
|
||||||
|
++diff.testCases.passed;
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
plugins/storage_test_plugin/src/catch2/catch_totals.hpp
Normal file
41
plugins/storage_test_plugin/src/catch2/catch_totals.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_TOTALS_HPP_INCLUDED
|
||||||
|
#define CATCH_TOTALS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct Counts {
|
||||||
|
Counts operator - ( Counts const& other ) const;
|
||||||
|
Counts& operator += ( Counts const& other );
|
||||||
|
|
||||||
|
std::uint64_t total() const;
|
||||||
|
bool allPassed() const;
|
||||||
|
bool allOk() const;
|
||||||
|
|
||||||
|
std::uint64_t passed = 0;
|
||||||
|
std::uint64_t failed = 0;
|
||||||
|
std::uint64_t failedButOk = 0;
|
||||||
|
std::uint64_t skipped = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Totals {
|
||||||
|
|
||||||
|
Totals operator - ( Totals const& other ) const;
|
||||||
|
Totals& operator += ( Totals const& other );
|
||||||
|
|
||||||
|
Totals delta( Totals const& prevTotals ) const;
|
||||||
|
|
||||||
|
Counts assertions;
|
||||||
|
Counts testCases;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CATCH_TOTALS_HPP_INCLUDED
|
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/catch_translate_exception.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Detail {
|
||||||
|
void registerTranslatorImpl(
|
||||||
|
Detail::unique_ptr<IExceptionTranslator>&& translator ) {
|
||||||
|
getMutableRegistryHub().registerTranslator(
|
||||||
|
CATCH_MOVE( translator ) );
|
||||||
|
}
|
||||||
|
} // namespace Detail
|
||||||
|
} // namespace Catch
|
@ -0,0 +1,88 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
|
||||||
|
#define CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/interfaces/catch_interfaces_exception.hpp>
|
||||||
|
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_name.hpp>
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Detail {
|
||||||
|
void registerTranslatorImpl(
|
||||||
|
Detail::unique_ptr<IExceptionTranslator>&& translator );
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExceptionTranslatorRegistrar {
|
||||||
|
template<typename T>
|
||||||
|
class ExceptionTranslator : public IExceptionTranslator {
|
||||||
|
public:
|
||||||
|
|
||||||
|
ExceptionTranslator( std::string(*translateFunction)( T const& ) )
|
||||||
|
: m_translateFunction( translateFunction )
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
try {
|
||||||
|
if( it == itEnd )
|
||||||
|
std::rethrow_exception(std::current_exception());
|
||||||
|
else
|
||||||
|
return (*it)->translate( it+1, itEnd );
|
||||||
|
}
|
||||||
|
catch( T const& ex ) {
|
||||||
|
return m_translateFunction( ex );
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return "You should never get here!";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string(*m_translateFunction)( T const& );
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
ExceptionTranslatorRegistrar( std::string(*translateFunction)( T const& ) ) {
|
||||||
|
Detail::registerTranslatorImpl(
|
||||||
|
Detail::make_unique<ExceptionTranslator<T>>(
|
||||||
|
translateFunction ) );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
|
||||||
|
static std::string translatorName( signature ); \
|
||||||
|
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||||
|
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||||
|
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
|
||||||
|
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||||
|
static std::string translatorName( signature )
|
||||||
|
|
||||||
|
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_DISABLE)
|
||||||
|
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \
|
||||||
|
static std::string translatorName( signature )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// This macro is always prefixed
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE)
|
||||||
|
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
|
||||||
|
#else
|
||||||
|
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
|
15
plugins/storage_test_plugin/src/catch2/catch_user_config.hpp
Normal file
15
plugins/storage_test_plugin/src/catch2/catch_user_config.hpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#ifndef CATCH_USER_CONFIG_HPP_INCLUDED
|
||||||
|
#define CATCH_USER_CONFIG_HPP_INCLUDED
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_NOSTDOUT
|
||||||
|
#define CATCH_CONFIG_NO_POSIX_SIGNALS
|
||||||
|
|
||||||
|
#endif // CATCH_USER_CONFIG_HPP_INCLUDED
|
43
plugins/storage_test_plugin/src/catch2/catch_version.cpp
Normal file
43
plugins/storage_test_plugin/src/catch2/catch_version.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/catch_version.hpp>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
Version::Version
|
||||||
|
( unsigned int _majorVersion,
|
||||||
|
unsigned int _minorVersion,
|
||||||
|
unsigned int _patchNumber,
|
||||||
|
char const * const _branchName,
|
||||||
|
unsigned int _buildNumber )
|
||||||
|
: majorVersion( _majorVersion ),
|
||||||
|
minorVersion( _minorVersion ),
|
||||||
|
patchNumber( _patchNumber ),
|
||||||
|
branchName( _branchName ),
|
||||||
|
buildNumber( _buildNumber )
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::ostream& operator << ( std::ostream& os, Version const& version ) {
|
||||||
|
os << version.majorVersion << '.'
|
||||||
|
<< version.minorVersion << '.'
|
||||||
|
<< version.patchNumber;
|
||||||
|
// branchName is never null -> 0th char is \0 if it is empty
|
||||||
|
if (version.branchName[0]) {
|
||||||
|
os << '-' << version.branchName
|
||||||
|
<< '.' << version.buildNumber;
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
Version const& libraryVersion() {
|
||||||
|
static Version version( 3, 4, 0, "", 0 );
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
39
plugins/storage_test_plugin/src/catch2/catch_version.hpp
Normal file
39
plugins/storage_test_plugin/src/catch2/catch_version.hpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_VERSION_HPP_INCLUDED
|
||||||
|
#define CATCH_VERSION_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <iosfwd>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
// Versioning information
|
||||||
|
struct Version {
|
||||||
|
Version( Version const& ) = delete;
|
||||||
|
Version& operator=( Version const& ) = delete;
|
||||||
|
Version( unsigned int _majorVersion,
|
||||||
|
unsigned int _minorVersion,
|
||||||
|
unsigned int _patchNumber,
|
||||||
|
char const * const _branchName,
|
||||||
|
unsigned int _buildNumber );
|
||||||
|
|
||||||
|
unsigned int const majorVersion;
|
||||||
|
unsigned int const minorVersion;
|
||||||
|
unsigned int const patchNumber;
|
||||||
|
|
||||||
|
// buildNumber is only used if branchName is not null
|
||||||
|
char const * const branchName;
|
||||||
|
unsigned int const buildNumber;
|
||||||
|
|
||||||
|
friend std::ostream& operator << ( std::ostream& os, Version const& version );
|
||||||
|
};
|
||||||
|
|
||||||
|
Version const& libraryVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CATCH_VERSION_HPP_INCLUDED
|
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||||
|
#define CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#define CATCH_VERSION_MAJOR 3
|
||||||
|
#define CATCH_VERSION_MINOR 4
|
||||||
|
#define CATCH_VERSION_PATCH 0
|
||||||
|
|
||||||
|
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/generators/catch_generator_exception.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
const char* GeneratorException::what() const noexcept {
|
||||||
|
return m_msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace Catch
|
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
|
||||||
|
#define CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
// Exception type to be thrown when a Generator runs into an error,
|
||||||
|
// e.g. it cannot initialize the first return value based on
|
||||||
|
// runtime information
|
||||||
|
class GeneratorException : public std::exception {
|
||||||
|
const char* const m_msg = "";
|
||||||
|
|
||||||
|
public:
|
||||||
|
GeneratorException(const char* msg):
|
||||||
|
m_msg(msg)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const char* what() const noexcept override final;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
|
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/generators/catch_generators.hpp>
|
||||||
|
#include <catch2/internal/catch_enforce.hpp>
|
||||||
|
#include <catch2/generators/catch_generator_exception.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
IGeneratorTracker::~IGeneratorTracker() = default;
|
||||||
|
|
||||||
|
namespace Generators {
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
|
||||||
|
[[noreturn]]
|
||||||
|
void throw_generator_exception(char const* msg) {
|
||||||
|
Catch::throw_exception(GeneratorException{ msg });
|
||||||
|
}
|
||||||
|
} // end namespace Detail
|
||||||
|
|
||||||
|
GeneratorUntypedBase::~GeneratorUntypedBase() = default;
|
||||||
|
|
||||||
|
IGeneratorTracker* acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) {
|
||||||
|
return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
|
||||||
|
SourceLineInfo lineInfo,
|
||||||
|
GeneratorBasePtr&& generator ) {
|
||||||
|
return getResultCapture().createGeneratorTracker(
|
||||||
|
generatorName, lineInfo, CATCH_MOVE( generator ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
} // namespace Catch
|
@ -0,0 +1,250 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_GENERATORS_HPP_INCLUDED
|
||||||
|
#define CATCH_GENERATORS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/catch_tostring.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
||||||
|
#include <catch2/internal/catch_source_line_info.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_name.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace Generators {
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
|
||||||
|
//! Throws GeneratorException with the provided message
|
||||||
|
[[noreturn]]
|
||||||
|
void throw_generator_exception(char const * msg);
|
||||||
|
|
||||||
|
} // end namespace detail
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class IGenerator : public GeneratorUntypedBase {
|
||||||
|
std::string stringifyImpl() const override {
|
||||||
|
return ::Catch::Detail::stringify( get() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
~IGenerator() override = default;
|
||||||
|
IGenerator() = default;
|
||||||
|
IGenerator(IGenerator const&) = default;
|
||||||
|
IGenerator& operator=(IGenerator const&) = default;
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the current element of the generator
|
||||||
|
//
|
||||||
|
// \Precondition The generator is either freshly constructed,
|
||||||
|
// or the last call to `next()` returned true
|
||||||
|
virtual T const& get() const = 0;
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using GeneratorPtr = Catch::Detail::unique_ptr<IGenerator<T>>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class GeneratorWrapper final {
|
||||||
|
GeneratorPtr<T> m_generator;
|
||||||
|
public:
|
||||||
|
//! Takes ownership of the passed pointer.
|
||||||
|
GeneratorWrapper(IGenerator<T>* generator):
|
||||||
|
m_generator(generator) {}
|
||||||
|
GeneratorWrapper(GeneratorPtr<T> generator):
|
||||||
|
m_generator(CATCH_MOVE(generator)) {}
|
||||||
|
|
||||||
|
T const& get() const {
|
||||||
|
return m_generator->get();
|
||||||
|
}
|
||||||
|
bool next() {
|
||||||
|
return m_generator->countedNext();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class SingleValueGenerator final : public IGenerator<T> {
|
||||||
|
T m_value;
|
||||||
|
public:
|
||||||
|
SingleValueGenerator(T const& value) :
|
||||||
|
m_value(value)
|
||||||
|
{}
|
||||||
|
SingleValueGenerator(T&& value):
|
||||||
|
m_value(CATCH_MOVE(value))
|
||||||
|
{}
|
||||||
|
|
||||||
|
T const& get() const override {
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
bool next() override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class FixedValuesGenerator final : public IGenerator<T> {
|
||||||
|
static_assert(!std::is_same<T, bool>::value,
|
||||||
|
"FixedValuesGenerator does not support bools because of std::vector<bool>"
|
||||||
|
"specialization, use SingleValue Generator instead.");
|
||||||
|
std::vector<T> m_values;
|
||||||
|
size_t m_idx = 0;
|
||||||
|
public:
|
||||||
|
FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
|
||||||
|
|
||||||
|
T const& get() const override {
|
||||||
|
return m_values[m_idx];
|
||||||
|
}
|
||||||
|
bool next() override {
|
||||||
|
++m_idx;
|
||||||
|
return m_idx < m_values.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename DecayedT = std::decay_t<T>>
|
||||||
|
GeneratorWrapper<DecayedT> value( T&& value ) {
|
||||||
|
return GeneratorWrapper<DecayedT>(
|
||||||
|
Catch::Detail::make_unique<SingleValueGenerator<DecayedT>>(
|
||||||
|
CATCH_FORWARD( value ) ) );
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
GeneratorWrapper<T> values(std::initializer_list<T> values) {
|
||||||
|
return GeneratorWrapper<T>(Catch::Detail::make_unique<FixedValuesGenerator<T>>(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Generators : public IGenerator<T> {
|
||||||
|
std::vector<GeneratorWrapper<T>> m_generators;
|
||||||
|
size_t m_current = 0;
|
||||||
|
|
||||||
|
void add_generator( GeneratorWrapper<T>&& generator ) {
|
||||||
|
m_generators.emplace_back( CATCH_MOVE( generator ) );
|
||||||
|
}
|
||||||
|
void add_generator( T const& val ) {
|
||||||
|
m_generators.emplace_back( value( val ) );
|
||||||
|
}
|
||||||
|
void add_generator( T&& val ) {
|
||||||
|
m_generators.emplace_back( value( CATCH_MOVE( val ) ) );
|
||||||
|
}
|
||||||
|
template <typename U>
|
||||||
|
std::enable_if_t<!std::is_same<std::decay_t<U>, T>::value>
|
||||||
|
add_generator( U&& val ) {
|
||||||
|
add_generator( T( CATCH_FORWARD( val ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> void add_generators( U&& valueOrGenerator ) {
|
||||||
|
add_generator( CATCH_FORWARD( valueOrGenerator ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U, typename... Gs>
|
||||||
|
void add_generators( U&& valueOrGenerator, Gs&&... moreGenerators ) {
|
||||||
|
add_generator( CATCH_FORWARD( valueOrGenerator ) );
|
||||||
|
add_generators( CATCH_FORWARD( moreGenerators )... );
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename... Gs>
|
||||||
|
Generators(Gs &&... moreGenerators) {
|
||||||
|
m_generators.reserve(sizeof...(Gs));
|
||||||
|
add_generators(CATCH_FORWARD(moreGenerators)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
T const& get() const override {
|
||||||
|
return m_generators[m_current].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next() override {
|
||||||
|
if (m_current >= m_generators.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const bool current_status = m_generators[m_current].next();
|
||||||
|
if (!current_status) {
|
||||||
|
++m_current;
|
||||||
|
}
|
||||||
|
return m_current < m_generators.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
GeneratorWrapper<std::tuple<std::decay_t<Ts>...>>
|
||||||
|
table( std::initializer_list<std::tuple<std::decay_t<Ts>...>> tuples ) {
|
||||||
|
return values<std::tuple<Ts...>>( tuples );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag type to signal that a generator sequence should convert arguments to a specific type
|
||||||
|
template <typename T>
|
||||||
|
struct as {};
|
||||||
|
|
||||||
|
template<typename T, typename... Gs>
|
||||||
|
auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
|
||||||
|
return Generators<T>(CATCH_MOVE(generator), CATCH_FORWARD(moreGenerators)...);
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
|
||||||
|
return Generators<T>(CATCH_MOVE(generator));
|
||||||
|
}
|
||||||
|
template<typename T, typename... Gs>
|
||||||
|
auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<std::decay_t<T>> {
|
||||||
|
return makeGenerators( value( CATCH_FORWARD( val ) ), CATCH_FORWARD( moreGenerators )... );
|
||||||
|
}
|
||||||
|
template<typename T, typename U, typename... Gs>
|
||||||
|
auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
|
||||||
|
return makeGenerators( value( T( CATCH_FORWARD( val ) ) ), CATCH_FORWARD( moreGenerators )... );
|
||||||
|
}
|
||||||
|
|
||||||
|
IGeneratorTracker* acquireGeneratorTracker( StringRef generatorName,
|
||||||
|
SourceLineInfo const& lineInfo );
|
||||||
|
IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
|
||||||
|
SourceLineInfo lineInfo,
|
||||||
|
GeneratorBasePtr&& generator );
|
||||||
|
|
||||||
|
template<typename L>
|
||||||
|
auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> typename decltype(generatorExpression())::type {
|
||||||
|
using UnderlyingType = typename decltype(generatorExpression())::type;
|
||||||
|
|
||||||
|
IGeneratorTracker* tracker = acquireGeneratorTracker( generatorName, lineInfo );
|
||||||
|
// Creation of tracker is delayed after generator creation, so
|
||||||
|
// that constructing generator can fail without breaking everything.
|
||||||
|
if (!tracker) {
|
||||||
|
tracker = createGeneratorTracker(
|
||||||
|
generatorName,
|
||||||
|
lineInfo,
|
||||||
|
Catch::Detail::make_unique<Generators<UnderlyingType>>(
|
||||||
|
generatorExpression() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker->getGenerator() );
|
||||||
|
return generator.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#define CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL( ... ) #__VA_ARGS__##_catch_sr
|
||||||
|
#define CATCH_INTERNAL_GENERATOR_STRINGIZE(...) CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define GENERATE( ... ) \
|
||||||
|
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||||
|
CATCH_INTERNAL_LINEINFO, \
|
||||||
|
[ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||||
|
#define GENERATE_COPY( ... ) \
|
||||||
|
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||||
|
CATCH_INTERNAL_LINEINFO, \
|
||||||
|
[=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||||
|
#define GENERATE_REF( ... ) \
|
||||||
|
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||||
|
CATCH_INTERNAL_LINEINFO, \
|
||||||
|
[&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||||
|
|
||||||
|
#endif // CATCH_GENERATORS_HPP_INCLUDED
|
@ -0,0 +1,241 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
|
||||||
|
#define CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/generators/catch_generators.hpp>
|
||||||
|
#include <catch2/internal/catch_meta.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Generators {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class TakeGenerator final : public IGenerator<T> {
|
||||||
|
GeneratorWrapper<T> m_generator;
|
||||||
|
size_t m_returned = 0;
|
||||||
|
size_t m_target;
|
||||||
|
public:
|
||||||
|
TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
|
||||||
|
m_generator(CATCH_MOVE(generator)),
|
||||||
|
m_target(target)
|
||||||
|
{
|
||||||
|
assert(target != 0 && "Empty generators are not allowed");
|
||||||
|
}
|
||||||
|
T const& get() const override {
|
||||||
|
return m_generator.get();
|
||||||
|
}
|
||||||
|
bool next() override {
|
||||||
|
++m_returned;
|
||||||
|
if (m_returned >= m_target) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto success = m_generator.next();
|
||||||
|
// If the underlying generator does not contain enough values
|
||||||
|
// then we cut short as well
|
||||||
|
if (!success) {
|
||||||
|
m_returned = m_target;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
|
||||||
|
return GeneratorWrapper<T>(Catch::Detail::make_unique<TakeGenerator<T>>(target, CATCH_MOVE(generator)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename Predicate>
|
||||||
|
class FilterGenerator final : public IGenerator<T> {
|
||||||
|
GeneratorWrapper<T> m_generator;
|
||||||
|
Predicate m_predicate;
|
||||||
|
public:
|
||||||
|
template <typename P = Predicate>
|
||||||
|
FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
|
||||||
|
m_generator(CATCH_MOVE(generator)),
|
||||||
|
m_predicate(CATCH_FORWARD(pred))
|
||||||
|
{
|
||||||
|
if (!m_predicate(m_generator.get())) {
|
||||||
|
// It might happen that there are no values that pass the
|
||||||
|
// filter. In that case we throw an exception.
|
||||||
|
auto has_initial_value = next();
|
||||||
|
if (!has_initial_value) {
|
||||||
|
Detail::throw_generator_exception("No valid value found in filtered generator");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T const& get() const override {
|
||||||
|
return m_generator.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next() override {
|
||||||
|
bool success = m_generator.next();
|
||||||
|
if (!success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename Predicate>
|
||||||
|
GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
|
||||||
|
return GeneratorWrapper<T>(Catch::Detail::make_unique<FilterGenerator<T, Predicate>>(CATCH_FORWARD(pred), CATCH_MOVE(generator)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class RepeatGenerator final : public IGenerator<T> {
|
||||||
|
static_assert(!std::is_same<T, bool>::value,
|
||||||
|
"RepeatGenerator currently does not support bools"
|
||||||
|
"because of std::vector<bool> specialization");
|
||||||
|
GeneratorWrapper<T> m_generator;
|
||||||
|
mutable std::vector<T> m_returned;
|
||||||
|
size_t m_target_repeats;
|
||||||
|
size_t m_current_repeat = 0;
|
||||||
|
size_t m_repeat_index = 0;
|
||||||
|
public:
|
||||||
|
RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
|
||||||
|
m_generator(CATCH_MOVE(generator)),
|
||||||
|
m_target_repeats(repeats)
|
||||||
|
{
|
||||||
|
assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
|
||||||
|
}
|
||||||
|
|
||||||
|
T const& get() const override {
|
||||||
|
if (m_current_repeat == 0) {
|
||||||
|
m_returned.push_back(m_generator.get());
|
||||||
|
return m_returned.back();
|
||||||
|
}
|
||||||
|
return m_returned[m_repeat_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next() override {
|
||||||
|
// There are 2 basic cases:
|
||||||
|
// 1) We are still reading the generator
|
||||||
|
// 2) We are reading our own cache
|
||||||
|
|
||||||
|
// In the first case, we need to poke the underlying generator.
|
||||||
|
// If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
|
||||||
|
if (m_current_repeat == 0) {
|
||||||
|
const auto success = m_generator.next();
|
||||||
|
if (!success) {
|
||||||
|
++m_current_repeat;
|
||||||
|
}
|
||||||
|
return m_current_repeat < m_target_repeats;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the second case, we need to move indices forward and check that we haven't run up against the end
|
||||||
|
++m_repeat_index;
|
||||||
|
if (m_repeat_index == m_returned.size()) {
|
||||||
|
m_repeat_index = 0;
|
||||||
|
++m_current_repeat;
|
||||||
|
}
|
||||||
|
return m_current_repeat < m_target_repeats;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
|
||||||
|
return GeneratorWrapper<T>(Catch::Detail::make_unique<RepeatGenerator<T>>(repeats, CATCH_MOVE(generator)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, typename Func>
|
||||||
|
class MapGenerator final : public IGenerator<T> {
|
||||||
|
// TBD: provide static assert for mapping function, for friendly error message
|
||||||
|
GeneratorWrapper<U> m_generator;
|
||||||
|
Func m_function;
|
||||||
|
// To avoid returning dangling reference, we have to save the values
|
||||||
|
T m_cache;
|
||||||
|
public:
|
||||||
|
template <typename F2 = Func>
|
||||||
|
MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
|
||||||
|
m_generator(CATCH_MOVE(generator)),
|
||||||
|
m_function(CATCH_FORWARD(function)),
|
||||||
|
m_cache(m_function(m_generator.get()))
|
||||||
|
{}
|
||||||
|
|
||||||
|
T const& get() const override {
|
||||||
|
return m_cache;
|
||||||
|
}
|
||||||
|
bool next() override {
|
||||||
|
const auto success = m_generator.next();
|
||||||
|
if (success) {
|
||||||
|
m_cache = m_function(m_generator.get());
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
|
||||||
|
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
|
||||||
|
return GeneratorWrapper<T>(
|
||||||
|
Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, typename Func>
|
||||||
|
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
|
||||||
|
return GeneratorWrapper<T>(
|
||||||
|
Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class ChunkGenerator final : public IGenerator<std::vector<T>> {
|
||||||
|
std::vector<T> m_chunk;
|
||||||
|
size_t m_chunk_size;
|
||||||
|
GeneratorWrapper<T> m_generator;
|
||||||
|
bool m_used_up = false;
|
||||||
|
public:
|
||||||
|
ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
|
||||||
|
m_chunk_size(size), m_generator(CATCH_MOVE(generator))
|
||||||
|
{
|
||||||
|
m_chunk.reserve(m_chunk_size);
|
||||||
|
if (m_chunk_size != 0) {
|
||||||
|
m_chunk.push_back(m_generator.get());
|
||||||
|
for (size_t i = 1; i < m_chunk_size; ++i) {
|
||||||
|
if (!m_generator.next()) {
|
||||||
|
Detail::throw_generator_exception("Not enough values to initialize the first chunk");
|
||||||
|
}
|
||||||
|
m_chunk.push_back(m_generator.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<T> const& get() const override {
|
||||||
|
return m_chunk;
|
||||||
|
}
|
||||||
|
bool next() override {
|
||||||
|
m_chunk.clear();
|
||||||
|
for (size_t idx = 0; idx < m_chunk_size; ++idx) {
|
||||||
|
if (!m_generator.next()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_chunk.push_back(m_generator.get());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
|
||||||
|
return GeneratorWrapper<std::vector<T>>(
|
||||||
|
Catch::Detail::make_unique<ChunkGenerator<T>>(size, CATCH_MOVE(generator))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
|
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
/** \file
|
||||||
|
* This is a convenience header for Catch2's Generator support. It includes
|
||||||
|
* **all** of Catch2 headers related to generators.
|
||||||
|
*
|
||||||
|
* Generally the Catch2 users should use specific includes they need,
|
||||||
|
* but this header can be used instead for ease-of-experimentation, or
|
||||||
|
* just plain convenience, at the cost of (significantly) increased
|
||||||
|
* compilation times.
|
||||||
|
*
|
||||||
|
* When a new header is added to either the `generators` folder,
|
||||||
|
* or to the corresponding internal subfolder, it should be added here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CATCH_GENERATORS_ALL_HPP_INCLUDED
|
||||||
|
#define CATCH_GENERATORS_ALL_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/generators/catch_generator_exception.hpp>
|
||||||
|
#include <catch2/generators/catch_generators.hpp>
|
||||||
|
#include <catch2/generators/catch_generators_adapters.hpp>
|
||||||
|
#include <catch2/generators/catch_generators_random.hpp>
|
||||||
|
#include <catch2/generators/catch_generators_range.hpp>
|
||||||
|
|
||||||
|
#endif // CATCH_GENERATORS_ALL_HPP_INCLUDED
|
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/generators/catch_generators_random.hpp>
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_context.hpp>
|
||||||
|
|
||||||
|
std::uint32_t Catch::Generators::Detail::getSeed() { return sharedRng()(); }
|
@ -0,0 +1,98 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_GENERATORS_RANDOM_HPP_INCLUDED
|
||||||
|
#define CATCH_GENERATORS_RANDOM_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_context.hpp>
|
||||||
|
#include <catch2/generators/catch_generators.hpp>
|
||||||
|
#include <catch2/internal/catch_random_number_generator.hpp>
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Generators {
|
||||||
|
namespace Detail {
|
||||||
|
// Returns a suitable seed for a random floating generator based off
|
||||||
|
// the primary internal rng. It does so by taking current value from
|
||||||
|
// the rng and returning it as the seed.
|
||||||
|
std::uint32_t getSeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Float>
|
||||||
|
class RandomFloatingGenerator final : public IGenerator<Float> {
|
||||||
|
Catch::SimplePcg32 m_rng;
|
||||||
|
std::uniform_real_distribution<Float> m_dist;
|
||||||
|
Float m_current_number;
|
||||||
|
public:
|
||||||
|
RandomFloatingGenerator( Float a, Float b, std::uint32_t seed ):
|
||||||
|
m_rng(seed),
|
||||||
|
m_dist(a, b) {
|
||||||
|
static_cast<void>(next());
|
||||||
|
}
|
||||||
|
|
||||||
|
Float const& get() const override {
|
||||||
|
return m_current_number;
|
||||||
|
}
|
||||||
|
bool next() override {
|
||||||
|
m_current_number = m_dist(m_rng);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Integer>
|
||||||
|
class RandomIntegerGenerator final : public IGenerator<Integer> {
|
||||||
|
Catch::SimplePcg32 m_rng;
|
||||||
|
std::uniform_int_distribution<Integer> m_dist;
|
||||||
|
Integer m_current_number;
|
||||||
|
public:
|
||||||
|
RandomIntegerGenerator( Integer a, Integer b, std::uint32_t seed ):
|
||||||
|
m_rng(seed),
|
||||||
|
m_dist(a, b) {
|
||||||
|
static_cast<void>(next());
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer const& get() const override {
|
||||||
|
return m_current_number;
|
||||||
|
}
|
||||||
|
bool next() override {
|
||||||
|
m_current_number = m_dist(m_rng);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::enable_if_t<std::is_integral<T>::value, GeneratorWrapper<T>>
|
||||||
|
random(T a, T b) {
|
||||||
|
static_assert(
|
||||||
|
!std::is_same<T, char>::value &&
|
||||||
|
!std::is_same<T, int8_t>::value &&
|
||||||
|
!std::is_same<T, uint8_t>::value &&
|
||||||
|
!std::is_same<T, signed char>::value &&
|
||||||
|
!std::is_same<T, unsigned char>::value &&
|
||||||
|
!std::is_same<T, bool>::value,
|
||||||
|
"The requested type is not supported by the underlying random distributions from std" );
|
||||||
|
return GeneratorWrapper<T>(
|
||||||
|
Catch::Detail::make_unique<RandomIntegerGenerator<T>>(a, b, Detail::getSeed())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::enable_if_t<std::is_floating_point<T>::value,
|
||||||
|
GeneratorWrapper<T>>
|
||||||
|
random(T a, T b) {
|
||||||
|
return GeneratorWrapper<T>(
|
||||||
|
Catch::Detail::make_unique<RandomFloatingGenerator<T>>(a, b, Detail::getSeed())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CATCH_GENERATORS_RANDOM_HPP_INCLUDED
|
@ -0,0 +1,110 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_GENERATORS_RANGE_HPP_INCLUDED
|
||||||
|
#define CATCH_GENERATORS_RANGE_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/generators/catch_generators.hpp>
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Generators {
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class RangeGenerator final : public IGenerator<T> {
|
||||||
|
T m_current;
|
||||||
|
T m_end;
|
||||||
|
T m_step;
|
||||||
|
bool m_positive;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RangeGenerator(T const& start, T const& end, T const& step):
|
||||||
|
m_current(start),
|
||||||
|
m_end(end),
|
||||||
|
m_step(step),
|
||||||
|
m_positive(m_step > T(0))
|
||||||
|
{
|
||||||
|
assert(m_current != m_end && "Range start and end cannot be equal");
|
||||||
|
assert(m_step != T(0) && "Step size cannot be zero");
|
||||||
|
assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
|
||||||
|
}
|
||||||
|
|
||||||
|
RangeGenerator(T const& start, T const& end):
|
||||||
|
RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
|
||||||
|
{}
|
||||||
|
|
||||||
|
T const& get() const override {
|
||||||
|
return m_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next() override {
|
||||||
|
m_current += m_step;
|
||||||
|
return (m_positive) ? (m_current < m_end) : (m_current > m_end);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
|
||||||
|
static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric");
|
||||||
|
return GeneratorWrapper<T>(Catch::Detail::make_unique<RangeGenerator<T>>(start, end, step));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
GeneratorWrapper<T> range(T const& start, T const& end) {
|
||||||
|
static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
|
||||||
|
return GeneratorWrapper<T>(Catch::Detail::make_unique<RangeGenerator<T>>(start, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class IteratorGenerator final : public IGenerator<T> {
|
||||||
|
static_assert(!std::is_same<T, bool>::value,
|
||||||
|
"IteratorGenerator currently does not support bools"
|
||||||
|
"because of std::vector<bool> specialization");
|
||||||
|
|
||||||
|
std::vector<T> m_elems;
|
||||||
|
size_t m_current = 0;
|
||||||
|
public:
|
||||||
|
template <typename InputIterator, typename InputSentinel>
|
||||||
|
IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {
|
||||||
|
if (m_elems.empty()) {
|
||||||
|
Detail::throw_generator_exception("IteratorGenerator received no valid values");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T const& get() const override {
|
||||||
|
return m_elems[m_current];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next() override {
|
||||||
|
++m_current;
|
||||||
|
return m_current != m_elems.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename InputIterator,
|
||||||
|
typename InputSentinel,
|
||||||
|
typename ResultType = typename std::iterator_traits<InputIterator>::value_type>
|
||||||
|
GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {
|
||||||
|
return GeneratorWrapper<ResultType>(Catch::Detail::make_unique<IteratorGenerator<ResultType>>(from, to));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Container,
|
||||||
|
typename ResultType = typename Container::value_type>
|
||||||
|
GeneratorWrapper<ResultType> from_range(Container const& cnt) {
|
||||||
|
return GeneratorWrapper<ResultType>(Catch::Detail::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CATCH_GENERATORS_RANGE_HPP_INCLUDED
|
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
/** \file
|
||||||
|
* This is a convenience header for Catch2's interfaces. It includes
|
||||||
|
* **all** of Catch2 headers related to interfaces.
|
||||||
|
*
|
||||||
|
* Generally the Catch2 users should use specific includes they need,
|
||||||
|
* but this header can be used instead for ease-of-experimentation, or
|
||||||
|
* just plain convenience, at the cost of somewhat increased compilation
|
||||||
|
* times.
|
||||||
|
*
|
||||||
|
* When a new header is added to either the `interfaces` folder, or to
|
||||||
|
* the corresponding internal subfolder, it should be added here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef CATCH_INTERFACES_ALL_HPP_INCLUDED
|
||||||
|
#define CATCH_INTERFACES_ALL_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_enum_values_registry.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_exception.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_tag_alias_registry.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_test_invoker.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_testcase.hpp>
|
||||||
|
|
||||||
|
#endif // CATCH_INTERFACES_ALL_HPP_INCLUDED
|
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
IResultCapture::~IResultCapture() = default;
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
|
||||||
|
#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
#include <catch2/internal/catch_result_type.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
class AssertionResult;
|
||||||
|
struct AssertionInfo;
|
||||||
|
struct SectionInfo;
|
||||||
|
struct SectionEndInfo;
|
||||||
|
struct MessageInfo;
|
||||||
|
struct MessageBuilder;
|
||||||
|
struct Counts;
|
||||||
|
struct AssertionReaction;
|
||||||
|
struct SourceLineInfo;
|
||||||
|
|
||||||
|
class ITransientExpression;
|
||||||
|
class IGeneratorTracker;
|
||||||
|
|
||||||
|
struct BenchmarkInfo;
|
||||||
|
|
||||||
|
namespace Generators {
|
||||||
|
class GeneratorUntypedBase;
|
||||||
|
using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class IResultCapture {
|
||||||
|
public:
|
||||||
|
virtual ~IResultCapture();
|
||||||
|
|
||||||
|
virtual void notifyAssertionStarted( AssertionInfo const& info ) = 0;
|
||||||
|
virtual bool sectionStarted( StringRef sectionName,
|
||||||
|
SourceLineInfo const& sectionLineInfo,
|
||||||
|
Counts& assertions ) = 0;
|
||||||
|
virtual void sectionEnded( SectionEndInfo&& endInfo ) = 0;
|
||||||
|
virtual void sectionEndedEarly( SectionEndInfo&& endInfo ) = 0;
|
||||||
|
|
||||||
|
virtual IGeneratorTracker*
|
||||||
|
acquireGeneratorTracker( StringRef generatorName,
|
||||||
|
SourceLineInfo const& lineInfo ) = 0;
|
||||||
|
virtual IGeneratorTracker*
|
||||||
|
createGeneratorTracker( StringRef generatorName,
|
||||||
|
SourceLineInfo lineInfo,
|
||||||
|
Generators::GeneratorBasePtr&& generator ) = 0;
|
||||||
|
|
||||||
|
virtual void benchmarkPreparing( StringRef name ) = 0;
|
||||||
|
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
|
||||||
|
virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
|
||||||
|
virtual void benchmarkFailed( StringRef error ) = 0;
|
||||||
|
|
||||||
|
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
|
||||||
|
virtual void popScopedMessage( MessageInfo const& message ) = 0;
|
||||||
|
|
||||||
|
virtual void emplaceUnscopedMessage( MessageBuilder&& builder ) = 0;
|
||||||
|
|
||||||
|
virtual void handleFatalErrorCondition( StringRef message ) = 0;
|
||||||
|
|
||||||
|
virtual void handleExpr
|
||||||
|
( AssertionInfo const& info,
|
||||||
|
ITransientExpression const& expr,
|
||||||
|
AssertionReaction& reaction ) = 0;
|
||||||
|
virtual void handleMessage
|
||||||
|
( AssertionInfo const& info,
|
||||||
|
ResultWas::OfType resultType,
|
||||||
|
StringRef message,
|
||||||
|
AssertionReaction& reaction ) = 0;
|
||||||
|
virtual void handleUnexpectedExceptionNotThrown
|
||||||
|
( AssertionInfo const& info,
|
||||||
|
AssertionReaction& reaction ) = 0;
|
||||||
|
virtual void handleUnexpectedInflightException
|
||||||
|
( AssertionInfo const& info,
|
||||||
|
std::string&& message,
|
||||||
|
AssertionReaction& reaction ) = 0;
|
||||||
|
virtual void handleIncomplete
|
||||||
|
( AssertionInfo const& info ) = 0;
|
||||||
|
virtual void handleNonExpr
|
||||||
|
( AssertionInfo const &info,
|
||||||
|
ResultWas::OfType resultType,
|
||||||
|
AssertionReaction &reaction ) = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool lastAssertionPassed() = 0;
|
||||||
|
virtual void assertionPassed() = 0;
|
||||||
|
|
||||||
|
// Deprecated, do not use:
|
||||||
|
virtual std::string getCurrentTestName() const = 0;
|
||||||
|
virtual const AssertionResult* getLastResult() const = 0;
|
||||||
|
virtual void exceptionEarlyReported() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
IResultCapture& getResultCapture();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
|
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
IConfig::~IConfig() = default;
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED
|
||||||
|
#define CATCH_INTERFACES_CONFIG_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_noncopyable.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
enum class Verbosity {
|
||||||
|
Quiet = 0,
|
||||||
|
Normal,
|
||||||
|
High
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WarnAbout { enum What {
|
||||||
|
Nothing = 0x00,
|
||||||
|
//! A test case or leaf section did not run any assertions
|
||||||
|
NoAssertions = 0x01,
|
||||||
|
//! A command line test spec matched no test cases
|
||||||
|
UnmatchedTestSpec = 0x02,
|
||||||
|
}; };
|
||||||
|
|
||||||
|
enum class ShowDurations {
|
||||||
|
DefaultForReporter,
|
||||||
|
Always,
|
||||||
|
Never
|
||||||
|
};
|
||||||
|
enum class TestRunOrder {
|
||||||
|
Declared,
|
||||||
|
LexicographicallySorted,
|
||||||
|
Randomized
|
||||||
|
};
|
||||||
|
enum class ColourMode : std::uint8_t {
|
||||||
|
//! Let Catch2 pick implementation based on platform detection
|
||||||
|
PlatformDefault,
|
||||||
|
//! Use ANSI colour code escapes
|
||||||
|
ANSI,
|
||||||
|
//! Use Win32 console colour API
|
||||||
|
Win32,
|
||||||
|
//! Don't use any colour
|
||||||
|
None
|
||||||
|
};
|
||||||
|
struct WaitForKeypress { enum When {
|
||||||
|
Never,
|
||||||
|
BeforeStart = 1,
|
||||||
|
BeforeExit = 2,
|
||||||
|
BeforeStartAndExit = BeforeStart | BeforeExit
|
||||||
|
}; };
|
||||||
|
|
||||||
|
class TestSpec;
|
||||||
|
class IStream;
|
||||||
|
|
||||||
|
class IConfig : public Detail::NonCopyable {
|
||||||
|
public:
|
||||||
|
virtual ~IConfig();
|
||||||
|
|
||||||
|
virtual bool allowThrows() const = 0;
|
||||||
|
virtual StringRef name() const = 0;
|
||||||
|
virtual bool includeSuccessfulResults() const = 0;
|
||||||
|
virtual bool shouldDebugBreak() const = 0;
|
||||||
|
virtual bool warnAboutMissingAssertions() const = 0;
|
||||||
|
virtual bool warnAboutUnmatchedTestSpecs() const = 0;
|
||||||
|
virtual bool zeroTestsCountAsSuccess() const = 0;
|
||||||
|
virtual int abortAfter() const = 0;
|
||||||
|
virtual bool showInvisibles() const = 0;
|
||||||
|
virtual ShowDurations showDurations() const = 0;
|
||||||
|
virtual double minDuration() const = 0;
|
||||||
|
virtual TestSpec const& testSpec() const = 0;
|
||||||
|
virtual bool hasTestFilters() const = 0;
|
||||||
|
virtual std::vector<std::string> const& getTestsOrTags() const = 0;
|
||||||
|
virtual TestRunOrder runOrder() const = 0;
|
||||||
|
virtual uint32_t rngSeed() const = 0;
|
||||||
|
virtual unsigned int shardCount() const = 0;
|
||||||
|
virtual unsigned int shardIndex() const = 0;
|
||||||
|
virtual ColourMode defaultColourMode() const = 0;
|
||||||
|
virtual std::vector<std::string> const& getSectionsToRun() const = 0;
|
||||||
|
virtual Verbosity verbosity() const = 0;
|
||||||
|
|
||||||
|
virtual bool skipBenchmarks() const = 0;
|
||||||
|
virtual bool benchmarkNoAnalysis() const = 0;
|
||||||
|
virtual unsigned int benchmarkSamples() const = 0;
|
||||||
|
virtual double benchmarkConfidenceInterval() const = 0;
|
||||||
|
virtual unsigned int benchmarkResamples() const = 0;
|
||||||
|
virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CATCH_INTERFACES_CONFIG_HPP_INCLUDED
|
@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
|
||||||
|
#define CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
struct EnumInfo {
|
||||||
|
StringRef m_name;
|
||||||
|
std::vector<std::pair<int, StringRef>> m_values;
|
||||||
|
|
||||||
|
~EnumInfo();
|
||||||
|
|
||||||
|
StringRef lookup( int value ) const;
|
||||||
|
};
|
||||||
|
} // namespace Detail
|
||||||
|
|
||||||
|
class IMutableEnumValuesRegistry {
|
||||||
|
public:
|
||||||
|
virtual ~IMutableEnumValuesRegistry(); // = default;
|
||||||
|
|
||||||
|
virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
|
||||||
|
|
||||||
|
template<typename E>
|
||||||
|
Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
|
||||||
|
static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
|
||||||
|
std::vector<int> intValues;
|
||||||
|
intValues.reserve( values.size() );
|
||||||
|
for( auto enumValue : values )
|
||||||
|
intValues.push_back( static_cast<int>( enumValue ) );
|
||||||
|
return registerEnum( enumName, allEnums, intValues );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // Catch
|
||||||
|
|
||||||
|
#endif // CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
|
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/interfaces/catch_interfaces_exception.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
IExceptionTranslator::~IExceptionTranslator() = default;
|
||||||
|
IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
|
||||||
|
#define CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
using exceptionTranslateFunction = std::string(*)();
|
||||||
|
|
||||||
|
class IExceptionTranslator;
|
||||||
|
using ExceptionTranslators = std::vector<Detail::unique_ptr<IExceptionTranslator const>>;
|
||||||
|
|
||||||
|
class IExceptionTranslator {
|
||||||
|
public:
|
||||||
|
virtual ~IExceptionTranslator(); // = default
|
||||||
|
virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IExceptionTranslatorRegistry {
|
||||||
|
public:
|
||||||
|
virtual ~IExceptionTranslatorRegistry(); // = default
|
||||||
|
virtual std::string translateActiveException() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
|
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Generators {
|
||||||
|
|
||||||
|
bool GeneratorUntypedBase::countedNext() {
|
||||||
|
auto ret = next();
|
||||||
|
if ( ret ) {
|
||||||
|
m_stringReprCache.clear();
|
||||||
|
++m_currentElementIndex;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringRef GeneratorUntypedBase::currentElementAsString() const {
|
||||||
|
if ( m_stringReprCache.empty() ) {
|
||||||
|
m_stringReprCache = stringifyImpl();
|
||||||
|
}
|
||||||
|
return m_stringReprCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
} // namespace Catch
|
@ -0,0 +1,90 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
|
||||||
|
#define CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace Generators {
|
||||||
|
class GeneratorUntypedBase {
|
||||||
|
// Caches result from `toStringImpl`, assume that when it is an
|
||||||
|
// empty string, the cache is invalidated.
|
||||||
|
mutable std::string m_stringReprCache;
|
||||||
|
|
||||||
|
// Counts based on `next` returning true
|
||||||
|
std::size_t m_currentElementIndex = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to move the generator to the next element
|
||||||
|
*
|
||||||
|
* Returns true iff the move succeeded (and a valid element
|
||||||
|
* can be retrieved).
|
||||||
|
*/
|
||||||
|
virtual bool next() = 0;
|
||||||
|
|
||||||
|
//! Customization point for `currentElementAsString`
|
||||||
|
virtual std::string stringifyImpl() const = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GeneratorUntypedBase() = default;
|
||||||
|
// Generation of copy ops is deprecated (and Clang will complain)
|
||||||
|
// if there is a user destructor defined
|
||||||
|
GeneratorUntypedBase(GeneratorUntypedBase const&) = default;
|
||||||
|
GeneratorUntypedBase& operator=(GeneratorUntypedBase const&) = default;
|
||||||
|
|
||||||
|
virtual ~GeneratorUntypedBase(); // = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to move the generator to the next element
|
||||||
|
*
|
||||||
|
* Serves as a non-virtual interface to `next`, so that the
|
||||||
|
* top level interface can provide sanity checking and shared
|
||||||
|
* features.
|
||||||
|
*
|
||||||
|
* As with `next`, returns true iff the move succeeded and
|
||||||
|
* the generator has new valid element to provide.
|
||||||
|
*/
|
||||||
|
bool countedNext();
|
||||||
|
|
||||||
|
std::size_t currentElementIndex() const { return m_currentElementIndex; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns generator's current element as user-friendly string.
|
||||||
|
*
|
||||||
|
* By default returns string equivalent to calling
|
||||||
|
* `Catch::Detail::stringify` on the current element, but generators
|
||||||
|
* can customize their implementation as needed.
|
||||||
|
*
|
||||||
|
* Not thread-safe due to internal caching.
|
||||||
|
*
|
||||||
|
* The returned ref is valid only until the generator instance
|
||||||
|
* is destructed, or it moves onto the next element, whichever
|
||||||
|
* comes first.
|
||||||
|
*/
|
||||||
|
StringRef currentElementAsString() const;
|
||||||
|
};
|
||||||
|
using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
|
||||||
|
class IGeneratorTracker {
|
||||||
|
public:
|
||||||
|
virtual ~IGeneratorTracker(); // = default;
|
||||||
|
virtual auto hasGenerator() const -> bool = 0;
|
||||||
|
virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
|
||||||
|
virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
|
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
IRegistryHub::~IRegistryHub() = default;
|
||||||
|
IMutableRegistryHub::~IMutableRegistryHub() = default;
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
|
||||||
|
#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
class TestCaseHandle;
|
||||||
|
struct TestCaseInfo;
|
||||||
|
class ITestCaseRegistry;
|
||||||
|
class IExceptionTranslatorRegistry;
|
||||||
|
class IExceptionTranslator;
|
||||||
|
class ReporterRegistry;
|
||||||
|
class IReporterFactory;
|
||||||
|
class ITagAliasRegistry;
|
||||||
|
class ITestInvoker;
|
||||||
|
class IMutableEnumValuesRegistry;
|
||||||
|
struct SourceLineInfo;
|
||||||
|
|
||||||
|
class StartupExceptionRegistry;
|
||||||
|
class EventListenerFactory;
|
||||||
|
|
||||||
|
using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
|
||||||
|
|
||||||
|
class IRegistryHub {
|
||||||
|
public:
|
||||||
|
virtual ~IRegistryHub(); // = default
|
||||||
|
|
||||||
|
virtual ReporterRegistry const& getReporterRegistry() const = 0;
|
||||||
|
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
|
||||||
|
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
|
||||||
|
virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
|
||||||
|
|
||||||
|
|
||||||
|
virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IMutableRegistryHub {
|
||||||
|
public:
|
||||||
|
virtual ~IMutableRegistryHub(); // = default
|
||||||
|
virtual void registerReporter( std::string const& name, IReporterFactoryPtr factory ) = 0;
|
||||||
|
virtual void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) = 0;
|
||||||
|
virtual void registerTest(Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker) = 0;
|
||||||
|
virtual void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) = 0;
|
||||||
|
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
|
||||||
|
virtual void registerStartupException() noexcept = 0;
|
||||||
|
virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
IRegistryHub const& getRegistryHub();
|
||||||
|
IMutableRegistryHub& getMutableRegistryHub();
|
||||||
|
void cleanUp();
|
||||||
|
std::string translateActiveException();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
|
@ -0,0 +1,101 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||||
|
#include <catch2/internal/catch_console_colour.hpp>
|
||||||
|
#include <catch2/internal/catch_console_width.hpp>
|
||||||
|
#include <catch2/catch_message.hpp>
|
||||||
|
#include <catch2/internal/catch_list.hpp>
|
||||||
|
#include <catch2/internal/catch_string_manip.hpp>
|
||||||
|
#include <catch2/catch_test_case_info.hpp>
|
||||||
|
#include <catch2/reporters/catch_reporter_helpers.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
#include <catch2/internal/catch_istream.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
ReporterConfig::ReporterConfig(
|
||||||
|
IConfig const* _fullConfig,
|
||||||
|
Detail::unique_ptr<IStream> _stream,
|
||||||
|
ColourMode colourMode,
|
||||||
|
std::map<std::string, std::string> customOptions ):
|
||||||
|
m_stream( CATCH_MOVE(_stream) ),
|
||||||
|
m_fullConfig( _fullConfig ),
|
||||||
|
m_colourMode( colourMode ),
|
||||||
|
m_customOptions( CATCH_MOVE( customOptions ) ) {}
|
||||||
|
|
||||||
|
Detail::unique_ptr<IStream> ReporterConfig::takeStream() && {
|
||||||
|
assert( m_stream );
|
||||||
|
return CATCH_MOVE( m_stream );
|
||||||
|
}
|
||||||
|
IConfig const * ReporterConfig::fullConfig() const { return m_fullConfig; }
|
||||||
|
ColourMode ReporterConfig::colourMode() const { return m_colourMode; }
|
||||||
|
|
||||||
|
std::map<std::string, std::string> const&
|
||||||
|
ReporterConfig::customOptions() const {
|
||||||
|
return m_customOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReporterConfig::~ReporterConfig() = default;
|
||||||
|
|
||||||
|
AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
|
||||||
|
std::vector<MessageInfo> const& _infoMessages,
|
||||||
|
Totals const& _totals )
|
||||||
|
: assertionResult( _assertionResult ),
|
||||||
|
infoMessages( _infoMessages ),
|
||||||
|
totals( _totals )
|
||||||
|
{
|
||||||
|
if( assertionResult.hasMessage() ) {
|
||||||
|
// Copy message into messages list.
|
||||||
|
// !TBD This should have been done earlier, somewhere
|
||||||
|
MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
|
||||||
|
builder.m_info.message = static_cast<std::string>(assertionResult.getMessage());
|
||||||
|
|
||||||
|
infoMessages.push_back( CATCH_MOVE(builder.m_info) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionStats::SectionStats( SectionInfo&& _sectionInfo,
|
||||||
|
Counts const& _assertions,
|
||||||
|
double _durationInSeconds,
|
||||||
|
bool _missingAssertions )
|
||||||
|
: sectionInfo( CATCH_MOVE(_sectionInfo) ),
|
||||||
|
assertions( _assertions ),
|
||||||
|
durationInSeconds( _durationInSeconds ),
|
||||||
|
missingAssertions( _missingAssertions )
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
|
||||||
|
Totals const& _totals,
|
||||||
|
std::string&& _stdOut,
|
||||||
|
std::string&& _stdErr,
|
||||||
|
bool _aborting )
|
||||||
|
: testInfo( &_testInfo ),
|
||||||
|
totals( _totals ),
|
||||||
|
stdOut( CATCH_MOVE(_stdOut) ),
|
||||||
|
stdErr( CATCH_MOVE(_stdErr) ),
|
||||||
|
aborting( _aborting )
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
TestRunStats::TestRunStats( TestRunInfo const& _runInfo,
|
||||||
|
Totals const& _totals,
|
||||||
|
bool _aborting )
|
||||||
|
: runInfo( _runInfo ),
|
||||||
|
totals( _totals ),
|
||||||
|
aborting( _aborting )
|
||||||
|
{}
|
||||||
|
|
||||||
|
IEventListener::~IEventListener() = default;
|
||||||
|
|
||||||
|
} // end namespace Catch
|
@ -0,0 +1,224 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED
|
||||||
|
#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/catch_section_info.hpp>
|
||||||
|
#include <catch2/catch_totals.hpp>
|
||||||
|
#include <catch2/catch_assertion_result.hpp>
|
||||||
|
#include <catch2/internal/catch_message_info.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
#include <catch2/internal/catch_test_run_info.hpp>
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||||
|
#include <catch2/benchmark/detail/catch_benchmark_stats.hpp>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <iosfwd>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct ReporterDescription;
|
||||||
|
struct ListenerDescription;
|
||||||
|
struct TagInfo;
|
||||||
|
struct TestCaseInfo;
|
||||||
|
class TestCaseHandle;
|
||||||
|
class IConfig;
|
||||||
|
class IStream;
|
||||||
|
enum class ColourMode : std::uint8_t;
|
||||||
|
|
||||||
|
struct ReporterConfig {
|
||||||
|
ReporterConfig( IConfig const* _fullConfig,
|
||||||
|
Detail::unique_ptr<IStream> _stream,
|
||||||
|
ColourMode colourMode,
|
||||||
|
std::map<std::string, std::string> customOptions );
|
||||||
|
|
||||||
|
ReporterConfig( ReporterConfig&& ) = default;
|
||||||
|
ReporterConfig& operator=( ReporterConfig&& ) = default;
|
||||||
|
~ReporterConfig(); // = default
|
||||||
|
|
||||||
|
Detail::unique_ptr<IStream> takeStream() &&;
|
||||||
|
IConfig const* fullConfig() const;
|
||||||
|
ColourMode colourMode() const;
|
||||||
|
std::map<std::string, std::string> const& customOptions() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Detail::unique_ptr<IStream> m_stream;
|
||||||
|
IConfig const* m_fullConfig;
|
||||||
|
ColourMode m_colourMode;
|
||||||
|
std::map<std::string, std::string> m_customOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AssertionStats {
|
||||||
|
AssertionStats( AssertionResult const& _assertionResult,
|
||||||
|
std::vector<MessageInfo> const& _infoMessages,
|
||||||
|
Totals const& _totals );
|
||||||
|
|
||||||
|
AssertionStats( AssertionStats const& ) = default;
|
||||||
|
AssertionStats( AssertionStats && ) = default;
|
||||||
|
AssertionStats& operator = ( AssertionStats const& ) = delete;
|
||||||
|
AssertionStats& operator = ( AssertionStats && ) = delete;
|
||||||
|
|
||||||
|
AssertionResult assertionResult;
|
||||||
|
std::vector<MessageInfo> infoMessages;
|
||||||
|
Totals totals;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SectionStats {
|
||||||
|
SectionStats( SectionInfo&& _sectionInfo,
|
||||||
|
Counts const& _assertions,
|
||||||
|
double _durationInSeconds,
|
||||||
|
bool _missingAssertions );
|
||||||
|
|
||||||
|
SectionInfo sectionInfo;
|
||||||
|
Counts assertions;
|
||||||
|
double durationInSeconds;
|
||||||
|
bool missingAssertions;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TestCaseStats {
|
||||||
|
TestCaseStats( TestCaseInfo const& _testInfo,
|
||||||
|
Totals const& _totals,
|
||||||
|
std::string&& _stdOut,
|
||||||
|
std::string&& _stdErr,
|
||||||
|
bool _aborting );
|
||||||
|
|
||||||
|
TestCaseInfo const * testInfo;
|
||||||
|
Totals totals;
|
||||||
|
std::string stdOut;
|
||||||
|
std::string stdErr;
|
||||||
|
bool aborting;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TestRunStats {
|
||||||
|
TestRunStats( TestRunInfo const& _runInfo,
|
||||||
|
Totals const& _totals,
|
||||||
|
bool _aborting );
|
||||||
|
|
||||||
|
TestRunInfo runInfo;
|
||||||
|
Totals totals;
|
||||||
|
bool aborting;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! By setting up its preferences, a reporter can modify Catch2's behaviour
|
||||||
|
//! in some regards, e.g. it can request Catch2 to capture writes to
|
||||||
|
//! stdout/stderr during test execution, and pass them to the reporter.
|
||||||
|
struct ReporterPreferences {
|
||||||
|
//! Catch2 should redirect writes to stdout and pass them to the
|
||||||
|
//! reporter
|
||||||
|
bool shouldRedirectStdOut = false;
|
||||||
|
//! Catch2 should call `Reporter::assertionEnded` even for passing
|
||||||
|
//! assertions
|
||||||
|
bool shouldReportAllAssertions = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The common base for all reporters and event listeners
|
||||||
|
*
|
||||||
|
* Implementing classes must also implement:
|
||||||
|
*
|
||||||
|
* //! User-friendly description of the reporter/listener type
|
||||||
|
* static std::string getDescription()
|
||||||
|
*
|
||||||
|
* Generally shouldn't be derived from by users of Catch2 directly,
|
||||||
|
* instead they should derive from one of the utility bases that
|
||||||
|
* derive from this class.
|
||||||
|
*/
|
||||||
|
class IEventListener {
|
||||||
|
protected:
|
||||||
|
//! Derived classes can set up their preferences here
|
||||||
|
ReporterPreferences m_preferences;
|
||||||
|
//! The test run's config as filled in from CLI and defaults
|
||||||
|
IConfig const* m_config;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IEventListener( IConfig const* config ): m_config( config ) {}
|
||||||
|
|
||||||
|
virtual ~IEventListener(); // = default;
|
||||||
|
|
||||||
|
// Implementing class must also provide the following static methods:
|
||||||
|
// static std::string getDescription();
|
||||||
|
|
||||||
|
ReporterPreferences const& getPreferences() const {
|
||||||
|
return m_preferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Called when no test cases match provided test spec
|
||||||
|
virtual void noMatchingTestCases( StringRef unmatchedSpec ) = 0;
|
||||||
|
//! Called for all invalid test specs from the cli
|
||||||
|
virtual void reportInvalidTestSpec( StringRef invalidArgument ) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called once in a testing run before tests are started
|
||||||
|
*
|
||||||
|
* Not called if tests won't be run (e.g. only listing will happen)
|
||||||
|
*/
|
||||||
|
virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
|
||||||
|
|
||||||
|
//! Called _once_ for each TEST_CASE, no matter how many times it is entered
|
||||||
|
virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
|
||||||
|
//! Called _every time_ a TEST_CASE is entered, including repeats (due to sections)
|
||||||
|
virtual void testCasePartialStarting( TestCaseInfo const& testInfo, uint64_t partNumber ) = 0;
|
||||||
|
//! Called when a `SECTION` is being entered. Not called for skipped sections
|
||||||
|
virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
|
||||||
|
|
||||||
|
//! Called when user-code is being probed before the actual benchmark runs
|
||||||
|
virtual void benchmarkPreparing( StringRef benchmarkName ) = 0;
|
||||||
|
//! Called after probe but before the user-code is being benchmarked
|
||||||
|
virtual void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) = 0;
|
||||||
|
//! Called with the benchmark results if benchmark successfully finishes
|
||||||
|
virtual void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) = 0;
|
||||||
|
//! Called if running the benchmarks fails for any reason
|
||||||
|
virtual void benchmarkFailed( StringRef benchmarkName ) = 0;
|
||||||
|
|
||||||
|
//! Called before assertion success/failure is evaluated
|
||||||
|
virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
|
||||||
|
|
||||||
|
//! Called after assertion was fully evaluated
|
||||||
|
virtual void assertionEnded( AssertionStats const& assertionStats ) = 0;
|
||||||
|
|
||||||
|
//! Called after a `SECTION` has finished running
|
||||||
|
virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
|
||||||
|
//! Called _every time_ a TEST_CASE is entered, including repeats (due to sections)
|
||||||
|
virtual void testCasePartialEnded(TestCaseStats const& testCaseStats, uint64_t partNumber ) = 0;
|
||||||
|
//! Called _once_ for each TEST_CASE, no matter how many times it is entered
|
||||||
|
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
|
||||||
|
/**
|
||||||
|
* Called once after all tests in a testing run are finished
|
||||||
|
*
|
||||||
|
* Not called if tests weren't run (e.g. only listings happened)
|
||||||
|
*/
|
||||||
|
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called with test cases that are skipped due to the test run aborting.
|
||||||
|
* NOT called for test cases that are explicitly skipped using the `SKIP` macro.
|
||||||
|
*
|
||||||
|
* Deprecated - will be removed in the next major release.
|
||||||
|
*/
|
||||||
|
virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
|
||||||
|
|
||||||
|
//! Called if a fatal error (signal/structured exception) occurred
|
||||||
|
virtual void fatalErrorEncountered( StringRef error ) = 0;
|
||||||
|
|
||||||
|
//! Writes out information about provided reporters using reporter-specific format
|
||||||
|
virtual void listReporters(std::vector<ReporterDescription> const& descriptions) = 0;
|
||||||
|
//! Writes out the provided listeners descriptions using reporter-specific format
|
||||||
|
virtual void listListeners(std::vector<ListenerDescription> const& descriptions) = 0;
|
||||||
|
//! Writes out information about provided tests using reporter-specific format
|
||||||
|
virtual void listTests(std::vector<TestCaseHandle> const& tests) = 0;
|
||||||
|
//! Writes out information about the provided tags using reporter-specific format
|
||||||
|
virtual void listTags(std::vector<TagInfo> const& tags) = 0;
|
||||||
|
};
|
||||||
|
using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED
|
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
IReporterFactory::~IReporterFactory() = default;
|
||||||
|
EventListenerFactory::~EventListenerFactory() = default;
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
|
||||||
|
#define CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct ReporterConfig;
|
||||||
|
class IConfig;
|
||||||
|
class IEventListener;
|
||||||
|
using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
|
||||||
|
|
||||||
|
|
||||||
|
class IReporterFactory {
|
||||||
|
public:
|
||||||
|
virtual ~IReporterFactory(); // = default
|
||||||
|
|
||||||
|
virtual IEventListenerPtr
|
||||||
|
create( ReporterConfig&& config ) const = 0;
|
||||||
|
virtual std::string getDescription() const = 0;
|
||||||
|
};
|
||||||
|
using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
|
||||||
|
|
||||||
|
class EventListenerFactory {
|
||||||
|
public:
|
||||||
|
virtual ~EventListenerFactory(); // = default
|
||||||
|
virtual IEventListenerPtr create( IConfig const* config ) const = 0;
|
||||||
|
//! Return a meaningful name for the listener, e.g. its type name
|
||||||
|
virtual StringRef getName() const = 0;
|
||||||
|
//! Return listener's description if available
|
||||||
|
virtual std::string getDescription() const = 0;
|
||||||
|
};
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
|
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
|
||||||
|
#define CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct TagAlias;
|
||||||
|
|
||||||
|
class ITagAliasRegistry {
|
||||||
|
public:
|
||||||
|
virtual ~ITagAliasRegistry(); // = default
|
||||||
|
// Nullptr if not present
|
||||||
|
virtual TagAlias const* find( std::string const& alias ) const = 0;
|
||||||
|
virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
|
||||||
|
|
||||||
|
static ITagAliasRegistry const& get();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
|
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
|
||||||
|
#define CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
class ITestInvoker {
|
||||||
|
public:
|
||||||
|
virtual void invoke() const = 0;
|
||||||
|
virtual ~ITestInvoker(); // = default
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
|
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/interfaces/catch_interfaces_testcase.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
ITestCaseRegistry::~ITestCaseRegistry() = default;
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#ifndef CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
|
||||||
|
#define CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct TestCaseInfo;
|
||||||
|
class TestCaseHandle;
|
||||||
|
class IConfig;
|
||||||
|
|
||||||
|
class ITestCaseRegistry {
|
||||||
|
public:
|
||||||
|
virtual ~ITestCaseRegistry(); // = default
|
||||||
|
// TODO: this exists only for adding filenames to test cases -- let's expose this in a saner way later
|
||||||
|
virtual std::vector<TestCaseInfo* > const& getAllInfos() const = 0;
|
||||||
|
virtual std::vector<TestCaseHandle> const& getAllTests() const = 0;
|
||||||
|
virtual std::vector<TestCaseHandle> const& getAllTestsSorted( IConfig const& config ) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
|
@ -0,0 +1,84 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
#include <catch2/internal/catch_assertion_handler.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||||
|
#include <catch2/internal/catch_context.hpp>
|
||||||
|
#include <catch2/internal/catch_enforce.hpp>
|
||||||
|
#include <catch2/internal/catch_debugger.hpp>
|
||||||
|
#include <catch2/internal/catch_test_failure_exception.hpp>
|
||||||
|
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||||
|
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
AssertionHandler::AssertionHandler
|
||||||
|
( StringRef macroName,
|
||||||
|
SourceLineInfo const& lineInfo,
|
||||||
|
StringRef capturedExpression,
|
||||||
|
ResultDisposition::Flags resultDisposition )
|
||||||
|
: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
|
||||||
|
m_resultCapture( getResultCapture() )
|
||||||
|
{
|
||||||
|
m_resultCapture.notifyAssertionStarted( m_assertionInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
|
||||||
|
m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
|
||||||
|
}
|
||||||
|
void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef message) {
|
||||||
|
m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AssertionHandler::allowThrows() const -> bool {
|
||||||
|
return getCurrentContext().getConfig()->allowThrows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssertionHandler::complete() {
|
||||||
|
m_completed = true;
|
||||||
|
if( m_reaction.shouldDebugBreak ) {
|
||||||
|
|
||||||
|
// If you find your debugger stopping you here then go one level up on the
|
||||||
|
// call-stack for the code that caused it (typically a failed assertion)
|
||||||
|
|
||||||
|
// (To go back to the test and change execution, jump over the throw, next)
|
||||||
|
CATCH_BREAK_INTO_DEBUGGER();
|
||||||
|
}
|
||||||
|
if (m_reaction.shouldThrow) {
|
||||||
|
throw_test_failure_exception();
|
||||||
|
}
|
||||||
|
if ( m_reaction.shouldSkip ) {
|
||||||
|
throw_test_skip_exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssertionHandler::handleUnexpectedInflightException() {
|
||||||
|
m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssertionHandler::handleExceptionThrownAsExpected() {
|
||||||
|
m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
|
||||||
|
}
|
||||||
|
void AssertionHandler::handleExceptionNotThrownAsExpected() {
|
||||||
|
m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssertionHandler::handleUnexpectedExceptionNotThrown() {
|
||||||
|
m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssertionHandler::handleThrowingCallSkipped() {
|
||||||
|
m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the overload that takes a string and infers the Equals matcher from it
|
||||||
|
// The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
|
||||||
|
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str ) {
|
||||||
|
handleExceptionMatchExpr( handler, Matchers::Equals( str ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Catch
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user