From ba06a404d1437c73ed3ba100d04a217fa69545b8 Mon Sep 17 00:00:00 2001 From: Yang Liu Date: Sun, 31 Dec 2023 14:00:46 +0800 Subject: [PATCH] Squashed 'externals/catch/' changes from ab6c7375b..53d0d913a MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 53d0d913a v3.5.0 1648c30ec Look just for 'Catch2 X.Y.Z' in doc placeholder update d4e9fb8aa Highlight that SECTIONs rerun the entire test case from beginning (#2749) b606bc280 Remove obsolete section in limitations.md 4ab0af8ba Fix minor typos in documentation (#2769) b7d70ddcd Ensure we always read 32 bit seed from std::random_device a6f22c516 Remove static instance of std::random_device in Benchmark::analyse_samples 1887d42e3 Use our PCG32 RNG instead of mt19937 in Benchmark::analyse_samples 1774dbfd5 Make it clearer that the JSON reporter is WIP cb07ff9a7 Fix uniform_floating_point_distribution for unit ranges ae4fe16b8 Make the user-facing random Generators reproducible 28c66fdc5 Make uniform_floating_point_distribution reproducible ed9d672b5 Add uniform_integer_distribution 04a829b0e Add helpers for implementing uniform integer distribution ab1b079e4 Add uniform_floating_point_distribution d139b4ff7 Add implementation of helpers for uniform float distribution bfd9f0f5a Move nextafter polyfill to polyfills.hpp 9a1e73568 Add test showing literals and complex generators in one GENERATE 21d2da23b Fix typo in tostring.md d1d7414eb Always run apt-get update before apt-get install dacbf4fd6 Drop VS 2017 support 0520ff443 [DOC] Replaced broken link (fixes #2770) 4a7be16c8 Fix compilation on Xbox platforms 32d9ae24b JSONWriter deals in StringRefs instead of std::strings de7ba4e88 fn need to be in parenthesis 733b901dd Fix special character escaping in JsonWriter 7bf136b50 Add JSON reporter (#2706) 2c68a0d05 lifted suggested version 01cac90c6 Bump up actions/checkout version to v4 (#2760) b735dfce2 Increase build parallelism on macOS (#2759) caffe79a3 Fix missing include in catch_message.hpp a8cf3e671 Mark `CATCH_CONFIG_` options as advanced 79d39a195 Fix tests for C++23's multi-arg index operator 6ebc013b8 Fix UDL definitions for C++23 966d36155 Improve formatting of test specification docs 766541d12 why-catch.md: Add JetBrains survey link 7b793314e Catch.cmake: Support CMake multi-config with PRE_TEST discovery mode (#2739) 0fb817e41 fix some bugprone-macro-parentheses warnings f161110be Merge pull request #2747 from xandox/devel db495acdb correct argument references in CatchAddTests.cmake 9c541ca72 Add test for multiple streaming parts in UNSCOPED_INFO 92672591c Make jackknife TU-local to stats.cpp 56fcd584c Make directCompare TU-local to stats.cpp aafe09bc1 Update meson.build to fix #2722 (#2742) 47a2c9693 Reduce the number of templates in Benchmarking fb96279ae Remove superfluous stdlib includes from catch_benchmark.hpp e14a08d73 Remove unused typedef from Benchmark::Environment 9bba07cb8 Replace vector iterator args in benchmarks with ptr args b4ffba508 Update sample output in docs/benchmarks.md 3a5cde55b implement stringify for std::nullopt_t 2a19ae16b Rewrite commandline test spec docs f24d39e42 Support C arrays and ADL ranges in from_range generator 85eb4652b Add nice license headers to files in examples/ and fuzzing/ 5bba3e403 Edited amalgamated file generator, to block REUSE from getting confused e09de7222 Small cleanup in XML reporter a64ff326b Change 'estimated' to 'est run time' in console reporter output ad5646347 Flush stream after benchmarkStarting in ConsoleReporter 9538d1600 Mention missing catch_user_config.hpp in FAQ a94bee771 Add missing line for v3.4.0 to ToC in release-notes.md d7304f0c4 Constify section hints in static-analysis mode cd60a0301 Assert Info reset need to also reset result disposition to normal to handle uncaught exception correctly (#2723) b593be211 Always default empty destructors ed4acded3 Don't define tryTranslators function if exception are disabled 4acc51828 Introduce CATCH_CONFIG_PREFIX_MESSAGES to only prefix a few logging related macros. (#2544) 6e79e682b v3.4.0 683c85772 Clean up explanation in tests 1b049bdba 2 more TEST_CASEs to DiscoverTests/register-tests.cpp e4b16053a Escape Catch2 test names in catch_discover_tests tests 42ee66b5e Fix handling of semicolon and backslash characters in CMake test discovery (#2676) a0c6a2846 Fix possible FP in catch_discover_tests tests c8363143e Add test scaffolding for catch_discover_tests 7a52dfa77 Fix typo in cross-docs links 913173663 Bazel support: Update skylib 0631b607e Test & document SKIP in generator constructor dff7513b2 Static analysis cleanup in tests bf5aa7b38 Experimental static analysis support in TEST_CASE and SECTION dba9197ec Add new config option: STATIC_ANALYSIS_SUPPORT f60c15364 Add macro for suppressing Wshadow b3cf1bfb5 Avoid unused variable warning in GeneratorsImpl tests 73b93ce6b Include catch_user_config.hpp in all catch_config_* files 8008625d7 Merge pull request #2693 from Ali-Amir/u/ali/optional-meson-unit-tests ce7b15302 Add option to disable building unit tests in Meson build file. 535205e2a Suppress -Wunused-result warning in gcc 689fdcd7d Fix some tests never being run a153fce72 Improve error messages for TEST_CASE tag parsing errors 06c0e1cfa Merge pull request #2689 from ThePhD/fix/includes/header-exception 05d7eb5a0 🛠 Add header where strictly necessary f53bb3ae7 meson: require version >=0.54.1 ce8a7b339 Merge pull request #2687 from ChrisThrasher/sfml 6dce539fa Add SFML to the list of open source users 5a40b2275 Update CatchConfigOptions.cmake 598895d04 Fix Wredundant-decls 0dc82e08d Move CATCH_INTERNAL_STRINGIFY macro into its own header 8ca504cbc Move AssertionResult when passing it inside RunContext c57b5cdf4 Move-enable Catch::optional d84777c9c Fix assertionStarting events being sent after the expr is evaluated 51fdbedd1 Internal linkage for outlier_variance 10f0a5864 Some template instantiation reductions fe64c2892 Reduce compilation costs of benchmarks 7d07efc92 Clean up iterator usage in benchmarks f3c678c0a Constexprify constants in estimate_clock.hpp 46539b6d9 Fix spelling 10596b227 Fix unreachable-code-return warnings 897fe2a01 cmake: Improve unreachable-code warnings aad926baf Catch.cmake: Add new DISCOVERY_MODE option to catch_discover_tests 4e8399d83 CatchAddTests.cmake: Refactor into callable method 9a2a4eadc Bump xml-format-version in XML reporter fb806da76 Add lineinfo to XML reporter output for INFO/WARN 50bf00e26 Fix reporter detection in catch_discover_tests 9f08097f5 Cleanup internal includes by splitting out some event structs 1f881ab46 Split ITestInvoker into its own header c487b27d9 Reduce misc includes all around 3230760db Cleanup in translating exceptions to messages b3ebce715 Cleanup benchmarking includes d0f70fdfd Unify IReporterRegistry and ReporterRegistry 4f4ad8ada Sprinkle some constexpr around 5b665be64 Cut out catch_interfaces_capture.hpp include from the main include 2598116aa Mark various anonymous classes final 173aa3f1f Devirtualize Context 28437e121 Remove pointless member variable from RunContext 3c8fb6bbb Internal linkage for generator trackers 72f3ce4db Outline the actual registering of listener factories to cpp file 62167d756 Reduce internal includes 678341134 Fixed extras installation and shard impl location 7b4dd326c Remove obsolete comment in multireporter 1dfaa8abe Outline throwing of TestSkipException ba94278bd Inline trivial function in AssertionHandler 8e5a4b6f7 Remove superfluous pointer copy in AssertionStats constructor 9b884d810 Fix refactoring 8a1b3b81c Add wxWidgets as another Open Source project using Catch e5aabb671 Add xmlwrapp to the list of Open Source projects using Catch 3a1ef1409 Use hasMessage() instead of getMessage().empty() 13fae1e2f Move exception's translation into AssertionResultData message 3220ae6d4 Add support for the IAR compiler 0a0ebf500 Support elements without op!= in VectorEquals 69f35a5ac Bazel support: Update skylib version 3f0283de7 v3.3.2 6fbb3f072 Add IsNaN matcher 9ff3cde87 Simplify test name creation for list-templated test cases 4d802ca58 Use StringRef UDL in more preprocessor-generated strings 13711be7c Use StringRef UDL for generated generator names 27ba26f74 Merge pull request #2643 from kisielk/patch-1 a209bcfb5 Update build instructions in contributing.md 584973a48 Early evaluate line loc in NameAndLoc::operator== 4f7c8cb28 Avoid copying NameAndLocationRef when passed as argument e1dbad4c9 Inline StringRef::operator== 2befd98da Inline some non-virtual functions in ITracker and TrackerContext 00f259aeb Move captured output into TestCaseStats when sending testCaseEnded fed143624 Avoid allocating trimmed name for SectionTracker 0477326ad Directly construct empty string for invalid SectionInfo f04c93462 Small refactoring in AssertionResult 1af351cea Remove unused TrackerContext::endRun function dcc9fa3f3 Use StringRef UDL for more string literals when expanding macros bf6a15a69 Rewrite -# docs 6135a78c3 Don't insert the foo part of [.foo] tag twice when parsing test spec e8ba329b6 Add support for iterator+sentinel pairs in Contains matcher 4aa88299a Preconstruct error message in RunContext::handleIncomplete 4ff9be3bc cmake-integration.md: Use "tests" as test target name in all examples. 76cdaa3b5 Merge pull request #2637 from jbadwaik/nvhpc_unused_warning 644294df6 Suppress declared_but_not_referenced warning for NVHPC cefa8fcf3 Enable use of UnorderedRangeEquals with iterator+sentinel pairs 772fa3f79 Add Catch::Detail::is_permutation that supports sentinels f3c0a3cd0 Fix RangeEquals matcher to handle iterator + sentinel ranges 42d9d4533 Add test for empty result of filter generator 618d44c44 Update docs about thread safe assertions 388f7e173 Cleanup unneeded allocations from reporters 2ab20a0e0 v3.3.1 60264b880 Avoid copying strings in sonarqube when sorting tests by file 65ffee518 Don't take ownership of SECTION's name for inactive sections 43f02027e Avoid allocations when looking for trackers 906552f8c Clean up extraneous copies in Messages 356dfc143 Move name and sample analysis in benchmarks into BenchmarkStats e5d1eb757 Move AssertionResultData into AssertionResult in RunContext 2403f5620 Move SectionEndInfo into sectionEnded call in SECTION's destructor d58491c85 Move sectionInfo into sectionEndInfo when SECTION ends c837cb4a8 v3.3.0 8359a6b24 Stop exceptions in generator constructors from aborting the binary adf43494e Add missing version information to matchers.md efca9a0f1 Added ElementsAre and UnorderedElementsAre (#2377) dd36f83b8 Merge pull request #2630 from ChrisThrasher/export_all_symbols baab9e8d2 Export symbols for all compilers on Windows 2d3c9713a Remove VS2015 workaround from Detail::generate 956f915e3 Document template macros are in spearate header aa8da505e Fix compatibility with previous CUDA versions e27bb7198 Fix macro-redefinition issue with MSVC+CUDA 3486f8ed9 Update generator docs b5be64204 catch_debugger.hpp: restore PPC support (#2619) d59572f46 Reword the SKIP docs a bit 16f48f8c7 Add SUCCEED and FAIL docs next to SKIP docs 367c2cb24 Update doc about what counts as unique test case d548be26e Add new SKIP macro for skipping tests at runtime (#2360) 52066dbc2 Fix build with GCC 13 (add missing include) cdf604f30 Update command-line.md 04382af4c Slightly better clang-format ac93f1943 Improved path normalization in approvalTests.py 72b60dfd2 Cleanup the Windows GHA builds 0c62167fe Merge pull request #2604 from ChrisThrasher/generated_includes_directory 1be954ff7 Keep generated headers within project binary directory 78bb4fda0 Mention that the benchmarks are not run by default next to example e6ec1c238 Fix benchmarking example in the main readme 477c1f515 Fixed typo in code example in top level README.md f8b9f7725 Prune Appveyor builds 77fbacb03 Add VS 2019-2022 C+14/17 jobs to GHA e3fc97dff fix compiler warning in parseUint and catch only relevant exceptions (#2572) 9c0533a90 Add MessageMatches matcher for exception (#2570) ed02710b8 Make AutoReg in test registration macros const 8b84438be Avoid usage of master when possible git-subtree-dir: externals/catch git-subtree-split: 53d0d913a422d356b23dd927547febdf69ee9081 --- .clang-format | 41 +- .github/workflows/linux-bazel-builds.yml | 2 +- .github/workflows/linux-meson-builds.yml | 6 +- .github/workflows/linux-other-builds.yml | 14 +- .github/workflows/linux-simple-builds.yml | 6 +- .github/workflows/mac-builds.yml | 7 +- .github/workflows/validate-header-guards.yml | 2 +- .github/workflows/windows-simple-builds.yml | 37 + BUILD.bazel | 3 + CMake/CatchConfigOptions.cmake | 12 +- CMake/CatchMiscFunctions.cmake | 4 +- CMakeLists.txt | 5 +- CMakePresets.json | 3 +- Doxyfile | 2 +- README.md | 20 +- WORKSPACE.bazel | 7 +- appveyor.yml | 57 - docs/Readme.md | 1 + docs/benchmarks.md | 2 +- docs/ci-and-misc.md | 2 +- docs/cmake-integration.md | 27 +- docs/command-line.md | 128 +- docs/configuration.md | 29 +- docs/contributing.md | 23 +- docs/deprecations.md | 9 + docs/faq.md | 27 +- docs/generators.md | 51 +- docs/limitations.md | 16 +- docs/matchers.md | 62 +- docs/opensource-users.md | 11 +- docs/release-notes.md | 139 +- docs/reporter-events.md | 12 +- docs/reporters.md | 2 +- docs/skipping-passing-failing.md | 135 + docs/test-cases-and-sections.md | 18 +- docs/tostring.md | 2 +- docs/tutorial.md | 9 +- docs/why-catch.md | 6 +- examples/010-TestCase.cpp | 8 + examples/020-TestCase-1.cpp | 8 + examples/020-TestCase-2.cpp | 8 + examples/030-Asn-Require-Check.cpp | 8 + examples/100-Fix-Section.cpp | 8 + examples/110-Fix-ClassFixture.cpp | 8 + examples/120-Bdd-ScenarioGivenWhenThen.cpp | 8 + examples/210-Evt-EventListeners.cpp | 8 + examples/231-Cfg-OutputStreams.cpp | 8 + examples/300-Gen-OwnGenerator.cpp | 8 + examples/301-Gen-MapTypeConversion.cpp | 8 + examples/302-Gen-Table.cpp | 12 +- examples/310-Gen-VariablesInGenerators.cpp | 8 + examples/311-Gen-CustomCapture.cpp | 8 + extras/Catch.cmake | 162 +- extras/CatchAddTests.cmake | 298 +- extras/CatchShardTests.cmake | 10 +- extras/catch_amalgamated.cpp | 2377 ++++++--- extras/catch_amalgamated.hpp | 4340 +++++++++++------ fuzzing/NullOStream.cpp | 8 + fuzzing/NullOStream.h | 8 + fuzzing/fuzz_TestSpecParser.cpp | 8 +- fuzzing/fuzz_XmlWriter.cpp | 8 +- fuzzing/fuzz_textflow.cpp | 8 +- meson.build | 8 +- meson_options.txt | 1 + src/CMakeLists.txt | 43 +- src/catch2/benchmark/catch_benchmark.hpp | 32 +- src/catch2/benchmark/catch_benchmark_all.hpp | 2 + src/catch2/benchmark/catch_chronometer.hpp | 6 +- src/catch2/benchmark/catch_clock.hpp | 16 +- src/catch2/benchmark/catch_environment.hpp | 14 +- src/catch2/benchmark/catch_estimate.hpp | 13 +- src/catch2/benchmark/catch_execution_plan.hpp | 38 +- src/catch2/benchmark/catch_optimizer.hpp | 13 +- .../benchmark/catch_sample_analysis.hpp | 26 +- src/catch2/benchmark/detail/catch_analyse.cpp | 85 + src/catch2/benchmark/detail/catch_analyse.hpp | 59 +- .../detail/catch_benchmark_function.hpp | 1 - .../detail/catch_benchmark_stats.hpp | 48 + .../detail/catch_benchmark_stats_fwd.hpp | 23 + .../detail/catch_complete_invoke.hpp | 5 - .../benchmark/detail/catch_estimate_clock.hpp | 64 +- src/catch2/benchmark/detail/catch_measure.hpp | 3 +- .../detail/catch_run_for_at_least.cpp | 3 +- .../detail/catch_run_for_at_least.hpp | 8 +- src/catch2/benchmark/detail/catch_stats.cpp | 448 +- src/catch2/benchmark/detail/catch_stats.hpp | 120 +- src/catch2/benchmark/detail/catch_timing.hpp | 8 +- src/catch2/catch_all.hpp | 10 + src/catch2/catch_approx.cpp | 4 +- src/catch2/catch_assertion_result.cpp | 22 +- src/catch2/catch_assertion_result.hpp | 2 +- src/catch2/catch_config.cpp | 2 +- src/catch2/catch_message.cpp | 10 +- src/catch2/catch_message.hpp | 26 +- src/catch2/catch_registry_hub.cpp | 5 +- src/catch2/catch_session.cpp | 11 +- src/catch2/catch_test_case_info.cpp | 24 +- src/catch2/catch_test_case_info.hpp | 1 + src/catch2/catch_test_macros.hpp | 4 + src/catch2/catch_test_spec.cpp | 20 +- src/catch2/catch_tostring.hpp | 7 +- src/catch2/catch_totals.cpp | 8 +- src/catch2/catch_totals.hpp | 1 + src/catch2/catch_translate_exception.cpp | 20 + src/catch2/catch_translate_exception.hpp | 10 +- src/catch2/catch_user_config.hpp.in | 12 +- src/catch2/catch_version.cpp | 2 +- src/catch2/catch_version_macros.hpp | 4 +- src/catch2/generators/catch_generators.cpp | 9 +- src/catch2/generators/catch_generators.hpp | 35 +- .../generators/catch_generators_random.cpp | 32 +- .../generators/catch_generators_random.hpp | 34 +- .../generators/catch_generators_range.hpp | 9 +- .../interfaces/catch_interfaces_all.hpp | 2 +- .../interfaces/catch_interfaces_capture.hpp | 32 +- .../interfaces/catch_interfaces_exception.hpp | 1 - .../catch_interfaces_registry_hub.hpp | 4 +- .../interfaces/catch_interfaces_reporter.cpp | 19 +- .../interfaces/catch_interfaces_reporter.hpp | 64 +- .../catch_interfaces_reporter_registry.hpp | 42 - .../catch_interfaces_test_invoker.hpp | 21 + .../interfaces/catch_interfaces_testcase.cpp | 1 - .../interfaces/catch_interfaces_testcase.hpp | 13 - .../internal/catch_assertion_handler.cpp | 13 +- .../internal/catch_assertion_handler.hpp | 5 +- src/catch2/internal/catch_commandline.cpp | 4 +- .../internal/catch_compiler_capabilities.hpp | 56 +- src/catch2/internal/catch_config_counter.hpp | 2 + .../internal/catch_config_prefix_messages.hpp | 29 + .../catch_config_static_analysis_support.hpp | 34 + .../catch_config_uncaught_exceptions.hpp | 2 + src/catch2/internal/catch_config_wchar.hpp | 2 + src/catch2/internal/catch_console_colour.cpp | 6 +- src/catch2/internal/catch_console_colour.hpp | 1 + src/catch2/internal/catch_context.cpp | 52 +- src/catch2/internal/catch_context.hpp | 47 +- src/catch2/internal/catch_debugger.hpp | 5 +- .../internal/catch_enum_values_registry.cpp | 2 +- .../catch_exception_translator_registry.cpp | 37 +- .../catch_exception_translator_registry.hpp | 1 - .../internal/catch_floating_point_helpers.cpp | 11 + .../internal/catch_floating_point_helpers.hpp | 5 + src/catch2/internal/catch_is_permutation.hpp | 138 + src/catch2/internal/catch_istream.cpp | 8 +- src/catch2/internal/catch_jsonwriter.cpp | 148 + src/catch2/internal/catch_jsonwriter.hpp | 120 + src/catch2/internal/catch_leak_detector.cpp | 2 +- src/catch2/internal/catch_list.cpp | 6 +- src/catch2/internal/catch_message_info.hpp | 2 +- src/catch2/internal/catch_optional.hpp | 53 +- src/catch2/internal/catch_parse_numbers.cpp | 15 +- src/catch2/internal/catch_polyfills.cpp | 8 + src/catch2/internal/catch_polyfills.hpp | 5 + .../catch_preprocessor_internal_stringify.hpp | 19 + .../catch_random_floating_point_helpers.hpp | 94 + .../internal/catch_random_integer_helpers.hpp | 202 + .../internal/catch_random_seed_generation.cpp | 9 +- .../internal/catch_reporter_registry.cpp | 86 +- .../internal/catch_reporter_registry.hpp | 45 +- .../internal/catch_reporter_spec_parser.cpp | 6 +- src/catch2/internal/catch_result_type.hpp | 2 + src/catch2/internal/catch_run_context.cpp | 411 +- src/catch2/internal/catch_run_context.hpp | 33 +- src/catch2/internal/catch_section.cpp | 30 +- src/catch2/internal/catch_section.hpp | 70 +- src/catch2/internal/catch_stream_end_stop.hpp | 4 +- src/catch2/internal/catch_string_manip.cpp | 7 +- src/catch2/internal/catch_string_manip.hpp | 1 + src/catch2/internal/catch_stringref.cpp | 4 - src/catch2/internal/catch_stringref.hpp | 7 +- .../internal/catch_tag_alias_registry.cpp | 2 +- .../internal/catch_template_test_registry.hpp | 4 +- .../catch_test_case_registry_impl.cpp | 63 +- .../catch_test_case_registry_impl.hpp | 21 +- .../internal/catch_test_case_tracker.cpp | 75 +- .../internal/catch_test_case_tracker.hpp | 79 +- .../internal/catch_test_failure_exception.cpp | 8 + .../internal/catch_test_failure_exception.hpp | 9 + src/catch2/internal/catch_test_macro_impl.hpp | 12 +- src/catch2/internal/catch_test_registry.cpp | 16 +- src/catch2/internal/catch_test_registry.hpp | 71 +- src/catch2/internal/catch_test_run_info.hpp | 22 + .../internal/catch_test_spec_parser.cpp | 2 - src/catch2/internal/catch_textflow.hpp | 2 +- ...ch_uniform_floating_point_distribution.hpp | 131 + .../catch_uniform_integer_distribution.hpp | 126 + src/catch2/internal/catch_xmlwriter.cpp | 1 + src/catch2/matchers/catch_matchers_all.hpp | 1 + .../matchers/catch_matchers_contains.hpp | 14 +- .../matchers/catch_matchers_exception.hpp | 26 + .../catch_matchers_floating_point.cpp | 29 +- .../catch_matchers_floating_point.hpp | 30 +- .../matchers/catch_matchers_range_equals.hpp | 144 + src/catch2/matchers/catch_matchers_vector.hpp | 9 +- .../matchers/internal/catch_matchers_impl.hpp | 7 +- src/catch2/meson.build | 20 +- .../reporters/catch_reporter_automake.cpp | 6 +- .../reporters/catch_reporter_automake.hpp | 1 - .../reporters/catch_reporter_compact.cpp | 13 +- .../reporters/catch_reporter_console.cpp | 106 +- .../catch_reporter_cumulative_base.cpp | 3 +- .../catch_reporter_cumulative_base.hpp | 3 +- .../reporters/catch_reporter_helpers.cpp | 9 +- src/catch2/reporters/catch_reporter_json.cpp | 372 ++ src/catch2/reporters/catch_reporter_json.hpp | 95 + src/catch2/reporters/catch_reporter_junit.cpp | 18 +- src/catch2/reporters/catch_reporter_multi.cpp | 1 - .../reporters/catch_reporter_registrars.cpp | 6 + .../reporters/catch_reporter_registrars.hpp | 9 +- .../reporters/catch_reporter_sonarqube.cpp | 21 +- .../reporters/catch_reporter_sonarqube.hpp | 2 +- .../catch_reporter_streaming_base.hpp | 1 - src/catch2/reporters/catch_reporter_tap.cpp | 11 +- .../reporters/catch_reporter_teamcity.cpp | 24 +- src/catch2/reporters/catch_reporter_xml.cpp | 67 +- src/catch2/reporters/catch_reporters_all.hpp | 1 + tests/CMakeLists.txt | 27 +- tests/ExtraTests/CMakeLists.txt | 28 + ...ingEventGoesBeforeAssertionIsEvaluated.cpp | 77 + .../ExtraTests/X93-AllSkipped.cpp | 9 +- .../Baselines/automake.sw.approved.txt | 28 +- .../Baselines/automake.sw.multi.approved.txt | 25 +- .../Baselines/compact.sw.approved.txt | 238 +- .../Baselines/compact.sw.multi.approved.txt | 235 +- .../Baselines/console.std.approved.txt | 198 +- .../Baselines/console.sw.approved.txt | 1273 ++++- .../Baselines/console.sw.multi.approved.txt | 1270 ++++- .../Baselines/console.swa4.approved.txt | 14 +- .../Baselines/default.sw.multi.approved.txt | 3 + .../SelfTest/Baselines/junit.sw.approved.txt | 529 +- .../Baselines/junit.sw.multi.approved.txt | 529 +- .../Baselines/sonarqube.sw.approved.txt | 518 +- .../Baselines/sonarqube.sw.multi.approved.txt | 518 +- tests/SelfTest/Baselines/tap.sw.approved.txt | 235 +- .../Baselines/tap.sw.multi.approved.txt | 232 +- .../Baselines/teamcity.sw.approved.txt | 382 +- .../Baselines/teamcity.sw.multi.approved.txt | 382 +- tests/SelfTest/Baselines/xml.sw.approved.txt | 3838 ++++++++++----- .../Baselines/xml.sw.multi.approved.txt | 3838 ++++++++++----- .../IntrospectiveTests/Algorithms.tests.cpp | 94 + .../AssertionHandler.tests.cpp | 17 + .../IntrospectiveTests/Details.tests.cpp | 41 + .../FloatingPoint.tests.cpp | 59 + .../GeneratorsImpl.tests.cpp | 40 + .../IntrospectiveTests/Integer.tests.cpp | 150 + .../InternalBenchmark.tests.cpp | 58 +- .../IntrospectiveTests/Json.tests.cpp | 152 + .../IntrospectiveTests/PartTracker.tests.cpp | 4 +- .../RandomNumberGeneration.tests.cpp | 528 ++ .../IntrospectiveTests/Reporters.tests.cpp | 9 +- .../IntrospectiveTests/String.tests.cpp | 2 +- .../SelfTest/IntrospectiveTests/Tag.tests.cpp | 19 +- tests/SelfTest/UsageTests/Exception.tests.cpp | 2 +- .../SelfTest/UsageTests/Generators.tests.cpp | 47 +- tests/SelfTest/UsageTests/Matchers.tests.cpp | 44 +- .../UsageTests/MatchersRanges.tests.cpp | 501 +- tests/SelfTest/UsageTests/Message.tests.cpp | 31 +- tests/SelfTest/UsageTests/Misc.tests.cpp | 12 + tests/SelfTest/UsageTests/Skip.tests.cpp | 100 + .../UsageTests/ToStringOptional.tests.cpp | 4 + tests/SelfTest/helpers/range_test_helpers.hpp | 210 + .../TestScripts/DiscoverTests/CMakeLists.txt | 16 + .../DiscoverTests/VerifyRegistration.py | 123 + .../DiscoverTests/register-tests.cpp | 16 + tests/meson.build | 2 + tools/scripts/approvalTests.py | 23 +- tools/scripts/buildAndTest.cmd | 2 +- tools/scripts/buildAndTest.sh | 2 +- tools/scripts/checkLicense.py | 3 +- tools/scripts/generateAmalgamatedFiles.py | 10 + tools/scripts/releaseCommon.py | 4 +- tools/scripts/updateDocumentToC.py | 2 +- 272 files changed, 22238 insertions(+), 7949 deletions(-) create mode 100644 .github/workflows/windows-simple-builds.yml create mode 100644 docs/skipping-passing-failing.md create mode 100644 meson_options.txt create mode 100644 src/catch2/benchmark/detail/catch_analyse.cpp create mode 100644 src/catch2/benchmark/detail/catch_benchmark_stats.hpp create mode 100644 src/catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp create mode 100644 src/catch2/catch_translate_exception.cpp delete mode 100644 src/catch2/interfaces/catch_interfaces_reporter_registry.hpp create mode 100644 src/catch2/interfaces/catch_interfaces_test_invoker.hpp create mode 100644 src/catch2/internal/catch_config_prefix_messages.hpp create mode 100644 src/catch2/internal/catch_config_static_analysis_support.hpp create mode 100644 src/catch2/internal/catch_is_permutation.hpp create mode 100644 src/catch2/internal/catch_jsonwriter.cpp create mode 100644 src/catch2/internal/catch_jsonwriter.hpp create mode 100644 src/catch2/internal/catch_preprocessor_internal_stringify.hpp create mode 100644 src/catch2/internal/catch_random_floating_point_helpers.hpp create mode 100644 src/catch2/internal/catch_random_integer_helpers.hpp create mode 100644 src/catch2/internal/catch_test_run_info.hpp create mode 100644 src/catch2/internal/catch_uniform_floating_point_distribution.hpp create mode 100644 src/catch2/internal/catch_uniform_integer_distribution.hpp create mode 100644 src/catch2/matchers/catch_matchers_range_equals.hpp create mode 100644 src/catch2/reporters/catch_reporter_json.cpp create mode 100644 src/catch2/reporters/catch_reporter_json.hpp create mode 100644 tests/ExtraTests/X20-AssertionStartingEventGoesBeforeAssertionIsEvaluated.cpp rename src/catch2/interfaces/catch_interfaces_reporter_registry.cpp => tests/ExtraTests/X93-AllSkipped.cpp (51%) create mode 100644 tests/SelfTest/IntrospectiveTests/Algorithms.tests.cpp create mode 100644 tests/SelfTest/IntrospectiveTests/AssertionHandler.tests.cpp create mode 100644 tests/SelfTest/IntrospectiveTests/Integer.tests.cpp create mode 100644 tests/SelfTest/IntrospectiveTests/Json.tests.cpp create mode 100644 tests/SelfTest/UsageTests/Skip.tests.cpp create mode 100644 tests/SelfTest/helpers/range_test_helpers.hpp create mode 100644 tests/TestScripts/DiscoverTests/CMakeLists.txt create mode 100644 tests/TestScripts/DiscoverTests/VerifyRegistration.py create mode 100644 tests/TestScripts/DiscoverTests/register-tests.cpp diff --git a/.clang-format b/.clang-format index f67a5862..9efb854d 100644 --- a/.clang-format +++ b/.clang-format @@ -4,41 +4,42 @@ Standard: c++14 # Note that we cannot use IncludeIsMainRegex functionality, because it # does not support includes in angle brackets (<>) -SortIncludes: True +SortIncludes: true IncludeBlocks: Regroup IncludeCategories: - - Regex: '' + - Regex: Priority: 1 - - Regex: '<.*/.*\.hpp>' + - Regex: <.*/.*\.hpp> Priority: 2 - - Regex: '<.*>' + - Regex: <.*> Priority: 3 - AllowShortBlocksOnASingleLine: Always AllowShortEnumsOnASingleLine: false AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: WithoutElse AllowShortLambdasOnASingleLine: Inline -AccessModifierOffset: '-4' +AccessModifierOffset: "-4" AlignEscapedNewlines: Left -AllowAllConstructorInitializersOnNextLine: 'true' -BinPackArguments: 'false' -BinPackParameters: 'false' +AllowAllConstructorInitializersOnNextLine: "true" +BinPackArguments: "false" +BinPackParameters: "false" BreakConstructorInitializers: AfterColon -ConstructorInitializerAllOnOneLineOrOnePerLine: 'true' -DerivePointerAlignment: 'false' -FixNamespaceComments: 'true' -IndentCaseLabels: 'false' +ConstructorInitializerAllOnOneLineOrOnePerLine: "true" +DerivePointerAlignment: "false" +FixNamespaceComments: "true" +IndentCaseLabels: "false" IndentPPDirectives: AfterHash -IndentWidth: '4' +IndentWidth: "4" NamespaceIndentation: All PointerAlignment: Left -SpaceBeforeCtorInitializerColon: 'false' -SpaceInEmptyParentheses: 'false' -SpacesInParentheses: 'true' -TabWidth: '4' +SpaceBeforeCtorInitializerColon: "false" +SpaceInEmptyParentheses: "false" +SpacesInParentheses: "true" +TabWidth: "4" UseTab: Never - -... +AlwaysBreakTemplateDeclarations: Yes +SpaceAfterTemplateKeyword: true +SortUsingDeclarations: true +ReflowComments: true diff --git a/.github/workflows/linux-bazel-builds.yml b/.github/workflows/linux-bazel-builds.yml index 9006652e..dc826ac0 100644 --- a/.github/workflows/linux-bazel-builds.yml +++ b/.github/workflows/linux-bazel-builds.yml @@ -11,7 +11,7 @@ jobs: compilation_mode: [fastbuild, dbg, opt] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Mount bazel cache uses: actions/cache@v3 diff --git a/.github/workflows/linux-meson-builds.yml b/.github/workflows/linux-meson-builds.yml index dec701b6..4ffa0243 100644 --- a/.github/workflows/linux-meson-builds.yml +++ b/.github/workflows/linux-meson-builds.yml @@ -18,10 +18,12 @@ jobs: other_pkgs: clang-11 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Prepare environment - run: sudo apt-get install -y meson ninja-build ${{matrix.other_pkgs}} + run: | + sudo apt-get update + sudo apt-get install -y meson ninja-build ${{matrix.other_pkgs}} - name: Configure build env: diff --git a/.github/workflows/linux-other-builds.yml b/.github/workflows/linux-other-builds.yml index cf4e2c06..4a7f5ecc 100644 --- a/.github/workflows/linux-other-builds.yml +++ b/.github/workflows/linux-other-builds.yml @@ -29,13 +29,13 @@ jobs: build_type: Debug std: 14 other_pkgs: g++-7 - cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON + cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_CMAKE_HELPER_TESTS=ON - cxx: g++-7 build_description: Extras + Examples build_type: Release std: 14 other_pkgs: g++-7 - cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON + cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_CMAKE_HELPER_TESTS=ON # Extras and examples with Clang-10 - cxx: clang++-10 @@ -43,13 +43,13 @@ jobs: build_type: Debug std: 17 other_pkgs: clang-10 - cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON + cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_CMAKE_HELPER_TESTS=ON - cxx: clang++-10 build_description: Extras + Examples build_type: Release std: 17 other_pkgs: clang-10 - cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON + cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_CMAKE_HELPER_TESTS=ON # Configure tests with Clang-10 - cxx: clang++-10 @@ -70,10 +70,12 @@ jobs: steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Prepare environment - run: sudo apt-get install -y ninja-build ${{matrix.other_pkgs}} + run: | + sudo apt-get update + sudo apt-get install -y ninja-build ${{matrix.other_pkgs}} - name: Configure build working-directory: ${{runner.workspace}} diff --git a/.github/workflows/linux-simple-builds.yml b/.github/workflows/linux-simple-builds.yml index 989c4942..a32eb597 100644 --- a/.github/workflows/linux-simple-builds.yml +++ b/.github/workflows/linux-simple-builds.yml @@ -83,7 +83,7 @@ jobs: other_pkgs: g++-10 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Add repositories for older GCC run: | @@ -92,7 +92,9 @@ jobs: if: ${{ matrix.cxx == 'g++-5' || matrix.cxx == 'g++-6' }} - name: Prepare environment - run: sudo apt-get install -y ninja-build ${{matrix.other_pkgs}} + run: | + sudo apt-get update + sudo apt-get install -y ninja-build ${{matrix.other_pkgs}} - name: Configure build working-directory: ${{runner.workspace}} diff --git a/.github/workflows/mac-builds.yml b/.github/workflows/mac-builds.yml index 955b81fc..259d8b36 100644 --- a/.github/workflows/mac-builds.yml +++ b/.github/workflows/mac-builds.yml @@ -22,7 +22,7 @@ jobs: extra_tests: ON steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Configure build working-directory: ${{runner.workspace}} @@ -42,11 +42,10 @@ jobs: - name: Build tests + lib working-directory: ${{runner.workspace}}/build - run: make -j 2 + run: make -j `sysctl -n hw.ncpu` - name: Run tests env: CTEST_OUTPUT_ON_FAILURE: 1 working-directory: ${{runner.workspace}}/build - # Hardcode 2 cores we know are there - run: ctest -C ${{matrix.build_type}} -j 2 + run: ctest -C ${{matrix.build_type}} -j `sysctl -n hw.ncpu` diff --git a/.github/workflows/validate-header-guards.yml b/.github/workflows/validate-header-guards.yml index c02b5d49..fa9d1574 100644 --- a/.github/workflows/validate-header-guards.yml +++ b/.github/workflows/validate-header-guards.yml @@ -9,7 +9,7 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Dependencies uses: actions/setup-python@v2 diff --git a/.github/workflows/windows-simple-builds.yml b/.github/workflows/windows-simple-builds.yml new file mode 100644 index 00000000..5fb7b8fe --- /dev/null +++ b/.github/workflows/windows-simple-builds.yml @@ -0,0 +1,37 @@ +name: Windows builds (basic) + +on: [push, pull_request] + +jobs: + build: + name: ${{matrix.os}}, ${{matrix.std}}, ${{matrix.build_type}}, ${{matrix.platform}} + runs-on: ${{matrix.os}} + strategy: + matrix: + os: [windows-2019, windows-2022] + platform: [Win32, x64] + build_type: [Debug, Release] + std: [14, 17] + steps: + - uses: actions/checkout@v4 + + - name: Configure build + working-directory: ${{runner.workspace}} + run: | + cmake -S $Env:GITHUB_WORKSPACE ` + -B ${{runner.workspace}}/build ` + -DCMAKE_CXX_STANDARD=${{matrix.std}} ` + -A ${{matrix.platform}} ` + --preset all-tests + + - name: Build tests + working-directory: ${{runner.workspace}} + run: cmake --build build --config ${{matrix.build_type}} --parallel %NUMBER_OF_PROCESSORS% + shell: cmd + + - name: Run tests + working-directory: ${{runner.workspace}}/build + env: + CTEST_OUTPUT_ON_FAILURE: 1 + run: ctest -C ${{matrix.build_type}} -j %NUMBER_OF_PROCESSORS% + shell: cmd diff --git a/BUILD.bazel b/BUILD.bazel index 3125e7c5..c51bf57e 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -43,12 +43,15 @@ expand_template( "#cmakedefine CATCH_CONFIG_NO_GLOBAL_NEXTAFTER": "", "#cmakedefine CATCH_CONFIG_NO_POSIX_SIGNALS": "", "#cmakedefine CATCH_CONFIG_NO_USE_ASYNC": "", + "#cmakedefine CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT": "", "#cmakedefine CATCH_CONFIG_NO_WCHAR": "", "#cmakedefine CATCH_CONFIG_NO_WINDOWS_SEH": "", "#cmakedefine CATCH_CONFIG_NOSTDOUT": "", "#cmakedefine CATCH_CONFIG_POSIX_SIGNALS": "", "#cmakedefine CATCH_CONFIG_PREFIX_ALL": "", + "#cmakedefine CATCH_CONFIG_PREFIX_MESSAGES": "", "#cmakedefine CATCH_CONFIG_SHARED_LIBRARY": "", + "#cmakedefine CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT": "", "#cmakedefine CATCH_CONFIG_USE_ASYNC": "", "#cmakedefine CATCH_CONFIG_WCHAR": "", "#cmakedefine CATCH_CONFIG_WINDOWS_CRTDBG": "", diff --git a/CMake/CatchConfigOptions.cmake b/CMake/CatchConfigOptions.cmake index 733ec65e..6eae220d 100644 --- a/CMake/CatchConfigOptions.cmake +++ b/CMake/CatchConfigOptions.cmake @@ -18,10 +18,12 @@ macro(AddOverridableConfigOption OptionBaseName) option(CATCH_CONFIG_${OptionBaseName} "Read docs/configuration.md for details" OFF) option(CATCH_CONFIG_NO_${OptionBaseName} "Read docs/configuration.md for details" OFF) + mark_as_advanced(CATCH_CONFIG_${OptionBaseName} CATCH_CONFIG_NO_${OptionBaseName}) endmacro() macro(AddConfigOption OptionBaseName) option(CATCH_CONFIG_${OptionBaseName} "Read docs/configuration.md for details" OFF) + mark_as_advanced(CATCH_CONFIG_${OptionBaseName}) endmacro() set(_OverridableOptions @@ -41,6 +43,7 @@ set(_OverridableOptions "WCHAR" "WINDOWS_SEH" "GETENV" + "EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT" ) foreach(OptionName ${_OverridableOptions}) @@ -61,6 +64,7 @@ set(_OtherConfigOptions "FAST_COMPILE" "NOSTDOUT" "PREFIX_ALL" + "PREFIX_MESSAGES" "WINDOWS_CRTDBG" ) @@ -68,11 +72,17 @@ set(_OtherConfigOptions foreach(OptionName ${_OtherConfigOptions}) AddConfigOption(${OptionName}) endforeach() -set(CATCH_CONFIG_SHARED_LIBRARY ${BUILD_SHARED_LIBS}) +if(DEFINED BUILD_SHARED_LIBS) + set(CATCH_CONFIG_SHARED_LIBRARY ${BUILD_SHARED_LIBS}) +else() + set(CATCH_CONFIG_SHARED_LIBRARY "") +endif() set(CATCH_CONFIG_DEFAULT_REPORTER "console" CACHE STRING "Read docs/configuration.md for details. The name of the reporter should be without quotes.") set(CATCH_CONFIG_CONSOLE_WIDTH "80" CACHE STRING "Read docs/configuration.md for details. Must form a valid integer literal.") +mark_as_advanced(CATCH_CONFIG_SHARED_LIBRARY CATCH_CONFIG_DEFAULT_REPORTER CATCH_CONFIG_CONSOLE_WIDTH) + # There is no good way to both turn this into a CMake cache variable, # and keep reasonable default semantics inside the project. Thus we do # not define it and users have to provide it as an outside variable. diff --git a/CMake/CatchMiscFunctions.cmake b/CMake/CatchMiscFunctions.cmake index 3758d956..de6b7ae3 100644 --- a/CMake/CatchMiscFunctions.cmake +++ b/CMake/CatchMiscFunctions.cmake @@ -46,7 +46,6 @@ function(add_warnings_to_targets targets) set(CHECKED_WARNING_FLAGS "-Wabsolute-value" "-Wall" - "-Wc++20-compat" "-Wcall-to-pure-virtual-from-ctor-dtor" "-Wcast-align" "-Wcatch-value" @@ -74,6 +73,7 @@ function(add_warnings_to_targets targets) "-Woverloaded-virtual" "-Wparentheses" "-Wpedantic" + "-Wredundant-decls" "-Wreorder" "-Wreturn-std-move" "-Wshadow" @@ -83,7 +83,7 @@ function(add_warnings_to_targets targets) "-Wundef" "-Wuninitialized" "-Wunneeded-internal-declaration" - "-Wunreachable-code" + "-Wunreachable-code-aggressive" "-Wunused" "-Wunused-function" "-Wunused-parameter" diff --git a/CMakeLists.txt b/CMakeLists.txt index d5a6b67a..2cfb6cd1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ cmake_dependent_option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" cmake_dependent_option(CATCH_ENABLE_WERROR "Enables Werror during build" ON "CATCH_DEVELOPMENT_BUILD" OFF) cmake_dependent_option(CATCH_BUILD_SURROGATES "Enable generating and building surrogate TUs for the main headers" OFF "CATCH_DEVELOPMENT_BUILD" OFF) cmake_dependent_option(CATCH_ENABLE_CONFIGURE_TESTS "Enable CMake configuration tests. WARNING: VERY EXPENSIVE" OFF "CATCH_DEVELOPMENT_BUILD" OFF) +cmake_dependent_option(CATCH_ENABLE_CMAKE_HELPER_TESTS "Enable CMake helper tests. WARNING: VERY EXPENSIVE" OFF "CATCH_DEVELOPMENT_BUILD" OFF) # Catch2's build breaks if done in-tree. You probably should not build @@ -31,7 +32,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) endif() project(Catch2 - VERSION 3.2.1 # CML version placeholder, don't delete + VERSION 3.5.0 # CML version placeholder, don't delete LANGUAGES CXX # HOMEPAGE_URL is not supported until CMake version 3.12, which # we do not target yet. @@ -148,6 +149,8 @@ if (NOT_SUBPROJECT) "extras/ParseAndAddCatchTests.cmake" "extras/Catch.cmake" "extras/CatchAddTests.cmake" + "extras/CatchShardTests.cmake" + "extras/CatchShardTestsImpl.cmake" DESTINATION ${CATCH_CMAKE_CONFIG_DESTINATION} ) diff --git a/CMakePresets.json b/CMakePresets.json index 00f3a6d3..88541285 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -18,7 +18,8 @@ "CATCH_BUILD_EXAMPLES": "ON", "CATCH_BUILD_EXTRA_TESTS": "ON", "CATCH_BUILD_SURROGATES": "ON", - "CATCH_ENABLE_CONFIGURE_TESTS": "ON" + "CATCH_ENABLE_CONFIGURE_TESTS": "ON", + "CATCH_ENABLE_CMAKE_HELPER_TESTS": "ON" } } ] diff --git a/Doxyfile b/Doxyfile index 68318416..07b385ec 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1319,7 +1319,7 @@ CHM_FILE = HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. diff --git a/README.md b/README.md index 4bc5b86d..3ea54a5d 100644 --- a/README.md +++ b/README.md @@ -47,24 +47,28 @@ TEST_CASE( "Factorials are computed", "[factorial]" ) { #include uint64_t fibonacci(uint64_t number) { - return number < 2 ? 1 : fibonacci(number - 1) + fibonacci(number - 2); + return number < 2 ? number : fibonacci(number - 1) + fibonacci(number - 2); } TEST_CASE("Benchmark Fibonacci", "[!benchmark]") { - REQUIRE(Fibonacci(5) == 5); + REQUIRE(fibonacci(5) == 5); - REQUIRE(Fibonacci(20) == 6'765); - BENCHMARK("Fibonacci 20") { - return Fibonacci(20); + REQUIRE(fibonacci(20) == 6'765); + BENCHMARK("fibonacci 20") { + return fibonacci(20); }; - REQUIRE(Fibonacci(25) == 75'025); - BENCHMARK("Fibonacci 25") { - return Fibonacci(25); + REQUIRE(fibonacci(25) == 75'025); + BENCHMARK("fibonacci 25") { + return fibonacci(25); }; } ``` +_Note that benchmarks are not run by default, so you need to run it explicitly +with the `[!benchmark]` tag._ + + ## Catch2 v3 has been released! You are on the `devel` branch, where the v3 version is being developed. diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index 6fd2ffa5..a5c6182d 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -4,12 +4,13 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "bazel_skylib", + sha256 = "66ffd9315665bfaafc96b52278f57c7e2dd09f5ede279ea6d39b2be471e7e3aa", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.4.2/bazel-skylib-1.4.2.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.2/bazel-skylib-1.4.2.tar.gz", ], - sha256 = "74d544d96f4a5bb630d465ca8bbcfe231e3594e5aae57e1edbf17a6eb3ca2506", ) load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") + bazel_skylib_workspace() diff --git a/appveyor.yml b/appveyor.yml index a8f77df0..7a0ad83f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -51,18 +51,6 @@ test_script: # build explicitly. environment: matrix: - - FLAVOR: VS 2019 x64 Debug Surrogates Configure Tests - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - surrogates: 1 - configure_tests: 1 - platform: x64 - configuration: Debug - - - FLAVOR: VS 2019 x64 Release - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - platform: x64 - configuration: Release - - FLAVOR: VS 2019 x64 Debug Coverage Examples APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 examples: 1 @@ -77,53 +65,8 @@ environment: platform: x64 configuration: Debug - - FLAVOR: VS 2019 Win32 Debug - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - platform: Win32 - configuration: Debug - - FLAVOR: VS 2019 x64 Debug Latest Strict APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 additional_flags: "/permissive- /std:c++latest" platform: x64 configuration: Debug - - - FLAVOR: VS 2017 x64 Debug - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - platform: x64 - configuration: Debug - - - FLAVOR: VS 2017 x64 Release - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - platform: x64 - configuration: Release - - - FLAVOR: VS 2017 x64 Release Coverage - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - coverage: 1 - platform: x64 - configuration: Debug - - - FLAVOR: VS 2017 Win32 Debug - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - platform: Win32 - configuration: Debug - - - FLAVOR: VS 2017 Win32 Debug Examples - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - examples: 1 - platform: Win32 - configuration: Debug - - - FLAVOR: VS 2017 Win32 Debug WMain - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - wmain: 1 - additional_flags: "/D_UNICODE /DUNICODE" - platform: Win32 - configuration: Debug - - - FLAVOR: VS 2017 x64 Debug Latest Strict - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - additional_flags: "/permissive- /std:c++latest" - platform: x64 - configuration: Debug diff --git a/docs/Readme.md b/docs/Readme.md index 52eb64a5..d84b4bfd 100644 --- a/docs/Readme.md +++ b/docs/Readme.md @@ -11,6 +11,7 @@ Once you're up and running consider the following reference material. * [Logging macros](logging.md#top) * [Test cases and sections](test-cases-and-sections.md#top) * [Test fixtures](test-fixtures.md#top) +* [Explicitly skipping, passing, and failing tests at runtime](skipping-passing-failing.md#top) * [Reporters (output customization)](reporters.md#top) * [Event Listeners](event-listeners.md#top) * [Data Generators (value parameterized tests)](generators.md#top) diff --git a/docs/benchmarks.md b/docs/benchmarks.md index 548913c7..9edbb93c 100644 --- a/docs/benchmarks.md +++ b/docs/benchmarks.md @@ -93,7 +93,7 @@ Fibonacci ------------------------------------------------------------------------------- C:\path\to\Catch2\Benchmark.tests.cpp(10) ............................................................................... -benchmark name samples iterations estimated +benchmark name samples iterations est run time mean low mean high mean std dev low std dev high std dev ------------------------------------------------------------------------------- diff --git a/docs/ci-and-misc.md b/docs/ci-and-misc.md index c07da29f..49bbd989 100644 --- a/docs/ci-and-misc.md +++ b/docs/ci-and-misc.md @@ -82,7 +82,7 @@ variable set to "1". ### CodeCoverage module (GCOV, LCOV...) -If you are using GCOV tool to get testing coverage of your code, and are not sure how to integrate it with CMake and Catch, there should be an external example over at https://github.com/fkromer/catch_cmake_coverage +If you are using GCOV tool to get testing coverage of your code, and are not sure how to integrate it with CMake and Catch, there should be an external example over at https://github.com/claremacrae/catch_cmake_coverage ### pkg-config diff --git a/docs/cmake-integration.md b/docs/cmake-integration.md index dd0f9e26..86666efe 100644 --- a/docs/cmake-integration.md +++ b/docs/cmake-integration.md @@ -51,7 +51,7 @@ Include(FetchContent) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v3.0.1 # or a later release + GIT_TAG v3.4.0 # or a later release ) FetchContent_MakeAvailable(Catch2) @@ -90,12 +90,12 @@ cmake_minimum_required(VERSION 3.5) project(baz LANGUAGES CXX VERSION 0.0.1) find_package(Catch2 REQUIRED) -add_executable(foo test.cpp) -target_link_libraries(foo PRIVATE Catch2::Catch2) +add_executable(tests test.cpp) +target_link_libraries(tests PRIVATE Catch2::Catch2) include(CTest) include(Catch) -catch_discover_tests(foo) +catch_discover_tests(tests) ``` When using `FetchContent`, `include(Catch)` will fail unless @@ -108,7 +108,7 @@ directory. list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras) include(CTest) include(Catch) -catch_discover_tests() +catch_discover_tests(tests) ``` #### Customization @@ -126,6 +126,7 @@ catch_discover_tests(target [OUTPUT_DIR dir] [OUTPUT_PREFIX prefix] [OUTPUT_SUFFIX suffix] + [DISCOVERY_MODE ] ) ``` @@ -198,6 +199,16 @@ If specified, `suffix` is added to each output file name, like so `--out dir/suffix`. This can be used to add a file extension to the output file name e.g. ".xml". +* `DISCOVERY_MODE mode` + +If specified allows control over when test discovery is performed. +For a value of `POST_BUILD` (default) test discovery is performed at build time. +For a value of `PRE_TEST` test discovery is delayed until just prior to test +execution (useful e.g. in cross-compilation environments). +``DISCOVERY_MODE`` defaults to the value of the +``CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE`` variable if it is not passed when +calling ``catch_discover_tests``. This provides a mechanism for globally +selecting a preferred test discovery behavior. ### `ParseAndAddCatchTests.cmake` @@ -222,12 +233,12 @@ cmake_minimum_required(VERSION 3.5) project(baz LANGUAGES CXX VERSION 0.0.1) find_package(Catch2 REQUIRED) -add_executable(foo test.cpp) -target_link_libraries(foo PRIVATE Catch2::Catch2) +add_executable(tests test.cpp) +target_link_libraries(tests PRIVATE Catch2::Catch2) include(CTest) include(ParseAndAddCatchTests) -ParseAndAddCatchTests(foo) +ParseAndAddCatchTests(tests) ``` diff --git a/docs/command-line.md b/docs/command-line.md index 21a0da4c..bb483959 100644 --- a/docs/command-line.md +++ b/docs/command-line.md @@ -85,43 +85,102 @@ Click one of the following links to take you straight to that option - or scroll
<test-spec> ...
-Test cases, wildcarded test cases, tags and tag expressions are all passed directly as arguments. Tags are distinguished by being enclosed in square brackets. +By providing a test spec, you filter which tests will be run. If you call +Catch2 without any test spec, then it will run all non-hidden test +cases. A test case is hidden if it has the `[!benchmark]` tag, any tag +with a dot at the start, e.g. `[.]` or `[.foo]`. -If no test specs are supplied then all test cases, except "hidden" tests, are run. -A test is hidden by giving it any tag starting with (or just) a period (```.```) - or, in the deprecated case, tagged ```[hide]``` or given name starting with `'./'`. To specify hidden tests from the command line ```[.]``` or ```[hide]``` can be used *regardless of how they were declared*. +There are three basic test specs that can then be combined into more +complex specs: -Specs must be enclosed in quotes if they contain spaces. If they do not contain spaces the quotes are optional. + * Full test name, e.g. `"Test 1"`. -Wildcards consist of the `*` character at the beginning and/or end of test case names and can substitute for any number of any characters (including none). + This allows only test cases whose name is "Test 1". -Test specs are case insensitive. + * Wildcarded test name, e.g. `"*Test"`, or `"Test*"`, or `"*Test*"`. -If a spec is prefixed with `exclude:` or the `~` character then the pattern matches an exclusion. This means that tests matching the pattern are excluded from the set - even if a prior inclusion spec included them. Subsequent inclusion specs will take precedence, however. -Inclusions and exclusions are evaluated in left-to-right order. + This allows any test case whose name ends with, starts with, or contains + in the middle the string "Test". Note that the wildcard can only be at + the start or end. -Test case examples: + * Tag name, e.g. `[some-tag]`. + This allows any test case tagged with "[some-tag]". Remember that some + tags are special, e.g. those that start with "." or with "!". + + +You can also combine the basic test specs to create more complex test +specs. You can: + + * Concatenate specs to apply all of them, e.g. `[some-tag][other-tag]`. + + This allows test cases that are tagged with **both** "[some-tag]" **and** + "[other-tag]". A test case with just "[some-tag]" will not pass the filter, + nor will test case with just "[other-tag]". + + * Comma-join specs to apply any of them, e.g. `[some-tag],[other-tag]`. + + This allows test cases that are tagged with **either** "[some-tag]" **or** + "[other-tag]". A test case with both will obviously also pass the filter. + + Note that commas take precendence over simple concatenation. This means + that `[a][b],[c]` accepts tests that are tagged with either both "[a]" and + "[b]", or tests that are tagged with just "[c]". + + * Negate the spec by prepending it with `~`, e.g. `~[some-tag]`. + + This rejects any test case that is tagged with "[some-tag]". Note that + rejection takes precedence over other filters. + + Note that negations always binds to the following _basic_ test spec. + This means that `~[foo][bar]` negates only the "[foo]" tag and not the + "[bar]" tag. + +Note that when Catch2 is deciding whether to include a test, first it +checks whether the test matches any negative filters. If it does, +the test is rejected. After that, the behaviour depends on whether there +are positive filters as well. If there are no positive filters, all +remaining non-hidden tests are included. If there are positive filters, +only tests that match the positive filters are included. + +You can also match test names with special characters by escaping them +with a backslash (`"\"`), e.g. a test named `"Do A, then B"` is matched +by "Do A\, then B" test spec. Backslash also escapes itself. + + +### Examples + +Given these TEST_CASEs, ``` -thisTestOnly Matches the test case called, 'thisTestOnly' -"this test only" Matches the test case called, 'this test only' -these* Matches all cases starting with 'these' -exclude:notThis Matches all tests except, 'notThis' -~notThis Matches all tests except, 'notThis' -~*private* Matches all tests except those that contain 'private' -a* ~ab* abc Matches all tests that start with 'a', except those that - start with 'ab', except 'abc', which is included -~[tag1] Matches all tests except those tagged with '[tag1]' --# [#somefile] Matches all tests from the file 'somefile.cpp' +TEST_CASE("Test 1") {} + +TEST_CASE("Test 2", "[.foo]") {} + +TEST_CASE("Test 3", "[.bar]") {} + +TEST_CASE("Test 4", "[.][foo][bar]") {} ``` -Names within square brackets are interpreted as tags. -A series of tags form an AND expression whereas a comma-separated sequence forms an OR expression. e.g.: +this is the result of these filters +``` +./tests # Selects only the first test, others are hidden +./tests "Test 1" # Selects only the first test, other do not match +./tests ~"Test 1" # Selects no tests. Test 1 is rejected, other tests are hidden +./tests "Test *" # Selects all tests. +./tests [bar] # Selects tests 3 and 4. Other tests are not tagged [bar] +./tests ~[foo] # Selects test 1, because it is the only non-hidden test without [foo] tag +./tests [foo][bar] # Selects test 4. +./tests [foo],[bar] # Selects tests 2, 3, 4. +./tests ~[foo][bar] # Selects test 3. 2 and 4 are rejected due to having [foo] tag +./tests ~"Test 2"[foo] # Selects test 4, because test 2 is explicitly rejected +./tests [foo][bar],"Test 1" # Selects tests 1 and 4. +./tests "Test 1*" # Selects test 1, wildcard can match zero characters +``` -
[one][two],[three]
-This matches all tests tagged `[one]` and `[two]`, as well as all tests tagged `[three]` +_Note: Using plain asterisk on a command line can cause issues with shell +expansion. Make sure that the asterisk is passed to Catch2 and is not +interpreted by the shell._ -Test names containing special characters, such as `,` or `[` can specify them on the command line using `\`. -`\` also escapes itself. ## Choosing a reporter to use @@ -148,7 +207,7 @@ validity, and throw an error if they are wrong._ > Support for passing arguments to reporters through the `-r`, `--reporter` flag was introduced in Catch2 3.0.1 There are multiple built-in reporters, you can see what they do by using the -[`--list-reporter`](command-line.md#listing-available-tests-tags-or-reporters) +[`--list-reporters`](command-line.md#listing-available-tests-tags-or-reporters) flag. If you need a reporter providing custom format outside of the already provided ones, look at the ["write your own reporter" part of the reporter documentation](reporters.md#writing-your-own-reporter). @@ -507,10 +566,13 @@ start of the first section.
## Filenames as tags
-#, --filenames-as-tags
-When this option is used then every test is given an additional tag which is formed of the unqualified -filename it is found in, with any extension stripped, prefixed with the `#` character. +This option adds an extra tag to all test cases. The tag is `#` followed +by the unqualified filename the test case is defined in, with the _last_ +extension stripped out. + +For example, tests within the file `tests\SelfTest\UsageTests\BDD.tests.cpp` +will be given the `[#BDD.tests]` tag. -So, for example, tests within the file `~\Dev\MyProject\Ferrets.cpp` would be tagged `[#Ferrets]`. ## Override output colouring @@ -561,10 +623,10 @@ processes, as is done with the [Bazel test sharding](https://docs.bazel.build/ve > Introduced in Catch2 3.0.1. -By default, Catch2 test binaries return non-0 exit code if no tests were -run, e.g. if the binary was compiled with no tests, or the provided test -spec matched no tests. This flag overrides that, so a test run with no -tests still returns 0. +By default, Catch2 test binaries return non-0 exit code if no tests were run, +e.g. if the binary was compiled with no tests, the provided test spec matched no +tests, or all tests [were skipped at runtime](skipping-passing-failing.md#top). This flag +overrides that, so a test run with no tests still returns 0. ## Output verbosity ``` diff --git a/docs/configuration.md b/docs/configuration.md index d4421f3c..8a3ddfab 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -15,6 +15,7 @@ [Enabling stringification](#enabling-stringification)
[Disabling exceptions](#disabling-exceptions)
[Overriding Catch's debug break (`-b`)](#overriding-catchs-debug-break--b)
+[Static analysis support](#static-analysis-support)
Catch2 is designed to "just work" as much as possible, and most of the configuration options below are changed automatically during compilation, @@ -25,7 +26,8 @@ with the same name. ## Prefixing Catch macros - CATCH_CONFIG_PREFIX_ALL + CATCH_CONFIG_PREFIX_ALL // Prefix all macros with CATCH_ + CATCH_CONFIG_PREFIX_MESSAGES // Prefix only INFO, UNSCOPED_INFO, WARN and CAPTURE To keep test code clean and uncluttered Catch uses short macro names (e.g. ```TEST_CASE``` and ```REQUIRE```). Occasionally these may conflict with identifiers from platform headers or the system under test. In this case the above identifier can be defined. This will cause all the Catch user macros to be prefixed with ```CATCH_``` (e.g. ```CATCH_TEST_CASE``` and ```CATCH_REQUIRE```). @@ -264,6 +266,31 @@ The macro will be used as is, that is, `CATCH_BREAK_INTO_DEBUGGER();` must compile and must break into debugger. +## Static analysis support + +> Introduced in Catch2 3.4.0. + +Some parts of Catch2, e.g. `SECTION`s, can be hard for static analysis +tools to reason about. Catch2 can change its internals to help static +analysis tools reason about the tests. + +Catch2 automatically detects some static analysis tools (initial +implementation checks for clang-tidy and Coverity), but you can override +its detection (in either direction) via + +``` +CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT // force enables static analysis help +CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT // force disables static analysis help +``` + +_As the name suggests, this is currently experimental, and thus we provide +no backwards compatibility guarantees._ + +**DO NOT ENABLE THIS FOR BUILDS YOU INTEND TO RUN.** The changed internals +are not meant to be runnable, only "scannable". + + + --- [Home](Readme.md#top) diff --git a/docs/contributing.md b/docs/contributing.md index a4c9220b..d9f87fc1 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -55,6 +55,15 @@ tests from `SelfTest` through a specific reporter and then compare the generated output with a known good output ("Baseline"). By default, new tests should be placed here. +To configure a Catch2 build with just the basic tests, use the `basic-tests` +preset, like so: + +``` +# Assuming you are in Catch2's root folder + +cmake -B basic-test-build -S . -DCMAKE_BUILD_TYPE=Debug --preset basic-tests +``` + However, not all tests can be written as plain unit tests. For example, checking that Catch2 orders tests randomly when asked to, and that this random ordering is subset-invariant, is better done as an integration @@ -76,21 +85,23 @@ configuration and require separate compilation. Finally, CMake config tests test that you set Catch2's compile-time configuration options through CMake, using CMake options of the same name. -None of these tests are enabled by default. To enable them, add +These test categories can be enabled one by one, by passing `-DCATCH_BUILD_EXAMPLES=ON`, `-DCATCH_BUILD_EXTRA_TESTS=ON`, and -`-DCATCH_ENABLE_CONFIGURE_TESTS=ON` when configuration the CMake build. +`-DCATCH_ENABLE_CONFIGURE_TESTS=ON` when configuring the build. -Bringing this all together, the steps below should configure, build, -and run all tests in the `Debug` compilation. +Catch2 also provides a preset that promises to enable _all_ test types, +`all-tests`. + +The snippet below will build & run all tests, in `Debug` compilation mode. ```sh -# 1. Regenerate the amalgamated distribution +# 1. Regenerate the amalgamated distribution (some tests are built against it) ./tools/scripts/generateAmalgamatedFiles.py # 2. Configure the full test build -cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug -DCATCH_DEVELOPMENT_BUILD=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_BUILD_EXTRA_TESTS=ON +cmake -B debug-build -S . -DCMAKE_BUILD_TYPE=Debug --preset all-tests # 3. Run the actual build cmake --build debug-build diff --git a/docs/deprecations.md b/docs/deprecations.md index 2c9bf551..1fb79aaa 100644 --- a/docs/deprecations.md +++ b/docs/deprecations.md @@ -26,6 +26,15 @@ to accurately probe the environment for this information so the flag where it will export `BAZEL_TEST=1` for purposes like the above. Catch2 will now instead inspect the environment instead of relying on build configuration. +### `IEventLister::skipTest( TestCaseInfo const& testInfo )` + +This event (including implementations in derived classes such as `ReporterBase`) +is deprecated and will be removed in the next major release. It is currently +invoked for all test cases that are not going to be executed due to the test run +being aborted (when using `--abort` or `--abortx`). It is however +**NOT** invoked for test cases that are [explicitly skipped using the `SKIP` +macro](skipping-passing-failing.md#top). + --- [Home](Readme.md#top) diff --git a/docs/faq.md b/docs/faq.md index 0f303ee5..80923d26 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -10,6 +10,7 @@ [Does Catch2 support running tests in parallel?](#does-catch2-support-running-tests-in-parallel)
[Can I compile Catch2 into a dynamic library?](#can-i-compile-catch2-into-a-dynamic-library)
[What repeatability guarantees does Catch2 provide?](#what-repeatability-guarantees-does-catch2-provide)
+[My build cannot find `catch2/catch_user_config.hpp`, how can I fix it?](#my-build-cannot-find-catch2catch_user_confighpp-how-can-i-fix-it)
## How do I run global setup/teardown only if tests will be run? @@ -28,7 +29,7 @@ depending on how often the cleanup needs to happen. ## Why cannot I derive from the built-in reporters? They are not made to be overridden, in that we do not attempt to maintain -a consistent internal state if a member function is overriden, and by +a consistent internal state if a member function is overridden, and by forbidding users from using them as a base class, we can refactor them as needed later. @@ -83,12 +84,30 @@ and it is also generally repeatable across versions, but we might break it from time to time. E.g. we broke repeatability with previous versions in v2.13.4 so that test cases with similar names are shuffled better. -Random generators currently rely on platform's stdlib, specifically -the distributions from ``. We thus provide no extra guarantee -above what your platform does. **Important: ``'s distributions +Since Catch2 3.5.0 the random generators use custom distributions, +that should be repeatable across different platforms, with few caveats. +For details see the section on random generators in the [Generator +documentation](generators.md#random-number-generators-details). + +Before this version, random generators relied on distributions from +platform's stdlib. We thus can provide no extra guarantee on top of the +ones given by your platform. **Important: ``'s distributions are not specified to be repeatable across different platforms.** +## My build cannot find `catch2/catch_user_config.hpp`, how can I fix it? + +`catch2/catch_user_config.hpp` is a generated header that contains user +compile time configuration. It is generated by CMake/Meson/Bazel during +build. If you are not using either of these, your three options are to + +1) Build Catch2 separately using build tool that will generate the header +2) Use the amalgamated files to build Catch2 +3) Use CMake to configure a build. This will generate the header and you + can copy it into your own checkout of Catch2. + + + --- [Home](Readme.md#top) diff --git a/docs/generators.md b/docs/generators.md index 7a865d43..8bca54c7 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -134,7 +134,7 @@ type, making their usage much nicer. These are * `map(func, GeneratorWrapper&&)` for `MapGenerator` (map `U` to `T`) * `chunk(chunk-size, GeneratorWrapper&&)` for `ChunkGenerator` * `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator` -* `range(Arithemtic start, Arithmetic end)` for `RangeGenerator` with a step size of `1` +* `range(Arithmetic start, Arithmetic end)` for `RangeGenerator` with a step size of `1` * `range(Arithmetic start, Arithmetic end, Arithmetic step)` for `RangeGenerator` with a custom step size * `from_range(InputIterator from, InputIterator to)` for `IteratorGenerator` * `from_range(Container const&)` for `IteratorGenerator` @@ -189,6 +189,31 @@ TEST_CASE("type conversion", "[generators]") { } ``` + +### Random number generators: details + +> This section applies from Catch2 3.5.0. Before that, random generators +> were a thin wrapper around distributions from ``. + +All of the `random(a, b)` generators in Catch2 currently generate uniformly +distributed number in closed interval \[a; b\]. This is different from +`std::uniform_real_distribution`, which should return numbers in interval +\[a; b) (but due to rounding can end up returning b anyway), but the +difference is intentional, so that `random(a, a)` makes sense. If there is +enough interest from users, we can provide API to pick any of CC, CO, OC, +or OO ranges. + +Unlike `std::uniform_int_distribution`, Catch2's generators also support +various single-byte integral types, such as `char` or `bool`. + +Given the same seed, the output from the integral generators is +reproducible across different platforms. For floating point generators, +we only promise reproducibility on platforms that obey the IEEE 754 +standard, and where `float` is 4 bytes and `double` is 8 bytes. We provide +no guarantees for `long double`, as the internals of `long double` can +vary wildly across different platforms. + + ## Generator interface You can also implement your own generators, by deriving from the @@ -205,15 +230,37 @@ struct IGenerator : GeneratorUntypedBase { // Precondition: // The generator is either freshly constructed or the last call to next() returned true virtual T const& get() const = 0; + + // Returns user-friendly string showing the current generator element + // Does not have to be overridden, IGenerator provides default implementation + virtual std::string stringifyImpl() const; }; ``` However, to be able to use your custom generator inside `GENERATE`, it will need to be wrapped inside a `GeneratorWrapper`. `GeneratorWrapper` is a value wrapper around a -`std::unique_ptr>`. +`Catch::Detail::unique_ptr>`. For full example of implementing your own generator, look into Catch2's examples, specifically [Generators: Create your own generator](../examples/300-Gen-OwnGenerator.cpp). + +### Handling empty generators + +The generator interface assumes that a generator always has at least one +element. This is not always true, e.g. if the generator depends on an external +datafile, the file might be missing. + +There are two ways to handle this, depending on whether you want this +to be an error or not. + + * If empty generator **is** an error, throw an exception in constructor. + * If empty generator **is not** an error, use the [`SKIP`](skipping-passing-failing.md#skipping-test-cases-at-runtime) in constructor. + + + +--- + +[Home](Readme.md#top) diff --git a/docs/limitations.md b/docs/limitations.md index 80471865..099dd82a 100644 --- a/docs/limitations.md +++ b/docs/limitations.md @@ -88,8 +88,8 @@ because only one thread passes the `REQUIRE` macro and this is not REQUIRE(cnt == 16); ``` -Because C++11 provides the necessary tools to do this, we are planning -to remove this limitation in the future. +We currently do not plan to support thread-safe assertions. + ### Process isolation in a test Catch does not support running tests in isolated (forked) processes. While this might in the future, the fact that Windows does not support forking and only allows full-on process creation and the desire to keep code as similar as possible across platforms, mean that this is likely to take significant development time, that is not currently available. @@ -155,7 +155,7 @@ with expansion: ### Clang/G++ -- skipping leaf sections after an exception -Some versions of `libc++` and `libstdc++` (or their runtimes) have a bug with `std::uncaught_exception()` getting stuck returning `true` after rethrow, even if there are no active exceptions. One such case is this snippet, which skipped the sections "a" and "b", when compiled against `libcxxrt` from master +Some versions of `libc++` and `libstdc++` (or their runtimes) have a bug with `std::uncaught_exception()` getting stuck returning `true` after rethrow, even if there are no active exceptions. One such case is this snippet, which skipped the sections "a" and "b", when compiled against `libcxxrt` from the master branch ```cpp #include @@ -173,13 +173,3 @@ TEST_CASE("b") { If you are seeing a problem like this, i.e. weird test paths that trigger only under Clang with `libc++`, or only under very specific version of `libstdc++`, it is very likely you are seeing this. The only known workaround is to use a fixed version of your standard library. - -### libstdc++, `_GLIBCXX_DEBUG` macro and random ordering of tests - -Running a Catch2 binary compiled against libstdc++ with `_GLIBCXX_DEBUG` -macro defined with `--order rand` will cause a debug check to trigger and -abort the run due to self-assignment. -[This is a known bug inside libstdc++](https://stackoverflow.com/questions/22915325/avoiding-self-assignment-in-stdshuffle/23691322) - -Workaround: Don't use `--order rand` when compiling against debug-enabled -libstdc++. diff --git a/docs/matchers.md b/docs/matchers.md index d3afe0f4..b96cc5f4 100644 --- a/docs/matchers.md +++ b/docs/matchers.md @@ -141,18 +141,27 @@ are a permutation of the ones in `some_vec`. ### Floating point matchers -Catch2 provides 3 matchers that target floating point numbers. These +Catch2 provides 4 matchers that target floating point numbers. These are: * `WithinAbs(double target, double margin)`, * `WithinULP(FloatingPoint target, uint64_t maxUlpDiff)`, and * `WithinRel(FloatingPoint target, FloatingPoint eps)`. +* `IsNaN()` > `WithinRel` matcher was introduced in Catch2 2.10.0 -For more details, read [the docs on comparing floating point +> `IsNaN` matcher was introduced in Catch2 3.3.2. + +The first three serve to compare two floating pointe numbers. For more +details about how they work, read [the docs on comparing floating point numbers](comparing-floating-point-numbers.md#floating-point-matchers). +`IsNaN` then does exactly what it says on the tin. It matches the input +if it is a NaN (Not a Number). The advantage of using it over just plain +`REQUIRE(std::isnan(x))`, is that if the check fails, with `REQUIRE` you +won't see the value of `x`, but with `REQUIRE_THAT(x, IsNaN())`, you will. + ### Miscellaneous matchers @@ -190,13 +199,23 @@ properties. The macro is `REQUIRE_THROWS_MATCHES(expr, ExceptionType, Matcher)`. > `REQUIRE_THROWS_MATCHES` macro lives in `catch2/matchers/catch_matchers.hpp` -Catch2 currently provides only one matcher for exceptions, -`Message(std::string message)`. `Message` checks that the exception's +Catch2 currently provides two matchers for exceptions. +These are: +* `Message(std::string message)`. +* `MessageMatches(Matcher matcher)`. + +> `MessageMatches` was [introduced](https://github.com/catchorg/Catch2/pull/2570) in Catch2 3.3.0 + +`Message` checks that the exception's message, as returned from `what` is exactly equal to `message`. +`MessageMatches` applies the provided matcher on the exception's +message, as returned from `what`. This is useful in conjunctions with the `std::string` matchers (e.g. `StartsWith`) + Example use: ```cpp REQUIRE_THROWS_MATCHES(throwsDerivedException(), DerivedException, Message("DerivedException::what")); +REQUIRE_THROWS_MATCHES(throwsDerivedException(), DerivedException, MessageMatches(StartsWith("DerivedException"))); ``` Note that `DerivedException` in the example above has to derive from @@ -218,11 +237,19 @@ definitions to handle generic range-like types. These are: * `Contains(T&& target_element, Comparator = std::equal_to<>{})` * `Contains(Matcher element_matcher)` * `AllMatch(Matcher element_matcher)` -* `NoneMatch(Matcher element_matcher)` * `AnyMatch(Matcher element_matcher)` -* `AllTrue()` -* `NoneTrue()` -* `AnyTrue()` +* `NoneMatch(Matcher element_matcher)` +* `AllTrue()`, `AnyTrue()`, `NoneTrue()` +* `RangeEquals(TargetRangeLike&&, Comparator = std::equal_to<>{})` +* `UnorderedRangeEquals(TargetRangeLike&&, Comparator = std::equal_to<>{})` + +> `IsEmpty`, `SizeIs`, `Contains` were introduced in Catch2 3.0.1 + +> `All/Any/NoneMatch` were introduced in Catch2 3.0.1 + +> `All/Any/NoneTrue` were introduced in Catch2 3.1.0 + +> `RangeEquals` and `UnorderedRangeEquals` matchers were [introduced](https://github.com/catchorg/Catch2/pull/2377) in Catch2 3.3.0 `IsEmpty` should be self-explanatory. It successfully matches objects that are empty according to either `std::empty`, or ADL-found `empty` @@ -249,6 +276,25 @@ all, none, or any of the contained elements are `true`, respectively. It works for ranges of `bool`s and ranges of elements (explicitly) convertible to `bool`. +`RangeEquals` compares the range that the matcher is constructed with +(the "target range") against the range to be tested, element-wise. The +match succeeds if all elements from the two ranges compare equal (using +`operator==` by default). The ranges do not need to be the same type, +and the element types do not need to be the same, as long as they are +comparable. (e.g. you may compare `std::vector` to `std::array`). + +`UnorderedRangeEquals` is similar to `RangeEquals`, but the order +does not matter. For example "1, 2, 3" would match "3, 2, 1", but not +"1, 1, 2, 3" As with `RangeEquals`, `UnorderedRangeEquals` compares +the individual elements using `operator==` by default. + +Both `RangeEquals` and `UnorderedRangeEquals` optionally accept a +predicate which can be used to compare the containers element-wise. + +To check a container elementwise against a given matcher, use +`AllMatch`. + + ## Writing custom matchers (old style) The old style of writing matchers has been introduced back in Catch diff --git a/docs/opensource-users.md b/docs/opensource-users.md index 12b4551c..a02d0b98 100644 --- a/docs/opensource-users.md +++ b/docs/opensource-users.md @@ -95,6 +95,9 @@ A C++ client library for Consul. Consul is a distributed tool for discovering an ### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp) A library of algorithms for values-distributed-in-time. +### [SFML](https://github.com/SFML/SFML) +Simple and Fast Multimedia Library. + ### [SOCI](https://github.com/SOCI/soci) The C++ Database Access Library. @@ -110,6 +113,12 @@ A header-only TOML parser and serializer for modern C++. ### [Trompeloeil](https://github.com/rollbear/trompeloeil) A thread-safe header-only mocking framework for C++14. +### [wxWidgets](https://www.wxwidgets.org/) +Cross-Platform C++ GUI Library. + +### [xmlwrapp](https://github.com/vslavik/xmlwrapp) +C++ XML parsing library using libxml2. + ## Applications & Tools ### [App Mesh](https://github.com/laoshanxi/app-mesh) @@ -137,7 +146,7 @@ Newsbeuter is an open-source RSS/Atom feed reader for text terminals. A 2D, Zombie, RPG game which is being made on our own engine. ### [raspigcd](https://github.com/pantadeusz/raspigcd) -Low level CLI app and library for execution of GCODE on Raspberry Pi without any additional microcontrolers (just RPi + Stepsticks). +Low level CLI app and library for execution of GCODE on Raspberry Pi without any additional microcontrollers (just RPi + Stepsticks). ### [SpECTRE](https://github.com/sxs-collaboration/spectre) SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gravitational physics. diff --git a/docs/release-notes.md b/docs/release-notes.md index 7659404b..d263487f 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,11 @@ # Release notes **Contents**
+[3.5.0](#350)
+[3.4.0](#340)
+[3.3.2](#332)
+[3.3.1](#331)
+[3.3.0](#330)
[3.2.1](#321)
[3.2.0](#320)
[3.1.1](#311)
@@ -54,6 +59,130 @@ +## 3.5.0 + +### Improvements +* Introduced `CATCH_CONFIG_PREFIX_MESSAGES` to prefix only logging macros (#2544) + * This means `INFO`, `UNSCOPED_INFO`, `WARN` and `CAPTURE`. +* Section hints in static analysis mode are now `const` + * This prevents Clang-Tidy from complaining about `misc-const-correctness`. +* `from_range` generator supports C arrays and ranges that require ADL (#2737) +* Stringification support for `std::optional` now also includes `std::nullopt` (#2740) +* The Console reporter flushes output after writing benchmark runtime estimate. + * This means that you can immediately see for how long the benchmark is expected to run. +* Added workaround to enable compilation with ICC 19.1 (#2551, #2766) +* Compiling Catch2 for XBox should work out of the box (#2772) + * Catch2 should automatically disable getenv when compiled for XBox. +* Compiling Catch2 with exceptions disabled no longer triggers `Wunused-function` (#2726) +* **`random` Generators for integral types are now reproducible across different platforms** + * Unlike ``, Catch2's generators also support 1 byte integral types (`char`, `bool`, ...) +* **`random` Generators for `float` and `double` are now reproducible across different platforms** + * `long double` varies across different platforms too much to be reproducible + * This guarantee applies only to platforms with IEEE 754 floats. + +### Fixes +* UDL declaration inside Catch2 are now strictly conforming to the standard + * `operator "" _a` is UB, `operator ""_a` is fine. Seriously. +* Fixed `CAPTURE` tests failing to compile in C++23 mode (#2744) +* Fixed missing include in `catch_message.hpp` (#2758) +* Fixed `CHECK_ELSE` suppressing failure from uncaught exceptions(#2723) + +### Miscellaneous +* The documentation for specifying which tests to run through commandline has been completely rewritten (#2738) +* Fixed installation when building Catch2 with meson (#2722, #2742) +* Fixed `catch_discover_tests` when using custom reporter and `PRE_TEST` discovery mode (#2747) +* `catch_discover_tests` supports multi-config CMake generator in `PRE_TEST` discovery mode (#2739, #2746) + + +## 3.4.0 + +### Improvements +* `VectorEquals` supports elements that provide only `==` and not `!=` (#2648) +* Catch2 supports compiling with IAR compiler (#2651) +* Various small internal performance improvements +* Various small internal compilation time improvements +* XMLReporter now reports location info for INFO and WARN (#1251) + * This bumps up the xml format version to 3 +* Documented that `SKIP` in generator constructor can be used to handle empty generator (#1593) +* Added experimental static analysis support to `TEST_CASE` and `SECTION` macros (#2681) + * The two macros are redefined in a way that helps the SA tools reason about the possible paths through a test case with sections. + * The support is controlled by the `CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT` option and autodetects clang-tidy and Coverity. +* `*_THROWS`, `*_THROWS_AS`, etc now suppress warning coming from `__attribute__((warn_unused_result))` on GCC (#2691) + * Unlike plain `[[nodiscard]]`, this warning is not silenced by void cast. WTF GCC? + +### Fixes +* Fixed `assertionStarting` events being sent after the expr is evaluated (#2678) +* Errors in `TEST_CASE` tags are now reported nicely (#2650) + +### Miscellaneous +* Bunch of improvements to `catch_discover_tests` + * Added DISCOVERY_MODE option, so the discovery can happen either post build or pre-run. + * Fixed handling of semicolons and backslashes in test names (#2674, #2676) +* meson build can disable building tests (#2693) +* meson build properly sets meson version 0.54.1 as the minimal supported version (#2688) + + +## 3.3.2 + +### Improvements +* Further reduced allocations + * The compact, console, TAP and XML reporters perform less allocations in various cases + * Removed 1 allocation per entered `SECTION`/`TEST_CASE`. + * Removed 2 allocations per test case exit, if stdout/stderr is captured +* Improved performance + * Section tracking is 10%-25% faster than in v3.3.0 + * Assertion handling is 5%-10% faster than in v3.3.0 + * Test case registration is 1%-2% faster than in v3.3.0 + * Tiny speedup for registering listeners + * Tiny speedup for `CAPTURE`, `TEST_CASE_METHOD`, `METHOD_AS_TEST_CASE`, and `TEMPLATE_LIST_TEST_*` macros. +* `Contains`, `RangeEquals` and `UnorderedRangeEquals` matchers now support ranges with iterator + sentinel pair +* Added `IsNaN` matcher + * Unlike `REQUIRE(isnan(x))`, `REQUIRE_THAT(x, IsNaN())` shows you the value of `x`. +* Suppressed `declared_but_not_referenced` warning for NVHPC (#2637) + +### Fixes +* Fixed performance regression in section tracking introduced in v3.3.1 + * Extreme cases would cause the tracking to run about 4x slower than in 3.3.0 + + +## 3.3.1 + +### Improvements +* Reduced allocations and improved performance + * The exact improvements are dependent on your usage of Catch2. + * For example running Catch2's SelfTest binary performs 8k less allocations. + * The main improvement comes from smarter handling of `SECTION`s, especially sibling `SECTION`s + + +## 3.3.0 + +### Improvements + +* Added `MessageMatches` exception matcher (#2570) +* Added `RangeEquals` and `UnorderedRangeEquals` generic range matchers (#2377) +* Added `SKIP` macro for skipping tests from within the test body (#2360) + * All built-in reporters have been extended to handle it properly, whether your custom reporter needs changes depends on how it was written + * `skipTest` reporter event **is unrelated** to this, and has been deprecated since it has practically no uses +* Restored support for PPC Macs in the break-into-debugger functionality (#2619) +* Made our warning suppression compatible with CUDA toolkit pre 11.5 (#2626) +* Cleaned out some static analysis complaints + + +### Fixes + +* Fixed macro redefinition warning when NVCC was reporting as MSVC (#2603) +* Fixed throws in generator constructor causing the whole binary to abort (#2615) + * Now it just fails the test +* Fixed missing transitive include with libstdc++13 (#2611) + + +### Miscellaneous + +* Improved support for dynamic library build with non-MSVC compilers on Windows (#2630) +* When used as a subproject, Catch2 keeps its generated header in a separate directory from the main project (#2604) + + + ## 3.2.1 ### Improvements @@ -85,7 +214,7 @@ ### Fixes * Cleaned out some warnings and static analysis issues - * Suppressed `-Wcomma` warning rarely occuring in templated test cases (#2543) + * Suppressed `-Wcomma` warning rarely occurring in templated test cases (#2543) * Constified implementation details in `INFO` (#2564) * Made `MatcherGenericBase` copy constructor const (#2566) * Fixed serialization of test filters so the output roundtrips @@ -288,7 +417,7 @@ v3 releases. * Added `STATIC_CHECK` macro, similar to `STATIC_REQUIRE` (#2318) * When deferred tu runtime, it behaves like `CHECK`, and not like `REQUIRE`. * You can have multiple tests with the same name, as long as other parts of the test identity differ (#1915, #1999, #2175) - * Test identity includes test's name, test's tags and and test's class name if applicable. + * Test identity includes test's name, test's tags and test's class name if applicable. * Added new warning, `UnmatchedTestSpec`, to error on test specs with no matching tests * The `-w`, `--warn` warning flags can now be provided multiple times to enable multiple warnings * The case-insensitive handling of tags is now more reliable and takes up less memory @@ -453,7 +582,7 @@ v3 releases. * The `SECTION`(s) before the `GENERATE` will not be run multiple times, the following ones will. * Added `-D`/`--min-duration` command line flag (#1910) * If a test takes longer to finish than the provided value, its name and duration will be printed. - * This flag is overriden by setting `-d`/`--duration`. + * This flag is overridden by setting `-d`/`--duration`. ### Fixes * `TAPReporter` no longer skips successful assertions (#1983) @@ -521,7 +650,7 @@ v3 releases. ### Fixes * Fixed computation of benchmarking column widths in ConsoleReporter (#1885, #1886) * Suppressed clang-tidy's `cppcoreguidelines-pro-type-vararg` in assertions (#1901) - * It was a false positive trigered by the new warning support workaround + * It was a false positive triggered by the new warning support workaround * Fixed bug in test specification parser handling of OR'd patterns using escaping (#1905) ### Miscellaneous @@ -858,7 +987,7 @@ v3 releases. ### Contrib * `ParseAndAddCatchTests` has learned how to use `DISABLED` CTest property (#1452) -* `ParseAndAddCatchTests` now works when there is a whitspace before the test name (#1493) +* `ParseAndAddCatchTests` now works when there is a whitespace before the test name (#1493) ### Miscellaneous diff --git a/docs/reporter-events.md b/docs/reporter-events.md index 32a0ae50..015f67be 100644 --- a/docs/reporter-events.md +++ b/docs/reporter-events.md @@ -96,12 +96,12 @@ void assertionStarting( AssertionInfo const& assertionInfo ); void assertionEnded( AssertionStats const& assertionStats ); ``` -`assertionStarting` is called after the expression is captured, but before -the assertion expression is evaluated. This might seem like a minor -distinction, but what it means is that if you have assertion like -`REQUIRE( a + b == c + d )`, then what happens is that `a + b` and `c + d` -are evaluated before `assertionStarting` is emitted, while the `==` is -evaluated after the event. +The `assertionStarting` event is emitted before the expression in the +assertion is captured or evaluated and `assertionEnded` is emitted +afterwards. This means that given assertion like `REQUIRE(a + b == c + d)`, +Catch2 first emits `assertionStarting` event, then `a + b` and `c + d` +are evaluated, then their results are captured, the comparison is evaluated, +and then `assertionEnded` event is emitted. ## Benchmarking events diff --git a/docs/reporters.md b/docs/reporters.md index 496c61a9..e2abfe34 100644 --- a/docs/reporters.md +++ b/docs/reporters.md @@ -52,7 +52,7 @@ its machine-readable XML output to file `result-junit.xml`, and the uses ANSI colour codes for colouring the output. Using multiple reporters (or one reporter and one-or-more [event -listeners](event-listener.md#top)) can have surprisingly complex semantics +listeners](event-listeners.md#top)) can have surprisingly complex semantics when using customization points provided to reporters by Catch2, namely capturing stdout/stderr from test cases. diff --git a/docs/skipping-passing-failing.md b/docs/skipping-passing-failing.md new file mode 100644 index 00000000..52bb18f7 --- /dev/null +++ b/docs/skipping-passing-failing.md @@ -0,0 +1,135 @@ + +# Explicitly skipping, passing, and failing tests at runtime + +## Skipping Test Cases at Runtime + +> [Introduced](https://github.com/catchorg/Catch2/pull/2360) in Catch2 3.3.0. + +In some situations it may not be possible to meaningfully execute a test case, +for example when the system under test is missing certain hardware capabilities. +If the required conditions can only be determined at runtime, it often +doesn't make sense to consider such a test case as either passed or failed, +because it simply cannot run at all. + +To properly express such scenarios, Catch2 provides a way to explicitly +_skip_ test cases, using the `SKIP` macro: + +``` +SKIP( [streamable expression] ) +``` + +Example usage: + +```c++ +TEST_CASE("copy files between drives") { + if(getNumberOfHardDrives() < 2) { + SKIP("at least two hard drives required"); + } + // ... +} +``` + +This test case is then reported as _skipped_ instead of _passed_ or _failed_. + +The `SKIP` macro behaves similarly to an explicit [`FAIL`](#passing-and-failing-test-cases), +in that it is the last expression that will be executed: + +```c++ +TEST_CASE("my test") { + printf("foo"); + SKIP(); + printf("bar"); // not printed +} +``` + +However a failed assertion _before_ a `SKIP` still causes the entire +test case to fail: + +```c++ +TEST_CASE("failing test") { + CHECK(1 == 2); + SKIP(); +} +``` + +### Interaction with Sections and Generators + +Sections, nested sections as well as specific outputs from [generators](generators.md#top) +can all be individually skipped, with the rest executing as usual: + +```c++ +TEST_CASE("complex test case") { + int value = GENERATE(2, 4, 6); + SECTION("a") { + SECTION("a1") { CHECK(value < 8); } + SECTION("a2") { + if (value == 4) { + SKIP(); + } + CHECK(value % 2 == 0); + } + } +} +``` + +This test case will report 5 passing assertions; one for each of the three +values in section `a1`, and then two in section `a2`, from values 2 and 4. + +Note that as soon as one section is skipped, the entire test case will +be reported as _skipped_ (unless there is a failing assertion, in which +case the test is handled as _failed_ instead). + +Note that if all test cases in a run are skipped, Catch2 returns a non-zero +exit code, same as it does if no test cases have run. This behaviour can +be overridden using the [--allow-running-no-tests](command-line.md#no-tests-override) +flag. + +### `SKIP` inside generators + +You can also use the `SKIP` macro inside generator's constructor to handle +cases where the generator is empty, but you do not want to fail the test +case. + + +## Passing and failing test cases + +Test cases can also be explicitly passed or failed, without the use of +assertions, and with a specific message. This can be useful to handle +complex preconditions/postconditions and give useful error messages +when they fail. + +* `SUCCEED( [streamable expression] )` + +`SUCCEED` is morally equivalent with `INFO( [streamable expression] ); REQUIRE( true );`. +Note that it does not stop further test execution, so it cannot be used +to guard failing assertions from being executed. + +_In practice, `SUCCEED` is usually used as a test placeholder, to avoid +[failing a test case due to missing assertions](command-line.md#warnings)._ + +```cpp +TEST_CASE( "SUCCEED showcase" ) { + int I = 1; + SUCCEED( "I is " << I ); + // ... execution continues here ... +} +``` + +* `FAIL( [streamable expression] )` + +`FAIL` is morally equivalent with `INFO( [streamable expression] ); REQUIRE( false );`. + +_In practice, `FAIL` is usually used to stop executing test that is currently +known to be broken, but has to be fixed later._ + +```cpp +TEST_CASE( "FAIL showcase" ) { + FAIL( "This test case causes segfault, which breaks CI." ); + // ... this will not be executed ... +} +``` + + +--- + +[Home](Readme.md#top) diff --git a/docs/test-cases-and-sections.md b/docs/test-cases-and-sections.md index 613bbd14..01c898bb 100644 --- a/docs/test-cases-and-sections.md +++ b/docs/test-cases-and-sections.md @@ -25,7 +25,8 @@ _section description_ can be used to provide long form description of a section while keeping the _section name_ short for use with the [`-c` command line parameter](command-line.md#specify-the-section-to-run). -**Test names must be unique within the Catch executable.** +**The combination of test names and tags must be unique within the Catch2 +executable.** For examples see the [Tutorial](tutorial.md#top) @@ -68,7 +69,8 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch. * `[!nonportable]` - Indicates that behaviour may vary between platforms or compilers. -* `[#]` - running with `-#` or `--filenames-as-tags` causes Catch to add the filename, prefixed with `#` (and with any extension stripped), as a tag to all contained tests, e.g. tests in testfile.cpp would all be tagged `[#testfile]`. +* `[#]` - these tags are added to test cases when you run Catch2 + with [`-#` or `--filenames-as-tags`](command-line.md#filenames-as-tags). * `[@]` - tag aliases all begin with `@` (see below). @@ -167,7 +169,11 @@ Other than the additional prefixes and the formatting in the console reporter th In addition to `TEST_CASE`s, Catch2 also supports test cases parametrised by types, in the form of `TEMPLATE_TEST_CASE`, -`TEMPLATE_PRODUCT_TEST_CASE` and `TEMPLATE_LIST_TEST_CASE`. +`TEMPLATE_PRODUCT_TEST_CASE` and `TEMPLATE_LIST_TEST_CASE`. These macros +are defined in the `catch_template_test_macros.hpp` header, so compiling +the code examples below also requires +`#include `. + * **TEMPLATE_TEST_CASE(** _test name_ , _tags_, _type1_, _type2_, ..., _typen_ **)** @@ -225,7 +231,7 @@ TEMPLATE_TEST_CASE( "vectors can be sized and resized", "[vector][template]", in > [Introduced](https://github.com/catchorg/Catch2/issues/1468) in Catch2 2.6.0. -_template-type1_ through _template-typen_ is list of template template +_template-type1_ through _template-typen_ is list of template types which should be combined with each of _template-arg1_ through _template-argm_, resulting in _n * m_ test cases. Inside the test case, the resulting type is available under the name of `TestType`. @@ -289,7 +295,9 @@ TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside std In addition to [type parametrised test cases](#type-parametrised-test-cases) Catch2 also supports signature base parametrised test cases, in form of `TEMPLATE_TEST_CASE_SIG` and `TEMPLATE_PRODUCT_TEST_CASE_SIG`. These test cases have similar syntax like [type parametrised test cases](#type-parametrised-test-cases), with one -additional positional argument which specifies the signature. +additional positional argument which specifies the signature. These macros are defined in the +`catch_template_test_macros.hpp` header, so compiling the code examples below also requires +`#include `. ### Signature Signature has some strict rules for these tests cases to work properly: diff --git a/docs/tostring.md b/docs/tostring.md index adce3cc7..b99b6742 100644 --- a/docs/tostring.md +++ b/docs/tostring.md @@ -75,7 +75,7 @@ CATCH_TRANSLATE_EXCEPTION( MyType const& ex ) { Enums that already have a `<<` overload for `std::ostream` will convert to strings as expected. If you only need to convert enums to strings for test reporting purposes you can provide a `StringMaker` specialisations as any other type. -However, as a convenience, Catch provides the `REGISTER_ENUM` helper macro that will generate the `StringMaker` specialiation for you with minimal code. +However, as a convenience, Catch provides the `REGISTER_ENUM` helper macro that will generate the `StringMaker` specialisation for you with minimal code. Simply provide it the (qualified) enum name, followed by all the enum values, and you're done! E.g. diff --git a/docs/tutorial.md b/docs/tutorial.md index 342c7381..dfccac88 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -119,7 +119,7 @@ This is best explained through an example ([code](../examples/100-Fix-Section.cp ```c++ TEST_CASE( "vectors can be sized and resized", "[vector]" ) { - + // This setup will be done 4 times in total, once for each section std::vector v( 5 ); REQUIRE( v.size() == 5 ); @@ -152,11 +152,12 @@ TEST_CASE( "vectors can be sized and resized", "[vector]" ) { } ``` -For each `SECTION` the `TEST_CASE` is executed from the start. This means +For each `SECTION` the `TEST_CASE` is **executed from the start**. This means that each section is entered with a freshly constructed vector `v`, that we know has size 5 and capacity at least 5, because the two assertions -are also checked before the section is entered. Each run through a test -case will execute one, and only one, leaf section. +are also checked before the section is entered. This behaviour may not be +ideal for tests where setup is expensive. Each run through a test case will +execute one, and only one, leaf section. Section can also be nested, in which case the parent section can be entered multiple times, once for each leaf section. Nested sections are diff --git a/docs/why-catch.md b/docs/why-catch.md index 2c0178ca..b7367496 100644 --- a/docs/why-catch.md +++ b/docs/why-catch.md @@ -30,7 +30,7 @@ So what does Catch2 bring to the party that differentiates it from these? Apart * Output is through modular reporter objects. Basic textual and XML reporters are included. Custom reporters can easily be added. * JUnit xml output is supported for integration with third-party tools, such as CI servers. * A default main() function is provided, but you can supply your own for complete control (e.g. integration into your own test runner GUI). -* A command line parser is provided and can still be used if you choose to provided your own main() function. +* A command line parser is provided and can still be used if you choose to provide your own main() function. * Alternative assertion macro(s) report failures but don't abort the test case * Good set of facilities for floating point comparisons (`Catch::Approx` and full set of matchers) * Internal and friendly macros are isolated so name clashes can be managed @@ -41,8 +41,8 @@ So what does Catch2 bring to the party that differentiates it from these? Apart ## Who else is using Catch2? -A whole lot of people. According to the 2021 JetBrains C++ ecosystem survey, -about 11% of C++ programmers use Catch2 for unit testing, making it the +A whole lot of people. According to [the 2022 JetBrains C++ ecosystem survey](https://www.jetbrains.com/lp/devecosystem-2022/cpp/#Which-unit-testing-frameworks-do-you-regularly-use), +about 12% of C++ programmers use Catch2 for unit testing, making it the second most popular unit testing framework. You can also take a look at the (incomplete) list of [open source projects](opensource-users.md#top) diff --git a/examples/010-TestCase.cpp b/examples/010-TestCase.cpp index 7ec208d5..9e5cd8cd 100644 --- a/examples/010-TestCase.cpp +++ b/examples/010-TestCase.cpp @@ -1,3 +1,11 @@ + +// 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 + // 010-TestCase.cpp // And write tests in the same file: #include diff --git a/examples/020-TestCase-1.cpp b/examples/020-TestCase-1.cpp index cec55799..a9d87dbc 100644 --- a/examples/020-TestCase-1.cpp +++ b/examples/020-TestCase-1.cpp @@ -1,3 +1,11 @@ + +// 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 + // 020-TestCase-1.cpp #include diff --git a/examples/020-TestCase-2.cpp b/examples/020-TestCase-2.cpp index 3f5767b3..72dd0ffb 100644 --- a/examples/020-TestCase-2.cpp +++ b/examples/020-TestCase-2.cpp @@ -1,3 +1,11 @@ + +// 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 + // 020-TestCase-2.cpp // main() provided by Catch in file 020-TestCase-1.cpp. diff --git a/examples/030-Asn-Require-Check.cpp b/examples/030-Asn-Require-Check.cpp index 0d027ca9..62cd3cfc 100644 --- a/examples/030-Asn-Require-Check.cpp +++ b/examples/030-Asn-Require-Check.cpp @@ -1,3 +1,11 @@ + +// 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 + // 030-Asn-Require-Check.cpp // Catch has two natural expression assertion macro's: diff --git a/examples/100-Fix-Section.cpp b/examples/100-Fix-Section.cpp index cfbfa79f..7c8d8aa8 100644 --- a/examples/100-Fix-Section.cpp +++ b/examples/100-Fix-Section.cpp @@ -1,3 +1,11 @@ + +// 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 + // 100-Fix-Section.cpp // Catch has two ways to express fixtures: diff --git a/examples/110-Fix-ClassFixture.cpp b/examples/110-Fix-ClassFixture.cpp index 75c10da6..614c3797 100644 --- a/examples/110-Fix-ClassFixture.cpp +++ b/examples/110-Fix-ClassFixture.cpp @@ -1,3 +1,11 @@ + +// 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 + // 110-Fix-ClassFixture.cpp // Catch has two ways to express fixtures: diff --git a/examples/120-Bdd-ScenarioGivenWhenThen.cpp b/examples/120-Bdd-ScenarioGivenWhenThen.cpp index 99cdf9ab..345d53c3 100644 --- a/examples/120-Bdd-ScenarioGivenWhenThen.cpp +++ b/examples/120-Bdd-ScenarioGivenWhenThen.cpp @@ -1,3 +1,11 @@ + +// 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 + // 120-Bdd-ScenarioGivenWhenThen.cpp // main() provided by linkage with Catch2WithMain diff --git a/examples/210-Evt-EventListeners.cpp b/examples/210-Evt-EventListeners.cpp index 6cedb885..56b050d4 100644 --- a/examples/210-Evt-EventListeners.cpp +++ b/examples/210-Evt-EventListeners.cpp @@ -1,3 +1,11 @@ + +// 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 + // 210-Evt-EventListeners.cpp // Contents: diff --git a/examples/231-Cfg-OutputStreams.cpp b/examples/231-Cfg-OutputStreams.cpp index b77c1273..da1713cf 100644 --- a/examples/231-Cfg-OutputStreams.cpp +++ b/examples/231-Cfg-OutputStreams.cpp @@ -1,3 +1,11 @@ + +// 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 + // 231-Cfg-OutputStreams.cpp // Show how to replace the streams with a simple custom made streambuf. diff --git a/examples/300-Gen-OwnGenerator.cpp b/examples/300-Gen-OwnGenerator.cpp index 09643d6f..b5d951ac 100644 --- a/examples/300-Gen-OwnGenerator.cpp +++ b/examples/300-Gen-OwnGenerator.cpp @@ -1,3 +1,11 @@ + +// 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 + // 300-Gen-OwnGenerator.cpp // Shows how to define a custom generator. diff --git a/examples/301-Gen-MapTypeConversion.cpp b/examples/301-Gen-MapTypeConversion.cpp index ba55f65f..a065d87a 100644 --- a/examples/301-Gen-MapTypeConversion.cpp +++ b/examples/301-Gen-MapTypeConversion.cpp @@ -1,3 +1,11 @@ + +// 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 + // 301-Gen-MapTypeConversion.cpp // Shows how to use map to modify generator's return type. diff --git a/examples/302-Gen-Table.cpp b/examples/302-Gen-Table.cpp index 74319518..3cdb1430 100644 --- a/examples/302-Gen-Table.cpp +++ b/examples/302-Gen-Table.cpp @@ -1,3 +1,11 @@ + +// 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 + // 302-Gen-Table.cpp // Shows how to use table to run a test many times with different inputs. Lifted from examples on // issue #850. @@ -44,11 +52,11 @@ TEST_CASE("Table allows pre-computed test inputs and outputs", "[example][genera /* Possible simplifications where less legacy toolchain support is needed: * - * - With libstdc++6 or newer, the make_tuple() calls can be ommitted + * - With libstdc++6 or newer, the make_tuple() calls can be omitted * (technically C++17 but does not require -std in GCC/Clang). See * https://stackoverflow.com/questions/12436586/tuple-vector-and-initializer-list * - * - In C++17 mode std::tie() and the preceding variable delcarations can be + * - In C++17 mode std::tie() and the preceding variable declarations can be * replaced by structured bindings: auto [test_input, expected] = GENERATE( * table({ ... */ diff --git a/examples/310-Gen-VariablesInGenerators.cpp b/examples/310-Gen-VariablesInGenerators.cpp index 0339c5f1..5d24d45a 100644 --- a/examples/310-Gen-VariablesInGenerators.cpp +++ b/examples/310-Gen-VariablesInGenerators.cpp @@ -1,3 +1,11 @@ + +// 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 + // 310-Gen-VariablesInGenerator.cpp // Shows how to use variables when creating generators. diff --git a/examples/311-Gen-CustomCapture.cpp b/examples/311-Gen-CustomCapture.cpp index d12ee709..ee310383 100644 --- a/examples/311-Gen-CustomCapture.cpp +++ b/examples/311-Gen-CustomCapture.cpp @@ -1,3 +1,11 @@ + +// 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 + // 311-Gen-CustomCapture.cpp // Shows how to provide custom capture list to the generator expression diff --git a/extras/Catch.cmake b/extras/Catch.cmake index bc553591..8f30688c 100644 --- a/extras/Catch.cmake +++ b/extras/Catch.cmake @@ -35,8 +35,9 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``. [TEST_LIST var] [REPORTER reporter] [OUTPUT_DIR dir] - [OUTPUT_PREFIX prefix} + [OUTPUT_PREFIX prefix] [OUTPUT_SUFFIX suffix] + [DISCOVERY_MODE ] ) ``catch_discover_tests`` sets up a post-build command on the test executable @@ -123,14 +124,28 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``. test executable and when the tests are executed themselves. This requires cmake/ctest >= 3.22. + `DISCOVERY_MODE mode`` + Provides control over when ``catch_discover_tests`` performs test discovery. + By default, ``POST_BUILD`` sets up a post-build command to perform test discovery + at build time. In certain scenarios, like cross-compiling, this ``POST_BUILD`` + behavior is not desirable. By contrast, ``PRE_TEST`` delays test discovery until + just prior to test execution. This way test discovery occurs in the target environment + where the test has a better chance at finding appropriate runtime dependencies. + + ``DISCOVERY_MODE`` defaults to the value of the + ``CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE`` variable if it is not passed when + calling ``catch_discover_tests``. This provides a mechanism for globally selecting + a preferred test discovery behavior without having to modify each call site. + #]=======================================================================] #------------------------------------------------------------------------------ function(catch_discover_tests TARGET) + cmake_parse_arguments( "" "" - "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX" + "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX;DISCOVERY_MODE" "TEST_SPEC;EXTRA_ARGS;PROPERTIES;DL_PATHS" ${ARGN} ) @@ -141,57 +156,128 @@ function(catch_discover_tests TARGET) if(NOT _TEST_LIST) set(_TEST_LIST ${TARGET}_TESTS) endif() - if (_DL_PATHS) if(${CMAKE_VERSION} VERSION_LESS "3.22.0") message(FATAL_ERROR "The DL_PATHS option requires at least cmake 3.22") endif() endif() + if(NOT _DISCOVERY_MODE) + if(NOT CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE) + set(CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE "POST_BUILD") + endif() + set(_DISCOVERY_MODE ${CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE}) + endif() + if (NOT _DISCOVERY_MODE MATCHES "^(POST_BUILD|PRE_TEST)$") + message(FATAL_ERROR "Unknown DISCOVERY_MODE: ${_DISCOVERY_MODE}") + endif() ## Generate a unique name based on the extra arguments string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX}") string(SUBSTRING ${args_hash} 0 7 args_hash) # Define rule to generate test list for aforementioned test executable - set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake") - set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake") + set(ctest_file_base "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-${args_hash}") + set(ctest_include_file "${ctest_file_base}_include.cmake") + set(ctest_tests_file "${ctest_file_base}_tests.cmake") + get_property(crosscompiling_emulator TARGET ${TARGET} PROPERTY CROSSCOMPILING_EMULATOR ) - add_custom_command( - TARGET ${TARGET} POST_BUILD - BYPRODUCTS "${ctest_tests_file}" - COMMAND "${CMAKE_COMMAND}" - -D "TEST_TARGET=${TARGET}" - -D "TEST_EXECUTABLE=$" - -D "TEST_EXECUTOR=${crosscompiling_emulator}" - -D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}" - -D "TEST_SPEC=${_TEST_SPEC}" - -D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}" - -D "TEST_PROPERTIES=${_PROPERTIES}" - -D "TEST_PREFIX=${_TEST_PREFIX}" - -D "TEST_SUFFIX=${_TEST_SUFFIX}" - -D "TEST_LIST=${_TEST_LIST}" - -D "TEST_REPORTER=${_REPORTER}" - -D "TEST_OUTPUT_DIR=${_OUTPUT_DIR}" - -D "TEST_OUTPUT_PREFIX=${_OUTPUT_PREFIX}" - -D "TEST_OUTPUT_SUFFIX=${_OUTPUT_SUFFIX}" - -D "TEST_DL_PATHS=${_DL_PATHS}" - -D "CTEST_FILE=${ctest_tests_file}" - -P "${_CATCH_DISCOVER_TESTS_SCRIPT}" - VERBATIM - ) - file(WRITE "${ctest_include_file}" - "if(EXISTS \"${ctest_tests_file}\")\n" - " include(\"${ctest_tests_file}\")\n" - "else()\n" - " add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n" - "endif()\n" - ) + if(_DISCOVERY_MODE STREQUAL "POST_BUILD") + add_custom_command( + TARGET ${TARGET} POST_BUILD + BYPRODUCTS "${ctest_tests_file}" + COMMAND "${CMAKE_COMMAND}" + -D "TEST_TARGET=${TARGET}" + -D "TEST_EXECUTABLE=$" + -D "TEST_EXECUTOR=${crosscompiling_emulator}" + -D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}" + -D "TEST_SPEC=${_TEST_SPEC}" + -D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}" + -D "TEST_PROPERTIES=${_PROPERTIES}" + -D "TEST_PREFIX=${_TEST_PREFIX}" + -D "TEST_SUFFIX=${_TEST_SUFFIX}" + -D "TEST_LIST=${_TEST_LIST}" + -D "TEST_REPORTER=${_REPORTER}" + -D "TEST_OUTPUT_DIR=${_OUTPUT_DIR}" + -D "TEST_OUTPUT_PREFIX=${_OUTPUT_PREFIX}" + -D "TEST_OUTPUT_SUFFIX=${_OUTPUT_SUFFIX}" + -D "TEST_DL_PATHS=${_DL_PATHS}" + -D "CTEST_FILE=${ctest_tests_file}" + -P "${_CATCH_DISCOVER_TESTS_SCRIPT}" + VERBATIM + ) - if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0") + file(WRITE "${ctest_include_file}" + "if(EXISTS \"${ctest_tests_file}\")\n" + " include(\"${ctest_tests_file}\")\n" + "else()\n" + " add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n" + "endif()\n" + ) + + elseif(_DISCOVERY_MODE STREQUAL "PRE_TEST") + + get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL + PROPERTY GENERATOR_IS_MULTI_CONFIG + ) + + if(GENERATOR_IS_MULTI_CONFIG) + set(ctest_tests_file "${ctest_file_base}_tests-$.cmake") + endif() + + string(CONCAT ctest_include_content + "if(EXISTS \"$\")" "\n" + " if(NOT EXISTS \"${ctest_tests_file}\" OR" "\n" + " NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"$\" OR\n" + " NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"\${CMAKE_CURRENT_LIST_FILE}\")\n" + " include(\"${_CATCH_DISCOVER_TESTS_SCRIPT}\")" "\n" + " catch_discover_tests_impl(" "\n" + " TEST_EXECUTABLE" " [==[" "$" "]==]" "\n" + " TEST_EXECUTOR" " [==[" "${crosscompiling_emulator}" "]==]" "\n" + " TEST_WORKING_DIR" " [==[" "${_WORKING_DIRECTORY}" "]==]" "\n" + " TEST_SPEC" " [==[" "${_TEST_SPEC}" "]==]" "\n" + " TEST_EXTRA_ARGS" " [==[" "${_EXTRA_ARGS}" "]==]" "\n" + " TEST_PROPERTIES" " [==[" "${_PROPERTIES}" "]==]" "\n" + " TEST_PREFIX" " [==[" "${_TEST_PREFIX}" "]==]" "\n" + " TEST_SUFFIX" " [==[" "${_TEST_SUFFIX}" "]==]" "\n" + " TEST_LIST" " [==[" "${_TEST_LIST}" "]==]" "\n" + " TEST_REPORTER" " [==[" "${_REPORTER}" "]==]" "\n" + " TEST_OUTPUT_DIR" " [==[" "${_OUTPUT_DIR}" "]==]" "\n" + " TEST_OUTPUT_PREFIX" " [==[" "${_OUTPUT_PREFIX}" "]==]" "\n" + " TEST_OUTPUT_SUFFIX" " [==[" "${_OUTPUT_SUFFIX}" "]==]" "\n" + " CTEST_FILE" " [==[" "${ctest_tests_file}" "]==]" "\n" + " TEST_DL_PATHS" " [==[" "${_DL_PATHS}" "]==]" "\n" + " CTEST_FILE" " [==[" "${CTEST_FILE}" "]==]" "\n" + " )" "\n" + " endif()" "\n" + " include(\"${ctest_tests_file}\")" "\n" + "else()" "\n" + " add_test(${TARGET}_NOT_BUILT ${TARGET}_NOT_BUILT)" "\n" + "endif()" "\n" + ) + + if(GENERATOR_IS_MULTI_CONFIG) + foreach(_config ${CMAKE_CONFIGURATION_TYPES}) + file(GENERATE OUTPUT "${ctest_file_base}_include-${_config}.cmake" CONTENT "${ctest_include_content}" CONDITION $) + endforeach() + string(CONCAT ctest_include_multi_content + "if(NOT CTEST_CONFIGURATION_TYPE)" "\n" + " message(\"No configuration for testing specified, use '-C '.\")" "\n" + "else()" "\n" + " include(\"${ctest_file_base}_include-\${CTEST_CONFIGURATION_TYPE}.cmake\")" "\n" + "endif()" "\n" + ) + file(GENERATE OUTPUT "${ctest_include_file}" CONTENT "${ctest_include_multi_content}") + else() + file(GENERATE OUTPUT "${ctest_file_base}_include.cmake" CONTENT "${ctest_include_content}") + file(WRITE "${ctest_include_file}" "include(\"${ctest_file_base}_include.cmake\")") + endif() + endif() + + if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0") # Add discovered tests to directory TEST_INCLUDE_FILES set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}" @@ -204,9 +290,7 @@ function(catch_discover_tests TARGET) PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}" ) else() - message(FATAL_ERROR - "Cannot set more than one TEST_INCLUDE_FILE" - ) + message(FATAL_ERROR "Cannot set more than one TEST_INCLUDE_FILE") endif() endif() diff --git a/extras/CatchAddTests.cmake b/extras/CatchAddTests.cmake index beec3aed..692e3405 100644 --- a/extras/CatchAddTests.cmake +++ b/extras/CatchAddTests.cmake @@ -1,28 +1,6 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. -set(prefix "${TEST_PREFIX}") -set(suffix "${TEST_SUFFIX}") -set(spec ${TEST_SPEC}) -set(extra_args ${TEST_EXTRA_ARGS}) -set(properties ${TEST_PROPERTIES}) -set(reporter ${TEST_REPORTER}) -set(output_dir ${TEST_OUTPUT_DIR}) -set(output_prefix ${TEST_OUTPUT_PREFIX}) -set(output_suffix ${TEST_OUTPUT_SUFFIX}) -set(dl_paths ${TEST_DL_PATHS}) -set(script) -set(suite) -set(tests) - -if(WIN32) - set(dl_paths_variable_name PATH) -elseif(APPLE) - set(dl_paths_variable_name DYLD_LIBRARY_PATH) -else() - set(dl_paths_variable_name LD_LIBRARY_PATH) -endif() - function(add_command NAME) set(_args "") # use ARGV* instead of ARGN, because ARGN splits arrays into multiple arguments @@ -38,119 +16,177 @@ function(add_command NAME) set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE) endfunction() -# Run test executable to get list of available tests -if(NOT EXISTS "${TEST_EXECUTABLE}") - message(FATAL_ERROR - "Specified test executable '${TEST_EXECUTABLE}' does not exist" +function(catch_discover_tests_impl) + + cmake_parse_arguments( + "" + "" + "TEST_EXECUTABLE;TEST_WORKING_DIR;TEST_DL_PATHS;TEST_OUTPUT_DIR;TEST_OUTPUT_PREFIX;TEST_OUTPUT_SUFFIX;TEST_PREFIX;TEST_REPORTER;TEST_SPEC;TEST_SUFFIX;TEST_LIST;CTEST_FILE" + "TEST_EXTRA_ARGS;TEST_PROPERTIES;TEST_EXECUTOR" + ${ARGN} ) -endif() -if(dl_paths) - cmake_path(CONVERT "${dl_paths}" TO_NATIVE_PATH_LIST paths) - set(ENV{${dl_paths_variable_name}} "${paths}") -endif() + set(prefix "${_TEST_PREFIX}") + set(suffix "${_TEST_SUFFIX}") + set(spec ${_TEST_SPEC}) + set(extra_args ${_TEST_EXTRA_ARGS}) + set(properties ${_TEST_PROPERTIES}) + set(reporter ${_TEST_REPORTER}) + set(output_dir ${_TEST_OUTPUT_DIR}) + set(output_prefix ${_TEST_OUTPUT_PREFIX}) + set(output_suffix ${_TEST_OUTPUT_SUFFIX}) + set(dl_paths ${_TEST_DL_PATHS}) + set(script) + set(suite) + set(tests) -execute_process( - COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-tests --verbosity quiet - OUTPUT_VARIABLE output - RESULT_VARIABLE result - WORKING_DIRECTORY "${TEST_WORKING_DIR}" -) -if(NOT ${result} EQUAL 0) - message(FATAL_ERROR - "Error running test executable '${TEST_EXECUTABLE}':\n" - " Result: ${result}\n" - " Output: ${output}\n" - ) -endif() - -string(REPLACE "\n" ";" output "${output}") - -# Run test executable to get list of available reporters -execute_process( - COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-reporters - OUTPUT_VARIABLE reporters_output - RESULT_VARIABLE reporters_result - WORKING_DIRECTORY "${TEST_WORKING_DIR}" -) -if(NOT ${reporters_result} EQUAL 0) - message(FATAL_ERROR - "Error running test executable '${TEST_EXECUTABLE}':\n" - " Result: ${reporters_result}\n" - " Output: ${reporters_output}\n" - ) -endif() -string(FIND "${reporters_output}" "${reporter}" reporter_is_valid) -if(reporter AND ${reporter_is_valid} EQUAL -1) - message(FATAL_ERROR - "\"${reporter}\" is not a valid reporter!\n" - ) -endif() - -# Prepare reporter -if(reporter) - set(reporter_arg "--reporter ${reporter}") -endif() - -# Prepare output dir -if(output_dir AND NOT IS_ABSOLUTE ${output_dir}) - set(output_dir "${TEST_WORKING_DIR}/${output_dir}") - if(NOT EXISTS ${output_dir}) - file(MAKE_DIRECTORY ${output_dir}) + if(WIN32) + set(dl_paths_variable_name PATH) + elseif(APPLE) + set(dl_paths_variable_name DYLD_LIBRARY_PATH) + else() + set(dl_paths_variable_name LD_LIBRARY_PATH) endif() -endif() -if(dl_paths) - foreach(path ${dl_paths}) - cmake_path(NATIVE_PATH path native_path) - list(APPEND environment_modifications "${dl_paths_variable_name}=path_list_prepend:${native_path}") + # Run test executable to get list of available tests + if(NOT EXISTS "${_TEST_EXECUTABLE}") + message(FATAL_ERROR + "Specified test executable '${_TEST_EXECUTABLE}' does not exist" + ) + endif() + + if(dl_paths) + cmake_path(CONVERT "${dl_paths}" TO_NATIVE_PATH_LIST paths) + set(ENV{${dl_paths_variable_name}} "${paths}") + endif() + + execute_process( + COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec} --list-tests --verbosity quiet + OUTPUT_VARIABLE output + RESULT_VARIABLE result + WORKING_DIRECTORY "${_TEST_WORKING_DIR}" + ) + if(NOT ${result} EQUAL 0) + message(FATAL_ERROR + "Error running test executable '${_TEST_EXECUTABLE}':\n" + " Result: ${result}\n" + " Output: ${output}\n" + ) + endif() + + # Make sure to escape ; (semicolons) in test names first, because + # that'd break the foreach loop for "Parse output" later and create + # wrongly splitted and thus failing test cases (false positives) + string(REPLACE ";" "\;" output "${output}") + string(REPLACE "\n" ";" output "${output}") + + # Prepare reporter + if(reporter) + set(reporter_arg "--reporter ${reporter}") + + # Run test executable to check whether reporter is available + # note that the use of --list-reporters is not the important part, + # we only want to check whether the execution succeeds with ${reporter_arg} + execute_process( + COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec} ${reporter_arg} --list-reporters + OUTPUT_VARIABLE reporter_check_output + RESULT_VARIABLE reporter_check_result + WORKING_DIRECTORY "${_TEST_WORKING_DIR}" + ) + if(${reporter_check_result} EQUAL 255) + message(FATAL_ERROR + "\"${reporter}\" is not a valid reporter!\n" + ) + elseif(NOT ${reporter_check_result} EQUAL 0) + message(FATAL_ERROR + "Error running test executable '${_TEST_EXECUTABLE}':\n" + " Result: ${reporter_check_result}\n" + " Output: ${reporter_check_output}\n" + ) + endif() + endif() + + # Prepare output dir + if(output_dir AND NOT IS_ABSOLUTE ${output_dir}) + set(output_dir "${_TEST_WORKING_DIR}/${output_dir}") + if(NOT EXISTS ${output_dir}) + file(MAKE_DIRECTORY ${output_dir}) + endif() + endif() + + if(dl_paths) + foreach(path ${dl_paths}) + cmake_path(NATIVE_PATH path native_path) + list(APPEND environment_modifications "${dl_paths_variable_name}=path_list_prepend:${native_path}") + endforeach() + endif() + + # Parse output + foreach(line ${output}) + set(test "${line}") + # Escape characters in test case names that would be parsed by Catch2 + # Note that the \ escaping must happen FIRST! Do not change the order. + set(test_name "${test}") + foreach(char \\ , [ ]) + string(REPLACE ${char} "\\${char}" test_name "${test_name}") + endforeach(char) + # ...add output dir + if(output_dir) + string(REGEX REPLACE "[^A-Za-z0-9_]" "_" test_name_clean "${test_name}") + set(output_dir_arg "--out ${output_dir}/${output_prefix}${test_name_clean}${output_suffix}") + endif() + + # ...and add to script + add_command(add_test + "${prefix}${test}${suffix}" + ${_TEST_EXECUTOR} + "${_TEST_EXECUTABLE}" + "${test_name}" + ${extra_args} + "${reporter_arg}" + "${output_dir_arg}" + ) + add_command(set_tests_properties + "${prefix}${test}${suffix}" + PROPERTIES + WORKING_DIRECTORY "${_TEST_WORKING_DIR}" + ${properties} + ) + + if(environment_modifications) + add_command(set_tests_properties + "${prefix}${test}${suffix}" + PROPERTIES + ENVIRONMENT_MODIFICATION "${environment_modifications}") + endif() + + list(APPEND tests "${prefix}${test}${suffix}") endforeach() + + # Create a list of all discovered tests, which users may use to e.g. set + # properties on the tests + add_command(set ${_TEST_LIST} ${tests}) + + # Write CTest script + file(WRITE "${_CTEST_FILE}" "${script}") +endfunction() + +if(CMAKE_SCRIPT_MODE_FILE) + catch_discover_tests_impl( + TEST_EXECUTABLE ${TEST_EXECUTABLE} + TEST_EXECUTOR ${TEST_EXECUTOR} + TEST_WORKING_DIR ${TEST_WORKING_DIR} + TEST_SPEC ${TEST_SPEC} + TEST_EXTRA_ARGS ${TEST_EXTRA_ARGS} + TEST_PROPERTIES ${TEST_PROPERTIES} + TEST_PREFIX ${TEST_PREFIX} + TEST_SUFFIX ${TEST_SUFFIX} + TEST_LIST ${TEST_LIST} + TEST_REPORTER ${TEST_REPORTER} + TEST_OUTPUT_DIR ${TEST_OUTPUT_DIR} + TEST_OUTPUT_PREFIX ${TEST_OUTPUT_PREFIX} + TEST_OUTPUT_SUFFIX ${TEST_OUTPUT_SUFFIX} + TEST_DL_PATHS ${TEST_DL_PATHS} + CTEST_FILE ${CTEST_FILE} + ) endif() - -# Parse output -foreach(line ${output}) - set(test ${line}) - # Escape characters in test case names that would be parsed by Catch2 - set(test_name ${test}) - foreach(char , [ ]) - string(REPLACE ${char} "\\${char}" test_name ${test_name}) - endforeach(char) - # ...add output dir - if(output_dir) - string(REGEX REPLACE "[^A-Za-z0-9_]" "_" test_name_clean ${test_name}) - set(output_dir_arg "--out ${output_dir}/${output_prefix}${test_name_clean}${output_suffix}") - endif() - - # ...and add to script - add_command(add_test - "${prefix}${test}${suffix}" - ${TEST_EXECUTOR} - "${TEST_EXECUTABLE}" - "${test_name}" - ${extra_args} - "${reporter_arg}" - "${output_dir_arg}" - ) - add_command(set_tests_properties - "${prefix}${test}${suffix}" - PROPERTIES - WORKING_DIRECTORY "${TEST_WORKING_DIR}" - ${properties} - ) - - if(environment_modifications) - add_command(set_tests_properties - "${prefix}${test}${suffix}" - PROPERTIES - ENVIRONMENT_MODIFICATION "${environment_modifications}") - endif() - - list(APPEND tests "${prefix}${test}${suffix}") -endforeach() - -# Create a list of all discovered tests, which users may use to e.g. set -# properties on the tests -add_command(set ${TEST_LIST} ${tests}) - -# Write CTest script -file(WRITE "${CTEST_FILE}" "${script}") diff --git a/extras/CatchShardTests.cmake b/extras/CatchShardTests.cmake index 5e043cf0..68228f5a 100644 --- a/extras/CatchShardTests.cmake +++ b/extras/CatchShardTests.cmake @@ -46,7 +46,7 @@ function(catch_add_sharded_tests TARGET) APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}" ) - set(shard_impl_script_file "${CMAKE_CURRENT_LIST_DIR}/CatchShardTestsImpl.cmake") + set(shard_impl_script_file "${_CATCH_DISCOVER_SHARD_TESTS_IMPL_SCRIPT}") add_custom_command( TARGET ${TARGET} POST_BUILD @@ -64,3 +64,11 @@ function(catch_add_sharded_tests TARGET) endfunction() + + +############################################################################### + +set(_CATCH_DISCOVER_SHARD_TESTS_IMPL_SCRIPT + ${CMAKE_CURRENT_LIST_DIR}/CatchShardTestsImpl.cmake + CACHE INTERNAL "Catch2 full path to CatchShardTestsImpl.cmake helper file" +) diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp index b27c4ec8..cfc38a46 100644 --- a/extras/catch_amalgamated.cpp +++ b/extras/catch_amalgamated.cpp @@ -1,3 +1,4 @@ + // Copyright Catch2 Authors // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at @@ -5,8 +6,8 @@ // SPDX-License-Identifier: BSL-1.0 -// Catch v3.2.1 -// Generated: 2022-12-09 23:01:15.713081 +// Catch v3.5.0 +// Generated: 2023-12-11 00:51:07.662625 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -48,6 +49,80 @@ namespace Catch { } // namespace Catch +// Adapted from donated nonius code. + + +#include + +namespace Catch { + namespace Benchmark { + namespace Detail { + SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last) { + if (!cfg.benchmarkNoAnalysis()) { + std::vector samples; + samples.reserve(static_cast(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.data(), + samples.data() + samples.size() ); + auto outliers = Catch::Benchmark::Detail::classify_outliers( + samples.data(), samples.data() + samples.size() ); + + auto wrap_estimate = [](Estimate e) { + return Estimate { + FDuration(e.point), + FDuration(e.lower_bound), + FDuration(e.upper_bound), + e.confidence_interval, + }; + }; + std::vector samples2; + samples2.reserve(samples.size()); + for (auto s : samples) { + samples2.push_back( FDuration( s ) ); + } + + return { + CATCH_MOVE(samples2), + wrap_estimate(analysis.mean), + wrap_estimate(analysis.standard_deviation), + outliers, + analysis.outlier_variance, + }; + } else { + std::vector samples; + samples.reserve(static_cast(last - first)); + + FDuration mean = FDuration(0); + int i = 0; + for (auto it = first; it < last; ++it, ++i) { + samples.push_back(FDuration(*it)); + mean += FDuration(*it); + } + mean /= i; + + return SampleAnalysis{ + CATCH_MOVE(samples), + Estimate{ mean, mean, mean, 0.0 }, + Estimate{ FDuration( 0 ), + FDuration( 0 ), + FDuration( 0 ), + 0.0 }, + OutlierClassification{}, + 0.0 + }; + } + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch + + namespace Catch { @@ -60,6 +135,7 @@ namespace Catch { + #include namespace Catch { @@ -86,9 +162,11 @@ namespace Catch { +#include #include +#include #include -#include +#include #include @@ -96,139 +174,204 @@ namespace Catch { #include #endif -namespace { +namespace Catch { + namespace Benchmark { + namespace Detail { + namespace { -using Catch::Benchmark::Detail::sample; + template + static sample + resample( URng& rng, + unsigned int resamples, + double const* first, + double const* last, + Estimator& estimator ) { + auto n = static_cast( last - first ); + std::uniform_int_distribution dist( 0, + n - 1 ); - template - sample resample(URng& rng, unsigned int resamples, std::vector::iterator first, std::vector::iterator last, Estimator& estimator) { - auto n = static_cast(last - first); - std::uniform_int_distribution dist(0, n - 1); + sample out; + out.reserve( resamples ); + // We allocate the vector outside the loop to avoid realloc + // per resample + std::vector 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( + dist( rng ) )] ); + } + const auto estimate = + estimator( resampled.data(), resampled.data() + resampled.size() ); + out.push_back( estimate ); + } + std::sort( out.begin(), out.end() ); + return out; + } - sample out; - out.reserve(resamples); - std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] { - std::vector resampled; - resampled.reserve(n); - std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[static_cast(dist(rng))]; }); - return estimator(resampled.begin(), resampled.end()); - }); - std::sort(out.begin(), out.end()); - return out; - } + static double outlier_variance( Estimate mean, + Estimate 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( -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( double const* first, double const* 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 ); + } + + static sample jackknife( double ( *estimator )( double const*, + double const* ), + double* first, + double* last ) { + const auto second = first + 1; + sample results; + results.reserve( static_cast( last - first ) ); + + for ( auto it = first; it != last; ++it ) { + std::iter_swap( it, first ); + results.push_back( estimator( second, last ) ); + } + + return results; + } - 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; - } - - double standard_deviation(std::vector::iterator first, std::vector::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::iterator first, std::vector::iterator last) { + double weighted_average_quantile( int k, + int q, + double* first, + double* last ) { auto count = last - first; double idx = (count - 1) * k / static_cast(q); int j = static_cast(idx); double g = idx - j; std::nth_element(first, first + j, last); auto xj = first[j]; - if ( directCompare( g, 0 ) ) { + if ( Catch::Detail::directCompare( g, 0 ) ) { return xj; } @@ -236,6 +379,48 @@ namespace Catch { return xj + g * (xj1 - xj); } + OutlierClassification + classify_outliers( double const* first, double const* last ) { + std::vector copy( first, last ); + + auto q1 = weighted_average_quantile( 1, 4, copy.data(), copy.data() + copy.size() ); + auto q3 = weighted_average_quantile( 3, 4, copy.data(), copy.data() + copy.size() ); + 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( double const* first, double const* last ) { + auto count = last - first; + double sum = 0.; + while (first != last) { + sum += *first; + ++first; + } + return sum / static_cast(count); + } + + double normal_cdf( double x ) { + return std::erfc( -x / std::sqrt( 2.0 ) ) / 2.0; + } double erfc_inv(double x) { return erf_inv(1.0 - x); @@ -257,50 +442,77 @@ namespace Catch { return result; } + Estimate + bootstrap( double confidence_level, + double* first, + double* last, + sample const& resample, + double ( *estimator )( double const*, double const* ) ) { + auto n_samples = last - first; - double outlier_variance(Estimate mean, Estimate 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; + double point = estimator( first, last ); + // Degenerate case with a single sample + if ( n_samples == 1 ) + return { point, point, point, confidence_level }; - 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(-2. * k0 / (k1 + std::sqrt(det))); + sample jack = jackknife( estimator, first, last ); + double jack_mean = + mean( jack.data(), jack.data() + jack.size() ); + 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( resample.size() ); + double prob_n = + std::count_if( resample.begin(), + resample.end(), + [point]( double x ) { return x < point; } ) / + static_cast( n ); + // degenerate case with uniform samples + if ( Catch::Detail::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( n ) ); }; - - auto var_out = [n, sb2, sg2](double c) { - double nc = n - c; - return (nc / n) * (sb2 - nc * sg2); + 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( (std::max)( cumn( a1 ), 0l ) ); + auto hi = + static_cast( (std::min)( cumn( a2 ), n - 1 ) ); - return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2; + return { point, resample[lo], resample[hi], confidence_level }; } - - bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector::iterator first, std::vector::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(last - first); // seriously, one can't use integral types without hell in C++ - - auto mean = &Detail::mean::iterator>; + bootstrap_analysis analyse_samples(double confidence_level, + unsigned int n_resamples, + double* first, + double* last) { + auto mean = &Detail::mean; auto stddev = &standard_deviation; #if defined(CATCH_CONFIG_USE_ASYNC) - auto Estimate = [=](double(*f)(std::vector::iterator, std::vector::iterator)) { - auto seed = entropy(); + auto Estimate = [=](double(*f)(double const*, double const*)) { + std::random_device rd; + auto seed = rd(); return std::async(std::launch::async, [=] { - std::mt19937 rng(seed); + SimplePcg32 rng( seed ); auto resampled = resample(rng, n_resamples, first, last, f); return bootstrap(confidence_level, first, last, resampled, f); }); @@ -312,9 +524,10 @@ namespace Catch { auto mean_estimate = mean_future.get(); auto stddev_estimate = stddev_future.get(); #else - auto Estimate = [=](double(*f)(std::vector::iterator, std::vector::iterator)) { - auto seed = entropy(); - std::mt19937 rng(seed); + auto Estimate = [=](double(*f)(double const* , double const*)) { + std::random_device rd; + auto seed = rd(); + SimplePcg32 rng( seed ); auto resampled = resample(rng, n_resamples, first, last, f); return bootstrap(confidence_level, first, last, resampled, f); }; @@ -323,6 +536,7 @@ namespace Catch { auto stddev_estimate = Estimate(stddev); #endif // CATCH_USE_ASYNC + auto n = static_cast(last - first); // seriously, one can't use integral types without hell in C++ double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n); return { mean_estimate, stddev_estimate, outlier_variance }; @@ -394,10 +608,10 @@ namespace Catch { } namespace literals { - Approx operator "" _a(long double val) { + Approx operator ""_a(long double val) { return Approx(val); } - Approx operator "" _a(unsigned long long val) { + Approx operator ""_a(unsigned long long val) { return Approx(val); } } // end namespace literals @@ -428,9 +642,9 @@ namespace Catch { return reconstructedExpression; } - AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData&& data ) : m_info( info ), - m_resultData( data ) + m_resultData( CATCH_MOVE(data) ) {} // Result was a success @@ -469,16 +683,15 @@ namespace Catch { } std::string AssertionResult::getExpressionInMacro() const { - std::string expr; - if( m_info.macroName.empty() ) - expr = static_cast(m_info.capturedExpression); - else { - expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); - expr += m_info.macroName; - expr += "( "; - expr += m_info.capturedExpression; - expr += " )"; + if ( m_info.macroName.empty() ) { + return static_cast( 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; } @@ -597,7 +810,7 @@ namespace Catch { elem = trim(elem); } - // Insert the default reporter if user hasn't asked for a specfic one + // 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 ) @@ -758,8 +971,8 @@ namespace Catch { //////////////////////////////////////////////////////////////////////////// - ScopedMessage::ScopedMessage( MessageBuilder const& builder ): - m_info( builder.m_info ) { + ScopedMessage::ScopedMessage( MessageBuilder&& builder ): + m_info( CATCH_MOVE(builder.m_info) ) { m_info.message = builder.m_stream.str(); getResultCapture().pushScopedMessage( m_info ); } @@ -776,7 +989,11 @@ namespace Catch { } - Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { + 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(names[start]))) { ++start; @@ -853,6 +1070,8 @@ namespace Catch { +#include + namespace Catch { namespace { @@ -863,7 +1082,7 @@ namespace Catch { public: // IRegistryHub RegistryHub() = default; - IReporterRegistry const& getReporterRegistry() const override { + ReporterRegistry const& getReporterRegistry() const override { return m_reporterRegistry; } ITestCaseRegistry const& getTestCaseRegistry() const override { @@ -939,6 +1158,7 @@ namespace Catch { #include #include +#include #include #include @@ -1253,6 +1473,12 @@ namespace Catch { 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 @@ -1415,12 +1641,20 @@ namespace Catch { for (size_t idx = 0; idx < originalTags.size(); ++idx) { auto c = originalTags[idx]; if (c == '[') { - assert(!inTag); + CATCH_ENFORCE( + !inTag, + "Found '[' inside a tag while registering test case '" + << _nameAndTags.name << "' at " << _lineInfo ); + inTag = true; tagStart = idx; } if (c == ']') { - assert(inTag); + CATCH_ENFORCE( + inTag, + "Found unmatched ']' while registering test case '" + << _nameAndTags.name << "' at " << _lineInfo ); + inTag = false; tagEnd = idx; assert(tagStart < tagEnd); @@ -1429,7 +1663,11 @@ namespace Catch { // 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(), "Empty tags are not allowed"); + 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 @@ -1443,8 +1681,12 @@ namespace Catch { // the tags. internalAppendTag(tagStr); } - (void)inTag; // Silence "set-but-unused" warning in release mode. } + CATCH_ENFORCE( !inTag, + "Found an unclosed tag while registering test case '" + << _nameAndTags.name << "' at " << _lineInfo ); + + // Add [.] if relevant if (isHidden()) { internalAppendTag("."_sr); @@ -1620,16 +1862,18 @@ namespace Catch { return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } ); } - TestSpec::Matches TestSpec::matchesByFilter( std::vector const& testCases, IConfig const& config ) const - { - Matches matches( m_filters.size() ); - std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){ + TestSpec::Matches TestSpec::matchesByFilter( std::vector const& testCases, IConfig const& config ) const { + Matches matches; + matches.reserve( m_filters.size() ); + for ( auto const& filter : m_filters ) { std::vector currentMatches; - for( auto const& test : testCases ) - if( isThrowSafe( test, config ) && filter.matches( test.getTestCaseInfo() ) ) + for ( auto const& test : testCases ) + if ( isThrowSafe( test, config ) && + filter.matches( test.getTestCaseInfo() ) ) currentMatches.emplace_back( &test ); - return FilterMatch{ extractFilterName(filter), currentMatches }; - } ); + matches.push_back( + FilterMatch{ extractFilterName( filter ), currentMatches } ); + } return matches; } @@ -1935,6 +2179,7 @@ namespace Catch { diff.passed = passed - other.passed; diff.failed = failed - other.failed; diff.failedButOk = failedButOk - other.failedButOk; + diff.skipped = skipped - other.skipped; return diff; } @@ -1942,14 +2187,15 @@ namespace Catch { passed += other.passed; failed += other.failed; failedButOk += other.failedButOk; + skipped += other.skipped; return *this; } std::uint64_t Counts::total() const { - return passed + failed + failedButOk; + return passed + failed + failedButOk + skipped; } bool Counts::allPassed() const { - return failed == 0 && failedButOk == 0; + return failed == 0 && failedButOk == 0 && skipped == 0; } bool Counts::allOk() const { return failed == 0; @@ -1974,6 +2220,8 @@ namespace Catch { ++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; @@ -1982,6 +2230,19 @@ namespace Catch { } + + +namespace Catch { + namespace Detail { + void registerTranslatorImpl( + Detail::unique_ptr&& translator ) { + getMutableRegistryHub().registerTranslator( + CATCH_MOVE( translator ) ); + } + } // namespace Detail +} // namespace Catch + + #include namespace Catch { @@ -2012,7 +2273,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 3, 2, 1, "", 0 ); + static Version version( 3, 5, 0, "", 0 ); return version; } @@ -2048,18 +2309,53 @@ namespace Detail { GeneratorUntypedBase::~GeneratorUntypedBase() = default; - auto acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + 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 +#include -std::uint32_t Catch::Generators::Detail::getSeed() { return sharedRng()(); } +namespace Catch { + namespace Generators { + namespace Detail { + std::uint32_t getSeed() { return sharedRng()(); } + } // namespace Detail + + struct RandomFloatingGenerator::PImpl { + PImpl( long double a, long double b, uint32_t seed ): + rng( seed ), dist( a, b ) {} + + Catch::SimplePcg32 rng; + std::uniform_real_distribution dist; + }; + + RandomFloatingGenerator::RandomFloatingGenerator( + long double a, long double b, std::uint32_t seed) : + m_pimpl(Catch::Detail::make_unique(a, b, seed)) { + static_cast( next() ); + } + + RandomFloatingGenerator::~RandomFloatingGenerator() = + default; + bool RandomFloatingGenerator::next() { + m_current_number = m_pimpl->dist( m_pimpl->rng ); + return true; + } + } // namespace Generators +} // namespace Catch @@ -2156,24 +2452,21 @@ namespace Catch { infoMessages( _infoMessages ), totals( _totals ) { - assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; - 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 << assertionResult.getMessage(); - builder.m_info.message = builder.m_stream.str(); + builder.m_info.message = static_cast(assertionResult.getMessage()); - infoMessages.push_back( builder.m_info ); + infoMessages.push_back( CATCH_MOVE(builder.m_info) ); } } - SectionStats::SectionStats( SectionInfo const& _sectionInfo, + SectionStats::SectionStats( SectionInfo&& _sectionInfo, Counts const& _assertions, double _durationInSeconds, bool _missingAssertions ) - : sectionInfo( _sectionInfo ), + : sectionInfo( CATCH_MOVE(_sectionInfo) ), assertions( _assertions ), durationInSeconds( _durationInSeconds ), missingAssertions( _missingAssertions ) @@ -2182,13 +2475,13 @@ namespace Catch { TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, + std::string&& _stdOut, + std::string&& _stdErr, bool _aborting ) : testInfo( &_testInfo ), totals( _totals ), - stdOut( _stdOut ), - stdErr( _stdErr ), + stdOut( CATCH_MOVE(_stdOut) ), + stdErr( CATCH_MOVE(_stdErr) ), aborting( _aborting ) {} @@ -2217,14 +2510,6 @@ namespace Catch { namespace Catch { - IReporterRegistry::~IReporterRegistry() = default; -} - - - - -namespace Catch { - ITestInvoker::~ITestInvoker() = default; ITestCaseRegistry::~ITestCaseRegistry() = default; } @@ -2239,7 +2524,9 @@ namespace Catch { 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 ); @@ -2253,7 +2540,7 @@ namespace Catch { } void AssertionHandler::complete() { - setCompleted(); + m_completed = true; if( m_reaction.shouldDebugBreak ) { // If you find your debugger stopping you here then go one level up on the @@ -2265,9 +2552,9 @@ namespace Catch { if (m_reaction.shouldThrow) { throw_test_failure_exception(); } - } - void AssertionHandler::setCompleted() { - m_completed = true; + if ( m_reaction.shouldSkip ) { + throw_test_skip_exception(); + } } void AssertionHandler::handleUnexpectedInflightException() { @@ -2895,7 +3182,7 @@ namespace Catch { auto const& reporterSpec = *parsed; - IReporterRegistry::FactoryMap const& factories = + auto const& factories = getRegistryHub().getReporterRegistry().getFactories(); auto result = factories.find( reporterSpec.name() ); @@ -3133,7 +3420,7 @@ namespace Catch { namespace { //! A do-nothing implementation of colour, used as fallback for unknown //! platforms, and when the user asks to deactivate all colours. - class NoColourImpl : public ColourImpl { + class NoColourImpl final : public ColourImpl { public: NoColourImpl( IStream* stream ): ColourImpl( stream ) {} @@ -3151,7 +3438,7 @@ namespace Catch { namespace Catch { namespace { - class Win32ColourImpl : public ColourImpl { + class Win32ColourImpl final : public ColourImpl { public: Win32ColourImpl(IStream* stream): ColourImpl(stream) { @@ -3217,7 +3504,7 @@ namespace { namespace Catch { namespace { - class ANSIColourImpl : public ColourImpl { + class ANSIColourImpl final : public ColourImpl { public: ANSIColourImpl( IStream* stream ): ColourImpl( stream ) {} @@ -3333,49 +3620,27 @@ namespace Catch { namespace Catch { - class Context : public IMutableContext, private Detail::NonCopyable { + Context* Context::currentContext = nullptr; - public: // IContext - IResultCapture* getResultCapture() override { - return m_resultCapture; - } - - IConfig const* getConfig() const override { - return m_config; - } - - ~Context() override; - - public: // IMutableContext - void setResultCapture( IResultCapture* resultCapture ) override { - m_resultCapture = resultCapture; - } - void setConfig( IConfig const* config ) override { - m_config = config; - } - - friend IMutableContext& getCurrentMutableContext(); - - private: - IConfig const* m_config = nullptr; - IResultCapture* m_resultCapture = nullptr; - }; - - IMutableContext *IMutableContext::currentContext = nullptr; - - void IMutableContext::createContext() - { + void cleanUpContext() { + delete Context::currentContext; + Context::currentContext = nullptr; + } + void Context::createContext() { currentContext = new Context(); } - void cleanUpContext() { - delete IMutableContext::currentContext; - IMutableContext::currentContext = nullptr; + Context& getCurrentMutableContext() { + if ( !Context::currentContext ) { Context::createContext(); } + // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) + return *Context::currentContext; } - IContext::~IContext() = default; - IMutableContext::~IMutableContext() = default; - Context::~Context() = default; + void Context::setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + + void Context::setConfig( IConfig const* config ) { m_config = config; } SimplePcg32& sharedRng() { static SimplePcg32 s_rng; @@ -3613,7 +3878,7 @@ namespace Catch { return parsed; } - EnumInfo::~EnumInfo() {} + EnumInfo::~EnumInfo() = default; StringRef EnumInfo::lookup( int value ) const { for( auto const& valueToName : m_values ) { @@ -3658,10 +3923,27 @@ namespace Catch { +#include + namespace Catch { - ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + namespace { + static std::string tryTranslators( + std::vector< + Detail::unique_ptr> const& translators ) { + if ( translators.empty() ) { + std::rethrow_exception( std::current_exception() ); + } else { + return translators[0]->translate( translators.begin() + 1, + translators.end() ); + } + } + } +#endif //!defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + + ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() = default; void ExceptionTranslatorRegistry::registerTranslator( Detail::unique_ptr&& translator ) { m_translators.push_back( CATCH_MOVE( translator ) ); @@ -3684,13 +3966,16 @@ namespace Catch { // First we try user-registered translators. If none of them can // handle the exception, it will be rethrown handled by our defaults. try { - return tryTranslators(); + return tryTranslators(m_translators); } // To avoid having to handle TFE explicitly everywhere, we just // rethrow it so that it goes back up the caller. catch( TestFailureException& ) { std::rethrow_exception(std::current_exception()); } + catch( TestSkipException& ) { + std::rethrow_exception(std::current_exception()); + } catch( std::exception const& ex ) { return ex.what(); } @@ -3705,25 +3990,12 @@ namespace Catch { } } - std::string ExceptionTranslatorRegistry::tryTranslators() const { - if (m_translators.empty()) { - std::rethrow_exception(std::current_exception()); - } else { - return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end()); - } - } - #else // ^^ Exceptions are enabled // Exceptions are disabled vv std::string ExceptionTranslatorRegistry::translateActiveException() const { CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); } - - std::string ExceptionTranslatorRegistry::tryTranslators() const { - CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); - } #endif - } @@ -3980,6 +4252,17 @@ namespace Catch { return i; } +#if defined( __GNUC__ ) || defined( __clang__ ) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + bool directCompare( float lhs, float rhs ) { return lhs == rhs; } + bool directCompare( double lhs, double rhs ) { return lhs == rhs; } +#if defined( __GNUC__ ) || defined( __clang__ ) +# pragma GCC diagnostic pop +#endif + + } // end namespace Detail } // end namespace Catch @@ -4028,7 +4311,7 @@ namespace Catch { namespace Detail { namespace { template - class StreamBufImpl : public std::streambuf { + class StreamBufImpl final : public std::streambuf { char data[bufferSize]; WriterF m_writer; @@ -4076,7 +4359,7 @@ namespace Detail { /////////////////////////////////////////////////////////////////////////// - class FileStream : public IStream { + class FileStream final : public IStream { std::ofstream m_ofs; public: FileStream( std::string const& filename ) { @@ -4093,7 +4376,7 @@ namespace Detail { /////////////////////////////////////////////////////////////////////////// - class CoutStream : public IStream { + class CoutStream final : public IStream { std::ostream m_os; public: // Store the streambuf from cout up-front because @@ -4122,7 +4405,7 @@ namespace Detail { /////////////////////////////////////////////////////////////////////////// - class DebugOutStream : public IStream { + class DebugOutStream final : public IStream { Detail::unique_ptr> m_streamBuf; std::ostream m_os; public: @@ -4164,6 +4447,147 @@ namespace Detail { +namespace Catch { + void JsonUtils::indent( std::ostream& os, std::uint64_t level ) { + for ( std::uint64_t i = 0; i < level; ++i ) { + os << " "; + } + } + void JsonUtils::appendCommaNewline( std::ostream& os, + bool& should_comma, + std::uint64_t level ) { + if ( should_comma ) { os << ','; } + should_comma = true; + os << '\n'; + indent( os, level ); + } + + JsonObjectWriter::JsonObjectWriter( std::ostream& os ): + JsonObjectWriter{ os, 0 } {} + + JsonObjectWriter::JsonObjectWriter( std::ostream& os, + std::uint64_t indent_level ): + m_os{ os }, m_indent_level{ indent_level } { + m_os << '{'; + } + JsonObjectWriter::JsonObjectWriter( JsonObjectWriter&& source ): + m_os{ source.m_os }, + m_indent_level{ source.m_indent_level }, + m_should_comma{ source.m_should_comma }, + m_active{ source.m_active } { + source.m_active = false; + } + + JsonObjectWriter::~JsonObjectWriter() { + if ( !m_active ) { return; } + + m_os << '\n'; + JsonUtils::indent( m_os, m_indent_level ); + m_os << '}'; + } + + JsonValueWriter JsonObjectWriter::write( StringRef key ) { + JsonUtils::appendCommaNewline( + m_os, m_should_comma, m_indent_level + 1 ); + + m_os << '"' << key << "\": "; + return JsonValueWriter{ m_os, m_indent_level + 1 }; + } + + JsonArrayWriter::JsonArrayWriter( std::ostream& os ): + JsonArrayWriter{ os, 0 } {} + JsonArrayWriter::JsonArrayWriter( std::ostream& os, + std::uint64_t indent_level ): + m_os{ os }, m_indent_level{ indent_level } { + m_os << '['; + } + JsonArrayWriter::JsonArrayWriter( JsonArrayWriter&& source ): + m_os{ source.m_os }, + m_indent_level{ source.m_indent_level }, + m_should_comma{ source.m_should_comma }, + m_active{ source.m_active } { + source.m_active = false; + } + JsonArrayWriter::~JsonArrayWriter() { + if ( !m_active ) { return; } + + m_os << '\n'; + JsonUtils::indent( m_os, m_indent_level ); + m_os << ']'; + } + + JsonObjectWriter JsonArrayWriter::writeObject() { + JsonUtils::appendCommaNewline( + m_os, m_should_comma, m_indent_level + 1 ); + return JsonObjectWriter{ m_os, m_indent_level + 1 }; + } + + JsonArrayWriter JsonArrayWriter::writeArray() { + JsonUtils::appendCommaNewline( + m_os, m_should_comma, m_indent_level + 1 ); + return JsonArrayWriter{ m_os, m_indent_level + 1 }; + } + + JsonArrayWriter& JsonArrayWriter::write( bool value ) { + return writeImpl( value ); + } + + JsonValueWriter::JsonValueWriter( std::ostream& os ): + JsonValueWriter{ os, 0 } {} + + JsonValueWriter::JsonValueWriter( std::ostream& os, + std::uint64_t indent_level ): + m_os{ os }, m_indent_level{ indent_level } {} + + JsonObjectWriter JsonValueWriter::writeObject() && { + return JsonObjectWriter{ m_os, m_indent_level }; + } + + JsonArrayWriter JsonValueWriter::writeArray() && { + return JsonArrayWriter{ m_os, m_indent_level }; + } + + void JsonValueWriter::write( Catch::StringRef value ) && { + writeImpl( value, true ); + } + + void JsonValueWriter::write( bool value ) && { + writeImpl( value ? "true"_sr : "false"_sr, false ); + } + + void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) { + if ( quote ) { m_os << '"'; } + for (char c : value) { + // Escape list taken from https://www.json.org/json-en.html, + // string definition. + // Note that while forward slash _can_ be escaped, it does + // not have to be, if JSON is not further embedded somewhere + // where forward slash is meaningful. + if ( c == '"' ) { + m_os << "\\\""; + } else if ( c == '\\' ) { + m_os << "\\\\"; + } else if ( c == '\b' ) { + m_os << "\\b"; + } else if ( c == '\f' ) { + m_os << "\\f"; + } else if ( c == '\n' ) { + m_os << "\\n"; + } else if ( c == '\r' ) { + m_os << "\\r"; + } else if ( c == '\t' ) { + m_os << "\\t"; + } else { + m_os << c; + } + } + if ( quote ) { m_os << '"'; } + } + +} // namespace Catch + + + namespace Catch { @@ -4206,7 +4630,7 @@ namespace Catch { #else // ^^ Windows crt debug heap enabled // Windows crt debug heap disabled vv - Catch::LeakDetector::LeakDetector() {} + Catch::LeakDetector::LeakDetector() = default; #endif // CATCH_CONFIG_WINDOWS_CRTDBG @@ -4252,7 +4676,7 @@ namespace Catch { void listReporters(IEventListener& reporter) { std::vector descriptions; - IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + auto const& factories = getRegistryHub().getReporterRegistry().getFactories(); descriptions.reserve(factories.size()); for (auto const& fac : factories) { descriptions.push_back({ fac.first, fac.second->getDescription() }); @@ -4509,8 +4933,8 @@ namespace Catch { - #include +#include namespace Catch { @@ -4538,11 +4962,14 @@ namespace Catch { return {}; } return static_cast(ret); - } CATCH_CATCH_ANON( std::exception const& ) { - // There was a larger issue with the input, e.g. the parsed - // number would be too large to fit within ull. - return {}; } + CATCH_CATCH_ANON( std::invalid_argument const& ) { + // no conversion could be performed + } + CATCH_CATCH_ANON( std::out_of_range const& ) { + // the input does not fit into an unsigned long long + } + return {}; } } // namespace Catch @@ -4571,6 +4998,14 @@ namespace Catch { } #endif +#if !defined( CATCH_CONFIG_GLOBAL_NEXTAFTER ) + float nextafter( float x, float y ) { return std::nextafter( x, y ); } + double nextafter( double x, double y ) { return std::nextafter( x, y ); } +#else + float nextafter( float x, float y ) { return ::nextafterf( x, y ); } + double nextafter( double x, double y ) { return ::nextafter( x, y ); } +#endif + } // end namespace Catch @@ -4652,10 +5087,10 @@ namespace Catch { return static_cast( std::time( nullptr ) ); case GenerateFrom::Default: - case GenerateFrom::RandomDevice: - // In theory, a platform could have random_device that returns just - // 16 bits. That is still some randomness, so we don't care too much - return static_cast( std::random_device{}() ); + case GenerateFrom::RandomDevice: { + std::random_device rd; + return Detail::fillBitsFrom( rd ); + } default: CATCH_ERROR("Unknown generation method"); @@ -4668,49 +5103,73 @@ namespace Catch { namespace Catch { + struct ReporterRegistry::ReporterRegistryImpl { + std::vector> listeners; + std::map + factories; + }; - ReporterRegistry::ReporterRegistry() { + ReporterRegistry::ReporterRegistry(): + m_impl( Detail::make_unique() ) { // Because it is impossible to move out of initializer list, // we have to add the elements manually - m_factories["Automake"] = Detail::make_unique>(); - m_factories["compact"] = Detail::make_unique>(); - m_factories["console"] = Detail::make_unique>(); - m_factories["JUnit"] = Detail::make_unique>(); - m_factories["SonarQube"] = Detail::make_unique>(); - m_factories["TAP"] = Detail::make_unique>(); - m_factories["TeamCity"] = Detail::make_unique>(); - m_factories["XML"] = Detail::make_unique>(); + m_impl->factories["Automake"] = + Detail::make_unique>(); + m_impl->factories["compact"] = + Detail::make_unique>(); + m_impl->factories["console"] = + Detail::make_unique>(); + m_impl->factories["JUnit"] = + Detail::make_unique>(); + m_impl->factories["SonarQube"] = + Detail::make_unique>(); + m_impl->factories["TAP"] = + Detail::make_unique>(); + m_impl->factories["TeamCity"] = + Detail::make_unique>(); + m_impl->factories["XML"] = + Detail::make_unique>(); + m_impl->factories["JSON"] = + Detail::make_unique>(); } ReporterRegistry::~ReporterRegistry() = default; - - IEventListenerPtr ReporterRegistry::create( std::string const& name, ReporterConfig&& config ) const { - auto it = m_factories.find( name ); - if( it == m_factories.end() ) - return nullptr; - return it->second->create( CATCH_MOVE(config) ); + IEventListenerPtr + ReporterRegistry::create( std::string const& name, + ReporterConfig&& config ) const { + auto it = m_impl->factories.find( name ); + if ( it == m_impl->factories.end() ) return nullptr; + return it->second->create( CATCH_MOVE( config ) ); } - void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr factory ) { + void ReporterRegistry::registerReporter( std::string const& name, + IReporterFactoryPtr factory ) { CATCH_ENFORCE( name.find( "::" ) == name.npos, - "'::' is not allowed in reporter name: '" + name + '\'' ); - auto ret = m_factories.emplace(name, CATCH_MOVE(factory)); - CATCH_ENFORCE( ret.second, "reporter using '" + name + "' as name was already registered" ); + "'::' is not allowed in reporter name: '" + name + + '\'' ); + auto ret = m_impl->factories.emplace( name, CATCH_MOVE( factory ) ); + CATCH_ENFORCE( ret.second, + "reporter using '" + name + + "' as name was already registered" ); } void ReporterRegistry::registerListener( Detail::unique_ptr factory ) { - m_listeners.push_back( CATCH_MOVE(factory) ); + m_impl->listeners.push_back( CATCH_MOVE( factory ) ); } - IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { - return m_factories; - } - IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { - return m_listeners; + std::map const& + ReporterRegistry::getFactories() const { + return m_impl->factories; } -} + std::vector> const& + ReporterRegistry::getListeners() const { + return m_impl->listeners; + } +} // namespace Catch @@ -4726,9 +5185,9 @@ namespace Catch { }; kvPair splitKVPair(StringRef kvString) { - auto splitPos = static_cast( std::distance( - kvString.begin(), - std::find( kvString.begin(), kvString.end(), '=' ) ) ); + auto splitPos = static_cast( + std::find( kvString.begin(), kvString.end(), '=' ) - + kvString.begin() ); return { kvString.substr( 0, splitPos ), kvString.substr( splitPos + 1, kvString.size() ) }; @@ -4960,149 +5419,152 @@ namespace Catch { namespace Catch { namespace Generators { - struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { - GeneratorBasePtr m_generator; + namespace { + struct GeneratorTracker final : TestCaseTracking::TrackerBase, + IGeneratorTracker { + GeneratorBasePtr m_generator; - GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( nameAndLocation, ctx, parent ) - {} - ~GeneratorTracker() override; + GeneratorTracker( + TestCaseTracking::NameAndLocation&& nameAndLocation, + TrackerContext& ctx, + ITracker* parent ): + TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ) {} + ~GeneratorTracker() override = default; - static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { - GeneratorTracker* tracker; + static GeneratorTracker* + acquire( TrackerContext& ctx, + TestCaseTracking::NameAndLocationRef const& + nameAndLocation ) { + GeneratorTracker* tracker; - ITracker& currentTracker = ctx.currentTracker(); - // Under specific circumstances, the generator we want - // to acquire is also the current tracker. If this is - // the case, we have to avoid looking through current - // tracker's children, and instead return the current - // tracker. - // A case where this check is important is e.g. - // for (int i = 0; i < 5; ++i) { - // int n = GENERATE(1, 2); - // } - // - // without it, the code above creates 5 nested generators. - if ( currentTracker.nameAndLocation() == nameAndLocation ) { - auto thisTracker = - currentTracker.parent()->findChild( nameAndLocation ); - assert( thisTracker ); - assert( thisTracker->isGeneratorTracker() ); - tracker = static_cast( thisTracker ); - } else if ( ITracker* childTracker = - currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isGeneratorTracker() ); - tracker = static_cast( childTracker ); - } else { - auto newTracker = - Catch::Detail::make_unique( - nameAndLocation, ctx, ¤tTracker ); - tracker = newTracker.get(); - currentTracker.addChild( CATCH_MOVE(newTracker) ); + ITracker& currentTracker = ctx.currentTracker(); + // Under specific circumstances, the generator we want + // to acquire is also the current tracker. If this is + // the case, we have to avoid looking through current + // tracker's children, and instead return the current + // tracker. + // A case where this check is important is e.g. + // for (int i = 0; i < 5; ++i) { + // int n = GENERATE(1, 2); + // } + // + // without it, the code above creates 5 nested generators. + if ( currentTracker.nameAndLocation() == nameAndLocation ) { + auto thisTracker = currentTracker.parent()->findChild( + nameAndLocation ); + assert( thisTracker ); + assert( thisTracker->isGeneratorTracker() ); + tracker = static_cast( thisTracker ); + } else if ( ITracker* childTracker = + currentTracker.findChild( + nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isGeneratorTracker() ); + tracker = + static_cast( childTracker ); + } else { + return nullptr; + } + + if ( !tracker->isComplete() ) { tracker->open(); } + + return tracker; } - if( !tracker->isComplete() ) { - tracker->open(); + // TrackerBase interface + bool isGeneratorTracker() const override { return true; } + auto hasGenerator() const -> bool override { + return !!m_generator; } - - return *tracker; - } - - // TrackerBase interface - bool isGeneratorTracker() const override { return true; } - auto hasGenerator() const -> bool override { - return !!m_generator; - } - void close() override { - TrackerBase::close(); - // If a generator has a child (it is followed by a section) - // and none of its children have started, then we must wait - // until later to start consuming its values. - // This catches cases where `GENERATE` is placed between two - // `SECTION`s. - // **The check for m_children.empty cannot be removed**. - // doing so would break `GENERATE` _not_ followed by `SECTION`s. - const bool should_wait_for_child = [&]() { - // No children -> nobody to wait for - if ( m_children.empty() ) { - return false; - } - // If at least one child started executing, don't wait - if ( std::find_if( - m_children.begin(), - m_children.end(), - []( TestCaseTracking::ITrackerPtr const& tracker ) { - return tracker->hasStarted(); - } ) != m_children.end() ) { - return false; - } - - // No children have started. We need to check if they _can_ - // start, and thus we should wait for them, or they cannot - // start (due to filters), and we shouldn't wait for them - ITracker* parent = m_parent; - // This is safe: there is always at least one section - // tracker in a test case tracking tree - while ( !parent->isSectionTracker() ) { - parent = parent->parent(); - } - assert( parent && - "Missing root (test case) level section" ); - - auto const& parentSection = - static_cast( *parent ); - auto const& filters = parentSection.getFilters(); - // No filters -> no restrictions on running sections - if ( filters.empty() ) { - return true; - } - - for ( auto const& child : m_children ) { - if ( child->isSectionTracker() && - std::find( - filters.begin(), - filters.end(), - static_cast( *child ) - .trimmedName() ) != filters.end() ) { - return true; + void close() override { + TrackerBase::close(); + // If a generator has a child (it is followed by a section) + // and none of its children have started, then we must wait + // until later to start consuming its values. + // This catches cases where `GENERATE` is placed between two + // `SECTION`s. + // **The check for m_children.empty cannot be removed**. + // doing so would break `GENERATE` _not_ followed by + // `SECTION`s. + const bool should_wait_for_child = [&]() { + // No children -> nobody to wait for + if ( m_children.empty() ) { return false; } + // If at least one child started executing, don't wait + if ( std::find_if( + m_children.begin(), + m_children.end(), + []( TestCaseTracking::ITrackerPtr const& + tracker ) { + return tracker->hasStarted(); + } ) != m_children.end() ) { + return false; } + + // No children have started. We need to check if they + // _can_ start, and thus we should wait for them, or + // they cannot start (due to filters), and we shouldn't + // wait for them + ITracker* parent = m_parent; + // This is safe: there is always at least one section + // tracker in a test case tracking tree + while ( !parent->isSectionTracker() ) { + parent = parent->parent(); + } + assert( parent && + "Missing root (test case) level section" ); + + auto const& parentSection = + static_cast( *parent ); + auto const& filters = parentSection.getFilters(); + // No filters -> no restrictions on running sections + if ( filters.empty() ) { return true; } + + for ( auto const& child : m_children ) { + if ( child->isSectionTracker() && + std::find( filters.begin(), + filters.end(), + static_cast( + *child ) + .trimmedName() ) != + filters.end() ) { + return true; + } + } + return false; + }(); + + // This check is a bit tricky, because m_generator->next() + // has a side-effect, where it consumes generator's current + // value, but we do not want to invoke the side-effect if + // this generator is still waiting for any child to start. + assert( m_generator && "Tracker without generator" ); + if ( should_wait_for_child || + ( m_runState == CompletedSuccessfully && + m_generator->countedNext() ) ) { + m_children.clear(); + m_runState = Executing; } - return false; - }(); - - // This check is a bit tricky, because m_generator->next() - // has a side-effect, where it consumes generator's current - // value, but we do not want to invoke the side-effect if - // this generator is still waiting for any child to start. - if ( should_wait_for_child || - ( m_runState == CompletedSuccessfully && - m_generator->countedNext() ) ) { - m_children.clear(); - m_runState = Executing; } - } - // IGeneratorTracker interface - auto getGenerator() const -> GeneratorBasePtr const& override { - return m_generator; - } - void setGenerator( GeneratorBasePtr&& generator ) override { - m_generator = CATCH_MOVE( generator ); - } - }; - GeneratorTracker::~GeneratorTracker() = default; + // IGeneratorTracker interface + auto getGenerator() const -> GeneratorBasePtr const& override { + return m_generator; + } + void setGenerator( GeneratorBasePtr&& generator ) override { + m_generator = CATCH_MOVE( generator ); + } + }; + } // namespace } RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter) : m_runInfo(_config->name()), - m_context(getCurrentMutableContext()), m_config(_config), m_reporter(CATCH_MOVE(reporter)), m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) { - m_context.setResultCapture(this); + getCurrentMutableContext().setResultCapture( this ); m_reporter->testRunStarting(m_runInfo); } @@ -5113,13 +5575,8 @@ namespace Catch { Totals RunContext::runTest(TestCaseHandle const& testCase) { const Totals prevTotals = m_totals; - std::string redirectedCout; - std::string redirectedCerr; - auto const& testInfo = testCase.getTestCaseInfo(); - m_reporter->testCaseStarting(testInfo); - m_activeTestCase = &testCase; @@ -5161,9 +5618,11 @@ namespace Catch { seedRng( *m_config ); uint64_t testRuns = 0; + std::string redirectedCout; + std::string redirectedCerr; do { m_trackerContext.startCycle(); - m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); + m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo)); m_reporter->testCasePartialStarting(testInfo, testRuns); @@ -5174,7 +5633,7 @@ namespace Catch { redirectedCerr += oneRunCerr; const auto singleRunTotals = m_totals.delta(beforeRunTotals); - auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, oneRunCout, oneRunCerr, aborting()); + auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting()); m_reporter->testCasePartialEnded(statsForOneRun, testRuns); ++testRuns; @@ -5189,8 +5648,8 @@ namespace Catch { m_totals.testCases += deltaTotals.testCases; m_reporter->testCaseEnded(TestCaseStats(testInfo, deltaTotals, - redirectedCout, - redirectedCerr, + CATCH_MOVE(redirectedCout), + CATCH_MOVE(redirectedCerr), aborting())); m_activeTestCase = nullptr; @@ -5200,10 +5659,13 @@ namespace Catch { } - void RunContext::assertionEnded(AssertionResult const & result) { + void RunContext::assertionEnded(AssertionResult&& result) { if (result.getResultType() == ResultWas::Ok) { m_totals.assertions.passed++; m_lastAssertionPassed = true; + } else if (result.getResultType() == ResultWas::ExplicitSkip) { + m_totals.assertions.skipped++; + m_lastAssertionPassed = true; } else if (!result.succeeded()) { m_lastAssertionPassed = false; if (result.isOk()) { @@ -5219,24 +5681,37 @@ namespace Catch { m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)); - if (result.getResultType() != ResultWas::Warning) + if ( result.getResultType() != ResultWas::Warning ) { m_messageScopes.clear(); + } - // Reset working state - resetAssertionInfo(); - m_lastResult = result; + // Reset working state. assertion info will be reset after + // populateReaction is run if it is needed + m_lastResult = CATCH_MOVE( result ); } void RunContext::resetAssertionInfo() { m_lastAssertionInfo.macroName = StringRef(); m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; + m_lastAssertionInfo.resultDisposition = ResultDisposition::Normal; } - bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { - ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); + void RunContext::notifyAssertionStarted( AssertionInfo const& info ) { + m_reporter->assertionStarting( info ); + } + + bool RunContext::sectionStarted( StringRef sectionName, + SourceLineInfo const& sectionLineInfo, + Counts& assertions ) { + ITracker& sectionTracker = + SectionTracker::acquire( m_trackerContext, + TestCaseTracking::NameAndLocationRef( + sectionName, sectionLineInfo ) ); + if (!sectionTracker.isOpen()) return false; m_activeSections.push_back(§ionTracker); + SectionInfo sectionInfo( sectionLineInfo, static_cast(sectionName) ); m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; m_reporter->sectionStarting(sectionInfo); @@ -5245,14 +5720,39 @@ namespace Catch { return true; } - auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + IGeneratorTracker* + RunContext::acquireGeneratorTracker( StringRef generatorName, + SourceLineInfo const& lineInfo ) { using namespace Generators; - GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext, - TestCaseTracking::NameAndLocation( static_cast(generatorName), lineInfo ) ); + GeneratorTracker* tracker = GeneratorTracker::acquire( + m_trackerContext, + TestCaseTracking::NameAndLocationRef( + generatorName, lineInfo ) ); m_lastAssertionInfo.lineInfo = lineInfo; return tracker; } + IGeneratorTracker* RunContext::createGeneratorTracker( + StringRef generatorName, + SourceLineInfo lineInfo, + Generators::GeneratorBasePtr&& generator ) { + + auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast( generatorName ), lineInfo ); + auto& currentTracker = m_trackerContext.currentTracker(); + assert( + currentTracker.nameAndLocation() != nameAndLoc && + "Trying to create tracker for a genreator that already has one" ); + + auto newTracker = Catch::Detail::make_unique( + CATCH_MOVE(nameAndLoc), m_trackerContext, ¤tTracker ); + auto ret = newTracker.get(); + currentTracker.addChild( CATCH_MOVE( newTracker ) ); + + ret->setGenerator( CATCH_MOVE( generator ) ); + ret->open(); + return ret; + } + bool RunContext::testForMissingAssertions(Counts& assertions) { if (assertions.total() != 0) return false; @@ -5265,7 +5765,7 @@ namespace Catch { return true; } - void RunContext::sectionEnded(SectionEndInfo const & endInfo) { + void RunContext::sectionEnded(SectionEndInfo&& endInfo) { Counts assertions = m_totals.assertions - endInfo.prevAssertions; bool missingAssertions = testForMissingAssertions(assertions); @@ -5274,19 +5774,20 @@ namespace Catch { m_activeSections.pop_back(); } - m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); + m_reporter->sectionEnded(SectionStats(CATCH_MOVE(endInfo.sectionInfo), assertions, endInfo.durationInSeconds, missingAssertions)); m_messages.clear(); m_messageScopes.clear(); } - void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { - if (m_unfinishedSections.empty()) + void RunContext::sectionEndedEarly(SectionEndInfo&& endInfo) { + if ( m_unfinishedSections.empty() ) { m_activeSections.back()->fail(); - else + } else { m_activeSections.back()->close(); + } m_activeSections.pop_back(); - m_unfinishedSections.push_back(endInfo); + m_unfinishedSections.push_back(CATCH_MOVE(endInfo)); } void RunContext::benchmarkPreparing( StringRef name ) { @@ -5310,8 +5811,8 @@ namespace Catch { m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); } - void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) { - m_messageScopes.emplace_back( builder ); + void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) { + m_messageScopes.emplace_back( CATCH_MOVE(builder) ); } std::string RunContext::getCurrentTestName() const { @@ -5336,9 +5837,10 @@ namespace Catch { // Instead, fake a result data. AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); tempResult.message = static_cast(message); - AssertionResult result(m_lastAssertionInfo, tempResult); + AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult)); - assertionEnded(result); + assertionEnded(CATCH_MOVE(result) ); + resetAssertionInfo(); handleUnfinishedSections(); @@ -5348,7 +5850,7 @@ namespace Catch { Counts assertions; assertions.failed = 1; - SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); + SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, false); m_reporter->sectionEnded(testCaseSectionStats); auto const& testInfo = m_activeTestCase->getTestCaseInfo(); @@ -5409,6 +5911,8 @@ namespace Catch { duration = timer.getElapsedSeconds(); } CATCH_CATCH_ANON (TestFailureException&) { // This just means the test was aborted due to failure + } CATCH_CATCH_ANON (TestSkipException&) { + // This just means the test was explicitly skipped } CATCH_CATCH_ALL { // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions // are reported without translation at the point of origin. @@ -5425,7 +5929,7 @@ namespace Catch { m_messages.clear(); m_messageScopes.clear(); - SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); + SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions); m_reporter->sectionEnded(testCaseSectionStats); } @@ -5449,7 +5953,7 @@ namespace Catch { itEnd = m_unfinishedSections.rend(); it != itEnd; ++it) - sectionEnded(*it); + sectionEnded(CATCH_MOVE(*it)); m_unfinishedSections.clear(); } @@ -5458,8 +5962,6 @@ namespace Catch { ITransientExpression const& expr, AssertionReaction& reaction ) { - m_reporter->assertionStarting( info ); - bool negated = isFalseTest( info.resultDisposition ); bool result = expr.getResult() != negated; @@ -5475,6 +5977,7 @@ namespace Catch { reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); populateReaction( reaction ); } + resetAssertionInfo(); } void RunContext::reportExpr( AssertionInfo const &info, @@ -5485,10 +5988,10 @@ namespace Catch { m_lastAssertionInfo = info; AssertionResultData data( resultType, LazyExpression( negated ) ); - AssertionResult assertionResult{ info, data }; + AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; - assertionEnded( assertionResult ); + assertionEnded( CATCH_MOVE(assertionResult) ); } void RunContext::handleMessage( @@ -5497,16 +6000,23 @@ namespace Catch { StringRef message, AssertionReaction& reaction ) { - m_reporter->assertionStarting( info ); - m_lastAssertionInfo = info; AssertionResultData data( resultType, LazyExpression( false ) ); data.message = static_cast(message); - AssertionResult assertionResult{ m_lastAssertionInfo, data }; - assertionEnded( assertionResult ); - if( !assertionResult.isOk() ) + AssertionResult assertionResult{ m_lastAssertionInfo, + CATCH_MOVE( data ) }; + + const auto isOk = assertionResult.isOk(); + assertionEnded( CATCH_MOVE(assertionResult) ); + if ( !isOk ) { populateReaction( reaction ); + } else if ( resultType == ResultWas::ExplicitSkip ) { + // TODO: Need to handle this explicitly, as ExplicitSkip is + // considered "OK" + reaction.shouldSkip = true; + } + resetAssertionInfo(); } void RunContext::handleUnexpectedExceptionNotThrown( AssertionInfo const& info, @@ -5517,16 +6027,17 @@ namespace Catch { void RunContext::handleUnexpectedInflightException( AssertionInfo const& info, - std::string const& message, + std::string&& message, AssertionReaction& reaction ) { m_lastAssertionInfo = info; AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); - data.message = message; - AssertionResult assertionResult{ info, data }; - assertionEnded( assertionResult ); + data.message = CATCH_MOVE(message); + AssertionResult assertionResult{ info, CATCH_MOVE(data) }; + assertionEnded( CATCH_MOVE(assertionResult) ); populateReaction( reaction ); + resetAssertionInfo(); } void RunContext::populateReaction( AssertionReaction& reaction ) { @@ -5537,12 +6048,14 @@ namespace Catch { void RunContext::handleIncomplete( AssertionInfo const& info ) { + using namespace std::string_literals; m_lastAssertionInfo = info; AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); - data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; - AssertionResult assertionResult{ info, data }; - assertionEnded( assertionResult ); + data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s; + AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; + assertionEnded( CATCH_MOVE(assertionResult) ); + resetAssertionInfo(); } void RunContext::handleNonExpr( AssertionInfo const &info, @@ -5552,11 +6065,12 @@ namespace Catch { m_lastAssertionInfo = info; AssertionResultData data( resultType, LazyExpression( false ) ); - AssertionResult assertionResult{ info, data }; - assertionEnded( assertionResult ); + AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; - if( !assertionResult.isOk() ) - populateReaction( reaction ); + const auto isOk = assertionResult.isOk(); + assertionEnded( CATCH_MOVE(assertionResult) ); + if ( !isOk ) { populateReaction( reaction ); } + resetAssertionInfo(); } @@ -5584,7 +6098,7 @@ namespace Catch { Section::Section( SectionInfo&& info ): m_info( CATCH_MOVE( info ) ), m_sectionIncluded( - getResultCapture().sectionStarted( m_info, m_assertions ) ) { + getResultCapture().sectionStarted( m_info.name, m_info.lineInfo, m_assertions ) ) { // Non-"included" sections will not use the timing information // anyway, so don't bother with the potential syscall. if (m_sectionIncluded) { @@ -5592,13 +6106,31 @@ namespace Catch { } } + Section::Section( SourceLineInfo const& _lineInfo, + StringRef _name, + const char* const ): + m_info( { "invalid", static_cast( -1 ) }, std::string{} ), + m_sectionIncluded( + getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) { + // We delay initialization the SectionInfo member until we know + // this section needs it, so we avoid allocating std::string for name. + // We also delay timer start to avoid the potential syscall unless we + // will actually use the result. + if ( m_sectionIncluded ) { + m_info.name = static_cast( _name ); + m_info.lineInfo = _lineInfo; + m_timer.start(); + } + } + Section::~Section() { if( m_sectionIncluded ) { - SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; - if( uncaught_exceptions() ) - getResultCapture().sectionEndedEarly( endInfo ); - else - getResultCapture().sectionEnded( endInfo ); + SectionEndInfo endInfo{ CATCH_MOVE(m_info), m_assertions, m_timer.getElapsedSeconds() }; + if ( uncaught_exceptions() ) { + getResultCapture().sectionEndedEarly( CATCH_MOVE(endInfo) ); + } else { + getResultCapture().sectionEnded( CATCH_MOVE( endInfo ) ); + } } } @@ -5707,7 +6239,6 @@ namespace Catch { -#include #include #include #include @@ -5731,9 +6262,9 @@ namespace Catch { return s.find( infix ) != std::string::npos; } void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), []( char c ) { - return toLower( c ); - } ); + for ( char& c : s ) { + c = toLower( c ); + } } std::string toLower( std::string const& s ) { std::string lc = s; @@ -5814,10 +6345,6 @@ namespace Catch { : StringRef( rawChars, std::strlen(rawChars) ) {} - auto StringRef::operator == ( StringRef other ) const noexcept -> bool { - return m_size == other.m_size - && (std::memcmp( m_start, other.m_start, m_size ) == 0); - } bool StringRef::operator<(StringRef rhs) const noexcept { if (m_size < rhs.m_size) { @@ -5870,7 +6397,7 @@ namespace Catch { namespace Catch { - TagAliasRegistry::~TagAliasRegistry() {} + TagAliasRegistry::~TagAliasRegistry() = default; TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { auto it = m_registry.find( alias ); @@ -5951,6 +6478,38 @@ namespace Catch { namespace Catch { + namespace { + static void enforceNoDuplicateTestCases( + std::vector const& tests ) { + auto testInfoCmp = []( TestCaseInfo const* lhs, + TestCaseInfo const* rhs ) { + return *lhs < *rhs; + }; + std::set seenTests( + testInfoCmp ); + for ( auto const& test : tests ) { + const auto infoPtr = &test.getTestCaseInfo(); + const auto prev = seenTests.insert( infoPtr ); + CATCH_ENFORCE( prev.second, + "error: test case \"" + << infoPtr->name << "\", with tags \"" + << infoPtr->tagsAsString() + << "\" already defined.\n" + << "\tFirst seen at " + << ( *prev.first )->lineInfo << "\n" + << "\tRedefined at " << infoPtr->lineInfo ); + } + } + + static bool matchTest( TestCaseHandle const& testCase, + TestSpec const& testSpec, + IConfig const& config ) { + return testSpec.matches( testCase.getTestCaseInfo() ) && + isThrowSafe( testCase, config ); + } + + } // end unnamed namespace + std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { switch (config.runOrder()) { case TestRunOrder::Declared: @@ -6007,29 +6566,6 @@ namespace Catch { return !testCase.getTestCaseInfo().throws() || config.allowThrows(); } - bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ) { - return testSpec.matches( testCase.getTestCaseInfo() ) && isThrowSafe( testCase, config ); - } - - void - enforceNoDuplicateTestCases( std::vector const& tests ) { - auto testInfoCmp = []( TestCaseInfo const* lhs, - TestCaseInfo const* rhs ) { - return *lhs < *rhs; - }; - std::set seenTests(testInfoCmp); - for ( auto const& test : tests ) { - const auto infoPtr = &test.getTestCaseInfo(); - const auto prev = seenTests.insert( infoPtr ); - CATCH_ENFORCE( - prev.second, - "error: test case \"" << infoPtr->name << "\", with tags \"" - << infoPtr->tagsAsString() << "\" already defined.\n" - << "\tFirst seen at " << ( *prev.first )->lineInfo << "\n" - << "\tRedefined at " << infoPtr->lineInfo ); - } - } - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { std::vector filtered; filtered.reserve( testCases.size() ); @@ -6070,13 +6606,6 @@ namespace Catch { return m_sortedFunctions; } - - - /////////////////////////////////////////////////////////////////////////// - void TestInvokerAsFunction::invoke() const { - m_testAsFunction(); - } - } // end namespace Catch @@ -6093,8 +6622,8 @@ namespace Catch { namespace Catch { namespace TestCaseTracking { - NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) - : name( _name ), + NameAndLocation::NameAndLocation( std::string&& _name, SourceLineInfo const& _location ) + : name( CATCH_MOVE(_name) ), location( _location ) {} @@ -6109,14 +6638,17 @@ namespace TestCaseTracking { m_children.push_back( CATCH_MOVE(child) ); } - ITracker* ITracker::findChild( NameAndLocation const& nameAndLocation ) { + ITracker* ITracker::findChild( NameAndLocationRef const& nameAndLocation ) { auto it = std::find_if( m_children.begin(), m_children.end(), [&nameAndLocation]( ITrackerPtr const& tracker ) { - return tracker->nameAndLocation().location == - nameAndLocation.location && - tracker->nameAndLocation().name == nameAndLocation.name; + auto const& tnameAndLoc = tracker->nameAndLocation(); + if ( tnameAndLoc.location.line != + nameAndLocation.location.line ) { + return false; + } + return tnameAndLoc == nameAndLocation; } ); return ( it != m_children.end() ) ? it->get() : nullptr; } @@ -6124,10 +6656,6 @@ namespace TestCaseTracking { bool ITracker::isSectionTracker() const { return false; } bool ITracker::isGeneratorTracker() const { return false; } - bool ITracker::isSuccessfullyCompleted() const { - return m_runState == CompletedSuccessfully; - } - bool ITracker::isOpen() const { return m_runState != NotStarted && !isComplete(); } @@ -6154,16 +6682,6 @@ namespace TestCaseTracking { return *m_rootTracker; } - void TrackerContext::endRun() { - m_rootTracker.reset(); - m_currentTracker = nullptr; - m_runState = NotStarted; - } - - void TrackerContext::startCycle() { - m_currentTracker = m_rootTracker.get(); - m_runState = Executing; - } void TrackerContext::completeCycle() { m_runState = CompletedCycle; } @@ -6171,16 +6689,13 @@ namespace TestCaseTracking { bool TrackerContext::completedCycle() const { return m_runState == CompletedCycle; } - ITracker& TrackerContext::currentTracker() { - return *m_currentTracker; - } void TrackerContext::setCurrentTracker( ITracker* tracker ) { m_currentTracker = tracker; } - TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ): - ITracker(nameAndLocation, parent), + TrackerBase::TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ): + ITracker(CATCH_MOVE(nameAndLocation), parent), m_ctx( ctx ) {} @@ -6240,13 +6755,14 @@ namespace TestCaseTracking { m_ctx.setCurrentTracker( this ); } - SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( nameAndLocation, ctx, parent ), - m_trimmed_name(trim(nameAndLocation.name)) + SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ), + m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name))) { if( parent ) { - while( !parent->isSectionTracker() ) + while ( !parent->isSectionTracker() ) { parent = parent->parent(); + } SectionTracker& parentSection = static_cast( *parent ); addNextFilters( parentSection.m_filters ); @@ -6266,24 +6782,30 @@ namespace TestCaseTracking { bool SectionTracker::isSectionTracker() const { return true; } - SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { - SectionTracker* section; + SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ) { + SectionTracker* tracker; ITracker& currentTracker = ctx.currentTracker(); if ( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isSectionTracker() ); - section = static_cast( childTracker ); + tracker = static_cast( childTracker ); } else { - auto newSection = Catch::Detail::make_unique( - nameAndLocation, ctx, ¤tTracker ); - section = newSection.get(); - currentTracker.addChild( CATCH_MOVE( newSection ) ); + auto newTracker = Catch::Detail::make_unique( + NameAndLocation{ static_cast(nameAndLocation.name), + nameAndLocation.location }, + ctx, + ¤tTracker ); + tracker = newTracker.get(); + currentTracker.addChild( CATCH_MOVE( newTracker ) ); } - if( !ctx.completedCycle() ) - section->tryOpen(); - return *section; + + if ( !ctx.completedCycle() ) { + tracker->tryOpen(); + } + + return *tracker; } void SectionTracker::tryOpen() { @@ -6304,10 +6826,6 @@ namespace TestCaseTracking { m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); } - std::vector const& SectionTracker::getFilters() const { - return m_filters; - } - StringRef SectionTracker::trimmedName() const { return m_trimmed_name; } @@ -6333,6 +6851,14 @@ namespace Catch { #endif } + void throw_test_skip_exception() { +#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) + throw Catch::TestSkipException(); +#else + CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" ); +#endif + } + } // namespace Catch @@ -6341,9 +6867,10 @@ namespace Catch { #include namespace Catch { + ITestInvoker::~ITestInvoker() = default; namespace { - StringRef extractClassName( StringRef classOrMethodName ) { + static StringRef extractClassName( StringRef classOrMethodName ) { if ( !startsWith( classOrMethodName, '&' ) ) { return classOrMethodName; } @@ -6370,6 +6897,18 @@ namespace Catch { static_cast( startIdx ), static_cast( classNameSize ) ); } + + class TestInvokerAsFunction final : public ITestInvoker { + using TestType = void ( * )(); + TestType m_testAsFunction; + + public: + TestInvokerAsFunction( TestType testAsFunction ) noexcept: + m_testAsFunction( testAsFunction ) {} + + void invoke() const override { m_testAsFunction(); } + }; + } // namespace Detail::unique_ptr makeTestInvoker( void(*testAsFunction)() ) { @@ -6606,10 +7145,8 @@ namespace Catch { token.erase(token.begin()); if (m_exclusion) { m_currentFilter.m_forbidden.emplace_back(Detail::make_unique(".", m_substring)); - m_currentFilter.m_forbidden.emplace_back(Detail::make_unique(token, m_substring)); } else { m_currentFilter.m_required.emplace_back(Detail::make_unique(".", m_substring)); - m_currentFilter.m_required.emplace_back(Detail::make_unique(token, m_substring)); } } if (m_exclusion) { @@ -6935,6 +7472,7 @@ namespace Catch { // while in /permissive- mode. No, I don't know why. // Tested on VS 2019, 18.{3, 4}.x +#include #include #include @@ -7364,26 +7902,11 @@ namespace { return ulpDist <= maxUlpDiff; } -#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) - - float nextafter(float x, float y) { - return ::nextafterf(x, y); - } - - double nextafter(double x, double y) { - return ::nextafter(x, y); - } - -#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^ template FP step(FP start, FP direction, uint64_t steps) { for (uint64_t i = 0; i < steps; ++i) { -#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) start = Catch::nextafter(start, direction); -#else - start = std::nextafter(start, direction); -#endif } return start; } @@ -7551,7 +8074,19 @@ WithinRelMatcher WithinRel(float target) { } -} // namespace Matchers + +bool IsNaNMatcher::match( double const& matchee ) const { + return std::isnan( matchee ); +} + +std::string IsNaNMatcher::describe() const { + using namespace std::string_literals; + return "is NaN"s; +} + +IsNaNMatcher IsNaN() { return IsNaNMatcher(); } + + } // namespace Matchers } // namespace Catch @@ -7745,12 +8280,14 @@ namespace Catch { namespace Catch { - AutomakeReporter::~AutomakeReporter() {} + AutomakeReporter::~AutomakeReporter() = default; void AutomakeReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR. m_stream << ":test-result: "; - if (_testCaseStats.totals.assertions.allPassed()) { + if ( _testCaseStats.totals.testCases.skipped > 0 ) { + m_stream << "SKIP"; + } else if (_testCaseStats.totals.assertions.allPassed()) { m_stream << "PASS"; } else if (_testCaseStats.totals.assertions.allOk()) { m_stream << "XFAIL"; @@ -7899,6 +8436,11 @@ public: printIssue("explicitly"); printRemainingMessages(Colour::None); break; + case ResultWas::ExplicitSkip: + printResultType(Colour::Skip, "skipped"_sr); + printMessage(); + printRemainingMessages(); + break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: @@ -7960,7 +8502,7 @@ private: return; const auto itEnd = messages.cend(); - const auto N = static_cast(std::distance(itMessage, itEnd)); + const auto N = static_cast(itEnd - itMessage); stream << colourImpl->guardColour( colour ) << " with " << pluralise( N, "message"_sr ) << ':'; @@ -7981,7 +8523,7 @@ private: private: std::ostream& stream; AssertionResult const& result; - std::vector messages; + std::vector const& messages; std::vector::const_iterator itMessage; bool printInfoMessages; ColourImpl* colourImpl; @@ -8014,7 +8556,7 @@ private: // Drop out if result was successful and we're not printing those if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) + if( result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip ) return; printInfoMessages = false; } @@ -8038,7 +8580,7 @@ private: StreamingReporterBase::testRunEnded( _testRunStats ); } - CompactReporter::~CompactReporter() {} + CompactReporter::~CompactReporter() = default; } // end namespace Catch @@ -8075,7 +8617,6 @@ public: stats(_stats), result(_stats.assertionResult), colour(Colour::None), - message(result.getMessage()), messages(_stats.infoMessages), colourImpl(colourImpl_), printInfoMessages(_printInfoMessages) { @@ -8084,10 +8625,10 @@ public: colour = Colour::Success; passOrFail = "PASSED"_sr; //if( result.hasMessage() ) - if (_stats.infoMessages.size() == 1) - messageLabel = "with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "with messages"; + if (messages.size() == 1) + messageLabel = "with message"_sr; + if (messages.size() > 1) + messageLabel = "with messages"_sr; break; case ResultWas::ExpressionFailed: if (result.isOk()) { @@ -8097,43 +8638,57 @@ public: colour = Colour::Error; passOrFail = "FAILED"_sr; } - if (_stats.infoMessages.size() == 1) - messageLabel = "with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "with messages"; + if (messages.size() == 1) + messageLabel = "with message"_sr; + if (messages.size() > 1) + messageLabel = "with messages"_sr; break; case ResultWas::ThrewException: colour = Colour::Error; passOrFail = "FAILED"_sr; - messageLabel = "due to unexpected exception with "; - if (_stats.infoMessages.size() == 1) - messageLabel += "message"; - if (_stats.infoMessages.size() > 1) - messageLabel += "messages"; + // todo switch + switch (messages.size()) { case 0: + messageLabel = "due to unexpected exception with "_sr; + break; + case 1: + messageLabel = "due to unexpected exception with message"_sr; + break; + default: + messageLabel = "due to unexpected exception with messages"_sr; + break; + } break; case ResultWas::FatalErrorCondition: colour = Colour::Error; passOrFail = "FAILED"_sr; - messageLabel = "due to a fatal error condition"; + messageLabel = "due to a fatal error condition"_sr; break; case ResultWas::DidntThrowException: colour = Colour::Error; passOrFail = "FAILED"_sr; - messageLabel = "because no exception was thrown where one was expected"; + messageLabel = "because no exception was thrown where one was expected"_sr; break; case ResultWas::Info: - messageLabel = "info"; + messageLabel = "info"_sr; break; case ResultWas::Warning: - messageLabel = "warning"; + messageLabel = "warning"_sr; break; case ResultWas::ExplicitFailure: passOrFail = "FAILED"_sr; colour = Colour::Error; - if (_stats.infoMessages.size() == 1) - messageLabel = "explicitly with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "explicitly with messages"; + if (messages.size() == 1) + messageLabel = "explicitly with message"_sr; + if (messages.size() > 1) + messageLabel = "explicitly with messages"_sr; + break; + case ResultWas::ExplicitSkip: + colour = Colour::Skip; + passOrFail = "SKIPPED"_sr; + if (messages.size() == 1) + messageLabel = "explicitly with message"_sr; + if (messages.size() > 1) + messageLabel = "explicitly with messages"_sr; break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: @@ -8197,9 +8752,8 @@ private: AssertionResult const& result; Colour::Code colour; StringRef passOrFail; - std::string messageLabel; - std::string message; - std::vector messages; + StringRef messageLabel; + std::vector const& messages; ColourImpl* colourImpl; bool printInfoMessages; }; @@ -8209,13 +8763,16 @@ std::size_t makeRatio( std::uint64_t number, std::uint64_t total ) { return (ratio == 0 && number > 0) ? 1 : static_cast(ratio); } -std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { - if (i > j && i > k) +std::size_t& +findMax( std::size_t& i, std::size_t& j, std::size_t& k, std::size_t& l ) { + if (i > j && i > k && i > l) return i; - else if (j > k) + else if (j > k && j > l) return j; - else + else if (k > l) return k; + else + return l; } enum class Justification { Left, Right }; @@ -8227,6 +8784,7 @@ struct ColumnInfo { }; struct ColumnBreak {}; struct RowBreak {}; +struct OutputFlush {}; class Duration { enum class Unit { @@ -8343,12 +8901,12 @@ public: } template - friend TablePrinter& operator << (TablePrinter& tp, T const& value) { + friend TablePrinter& operator<< (TablePrinter& tp, T const& value) { tp.m_oss << value; return tp; } - friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { + friend TablePrinter& operator<< (TablePrinter& tp, ColumnBreak) { auto colStr = tp.m_oss.str(); const auto strSize = colStr.size(); tp.m_oss.str(""); @@ -8370,13 +8928,18 @@ public: return tp; } - friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { + friend TablePrinter& operator<< (TablePrinter& tp, RowBreak) { if (tp.m_currentColumn > 0) { tp.m_os << '\n'; tp.m_currentColumn = -1; } return tp; } + + friend TablePrinter& operator<<(TablePrinter& tp, OutputFlush) { + tp.m_os << std::flush; + return tp; + } }; ConsoleReporter::ConsoleReporter(ReporterConfig&& config): @@ -8398,7 +8961,7 @@ ConsoleReporter::ConsoleReporter(ReporterConfig&& config): { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left }, { "samples mean std dev", 14, Justification::Right }, { "iterations low mean low std dev", 14, Justification::Right }, - { "estimated high mean high std dev", 14, Justification::Right } + { "est run time high mean high std dev", 14, Justification::Right } }; } }())) {} @@ -8424,7 +8987,8 @@ void ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); // Drop out if result was successful but we're not printing them. - if (!includeResults && result.getResultType() != ResultWas::Warning) + // TODO: Make configurable whether skips should be printed + if (!includeResults && result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip) return; lazyPrint(); @@ -8481,8 +9045,11 @@ void ConsoleReporter::benchmarkPreparing( StringRef name ) { void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { (*m_tablePrinter) << info.samples << ColumnBreak() << info.iterations << ColumnBreak(); - if (!m_config->benchmarkNoAnalysis()) - (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak(); + if ( !m_config->benchmarkNoAnalysis() ) { + ( *m_tablePrinter ) + << Duration( info.estimatedDuration ) << ColumnBreak(); + } + ( *m_tablePrinter ) << OutputFlush{}; } void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) { if (m_config->benchmarkNoAnalysis()) @@ -8627,10 +9194,11 @@ void ConsoleReporter::printTotalsDivider(Totals const& totals) { std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); - while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) - findMax(failedRatio, failedButOkRatio, passedRatio)++; + std::size_t skippedRatio = makeRatio(totals.testCases.skipped, totals.testCases.total()); + while (failedRatio + failedButOkRatio + passedRatio + skippedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)++; while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) - findMax(failedRatio, failedButOkRatio, passedRatio)--; + findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)--; m_stream << m_colour->guardColour( Colour::Error ) << std::string( failedRatio, '=' ) @@ -8643,6 +9211,8 @@ void ConsoleReporter::printTotalsDivider(Totals const& totals) { m_stream << m_colour->guardColour( Colour::Success ) << std::string( passedRatio, '=' ); } + m_stream << m_colour->guardColour( Colour::Skip ) + << std::string( skippedRatio, '=' ); } else { m_stream << m_colour->guardColour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH - 1, '=' ); @@ -8724,7 +9294,8 @@ namespace Catch { void CumulativeReporterBase::sectionStarting( SectionInfo const& sectionInfo ) { - SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + // We need a copy, because SectionStats expect to take ownership + SectionStats incompleteStats( SectionInfo(sectionInfo), Counts(), 0, false ); SectionNode* node; if ( m_sectionStack.empty() ) { if ( !m_rootSection ) { @@ -9147,15 +9718,22 @@ namespace Catch { } std::vector columns; + // Don't include "skipped assertions" in total count + const auto totalAssertionCount = + totals.assertions.total() - totals.assertions.skipped; columns.push_back( SummaryColumn( "", Colour::None ) .addRow( totals.testCases.total() ) - .addRow( totals.assertions.total() ) ); + .addRow( totalAssertionCount ) ); columns.push_back( SummaryColumn( "passed", Colour::Success ) .addRow( totals.testCases.passed ) .addRow( totals.assertions.passed ) ); columns.push_back( SummaryColumn( "failed", Colour::ResultError ) .addRow( totals.testCases.failed ) .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "skipped", Colour::Skip ) + .addRow( totals.testCases.skipped ) + // Don't print "skipped assertions" + .addRow( 0 ) ); columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) .addRow( totals.testCases.failedButOk ) @@ -9167,6 +9745,366 @@ namespace Catch { } // namespace Catch +// + +namespace Catch { + namespace { + void writeSourceInfo( JsonObjectWriter& writer, + SourceLineInfo const& sourceInfo ) { + auto source_location_writer = + writer.write( "source-location"_sr ).writeObject(); + source_location_writer.write( "filename"_sr ) + .write( sourceInfo.file ); + source_location_writer.write( "line"_sr ).write( sourceInfo.line ); + } + + void writeTags( JsonArrayWriter writer, std::vector const& tags ) { + for ( auto const& tag : tags ) { + writer.write( tag.original ); + } + } + + void writeProperties( JsonArrayWriter writer, + TestCaseInfo const& info ) { + if ( info.isHidden() ) { writer.write( "is-hidden"_sr ); } + if ( info.okToFail() ) { writer.write( "ok-to-fail"_sr ); } + if ( info.expectedToFail() ) { + writer.write( "expected-to-fail"_sr ); + } + if ( info.throws() ) { writer.write( "throws"_sr ); } + } + + } // namespace + + JsonReporter::JsonReporter( ReporterConfig&& config ): + StreamingReporterBase{ CATCH_MOVE( config ) } { + + m_preferences.shouldRedirectStdOut = true; + // TBD: Do we want to report all assertions? XML reporter does + // not, but for machine-parseable reporters I think the answer + // should be yes. + m_preferences.shouldReportAllAssertions = true; + + m_objectWriters.emplace( m_stream ); + m_writers.emplace( Writer::Object ); + auto& writer = m_objectWriters.top(); + + writer.write( "version"_sr ).write( 1 ); + + { + auto metadata_writer = writer.write( "metadata"_sr ).writeObject(); + metadata_writer.write( "name"_sr ).write( m_config->name() ); + metadata_writer.write( "rng-seed"_sr ).write( m_config->rngSeed() ); + metadata_writer.write( "catch2-version"_sr ) + .write( libraryVersion() ); + if ( m_config->testSpec().hasFilters() ) { + metadata_writer.write( "filters"_sr ) + .write( m_config->testSpec() ); + } + } + } + + JsonReporter::~JsonReporter() { + endListing(); + // TODO: Ensure this closes the top level object, add asserts + assert( m_writers.size() == 1 && "Only the top level object should be open" ); + assert( m_writers.top() == Writer::Object ); + endObject(); + m_stream << '\n' << std::flush; + assert( m_writers.empty() ); + } + + JsonArrayWriter& JsonReporter::startArray() { + m_arrayWriters.emplace( m_arrayWriters.top().writeArray() ); + m_writers.emplace( Writer::Array ); + return m_arrayWriters.top(); + } + JsonArrayWriter& JsonReporter::startArray( StringRef key ) { + m_arrayWriters.emplace( + m_objectWriters.top().write( key ).writeArray() ); + m_writers.emplace( Writer::Array ); + return m_arrayWriters.top(); + } + + JsonObjectWriter& JsonReporter::startObject() { + m_objectWriters.emplace( m_arrayWriters.top().writeObject() ); + m_writers.emplace( Writer::Object ); + return m_objectWriters.top(); + } + JsonObjectWriter& JsonReporter::startObject( StringRef key ) { + m_objectWriters.emplace( + m_objectWriters.top().write( key ).writeObject() ); + m_writers.emplace( Writer::Object ); + return m_objectWriters.top(); + } + + void JsonReporter::endObject() { + assert( isInside( Writer::Object ) ); + m_objectWriters.pop(); + m_writers.pop(); + } + void JsonReporter::endArray() { + assert( isInside( Writer::Array ) ); + m_arrayWriters.pop(); + m_writers.pop(); + } + + bool JsonReporter::isInside( Writer writer ) { + return !m_writers.empty() && m_writers.top() == writer; + } + + void JsonReporter::startListing() { + if ( !m_startedListing ) { startObject( "listings"_sr ); } + m_startedListing = true; + } + void JsonReporter::endListing() { + if ( m_startedListing ) { endObject(); } + m_startedListing = false; + } + + std::string JsonReporter::getDescription() { + return "Outputs listings as JSON. Test listing is Work-in-Progress!"; + } + + void JsonReporter::testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + endListing(); + + assert( isInside( Writer::Object ) ); + startObject( "test-run"_sr ); + startArray( "test-cases"_sr ); + } + + static void writeCounts( JsonObjectWriter&& writer, Counts const& counts ) { + writer.write( "passed"_sr ).write( counts.passed ); + writer.write( "failed"_sr ).write( counts.failed ); + writer.write( "fail-but-ok"_sr ).write( counts.failedButOk ); + writer.write( "skipped"_sr ).write( counts.skipped ); + } + + void JsonReporter::testRunEnded(TestRunStats const& runStats) { + assert( isInside( Writer::Array ) ); + // End "test-cases" + endArray(); + + { + auto totals = + m_objectWriters.top().write( "totals"_sr ).writeObject(); + writeCounts( totals.write( "assertions"_sr ).writeObject(), + runStats.totals.assertions ); + writeCounts( totals.write( "test-cases"_sr ).writeObject(), + runStats.totals.testCases ); + } + + // End the "test-run" object + endObject(); + } + + void JsonReporter::testCaseStarting( TestCaseInfo const& tcInfo ) { + StreamingReporterBase::testCaseStarting( tcInfo ); + + assert( isInside( Writer::Array ) && + "We should be in the 'test-cases' array" ); + startObject(); + // "test-info" prelude + { + auto testInfo = + m_objectWriters.top().write( "test-info"_sr ).writeObject(); + // TODO: handle testName vs className!! + testInfo.write( "name"_sr ).write( tcInfo.name ); + writeSourceInfo(testInfo, tcInfo.lineInfo); + writeTags( testInfo.write( "tags"_sr ).writeArray(), tcInfo.tags ); + writeProperties( testInfo.write( "properties"_sr ).writeArray(), + tcInfo ); + } + + + // Start the array for individual test runs (testCasePartial pairs) + startArray( "runs"_sr ); + } + + void JsonReporter::testCaseEnded( TestCaseStats const& tcStats ) { + StreamingReporterBase::testCaseEnded( tcStats ); + + // We need to close the 'runs' array before finishing the test case + assert( isInside( Writer::Array ) ); + endArray(); + + { + auto totals = + m_objectWriters.top().write( "totals"_sr ).writeObject(); + writeCounts( totals.write( "assertions"_sr ).writeObject(), + tcStats.totals.assertions ); + // We do not write the test case totals, because there will always be just one test case here. + // TODO: overall "result" -> success, skip, fail here? Or in partial result? + } + // We do not write out stderr/stdout, because we instead wrote those out in partial runs + + // TODO: aborting? + + // And we also close this test case's object + assert( isInside( Writer::Object ) ); + endObject(); + } + + void JsonReporter::testCasePartialStarting( TestCaseInfo const& /*tcInfo*/, + uint64_t index ) { + startObject(); + m_objectWriters.top().write( "run-idx"_sr ).write( index ); + startArray( "path"_sr ); + // TODO: we want to delay most of the printing to the 'root' section + // TODO: childSection key name? + } + + void JsonReporter::testCasePartialEnded( TestCaseStats const& tcStats, + uint64_t /*index*/ ) { + // Fixme: the top level section handles this. + //// path object + endArray(); + if ( !tcStats.stdOut.empty() ) { + m_objectWriters.top() + .write( "captured-stdout"_sr ) + .write( tcStats.stdOut ); + } + if ( !tcStats.stdErr.empty() ) { + m_objectWriters.top() + .write( "captured-stderr"_sr ) + .write( tcStats.stdErr ); + } + { + auto totals = + m_objectWriters.top().write( "totals"_sr ).writeObject(); + writeCounts( totals.write( "assertions"_sr ).writeObject(), + tcStats.totals.assertions ); + // We do not write the test case totals, because there will + // always be just one test case here. + // TODO: overall "result" -> success, skip, fail here? Or in + // partial result? + } + // TODO: aborting? + // run object + endObject(); + } + + void JsonReporter::sectionStarting( SectionInfo const& sectionInfo ) { + assert( isInside( Writer::Array ) && + "Section should always start inside an object" ); + // We want to nest top level sections, even though it shares name + // and source loc with the TEST_CASE + auto& sectionObject = startObject(); + sectionObject.write( "kind"_sr ).write( "section"_sr ); + sectionObject.write( "name"_sr ).write( sectionInfo.name ); + writeSourceInfo( m_objectWriters.top(), sectionInfo.lineInfo ); + + + // TBD: Do we want to create this event lazily? It would become + // rather complex, but we could do it, and it would look + // better for empty sections. OTOH, empty sections should + // be rare. + startArray( "path"_sr ); + } + void JsonReporter::sectionEnded( SectionStats const& /*sectionStats */) { + // End the subpath array + endArray(); + // TODO: metadata + // TODO: what info do we have here? + + // End the section object + endObject(); + } + + void JsonReporter::assertionStarting( AssertionInfo const& /*assertionInfo*/ ) {} + void JsonReporter::assertionEnded( AssertionStats const& assertionStats ) { + // TODO: There is lot of different things to handle here, but + // we can fill it in later, after we show that the basic + // outline and streaming reporter impl works well enough. + //if ( !m_config->includeSuccessfulResults() + // && assertionStats.assertionResult.isOk() ) { + // return; + //} + assert( isInside( Writer::Array ) ); + auto assertionObject = m_arrayWriters.top().writeObject(); + + assertionObject.write( "kind"_sr ).write( "assertion"_sr ); + writeSourceInfo( assertionObject, + assertionStats.assertionResult.getSourceInfo() ); + assertionObject.write( "status"_sr ) + .write( assertionStats.assertionResult.isOk() ); + // TODO: handling of result. + // TODO: messages + // TODO: totals? + } + + + void JsonReporter::benchmarkPreparing( StringRef name ) { (void)name; } + void JsonReporter::benchmarkStarting( BenchmarkInfo const& ) {} + void JsonReporter::benchmarkEnded( BenchmarkStats<> const& ) {} + void JsonReporter::benchmarkFailed( StringRef error ) { (void)error; } + + void JsonReporter::listReporters( + std::vector const& descriptions ) { + startListing(); + + auto writer = + m_objectWriters.top().write( "reporters"_sr ).writeArray(); + for ( auto const& desc : descriptions ) { + auto desc_writer = writer.writeObject(); + desc_writer.write( "name"_sr ).write( desc.name ); + desc_writer.write( "description"_sr ).write( desc.description ); + } + } + void JsonReporter::listListeners( + std::vector const& descriptions ) { + startListing(); + + auto writer = + m_objectWriters.top().write( "listeners"_sr ).writeArray(); + + for ( auto const& desc : descriptions ) { + auto desc_writer = writer.writeObject(); + desc_writer.write( "name"_sr ).write( desc.name ); + desc_writer.write( "description"_sr ).write( desc.description ); + } + } + void JsonReporter::listTests( std::vector const& tests ) { + startListing(); + + auto writer = m_objectWriters.top().write( "tests"_sr ).writeArray(); + + for ( auto const& test : tests ) { + auto desc_writer = writer.writeObject(); + auto const& info = test.getTestCaseInfo(); + + desc_writer.write( "name"_sr ).write( info.name ); + desc_writer.write( "class-name"_sr ).write( info.className ); + { + auto tag_writer = desc_writer.write( "tags"_sr ).writeArray(); + for ( auto const& tag : info.tags ) { + tag_writer.write( tag.original ); + } + } + writeSourceInfo( desc_writer, info.lineInfo ); + } + } + void JsonReporter::listTags( std::vector const& tags ) { + startListing(); + + auto writer = m_objectWriters.top().write( "tags"_sr ).writeArray(); + for ( auto const& tag : tags ) { + auto tag_writer = writer.writeObject(); + { + auto aliases_writer = + tag_writer.write( "aliases"_sr ).writeArray(); + for ( auto alias : tag.spellings ) { + aliases_writer.write( alias ); + } + } + tag_writer.write( "count"_sr ).write( tag.count ); + } + } +} // namespace Catch + + #include @@ -9186,6 +10124,8 @@ namespace Catch { gmtime_s(&timeInfo, &rawtime); #elif defined (CATCH_PLATFORM_PLAYSTATION) gmtime_s(&rawtime, &timeInfo); +#elif defined (__IAR_SYSTEMS_ICC__) + timeInfo = *std::gmtime(&rawtime); #else gmtime_r(&rawtime, &timeInfo); #endif @@ -9285,6 +10225,7 @@ namespace Catch { xml.writeAttribute( "name"_sr, stats.runInfo.name ); xml.writeAttribute( "errors"_sr, unexpectedExceptions ); xml.writeAttribute( "failures"_sr, stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "skipped"_sr, stats.totals.assertions.skipped ); xml.writeAttribute( "tests"_sr, stats.totals.assertions.total() ); xml.writeAttribute( "hostname"_sr, "tbd"_sr ); // !TBD if( m_config->showDurations() == ShowDurations::Never ) @@ -9397,7 +10338,8 @@ namespace Catch { void JunitReporter::writeAssertion( AssertionStats const& stats ) { AssertionResult const& result = stats.assertionResult; - if( !result.isOk() ) { + if ( !result.isOk() || + result.getResultType() == ResultWas::ExplicitSkip ) { std::string elementName; switch( result.getResultType() ) { case ResultWas::ThrewException: @@ -9409,7 +10351,9 @@ namespace Catch { case ResultWas::DidntThrowException: elementName = "failure"; break; - + case ResultWas::ExplicitSkip: + elementName = "skipped"; + break; // We should never see these here: case ResultWas::Info: case ResultWas::Warning: @@ -9427,7 +10371,9 @@ namespace Catch { xml.writeAttribute( "type"_sr, result.getTestMacroName() ); ReusableStringStream rss; - if (stats.totals.assertions.total() > 0) { + if ( result.getResultType() == ResultWas::ExplicitSkip ) { + rss << "SKIPPED\n"; + } else { rss << "FAILED" << ":\n"; if (result.hasExpression()) { rss << " "; @@ -9438,11 +10384,9 @@ namespace Catch { rss << "with expansion:\n"; rss << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n'; } - } else { - rss << '\n'; } - if( !result.getMessage().empty() ) + if( result.hasMessage() ) rss << result.getMessage() << '\n'; for( auto const& msg : stats.infoMessages ) if( msg.type == ResultWas::Info ) @@ -9561,7 +10505,6 @@ namespace Catch { } } - // The return value indicates if the messages buffer should be cleared: void MultiReporter::assertionEnded( AssertionStats const& assertionStats ) { const bool reportByDefault = assertionStats.assertionResult.getResultType() != ResultWas::Ok || @@ -9664,6 +10607,11 @@ namespace Catch { } } + void registerListenerImpl( Detail::unique_ptr listenerFactory ) { + getMutableRegistryHub().registerListener( CATCH_MOVE(listenerFactory) ); + } + + } // namespace Detail } // namespace Catch @@ -9696,7 +10644,7 @@ namespace Catch { } void SonarQubeReporter::writeRun( TestRunNode const& runNode ) { - std::map> testsPerFile; + std::map> testsPerFile; for ( auto const& child : runNode.children ) { testsPerFile[child->value.testInfo->lineInfo.file].push_back( @@ -9708,7 +10656,7 @@ namespace Catch { } } - void SonarQubeReporter::writeTestFile(std::string const& filename, std::vector const& testCaseNodes) { + void SonarQubeReporter::writeTestFile(StringRef filename, std::vector const& testCaseNodes) { XmlWriter::ScopedElement e = xml.scopedElement("file"); xml.writeAttribute("path"_sr, filename); @@ -9753,7 +10701,8 @@ namespace Catch { void SonarQubeReporter::writeAssertion(AssertionStats const& stats, bool okToFail) { AssertionResult const& result = stats.assertionResult; - if (!result.isOk()) { + if ( !result.isOk() || + result.getResultType() == ResultWas::ExplicitSkip ) { std::string elementName; if (okToFail) { elementName = "skipped"; @@ -9764,15 +10713,13 @@ namespace Catch { elementName = "error"; break; case ResultWas::ExplicitFailure: - elementName = "failure"; - break; case ResultWas::ExpressionFailed: - elementName = "failure"; - break; case ResultWas::DidntThrowException: elementName = "failure"; break; - + case ResultWas::ExplicitSkip: + elementName = "skipped"; + break; // We should never see these here: case ResultWas::Info: case ResultWas::Warning: @@ -9792,7 +10739,9 @@ namespace Catch { xml.writeAttribute("message"_sr, messageRss.str()); ReusableStringStream textRss; - if (stats.totals.assertions.total() > 0) { + if ( result.getResultType() == ResultWas::ExplicitSkip ) { + textRss << "SKIPPED\n"; + } else { textRss << "FAILED:\n"; if (result.hasExpression()) { textRss << '\t' << result.getExpressionInMacro() << '\n'; @@ -9802,7 +10751,7 @@ namespace Catch { } } - if (!result.getMessage().empty()) + if (result.hasMessage()) textRss << result.getMessage() << '\n'; for (auto const& msg : stats.infoMessages) @@ -9836,7 +10785,6 @@ namespace Catch { #include -#include #include namespace Catch { @@ -9922,6 +10870,12 @@ namespace Catch { printIssue("explicitly"_sr); printRemainingMessages(Colour::None); break; + case ResultWas::ExplicitSkip: + printResultType(tapPassedString); + printIssue(" # SKIP"_sr); + printMessage(); + printRemainingMessages(); + break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: @@ -9981,7 +10935,7 @@ namespace Catch { // using messages.end() directly (or auto) yields compilation error: std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast(std::distance(itMessage, itEnd)); + const std::size_t N = static_cast(itEnd - itMessage); stream << colourImpl->guardColour( colour ) << " with " << pluralise( N, "message"_sr ) << ':'; @@ -10000,7 +10954,7 @@ namespace Catch { private: std::ostream& stream; AssertionResult const& result; - std::vector messages; + std::vector const& messages; std::vector::const_iterator itMessage; bool printInfoMessages; std::size_t counter; @@ -10079,7 +11033,7 @@ namespace Catch { } // end anonymous namespace - TeamCityReporter::~TeamCityReporter() {} + TeamCityReporter::~TeamCityReporter() = default; void TeamCityReporter::testRunStarting( TestRunInfo const& runInfo ) { m_stream << "##teamcity[testSuiteStarted name='" << escape( runInfo.name ) @@ -10093,7 +11047,8 @@ namespace Catch { void TeamCityReporter::assertionEnded(AssertionStats const& assertionStats) { AssertionResult const& result = assertionStats.assertionResult; - if (!result.isOk()) { + if ( !result.isOk() || + result.getResultType() == ResultWas::ExplicitSkip ) { ReusableStringStream msg; if (!m_headerPrintedForThisSection) @@ -10118,6 +11073,9 @@ namespace Catch { case ResultWas::ExplicitFailure: msg << "explicit failure"; break; + case ResultWas::ExplicitSkip: + msg << "explicit skip"; + break; // We shouldn't get here because of the isOk() test case ResultWas::Ok: @@ -10145,18 +11103,16 @@ namespace Catch { " " << result.getExpandedExpression() << '\n'; } - if (currentTestCaseInfo->okToFail()) { + if ( result.getResultType() == ResultWas::ExplicitSkip ) { + m_stream << "##teamcity[testIgnored"; + } else if ( currentTestCaseInfo->okToFail() ) { msg << "- failure ignore as test marked as 'ok to fail'\n"; - m_stream << "##teamcity[testIgnored" - << " name='" << escape(currentTestCaseInfo->name) << '\'' - << " message='" << escape(msg.str()) << '\'' - << "]\n"; + m_stream << "##teamcity[testIgnored"; } else { - m_stream << "##teamcity[testFailed" - << " name='" << escape(currentTestCaseInfo->name) << '\'' - << " message='" << escape(msg.str()) << '\'' - << "]\n"; + m_stream << "##teamcity[testFailed"; } + m_stream << " name='" << escape( currentTestCaseInfo->name ) << '\'' + << " message='" << escape( msg.str() ) << '\'' << "]\n"; } m_stream.flush(); } @@ -10251,7 +11207,7 @@ namespace Catch { m_xml.startElement("Catch2TestRun") .writeAttribute("name"_sr, m_config->name()) .writeAttribute("rng-seed"_sr, m_config->rngSeed()) - .writeAttribute("xml-format-version"_sr, 2) + .writeAttribute("xml-format-version"_sr, 3) .writeAttribute("catch2-version"_sr, libraryVersion()); if ( m_config->testSpec().hasFilters() ) { m_xml.writeAttribute( "filters"_sr, m_config->testSpec() ); @@ -10261,7 +11217,7 @@ namespace Catch { void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ) - .writeAttribute( "name"_sr, trim( testInfo.name ) ) + .writeAttribute( "name"_sr, trim( StringRef(testInfo.name) ) ) .writeAttribute( "tags"_sr, testInfo.tagsAsString() ); writeSourceInfo( testInfo.lineInfo ); @@ -10275,7 +11231,7 @@ namespace Catch { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) - .writeAttribute( "name"_sr, trim( sectionInfo.name ) ); + .writeAttribute( "name"_sr, trim( StringRef(sectionInfo.name) ) ); writeSourceInfo( sectionInfo.lineInfo ); m_xml.ensureTagClosed(); } @@ -10293,19 +11249,22 @@ namespace Catch { // Print any info messages in tags. for( auto const& msg : assertionStats.infoMessages ) { if( msg.type == ResultWas::Info && includeResults ) { - m_xml.scopedElement( "Info" ) - .writeText( msg.message ); + auto t = m_xml.scopedElement( "Info" ); + writeSourceInfo( msg.lineInfo ); + t.writeText( msg.message ); } else if ( msg.type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( msg.message ); + auto t = m_xml.scopedElement( "Warning" ); + writeSourceInfo( msg.lineInfo ); + t.writeText( msg.message ); } } } // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) + if ( !includeResults && result.getResultType() != ResultWas::Warning && + result.getResultType() != ResultWas::ExplicitSkip ) { return; - + } // Print the expression if there is one. if( result.hasExpression() ) { @@ -10348,6 +11307,12 @@ namespace Catch { m_xml.writeText( result.getMessage() ); m_xml.endElement(); break; + case ResultWas::ExplicitSkip: + m_xml.startElement( "Skip" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; default: break; } @@ -10358,15 +11323,18 @@ namespace Catch { void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { StreamingReporterBase::sectionEnded( sectionStats ); - if( --m_sectionDepth > 0 ) { - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); - e.writeAttribute( "successes"_sr, sectionStats.assertions.passed ); - e.writeAttribute( "failures"_sr, sectionStats.assertions.failed ); - e.writeAttribute( "expectedFailures"_sr, sectionStats.assertions.failedButOk ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds"_sr, sectionStats.durationInSeconds ); + if ( --m_sectionDepth > 0 ) { + { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes"_sr, sectionStats.assertions.passed ); + e.writeAttribute( "failures"_sr, sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures"_sr, sectionStats.assertions.failedButOk ); + e.writeAttribute( "skipped"_sr, sectionStats.assertions.skipped > 0 ); + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds"_sr, sectionStats.durationInSeconds ); + } + // Ends assertion tag m_xml.endElement(); } } @@ -10375,14 +11343,14 @@ namespace Catch { StreamingReporterBase::testCaseEnded( testCaseStats ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); e.writeAttribute( "success"_sr, testCaseStats.totals.assertions.allOk() ); + e.writeAttribute( "skips"_sr, testCaseStats.totals.assertions.skipped ); if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() ); - if( !testCaseStats.stdOut.empty() ) - m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline ); + m_xml.scopedElement( "StdOut" ).writeText( trim( StringRef(testCaseStats.stdOut) ), XmlFormatting::Newline ); if( !testCaseStats.stdErr.empty() ) - m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline ); + m_xml.scopedElement( "StdErr" ).writeText( trim( StringRef(testCaseStats.stdErr) ), XmlFormatting::Newline ); m_xml.endElement(); } @@ -10392,11 +11360,13 @@ namespace Catch { m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes"_sr, testRunStats.totals.assertions.passed ) .writeAttribute( "failures"_sr, testRunStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures"_sr, testRunStats.totals.assertions.failedButOk ); + .writeAttribute( "expectedFailures"_sr, testRunStats.totals.assertions.failedButOk ) + .writeAttribute( "skips"_sr, testRunStats.totals.assertions.skipped ); m_xml.scopedElement( "OverallResultsCases") .writeAttribute( "successes"_sr, testRunStats.totals.testCases.passed ) .writeAttribute( "failures"_sr, testRunStats.totals.testCases.failed ) - .writeAttribute( "expectedFailures"_sr, testRunStats.totals.testCases.failedButOk ); + .writeAttribute( "expectedFailures"_sr, testRunStats.totals.testCases.failedButOk ) + .writeAttribute( "skips"_sr, testRunStats.totals.testCases.skipped ); m_xml.endElement(); } @@ -10415,26 +11385,23 @@ namespace Catch { } void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { - m_xml.startElement("mean") + m_xml.scopedElement("mean") .writeAttribute("value"_sr, benchmarkStats.mean.point.count()) .writeAttribute("lowerBound"_sr, benchmarkStats.mean.lower_bound.count()) .writeAttribute("upperBound"_sr, benchmarkStats.mean.upper_bound.count()) .writeAttribute("ci"_sr, benchmarkStats.mean.confidence_interval); - m_xml.endElement(); - m_xml.startElement("standardDeviation") + m_xml.scopedElement("standardDeviation") .writeAttribute("value"_sr, benchmarkStats.standardDeviation.point.count()) .writeAttribute("lowerBound"_sr, benchmarkStats.standardDeviation.lower_bound.count()) .writeAttribute("upperBound"_sr, benchmarkStats.standardDeviation.upper_bound.count()) .writeAttribute("ci"_sr, benchmarkStats.standardDeviation.confidence_interval); - m_xml.endElement(); - m_xml.startElement("outliers") + m_xml.scopedElement("outliers") .writeAttribute("variance"_sr, benchmarkStats.outlierVariance) .writeAttribute("lowMild"_sr, benchmarkStats.outliers.low_mild) .writeAttribute("lowSevere"_sr, benchmarkStats.outliers.low_severe) .writeAttribute("highMild"_sr, benchmarkStats.outliers.high_mild) .writeAttribute("highSevere"_sr, benchmarkStats.outliers.high_severe); m_xml.endElement(); - m_xml.endElement(); } void XmlReporter::benchmarkFailed(StringRef error) { diff --git a/extras/catch_amalgamated.hpp b/extras/catch_amalgamated.hpp index e91734a4..bec588d4 100644 --- a/extras/catch_amalgamated.hpp +++ b/extras/catch_amalgamated.hpp @@ -1,3 +1,4 @@ + // Copyright Catch2 Authors // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at @@ -5,8 +6,8 @@ // SPDX-License-Identifier: BSL-1.0 -// Catch v3.2.1 -// Generated: 2022-12-09 23:01:14.526666 +// Catch v3.5.0 +// Generated: 2023-12-11 00:51:06.770598 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -59,233 +60,6 @@ -#ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED -#define CATCH_INTERFACES_CONFIG_HPP_INCLUDED - - - -#ifndef CATCH_NONCOPYABLE_HPP_INCLUDED -#define CATCH_NONCOPYABLE_HPP_INCLUDED - -namespace Catch { - namespace Detail { - - //! Deriving classes become noncopyable and nonmovable - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable&& ) = delete; - NonCopyable& operator=( NonCopyable const& ) = delete; - NonCopyable& operator=( NonCopyable&& ) = delete; - - protected: - NonCopyable() noexcept = default; - }; - - } // namespace Detail -} // namespace Catch - -#endif // CATCH_NONCOPYABLE_HPP_INCLUDED - - -#ifndef CATCH_STRINGREF_HPP_INCLUDED -#define CATCH_STRINGREF_HPP_INCLUDED - -#include -#include -#include -#include - -namespace Catch { - - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. - class StringRef { - public: - using size_type = std::size_t; - using const_iterator = const char*; - - private: - static constexpr char const* const s_empty = ""; - - char const* m_start = s_empty; - size_type m_size = 0; - - public: // construction - constexpr StringRef() noexcept = default; - - StringRef( char const* rawChars ) noexcept; - - constexpr StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - {} - - StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} - - explicit operator std::string() const { - return std::string(m_start, m_size); - } - - public: // operators - auto operator == ( StringRef other ) const noexcept -> bool; - auto operator != (StringRef other) const noexcept -> bool { - return !(*this == other); - } - - constexpr auto operator[] ( size_type index ) const noexcept -> char { - assert(index < m_size); - return m_start[index]; - } - - bool operator<(StringRef rhs) const noexcept; - - public: // named queries - constexpr auto empty() const noexcept -> bool { - return m_size == 0; - } - constexpr auto size() const noexcept -> size_type { - return m_size; - } - - // Returns a substring of [start, start + length). - // If start + length > size(), then the substring is [start, start + size()). - // If start > size(), then the substring is empty. - constexpr StringRef substr(size_type start, size_type length) const noexcept { - if (start < m_size) { - const auto shortened_size = m_size - start; - return StringRef(m_start + start, (shortened_size < length) ? shortened_size : length); - } else { - return StringRef(); - } - } - - // Returns the current start pointer. May not be null-terminated. - constexpr char const* data() const noexcept { - return m_start; - } - - constexpr const_iterator begin() const { return m_start; } - constexpr const_iterator end() const { return m_start + m_size; } - - - friend std::string& operator += (std::string& lhs, StringRef sr); - friend std::ostream& operator << (std::ostream& os, StringRef sr); - friend std::string operator+(StringRef lhs, StringRef rhs); - - /** - * Provides a three-way comparison with rhs - * - * Returns negative number if lhs < rhs, 0 if lhs == rhs, and a positive - * number if lhs > rhs - */ - int compare( StringRef rhs ) const; - }; - - - constexpr auto operator ""_sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { - return StringRef( rawChars, size ); - } -} // namespace Catch - -constexpr auto operator ""_catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { - return Catch::StringRef( rawChars, size ); -} - -#endif // CATCH_STRINGREF_HPP_INCLUDED - -#include -#include -#include -#include - -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 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 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 - - #ifndef CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED #define CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED @@ -352,7 +126,7 @@ namespace Catch { // Only GCC compiler should be used in this block, so other compilers trying to // mask themselves as GCC should be ignored. -#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) && !defined(__NVCOMPILER) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) @@ -361,20 +135,37 @@ namespace Catch { # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ + _Pragma( "GCC diagnostic ignored \"-Wunused-result\"" ) + # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ _Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" ) # define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ _Pragma( "GCC diagnostic ignored \"-Wuseless-cast\"" ) +# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + _Pragma( "GCC diagnostic ignored \"-Wshadow\"" ) + # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) #endif +#if defined(__NVCOMPILER) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "diag push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "diag pop" ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress declared_but_not_referenced" ) +#endif + #if defined(__CUDACC__) && !defined(__clang__) +# ifdef __NVCC_DIAG_PRAGMA_SUPPORT__ +// New pragmas introduced in CUDA 11.5+ # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic pop" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "nv_diag_suppress 177" ) +# else +# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress 177" ) +# endif #endif // clang-cl defines _MSC_VER as well as __clang__, which could cause the @@ -428,6 +219,9 @@ namespace Catch { # define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wcomma\"" ) +# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wshadow\"" ) + #endif // __clang__ @@ -447,7 +241,9 @@ namespace Catch { //////////////////////////////////////////////////////////////////////////////// // Assume that some platforms do not support getenv. -#if defined(CATCH_PLATFORM_WINDOWS_UWP) || defined(CATCH_PLATFORM_PLAYSTATION) +#if defined( CATCH_PLATFORM_WINDOWS_UWP ) || \ + defined( CATCH_PLATFORM_PLAYSTATION ) || \ + defined( _GAMING_XBOX ) # define CATCH_INTERNAL_CONFIG_NO_GETENV #else # define CATCH_INTERNAL_CONFIG_GETENV @@ -492,8 +288,14 @@ namespace Catch { // Visual C++ #if defined(_MSC_VER) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) +// We want to defer to nvcc-specific warning suppression if we are compiled +// with nvcc masquerading for MSVC. +# if !defined( __CUDACC__ ) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + __pragma( warning( push ) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + __pragma( warning( pop ) ) +# endif // Universal Windows platform does not support SEH // Or console colours (or console at all...) @@ -659,6 +461,9 @@ namespace Catch { #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS #endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS #endif @@ -668,6 +473,16 @@ namespace Catch { #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS #endif +#if !defined( CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif +#if !defined( CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS ) +# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS +#endif +#if !defined( CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS ) +# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS +#endif + // The goal of this macro is to avoid evaluation of the arguments, but // still have the compiler warn on problems inside... @@ -681,13 +496,6 @@ namespace Catch { # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if !defined(CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS -#endif #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) #define CATCH_TRY if ((true)) @@ -733,38 +541,31 @@ namespace Catch { class IResultCapture; class IConfig; - class IContext { - public: - virtual ~IContext(); // = default + class Context { + IConfig const* m_config = nullptr; + IResultCapture* m_resultCapture = nullptr; - virtual IResultCapture* getResultCapture() = 0; - virtual IConfig const* getConfig() const = 0; - }; - - class IMutableContext : public IContext { - public: - ~IMutableContext() override; // = default - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setConfig( IConfig const* config ) = 0; - - private: - CATCH_EXPORT static IMutableContext* currentContext; - friend IMutableContext& getCurrentMutableContext(); - friend void cleanUpContext(); + CATCH_EXPORT static Context* currentContext; + friend Context& getCurrentMutableContext(); + friend Context const& getCurrentContext(); static void createContext(); + friend void cleanUpContext(); + + public: + IResultCapture* getResultCapture() const { return m_resultCapture; } + IConfig const* getConfig() const { return m_config; } + void setResultCapture( IResultCapture* resultCapture ); + void setConfig( IConfig const* config ); }; - inline IMutableContext& getCurrentMutableContext() - { - if( !IMutableContext::currentContext ) - IMutableContext::createContext(); - // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) - return *IMutableContext::currentContext; - } + Context& getCurrentMutableContext(); - inline IContext& getCurrentContext() - { - return getCurrentMutableContext(); + inline Context const& getCurrentContext() { + // We duplicate the logic from `getCurrentMutableContext` here, + // to avoid paying the call overhead in debug mode. + if ( !Context::currentContext ) { Context::createContext(); } + // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) + return *Context::currentContext; } void cleanUpContext(); @@ -776,16 +577,6 @@ namespace Catch { #endif // CATCH_CONTEXT_HPP_INCLUDED -#ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED -#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED - - - -#ifndef CATCH_SECTION_INFO_HPP_INCLUDED -#define CATCH_SECTION_INFO_HPP_INCLUDED - - - #ifndef CATCH_MOVE_AND_FORWARD_HPP_INCLUDED #define CATCH_MOVE_AND_FORWARD_HPP_INCLUDED @@ -800,109 +591,199 @@ namespace Catch { #endif // CATCH_MOVE_AND_FORWARD_HPP_INCLUDED -#ifndef CATCH_SOURCE_LINE_INFO_HPP_INCLUDED -#define CATCH_SOURCE_LINE_INFO_HPP_INCLUDED - -#include -#include +#ifndef CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED +#define CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED namespace Catch { - struct SourceLineInfo { + //! Used to signal that an assertion macro failed + struct TestFailureException{}; + //! Used to signal that the remainder of a test should be skipped + struct TestSkipException {}; - SourceLineInfo() = delete; - constexpr SourceLineInfo( char const* _file, std::size_t _line ) noexcept: - file( _file ), - line( _line ) - {} + /** + * Outlines throwing of `TestFailureException` into a single TU + * + * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers. + */ + [[noreturn]] void throw_test_failure_exception(); - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; + /** + * Outlines throwing of `TestSkipException` into a single TU + * + * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers. + */ + [[noreturn]] void throw_test_skip_exception(); - char const* file; - std::size_t line; +} // namespace Catch - friend std::ostream& operator << (std::ostream& os, SourceLineInfo const& info); - }; -} - -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) - -#endif // CATCH_SOURCE_LINE_INFO_HPP_INCLUDED +#endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED -#ifndef CATCH_TOTALS_HPP_INCLUDED -#define CATCH_TOTALS_HPP_INCLUDED +#ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED +#define CATCH_UNIQUE_NAME_HPP_INCLUDED -#include -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; +/** \file + * Wrapper for the CONFIG configuration option + * + * When generating internal unique names, there are two options. Either + * we mix in the current line number, or mix in an incrementing number. + * We prefer the latter, using `__COUNTER__`, but users might want to + * use the former. + */ - std::uint64_t passed = 0; - std::uint64_t failed = 0; - std::uint64_t failedButOk = 0; - }; +#ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED +#define CATCH_CONFIG_COUNTER_HPP_INCLUDED - struct Totals { - Totals operator - ( Totals const& other ) const; - Totals& operator += ( Totals const& other ); +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif - Totals delta( Totals const& prevTotals ) const; +#if defined( CATCH_INTERNAL_CONFIG_COUNTER ) && \ + !defined( CATCH_CONFIG_NO_COUNTER ) && \ + !defined( CATCH_CONFIG_COUNTER ) +# define CATCH_CONFIG_COUNTER +#endif - Counts assertions; - Counts testCases; - }; -} -#endif // CATCH_TOTALS_HPP_INCLUDED +#endif // CATCH_CONFIG_COUNTER_HPP_INCLUDED +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#endif // CATCH_UNIQUE_NAME_HPP_INCLUDED + + +#ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED +#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED #include +#include + + + +#ifndef CATCH_STRINGREF_HPP_INCLUDED +#define CATCH_STRINGREF_HPP_INCLUDED + +#include +#include +#include +#include + +#include 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) - {} + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char*; - std::string name; - SourceLineInfo lineInfo; + private: + static constexpr char const* const s_empty = ""; + + char const* m_start = s_empty; + size_type m_size = 0; + + public: // construction + constexpr StringRef() noexcept = default; + + StringRef( char const* rawChars ) noexcept; + + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + explicit operator std::string() const { + return std::string(m_start, m_size); + } + + public: // operators + auto operator == ( StringRef other ) const noexcept -> bool { + return m_size == other.m_size + && (std::memcmp( m_start, other.m_start, m_size ) == 0); + } + auto operator != (StringRef other) const noexcept -> bool { + return !(*this == other); + } + + constexpr auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } + + bool operator<(StringRef rhs) const noexcept; + + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } + + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, start + size()). + // If start > size(), then the substring is empty. + constexpr StringRef substr(size_type start, size_type length) const noexcept { + if (start < m_size) { + const auto shortened_size = m_size - start; + return StringRef(m_start + start, (shortened_size < length) ? shortened_size : length); + } else { + return StringRef(); + } + } + + // Returns the current start pointer. May not be null-terminated. + constexpr char const* data() const noexcept { + return m_start; + } + + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + + + friend std::string& operator += (std::string& lhs, StringRef sr); + friend std::ostream& operator << (std::ostream& os, StringRef sr); + friend std::string operator+(StringRef lhs, StringRef rhs); + + /** + * Provides a three-way comparison with rhs + * + * Returns negative number if lhs < rhs, 0 if lhs == rhs, and a positive + * number if lhs > rhs + */ + int compare( StringRef rhs ) const; }; - struct SectionEndInfo { - SectionInfo sectionInfo; - Counts prevAssertions; - double durationInSeconds; - }; -} // end namespace Catch + constexpr auto operator ""_sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch -#endif // CATCH_SECTION_INFO_HPP_INCLUDED - - -#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED -#define CATCH_ASSERTION_RESULT_HPP_INCLUDED - - - -#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED -#define CATCH_ASSERTION_INFO_HPP_INCLUDED +constexpr auto operator ""_catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} +#endif // CATCH_STRINGREF_HPP_INCLUDED #ifndef CATCH_RESULT_TYPE_HPP_INCLUDED @@ -916,6 +797,8 @@ namespace Catch { Ok = 0, Info = 1, Warning = 2, + // TODO: Should explicit skip be considered "not OK" (cf. isOk)? I.e., should it have the failure bit? + ExplicitSkip = 4, FailureBit = 0x10, @@ -954,224 +837,6 @@ namespace Catch { #endif // CATCH_RESULT_TYPE_HPP_INCLUDED -namespace Catch { - - struct AssertionInfo { - // AssertionInfo() = delete; - - StringRef macroName; - SourceLineInfo lineInfo; - StringRef capturedExpression; - ResultDisposition::Flags resultDisposition; - }; - -} // end namespace Catch - -#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED - - -#ifndef CATCH_LAZY_EXPR_HPP_INCLUDED -#define CATCH_LAZY_EXPR_HPP_INCLUDED - -#include - -namespace Catch { - - class ITransientExpression; - - class LazyExpression { - friend class AssertionHandler; - friend struct AssertionStats; - friend class RunContext; - - ITransientExpression const* m_transientExpression = nullptr; - bool m_isNegated; - public: - LazyExpression( bool isNegated ): - m_isNegated(isNegated) - {} - LazyExpression(LazyExpression const& other) = default; - LazyExpression& operator = ( LazyExpression const& ) = delete; - - explicit operator bool() const { - return m_transientExpression != nullptr; - } - - friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; - }; - -} // namespace Catch - -#endif // CATCH_LAZY_EXPR_HPP_INCLUDED - -#include - -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 const& 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 - - -#ifndef CATCH_MESSAGE_INFO_HPP_INCLUDED -#define CATCH_MESSAGE_INFO_HPP_INCLUDED - - - -#ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED -#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED - -#include -#include - - -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; - template > - struct BenchmarkStats; - - class IResultCapture { - public: - virtual ~IResultCapture(); - - virtual bool sectionStarted( SectionInfo const& sectionInfo, - Counts& assertions ) = 0; - virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; - virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - - virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 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 const& 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 const& 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 - -#include - -namespace Catch { - - struct MessageInfo { - MessageInfo( StringRef _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ); - - StringRef macroName; - std::string message; - SourceLineInfo lineInfo; - ResultWas::OfType type; - unsigned int sequence; - - bool operator == (MessageInfo const& other) const { - return sequence == other.sequence; - } - bool operator < (MessageInfo const& other) const { - return sequence < other.sequence; - } - private: - static unsigned int globalCount; - }; - -} // end namespace Catch - -#endif // CATCH_MESSAGE_INFO_HPP_INCLUDED - #ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED #define CATCH_UNIQUE_PTR_HPP_INCLUDED @@ -1285,6 +950,319 @@ namespace Detail { #endif // CATCH_UNIQUE_PTR_HPP_INCLUDED +#ifndef CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED +#define CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED + + + +// Adapted from donated nonius code. + +#ifndef CATCH_CLOCK_HPP_INCLUDED +#define CATCH_CLOCK_HPP_INCLUDED + +#include + +namespace Catch { + namespace Benchmark { + using IDuration = std::chrono::nanoseconds; + using FDuration = std::chrono::duration; + + template + using TimePoint = typename Clock::time_point; + + using default_clock = std::chrono::steady_clock; + } // namespace Benchmark +} // namespace Catch + +#endif // CATCH_CLOCK_HPP_INCLUDED + +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 + struct BenchmarkStats; + +} // end namespace Catch + +#endif // CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED + +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; + } + + + 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 + + +#ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED +#define CATCH_INTERFACES_CONFIG_HPP_INCLUDED + + + +#ifndef CATCH_NONCOPYABLE_HPP_INCLUDED +#define CATCH_NONCOPYABLE_HPP_INCLUDED + +namespace Catch { + namespace Detail { + + //! Deriving classes become noncopyable and nonmovable + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable&& ) = delete; + NonCopyable& operator=( NonCopyable const& ) = delete; + NonCopyable& operator=( NonCopyable&& ) = delete; + + protected: + NonCopyable() noexcept = default; + }; + + } // namespace Detail +} // namespace Catch + +#endif // CATCH_NONCOPYABLE_HPP_INCLUDED + +#include +#include +#include +#include + +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 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 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 + + +#ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED +#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED + + +#include + +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; + + 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 factory ) = 0; + virtual void registerTest(Detail::unique_ptr&& testInfo, Detail::unique_ptr&& invoker) = 0; + virtual void registerTranslator( Detail::unique_ptr&& 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 + + +#ifndef CATCH_BENCHMARK_STATS_HPP_INCLUDED +#define CATCH_BENCHMARK_STATS_HPP_INCLUDED + + + // Adapted from donated nonius code. #ifndef CATCH_ESTIMATE_HPP_INCLUDED @@ -1292,17 +1270,12 @@ namespace Detail { namespace Catch { namespace Benchmark { - template + template struct Estimate { - Duration point; - Duration lower_bound; - Duration upper_bound; + Type point; + Type lower_bound; + Type upper_bound; double confidence_interval; - - template - operator Estimate() const { - return { point, lower_bound, upper_bound, confidence_interval }; - } }; } // namespace Benchmark } // namespace Catch @@ -1332,103 +1305,14 @@ namespace Catch { } // namespace Catch #endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED +// The fwd decl & default specialization needs to be seen by VS2017 before +// BenchmarkStats itself, or VS2017 will report compilation error. - -#include #include #include -#include 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 _stream, - ColourMode colourMode, - std::map customOptions ); - - ReporterConfig( ReporterConfig&& ) = default; - ReporterConfig& operator=( ReporterConfig&& ) = default; - ~ReporterConfig(); // = default - - Detail::unique_ptr takeStream() &&; - IConfig const* fullConfig() const; - ColourMode colourMode() const; - std::map const& customOptions() const; - - private: - Detail::unique_ptr m_stream; - IConfig const* m_fullConfig; - ColourMode m_colourMode; - std::map m_customOptions; - }; - - struct TestRunInfo { - constexpr TestRunInfo(StringRef _name) : name(_name) {} - StringRef name; - }; - - struct AssertionStats { - AssertionStats( AssertionResult const& _assertionResult, - std::vector 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 infoMessages; - Totals totals; - }; - - struct SectionStats { - SectionStats( SectionInfo const& _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 const& _stdOut, - std::string const& _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; - }; - - struct BenchmarkInfo { std::string name; double estimatedDuration; @@ -1439,185 +1323,59 @@ namespace Catch { double clockCost; }; - template + // We need to keep template parameter for backwards compatibility, + // but we also do not want to use the template paraneter. + template struct BenchmarkStats { BenchmarkInfo info; - std::vector samples; - Benchmark::Estimate mean; - Benchmark::Estimate standardDeviation; + std::vector samples; + Benchmark::Estimate mean; + Benchmark::Estimate standardDeviation; Benchmark::OutlierClassification outliers; double outlierVariance; - - template - operator BenchmarkStats() const { - std::vector samples2; - samples2.reserve(samples.size()); - for (auto const& sample : samples) { - samples2.push_back(Duration2(sample)); - } - return { - info, - CATCH_MOVE(samples2), - mean, - standardDeviation, - outliers, - outlierVariance, - }; - } }; - //! 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 - virtual void skipTest( TestCaseInfo const& testInfo ) = 0; - - //! Called if a fatal error (signal/structured exception) occured - virtual void fatalErrorEncountered( StringRef error ) = 0; - - //! Writes out information about provided reporters using reporter-specific format - virtual void listReporters(std::vector const& descriptions) = 0; - //! Writes out the provided listeners descriptions using reporter-specific format - virtual void listListeners(std::vector const& descriptions) = 0; - //! Writes out information about provided tests using reporter-specific format - virtual void listTests(std::vector const& tests) = 0; - //! Writes out information about the provided tags using reporter-specific format - virtual void listTags(std::vector const& tags) = 0; - }; - using IEventListenerPtr = Detail::unique_ptr; } // end namespace Catch -#endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED +#endif // CATCH_BENCHMARK_STATS_HPP_INCLUDED -#ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED -#define CATCH_UNIQUE_NAME_HPP_INCLUDED +// Adapted from donated nonius code. + +#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED +#define CATCH_ENVIRONMENT_HPP_INCLUDED + + +namespace Catch { + namespace Benchmark { + struct EnvironmentEstimate { + FDuration mean; + OutlierClassification outliers; + }; + struct Environment { + EnvironmentEstimate clock_resolution; + EnvironmentEstimate clock_cost; + }; + } // namespace Benchmark +} // namespace Catch + +#endif // CATCH_ENVIRONMENT_HPP_INCLUDED + + +// Adapted from donated nonius code. + +#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED +#define CATCH_EXECUTION_PLAN_HPP_INCLUDED +// Adapted from donated nonius code. -/** \file - * Wrapper for the CONFIG configuration option - * - * When generating internal unique names, there are two options. Either - * we mix in the current line number, or mix in an incrementing number. - * We prefer the latter, using `__COUNTER__`, but users might want to - * use the former. - */ +#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED +#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED -#ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED -#define CATCH_CONFIG_COUNTER_HPP_INCLUDED - -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER -#endif - -#if defined( CATCH_INTERNAL_CONFIG_COUNTER ) && \ - !defined( CATCH_CONFIG_NO_COUNTER ) && \ - !defined( CATCH_CONFIG_COUNTER ) -# define CATCH_CONFIG_COUNTER -#endif - - -#endif // CATCH_CONFIG_COUNTER_HPP_INCLUDED -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) -#else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) -#endif - -#endif // CATCH_UNIQUE_NAME_HPP_INCLUDED // Adapted from donated nonius code. @@ -1627,46 +1385,12 @@ namespace Catch { -// Adapted from donated nonius code. - -#ifndef CATCH_CLOCK_HPP_INCLUDED -#define CATCH_CLOCK_HPP_INCLUDED - -#include -#include - -namespace Catch { - namespace Benchmark { - template - using ClockDuration = typename Clock::duration; - template - using FloatDuration = std::chrono::duration; - - template - using TimePoint = typename Clock::time_point; - - using default_clock = std::chrono::steady_clock; - - template - struct now { - TimePoint operator()() const { - return Clock::now(); - } - }; - - using fp_seconds = std::chrono::duration>; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_CLOCK_HPP_INCLUDED - - // Adapted from donated nonius code. #ifndef CATCH_OPTIMIZER_HPP_INCLUDED #define CATCH_OPTIMIZER_HPP_INCLUDED -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__) # include // atomic_thread_fence #endif @@ -1687,16 +1411,23 @@ namespace Catch { namespace Detail { inline void optimizer_barrier() { keep_memory(); } } // namespace Detail -#elif defined(_MSC_VER) +#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 inline void keep_memory(T* p) { // thanks @milleniumbug *reinterpret_cast(p) = *reinterpret_cast(p); } // TODO equivalent keep_memory() +#if defined(_MSVC_VER) #pragma optimize("", on) +#endif namespace Detail { inline void optimizer_barrier() { @@ -1718,7 +1449,7 @@ namespace Catch { template inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t::value> { - CATCH_FORWARD(fn) (CATCH_FORWARD(args)...); + CATCH_FORWARD((fn)) (CATCH_FORWARD(args)...); } } // namespace Benchmark } // namespace Catch @@ -1726,33 +1457,6 @@ namespace Catch { #endif // CATCH_OPTIMIZER_HPP_INCLUDED -// Adapted from donated nonius code. - -#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED -#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED - - - -#ifndef CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED -#define CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED - -namespace Catch { - - //! Used to signal that an assertion macro failed - struct TestFailureException{}; - - /** - * Outlines throwing of `TestFailureException` into a single TU - * - * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers. - */ - [[noreturn]] void throw_test_failure_exception(); - -} // namespace Catch - -#endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED - - #ifndef CATCH_META_HPP_INCLUDED #define CATCH_META_HPP_INCLUDED @@ -1794,112 +1498,6 @@ namespace mpl_{ #endif // CATCH_META_HPP_INCLUDED - -#ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED -#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED - - -#include - -namespace Catch { - - class TestCaseHandle; - struct TestCaseInfo; - class ITestCaseRegistry; - class IExceptionTranslatorRegistry; - class IExceptionTranslator; - class IReporterRegistry; - class IReporterFactory; - class ITagAliasRegistry; - class ITestInvoker; - class IMutableEnumValuesRegistry; - struct SourceLineInfo; - - class StartupExceptionRegistry; - class EventListenerFactory; - - using IReporterFactoryPtr = Detail::unique_ptr; - - class IRegistryHub { - public: - virtual ~IRegistryHub(); // = default - - virtual IReporterRegistry 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 factory ) = 0; - virtual void registerTest(Detail::unique_ptr&& testInfo, Detail::unique_ptr&& invoker) = 0; - virtual void registerTranslator( Detail::unique_ptr&& 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 - -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - struct CompleteType { using type = T; }; - template <> - struct CompleteType { struct type {}; }; - - template - using CompleteType_t = typename CompleteType::type; - - template - struct CompleteInvoker { - template - static Result invoke(Fun&& fun, Args&&... args) { - return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); - } - }; - template <> - struct CompleteInvoker { - template - static CompleteType_t invoke(Fun&& fun, Args&&... args) { - CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); - return {}; - } - }; - - // invoke and not return void :( - template - CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { - return CompleteInvoker>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...); - } - - } // namespace Detail - - template - Detail::CompleteType_t> user_code(Fun&& fun) { - return Detail::complete_invoke(CATCH_FORWARD(fun)); - } - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED - namespace Catch { namespace Benchmark { namespace Detail { @@ -1917,7 +1515,10 @@ namespace Catch { void start() override { started = Clock::now(); } void finish() override { finished = Clock::now(); } - ClockDuration elapsed() const { return finished - started; } + IDuration elapsed() const { + return std::chrono::duration_cast( + finished - started ); + } TimePoint started; TimePoint finished; @@ -1958,50 +1559,6 @@ namespace Catch { #endif // CATCH_CHRONOMETER_HPP_INCLUDED - -// Adapted from donated nonius code. - -#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED -#define CATCH_ENVIRONMENT_HPP_INCLUDED - - -namespace Catch { - namespace Benchmark { - template - struct EnvironmentEstimate { - Duration mean; - OutlierClassification outliers; - - template - operator EnvironmentEstimate() const { - return { mean, outliers }; - } - }; - template - struct Environment { - using clock_type = Clock; - EnvironmentEstimate> clock_resolution; - EnvironmentEstimate> clock_cost; - }; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_ENVIRONMENT_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED -#define CATCH_EXECUTION_PLAN_HPP_INCLUDED - - - -// Adapted from donated nonius code. - -#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED -#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED - - #include namespace Catch { @@ -2138,6 +1695,57 @@ namespace Catch { +// Adapted from donated nonius code. + +#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED +#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED + + +namespace Catch { + namespace Benchmark { + namespace Detail { + template + struct CompleteType { using type = T; }; + template <> + struct CompleteType { struct type {}; }; + + template + using CompleteType_t = typename CompleteType::type; + + template + struct CompleteInvoker { + template + static Result invoke(Fun&& fun, Args&&... args) { + return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); + } + }; + template <> + struct CompleteInvoker { + template + static CompleteType_t invoke(Fun&& fun, Args&&... args) { + CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); + return {}; + } + }; + + // invoke and not return void :( + template + CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { + return CompleteInvoker>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...); + } + + } // namespace Detail + + template + Detail::CompleteType_t> user_code(Fun&& fun) { + return Detail::complete_invoke(CATCH_FORWARD(fun)); + } + } // namespace Benchmark +} // namespace Catch + +#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED + + // Adapted from donated nonius code. #ifndef CATCH_TIMING_HPP_INCLUDED @@ -2148,14 +1756,14 @@ namespace Catch { namespace Catch { namespace Benchmark { - template + template struct Timing { - Duration elapsed; + IDuration elapsed; Result result; int iterations; }; - template - using TimingOf = Timing, Detail::CompleteType_t>>; + template + using TimingOf = Timing>>; } // namespace Benchmark } // namespace Catch @@ -2165,7 +1773,7 @@ namespace Catch { namespace Benchmark { namespace Detail { template - TimingOf measure(Fun&& fun, Args&&... args) { + TimingOf measure(Fun&& fun, Args&&... args) { auto start = Clock::now(); auto&& r = Detail::complete_invoke(fun, CATCH_FORWARD(args)...); auto end = Clock::now(); @@ -2184,11 +1792,11 @@ namespace Catch { namespace Benchmark { namespace Detail { template - TimingOf measure_one(Fun&& fun, int iters, std::false_type) { + TimingOf measure_one(Fun&& fun, int iters, std::false_type) { return Detail::measure(fun, iters); } template - TimingOf measure_one(Fun&& fun, int iters, std::true_type) { + TimingOf measure_one(Fun&& fun, int iters, std::true_type) { Detail::ChronometerModel meter; auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); @@ -2203,8 +1811,8 @@ namespace Catch { void throw_optimized_away_error(); template - TimingOf> - run_for_at_least(ClockDuration how_long, + TimingOf> + run_for_at_least(IDuration how_long, const int initial_iterations, Fun&& fun) { auto iters = initial_iterations; @@ -2224,38 +1832,38 @@ namespace Catch { #endif // CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED -#include -#include +#include namespace Catch { namespace Benchmark { - template struct ExecutionPlan { int iterations_per_sample; - Duration estimated_duration; + FDuration estimated_duration; Detail::BenchmarkFunction benchmark; - Duration warmup_time; + FDuration warmup_time; int warmup_iterations; - template - operator ExecutionPlan() const { - return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations }; - } - template - std::vector> run(const IConfig &cfg, Environment> env) const { + std::vector run(const IConfig &cfg, Environment env) const { // warmup a bit - Detail::run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_iterations, Detail::repeat(now{})); + Detail::run_for_at_least( + std::chrono::duration_cast( warmup_time ), + warmup_iterations, + Detail::repeat( []() { return Clock::now(); } ) + ); - std::vector> times; - times.reserve(cfg.benchmarkSamples()); - std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { + std::vector times; + const auto num_samples = cfg.benchmarkSamples(); + times.reserve( num_samples ); + for ( size_t i = 0; i < num_samples; ++i ) { Detail::ChronometerModel model; - this->benchmark(Chronometer(model, iterations_per_sample)); + this->benchmark( Chronometer( model, iterations_per_sample ) ); auto sample_time = model.elapsed() - env.clock_cost.mean; - if (sample_time < FloatDuration::zero()) sample_time = FloatDuration::zero(); - return sample_time / iterations_per_sample; - }); + if ( sample_time < FDuration::zero() ) { + sample_time = FDuration::zero(); + } + times.push_back(sample_time / iterations_per_sample); + } return times; } }; @@ -2278,122 +1886,35 @@ namespace Catch { #define CATCH_STATS_HPP_INCLUDED -#include #include -#include -#include -#include namespace Catch { namespace Benchmark { namespace Detail { using sample = std::vector; - // 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, + double* first, + double* last ); - double weighted_average_quantile(int k, int q, std::vector::iterator first, std::vector::iterator last); + OutlierClassification + classify_outliers( double const* first, double const* last ); - template - OutlierClassification classify_outliers(Iterator first, Iterator last) { - std::vector copy(first, last); + double mean( double const* first, double const* 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) { - auto&& 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; - } - - template - double mean(Iterator first, Iterator last) { - auto count = last - first; - double sum = std::accumulate(first, last, 0.); - return sum / static_cast(count); - } - - template - sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { - auto n = static_cast(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 normal_cdf( double x ); double erfc_inv(double x); double normal_quantile(double p); - template - Estimate bootstrap(double confidence_level, Iterator first, 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, sum_cubes; - std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair sqcb, double x) -> std::pair { - auto d = jack_mean - x; - auto d2 = d * d; - auto d3 = d2 * d; - return { sqcb.first + d2, sqcb.second + d3 }; - }); - - double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); - long n = static_cast(resample.size()); - double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / static_cast(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(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((std::max)(cumn(a1), 0l)); - auto hi = static_cast((std::min)(cumn(a2), n - 1)); - - return { point, resample[lo], resample[hi], confidence_level }; - } - - double outlier_variance(Estimate mean, Estimate stddev, int n); + Estimate + bootstrap( double confidence_level, + double* first, + double* last, + sample const& resample, + double ( *estimator )( double const*, double const* ) ); struct bootstrap_analysis { Estimate mean; @@ -2401,7 +1922,10 @@ namespace Catch { double outlier_variance; }; - bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector::iterator first, std::vector::iterator last); + bootstrap_analysis analyse_samples(double confidence_level, + unsigned int n_resamples, + double* first, + double* last); } // namespace Detail } // namespace Benchmark } // namespace Catch @@ -2409,7 +1933,6 @@ namespace Catch { #endif // CATCH_STATS_HPP_INCLUDED #include -#include #include #include @@ -2420,46 +1943,49 @@ namespace Catch { std::vector resolution(int k) { std::vector> times; times.reserve(static_cast(k + 1)); - std::generate_n(std::back_inserter(times), k + 1, now{}); + for ( int i = 0; i < k + 1; ++i ) { + times.push_back( Clock::now() ); + } std::vector deltas; deltas.reserve(static_cast(k)); - std::transform(std::next(times.begin()), times.end(), times.begin(), - std::back_inserter(deltas), - [](TimePoint a, TimePoint b) { return static_cast((a - b).count()); }); + for ( size_t idx = 1; idx < times.size(); ++idx ) { + deltas.push_back( static_cast( + ( times[idx] - times[idx - 1] ).count() ) ); + } return deltas; } - const auto warmup_iterations = 10000; - const auto warmup_time = std::chrono::milliseconds(100); - const auto minimum_ticks = 1000; - const auto warmup_seed = 10000; - const auto clock_resolution_estimation_time = std::chrono::milliseconds(500); - const auto clock_cost_estimation_time_limit = std::chrono::seconds(1); - const auto clock_cost_estimation_tick_limit = 100000; - const auto clock_cost_estimation_time = std::chrono::milliseconds(10); - const auto clock_cost_estimation_iterations = 10000; + 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 int warmup() { - return run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_seed, &resolution) + return run_for_at_least(std::chrono::duration_cast(warmup_time), warmup_seed, &resolution) .iterations; } template - EnvironmentEstimate> estimate_clock_resolution(int iterations) { - auto r = run_for_at_least(std::chrono::duration_cast>(clock_resolution_estimation_time), iterations, &resolution) + EnvironmentEstimate estimate_clock_resolution(int iterations) { + auto r = run_for_at_least(std::chrono::duration_cast(clock_resolution_estimation_time), iterations, &resolution) .result; return { - FloatDuration(mean(r.begin(), r.end())), - classify_outliers(r.begin(), r.end()), + FDuration(mean(r.data(), r.data() + r.size())), + classify_outliers(r.data(), r.data() + r.size()), }; } template - EnvironmentEstimate> estimate_clock_cost(FloatDuration resolution) { + EnvironmentEstimate estimate_clock_cost(FDuration resolution) { auto time_limit = (std::min)( resolution * clock_cost_estimation_tick_limit, - FloatDuration(clock_cost_estimation_time_limit)); + FDuration(clock_cost_estimation_time_limit)); auto time_clock = [](int k) { return Detail::measure([k] { for (int i = 0; i < k; ++i) { @@ -2470,26 +1996,28 @@ namespace Catch { }; time_clock(1); int iters = clock_cost_estimation_iterations; - auto&& r = run_for_at_least(std::chrono::duration_cast>(clock_cost_estimation_time), iters, time_clock); + auto&& r = run_for_at_least(std::chrono::duration_cast(clock_cost_estimation_time), iters, time_clock); std::vector times; int nsamples = static_cast(std::ceil(time_limit / r.elapsed)); times.reserve(static_cast(nsamples)); - std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { - return static_cast((time_clock(r.iterations) / r.iterations).count()); - }); + for ( int s = 0; s < nsamples; ++s ) { + times.push_back( static_cast( + ( time_clock( r.iterations ) / r.iterations ) + .count() ) ); + } return { - FloatDuration(mean(times.begin(), times.end())), - classify_outliers(times.begin(), times.end()), + FDuration(mean(times.data(), times.data() + times.size())), + classify_outliers(times.data(), times.data() + times.size()), }; } template - Environment> measure_environment() { + Environment measure_environment() { #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wexit-time-destructors" #endif - static Catch::Detail::unique_ptr>> env; + static Catch::Detail::unique_ptr env; #if defined(__clang__) # pragma clang diagnostic pop #endif @@ -2501,7 +2029,7 @@ namespace Catch { auto resolution = Detail::estimate_clock_resolution(iters); auto cost = Detail::estimate_clock_cost(resolution.mean); - env = Catch::Detail::make_unique>>( Environment>{resolution, cost} ); + env = Catch::Detail::make_unique( Environment{resolution, cost} ); return *env; } } // namespace Detail @@ -2524,95 +2052,29 @@ namespace Catch { #define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED -#include #include -#include namespace Catch { namespace Benchmark { - template struct SampleAnalysis { - std::vector samples; - Estimate mean; - Estimate standard_deviation; + std::vector samples; + Estimate mean; + Estimate standard_deviation; OutlierClassification outliers; double outlier_variance; - - template - operator SampleAnalysis() const { - std::vector samples2; - samples2.reserve(samples.size()); - std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); - return { - CATCH_MOVE(samples2), - mean, - standard_deviation, - outliers, - outlier_variance, - }; - } }; } // namespace Benchmark } // namespace Catch #endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED -#include -#include -#include namespace Catch { + class IConfig; + namespace Benchmark { namespace Detail { - template - SampleAnalysis analyse(const IConfig &cfg, Environment, Iterator first, Iterator last) { - if (!cfg.benchmarkNoAnalysis()) { - std::vector samples; - samples.reserve(static_cast(last - first)); - std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.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 e) { - return Estimate { - Duration(e.point), - Duration(e.lower_bound), - Duration(e.upper_bound), - e.confidence_interval, - }; - }; - std::vector samples2; - samples2.reserve(samples.size()); - std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); - return { - CATCH_MOVE(samples2), - wrap_estimate(analysis.mean), - wrap_estimate(analysis.standard_deviation), - outliers, - analysis.outlier_variance, - }; - } else { - std::vector samples; - samples.reserve(static_cast(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{mean, mean, mean, 0.0}, - Estimate{Duration(0), Duration(0), Duration(0), 0.0}, - OutlierClassification{}, - 0.0 - }; - } - } + SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last); } // namespace Detail } // namespace Benchmark } // namespace Catch @@ -2620,9 +2082,9 @@ namespace Catch { #endif // CATCH_ANALYSE_HPP_INCLUDED #include -#include +#include +#include #include -#include #include namespace Catch { @@ -2636,16 +2098,18 @@ namespace Catch { : fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {} template - ExecutionPlan> prepare(const IConfig &cfg, Environment> env) const { + ExecutionPlan prepare(const IConfig &cfg, Environment env) const { auto min_time = env.clock_resolution.mean * Detail::minimum_ticks; auto run_time = std::max(min_time, std::chrono::duration_cast(cfg.benchmarkWarmupTime())); - auto&& test = Detail::run_for_at_least(std::chrono::duration_cast>(run_time), 1, fun); + auto&& test = Detail::run_for_at_least(std::chrono::duration_cast(run_time), 1, fun); int new_iters = static_cast(std::ceil(min_time * test.iterations / test.elapsed)); - return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations }; + return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast(cfg.benchmarkWarmupTime()), Detail::warmup_iterations }; } template void run() { + static_assert( Clock::is_steady, + "Benchmarking clock should be steady" ); auto const* cfg = getCurrentContext().getConfig(); auto env = Detail::measure_environment(); @@ -2657,7 +2121,7 @@ namespace Catch { }); BenchmarkInfo info { - name, + CATCH_MOVE(name), plan.estimated_duration.count(), plan.iterations_per_sample, cfg->benchmarkSamples(), @@ -2672,10 +2136,10 @@ namespace Catch { return plan.template run(*cfg, env); }); - auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); - BenchmarkStats> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance }; + auto analysis = Detail::analyse(*cfg, samples.data(), samples.data() + samples.size()); + BenchmarkStats<> 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) { + } CATCH_CATCH_ANON (TestFailureException const&) { getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr); } CATCH_CATCH_ALL{ getResultCapture().benchmarkFailed(translateActiveException()); @@ -2843,6 +2307,7 @@ namespace Catch { #ifndef CATCH_CONFIG_WCHAR_HPP_INCLUDED #define CATCH_CONFIG_WCHAR_HPP_INCLUDED + // We assume that WCHAR should be enabled by default, and only disabled // for a shortlist (so far only DJGPP) of compilers. @@ -3066,7 +2531,6 @@ namespace Catch { } // namespace Detail - // If we decide for C++14, change these to enable_if_ts template struct StringMaker { template @@ -3349,6 +2813,12 @@ namespace Catch { } } }; + template <> + struct StringMaker { + static std::string convert(const std::nullopt_t&) { + return "{ }"; + } + }; } #endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER @@ -3735,6 +3205,143 @@ struct StringMaker { #endif // CATCH_APPROX_HPP_INCLUDED +#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED +#define CATCH_ASSERTION_INFO_HPP_INCLUDED + + + +#ifndef CATCH_SOURCE_LINE_INFO_HPP_INCLUDED +#define CATCH_SOURCE_LINE_INFO_HPP_INCLUDED + +#include +#include + +namespace Catch { + + struct SourceLineInfo { + + SourceLineInfo() = delete; + constexpr SourceLineInfo( char const* _file, std::size_t _line ) noexcept: + file( _file ), + line( _line ) + {} + + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + + friend std::ostream& operator << (std::ostream& os, SourceLineInfo const& info); + }; +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +#endif // CATCH_SOURCE_LINE_INFO_HPP_INCLUDED + +namespace Catch { + + struct AssertionInfo { + // AssertionInfo() = delete; + + StringRef macroName; + SourceLineInfo lineInfo; + StringRef capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + +} // end namespace Catch + +#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED + + +#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED +#define CATCH_ASSERTION_RESULT_HPP_INCLUDED + + + +#ifndef CATCH_LAZY_EXPR_HPP_INCLUDED +#define CATCH_LAZY_EXPR_HPP_INCLUDED + +#include + +namespace Catch { + + class ITransientExpression; + + class LazyExpression { + friend class AssertionHandler; + friend struct AssertionStats; + friend class RunContext; + + ITransientExpression const* m_transientExpression = nullptr; + bool m_isNegated; + public: + LazyExpression( bool isNegated ): + m_isNegated(isNegated) + {} + LazyExpression(LazyExpression const& other) = default; + LazyExpression& operator = ( LazyExpression const& ) = delete; + + explicit operator bool() const { + return m_transientExpression != nullptr; + } + + friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; + }; + +} // namespace Catch + +#endif // CATCH_LAZY_EXPR_HPP_INCLUDED + +#include + +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 + + #ifndef CATCH_CONFIG_HPP_INCLUDED #define CATCH_CONFIG_HPP_INCLUDED @@ -3899,6 +3506,7 @@ namespace Catch { #ifndef CATCH_OPTIONAL_HPP_INCLUDED #define CATCH_OPTIONAL_HPP_INCLUDED + #include namespace Catch { @@ -3907,35 +3515,50 @@ namespace Catch { template class Optional { public: - Optional() : nullableValue( nullptr ) {} - Optional( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Optional( Optional const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) - {} + Optional(): nullableValue( nullptr ) {} + ~Optional() { reset(); } - ~Optional() { + Optional( T const& _value ): + nullableValue( new ( storage ) T( _value ) ) {} + Optional( T&& _value ): + nullableValue( new ( storage ) T( CATCH_MOVE( _value ) ) ) {} + + Optional& operator=( T const& _value ) { reset(); + nullableValue = new ( storage ) T( _value ); + return *this; + } + Optional& operator=( T&& _value ) { + reset(); + nullableValue = new ( storage ) T( CATCH_MOVE( _value ) ); + return *this; } - Optional& operator= ( Optional const& _other ) { - if( &_other != this ) { + Optional( Optional const& _other ): + nullableValue( _other ? new ( storage ) T( *_other ) : nullptr ) {} + Optional( Optional&& _other ): + nullableValue( _other ? new ( storage ) T( CATCH_MOVE( *_other ) ) + : nullptr ) {} + + Optional& operator=( Optional const& _other ) { + if ( &_other != this ) { reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); + if ( _other ) { nullableValue = new ( storage ) T( *_other ); } } return *this; } - Optional& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); + Optional& operator=( Optional&& _other ) { + if ( &_other != this ) { + reset(); + if ( _other ) { + nullableValue = new ( storage ) T( CATCH_MOVE( *_other ) ); + } + } return *this; } void reset() { - if( nullableValue ) - nullableValue->~T(); + if ( nullableValue ) { nullableValue->~T(); } nullableValue = nullptr; } @@ -3982,7 +3605,7 @@ namespace Catch { } private: - T *nullableValue; + T* nullableValue; alignas(alignof(T)) char storage[sizeof(T)]; }; @@ -4058,6 +3681,7 @@ namespace Catch { Error = BrightRed, Success = Green, + Skip = LightGrey, OriginalExpression = Cyan, ReconstructedExpression = BrightYellow, @@ -4377,6 +4001,29 @@ namespace Catch { + +/** \file + * Wrapper for the CATCH_CONFIG_PREFIX_MESSAGES configuration option + * + * CATCH_CONFIG_PREFIX_ALL can be used to avoid clashes with other macros + * by prepending CATCH_. This may not be desirable if the only clashes are with + * logger macros such as INFO and WARN. In this cases + * CATCH_CONFIG_PREFIX_MESSAGES can be used to only prefix a small subset + * of relevant macros. + * + */ + +#ifndef CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED +#define CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED + + +#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_PREFIX_MESSAGES) + #define CATCH_CONFIG_PREFIX_MESSAGES +#endif + +#endif // CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED + + #ifndef CATCH_STREAM_END_STOP_HPP_INCLUDED #define CATCH_STREAM_END_STOP_HPP_INCLUDED @@ -4388,10 +4035,10 @@ namespace Catch { // as well as // << stuff +StreamEndStop struct StreamEndStop { - StringRef operator+() const { return StringRef(); } + constexpr StringRef operator+() const { return StringRef(); } template - friend T const& operator+( T const& value, StreamEndStop ) { + constexpr friend T const& operator+( T const& value, StreamEndStop ) { return value; } }; @@ -4400,12 +4047,47 @@ namespace Catch { #endif // CATCH_STREAM_END_STOP_HPP_INCLUDED + +#ifndef CATCH_MESSAGE_INFO_HPP_INCLUDED +#define CATCH_MESSAGE_INFO_HPP_INCLUDED + + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( StringRef _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + StringRef macroName; + std::string message; + SourceLineInfo lineInfo; + ResultWas::OfType type; + unsigned int sequence; + + bool operator == (MessageInfo const& other) const { + return sequence == other.sequence; + } + bool operator < (MessageInfo const& other) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + +} // end namespace Catch + +#endif // CATCH_MESSAGE_INFO_HPP_INCLUDED + #include #include namespace Catch { struct SourceLineInfo; + class IResultCapture; struct MessageStream { @@ -4424,11 +4106,10 @@ namespace Catch { ResultWas::OfType type ): m_info(macroName, lineInfo, type) {} - template - MessageBuilder& operator << ( T const& value ) { + MessageBuilder&& operator << ( T const& value ) && { m_stream << value; - return *this; + return CATCH_MOVE(*this); } MessageInfo m_info; @@ -4436,7 +4117,7 @@ namespace Catch { class ScopedMessage { public: - explicit ScopedMessage( MessageBuilder const& builder ); + explicit ScopedMessage( MessageBuilder&& builder ); ScopedMessage( ScopedMessage& duplicate ) = delete; ScopedMessage( ScopedMessage&& old ) noexcept; ~ScopedMessage(); @@ -4447,7 +4128,7 @@ namespace Catch { class Capturer { std::vector m_messages; - IResultCapture& m_resultCapture = getResultCapture(); + IResultCapture& m_resultCapture; size_t m_captured = 0; public: Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); @@ -4483,7 +4164,10 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ - Catch::Capturer varName( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \ + Catch::Capturer varName( macroName##_catch_sr, \ + CATCH_INTERNAL_LINEINFO, \ + Catch::ResultWas::Info, \ + #__VA_ARGS__##_catch_sr ); \ varName.captureValues( 0, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// @@ -4495,28 +4179,28 @@ namespace Catch { 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) +#if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !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) +#elif defined(CATCH_CONFIG_PREFIX_MESSAGES) && 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) +#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && !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) +#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE) #define INFO( msg ) (void)(0) #define UNSCOPED_INFO( msg ) (void)(0) @@ -4531,6 +4215,75 @@ namespace Catch { #endif // CATCH_MESSAGE_HPP_INCLUDED +#ifndef CATCH_SECTION_INFO_HPP_INCLUDED +#define CATCH_SECTION_INFO_HPP_INCLUDED + + + +#ifndef CATCH_TOTALS_HPP_INCLUDED +#define CATCH_TOTALS_HPP_INCLUDED + +#include + +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 + +#include + +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 + + #ifndef CATCH_SESSION_HPP_INCLUDED #define CATCH_SESSION_HPP_INCLUDED @@ -5806,11 +5559,10 @@ namespace Catch { namespace Catch { - class IResultCapture; - struct AssertionReaction { bool shouldDebugBreak = false; bool shouldThrow = false; + bool shouldSkip = false; }; class AssertionHandler { @@ -5847,7 +5599,6 @@ namespace Catch { void handleUnexpectedInflightException(); void complete(); - void setCompleted(); // query auto allowThrows() const -> bool; @@ -5859,6 +5610,19 @@ namespace Catch { #endif // CATCH_ASSERTION_HANDLER_HPP_INCLUDED + +#ifndef CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED +#define CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED + + +#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) + #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr +#else + #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr +#endif + +#endif // CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_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 #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ <= 9 @@ -5867,12 +5631,6 @@ namespace Catch { #if !defined(CATCH_CONFIG_DISABLE) -#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) - #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ -#else - #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" -#endif - #if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) /////////////////////////////////////////////////////////////////////////////// @@ -5884,7 +5642,7 @@ namespace Catch { #else // CATCH_CONFIG_FAST_COMPILE #define INTERNAL_CATCH_TRY try -#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } +#define INTERNAL_CATCH_CATCH( handler ) catch(...) { (handler).handleUnexpectedInflightException(); } #endif @@ -5940,6 +5698,7 @@ namespace Catch { if( catchAssertionHandler.allowThrows() ) \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(__VA_ARGS__); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ @@ -5960,6 +5719,7 @@ namespace Catch { if( catchAssertionHandler.allowThrows() ) \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(expr); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ @@ -5986,6 +5746,7 @@ namespace Catch { if( catchAssertionHandler.allowThrows() ) \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(__VA_ARGS__); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ @@ -6009,6 +5770,34 @@ namespace Catch { + +/** \file + * Wrapper for the STATIC_ANALYSIS_SUPPORT configuration option + * + * Some of Catch2's macros can be defined differently to work better with + * static analysis tools, like clang-tidy or coverity. + * Currently the main use case is to show that `SECTION`s are executed + * exclusively, and not all in one run of a `TEST_CASE`. + */ + +#ifndef CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED +#define CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED + + +#if defined(__clang_analyzer__) || defined(__COVERITY__) + #define CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT +#endif + +#if defined( CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT ) && \ + !defined( CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) && \ + !defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) +# define CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT +#endif + + +#endif // CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED + + #ifndef CATCH_TIMER_HPP_INCLUDED #define CATCH_TIMER_HPP_INCLUDED @@ -6035,6 +5824,9 @@ namespace Catch { class Section : Detail::NonCopyable { public: Section( SectionInfo&& info ); + Section( SourceLineInfo const& _lineInfo, + StringRef _name, + const char* const = nullptr ); ~Section(); // This indicates whether the section should be executed or not @@ -6050,17 +5842,63 @@ namespace Catch { } // end namespace Catch -#define INTERNAL_CATCH_SECTION( ... ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT) +# define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \ + catch_internal_Section ) = \ + Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \ + catch_internal_Section ) = \ + Catch::SectionInfo( \ + CATCH_INTERNAL_LINEINFO, \ + ( Catch::ReusableStringStream() << __VA_ARGS__ ) \ + .str() ) ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +#else + +// These section definitions imply that at most one section at one level +// will be intered (because only one section's __LINE__ can be equal to +// the dummy `catchInternalSectionHint` variable from `TEST_CASE`). + +namespace Catch { + namespace Detail { + // Intentionally without linkage, as it should only be used as a dummy + // symbol for static analysis. + int GetNewSectionHint(); + } // namespace Detail +} // namespace Catch + + +# define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \ + catchInternalSectionHint, \ + catchInternalSectionHint = Catch::Detail::GetNewSectionHint(); \ + catchInternalPreviousSectionHint == __LINE__ ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \ + catchInternalSectionHint, \ + catchInternalSectionHint = Catch::Detail::GetNewSectionHint(); \ + catchInternalPreviousSectionHint == __LINE__ ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +#endif -#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #endif // CATCH_SECTION_HPP_INCLUDED @@ -6070,42 +5908,20 @@ namespace Catch { -#ifndef CATCH_INTERFACES_TESTCASE_HPP_INCLUDED -#define CATCH_INTERFACES_TESTCASE_HPP_INCLUDED - -#include +#ifndef CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED +#define CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED namespace Catch { - class TestSpec; - struct TestCaseInfo; - class ITestInvoker { public: - virtual void invoke () const = 0; + virtual void invoke() const = 0; virtual ~ITestInvoker(); // = default }; - class TestCaseHandle; - class IConfig; +} // namespace Catch - 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 const& getAllInfos() const = 0; - virtual std::vector const& getAllTests() const = 0; - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; - }; - - bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ); - bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - -} - -#endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED +#endif // CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED #ifndef CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED @@ -6177,25 +5993,55 @@ struct AutoReg : Detail::NonCopyable { void TestName::test() #endif + +#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT) + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + namespace{ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__ ) - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + + +// Dummy registrator for the dumy test case macros +namespace Catch { + namespace Detail { + struct DummyUse { + DummyUse( void ( * )( int ) ); + }; + } // namespace Detail +} // namespace Catch + +// Note that both the presence of the argument and its exact name are +// necessary for the section support. + +// We provide a shadowed variable so that a `SECTION` inside non-`TEST_CASE` +// tests can compile. The redefined `TEST_CASE` shadows this with param. +static int catchInternalSectionHint = 0; + +# define INTERNAL_CATCH_TESTCASE2( fname ) \ + static void fname( int ); \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + static const Catch::Detail::DummyUse INTERNAL_CATCH_UNIQUE_NAME( \ + dummyUser )( &(fname) ); \ + CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + static void fname( [[maybe_unused]] int catchInternalSectionHint ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +# define INTERNAL_CATCH_TESTCASE( ... ) \ + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( dummyFunction ) ) + + +#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ @@ -6206,13 +6052,33 @@ struct AutoReg : Detail::NonCopyable { struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ void test(); \ }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \ + Catch::makeTestInvoker( &TestName::test ), \ + CATCH_INTERNAL_LINEINFO, \ + #ClassName##_catch_sr, \ + Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ } \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + namespace { \ + const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \ + Catch::makeTestInvoker( &QualifiedMethod ), \ + CATCH_INTERNAL_LINEINFO, \ + "&" #QualifiedMethod##_catch_sr, \ + Catch::NameAndTags{ __VA_ARGS__ } ); \ + } /* NOLINT */ \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ do { \ @@ -6260,6 +6126,7 @@ struct AutoReg : Detail::NonCopyable { #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) @@ -6313,6 +6180,7 @@ struct AutoReg : Detail::NonCopyable { #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) @@ -6357,6 +6225,7 @@ struct AutoReg : Detail::NonCopyable { #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) @@ -6409,6 +6278,7 @@ struct AutoReg : Detail::NonCopyable { #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) @@ -6835,7 +6705,7 @@ struct AutoReg : Detail::NonCopyable { void reg_tests() { \ size_t index = 0; \ using expander = size_t[]; \ - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ } \ };\ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ @@ -6970,7 +6840,7 @@ struct AutoReg : Detail::NonCopyable { void reg_tests(){\ size_t index = 0;\ using expander = size_t[];\ - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ }\ };\ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ @@ -7098,6 +6968,7 @@ struct AutoReg : Detail::NonCopyable { +#include #include #include @@ -7250,6 +7121,10 @@ namespace Catch { #include namespace Catch { + namespace Detail { + void registerTranslatorImpl( + Detail::unique_ptr&& translator ); + } class ExceptionTranslatorRegistrar { template @@ -7283,9 +7158,9 @@ namespace Catch { public: template ExceptionTranslatorRegistrar( std::string(*translateFunction)( T const& ) ) { - getMutableRegistryHub().registerTranslator( - Detail::make_unique>(translateFunction) - ); + Detail::registerTranslatorImpl( + Detail::make_unique>( + translateFunction ) ); } }; @@ -7357,8 +7232,8 @@ namespace Catch { #define CATCH_VERSION_MACROS_HPP_INCLUDED #define CATCH_VERSION_MAJOR 3 -#define CATCH_VERSION_MINOR 2 -#define CATCH_VERSION_PATCH 1 +#define CATCH_VERSION_MINOR 5 +#define CATCH_VERSION_PATCH 0 #endif // CATCH_VERSION_MACROS_HPP_INCLUDED @@ -7682,37 +7557,47 @@ namespace Detail { return makeGenerators( value( T( CATCH_FORWARD( val ) ) ), CATCH_FORWARD( moreGenerators )... ); } - auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; + IGeneratorTracker* acquireGeneratorTracker( StringRef generatorName, + SourceLineInfo const& lineInfo ); + IGeneratorTracker* createGeneratorTracker( StringRef generatorName, + SourceLineInfo lineInfo, + GeneratorBasePtr&& generator ); template - // Note: The type after -> is weird, because VS2015 cannot parse - // the expression used in the typedef inside, when it is in - // return type. Yeah. - auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval().get()) { + 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 ); - if (!tracker.hasGenerator()) { - tracker.setGenerator(Catch::Detail::make_unique>(generatorExpression())); + 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>( + generatorExpression() ) ); } - auto const& generator = static_cast const&>( *tracker.getGenerator() ); + auto const& generator = static_cast 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( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + 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( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + 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( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + 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) @@ -8010,7 +7895,550 @@ namespace Catch { #endif // CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED -#include + + +#ifndef CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED +#define CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED + + + + +#ifndef CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED +#define CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + namespace Detail { + + template + struct SizedUnsignedType; +#define SizedUnsignedTypeHelper( TYPE ) \ + template <> \ + struct SizedUnsignedType { \ + using type = TYPE; \ + } + + SizedUnsignedTypeHelper( std::uint8_t ); + SizedUnsignedTypeHelper( std::uint16_t ); + SizedUnsignedTypeHelper( std::uint32_t ); + SizedUnsignedTypeHelper( std::uint64_t ); +#undef SizedUnsignedTypeHelper + + template + using SizedUnsignedType_t = typename SizedUnsignedType::type; + + template + using DoubleWidthUnsignedType_t = SizedUnsignedType_t<2 * sizeof( T )>; + + template + struct ExtendedMultResult { + T upper; + T lower; + friend bool operator==( ExtendedMultResult const& lhs, + ExtendedMultResult const& rhs ) { + return lhs.upper == rhs.upper && lhs.lower == rhs.lower; + } + }; + + // Returns 128 bit result of multiplying lhs and rhs + constexpr ExtendedMultResult + extendedMult( std::uint64_t lhs, std::uint64_t rhs ) { + // We use the simple long multiplication approach for + // correctness, we can use platform specific builtins + // for performance later. + + // Split the lhs and rhs into two 32bit "digits", so that we can + // do 64 bit arithmetic to handle carry bits. + // 32b 32b 32b 32b + // lhs L1 L2 + // * rhs R1 R2 + // ------------------------ + // | R2 * L2 | + // | R2 * L1 | + // | R1 * L2 | + // | R1 * L1 | + // ------------------------- + // | a | b | c | d | + +#define CarryBits( x ) ( x >> 32 ) +#define Digits( x ) ( x & 0xFF'FF'FF'FF ) + + auto r2l2 = Digits( rhs ) * Digits( lhs ); + auto r2l1 = Digits( rhs ) * CarryBits( lhs ); + auto r1l2 = CarryBits( rhs ) * Digits( lhs ); + auto r1l1 = CarryBits( rhs ) * CarryBits( lhs ); + + // Sum to columns first + auto d = Digits( r2l2 ); + auto c = CarryBits( r2l2 ) + Digits( r2l1 ) + Digits( r1l2 ); + auto b = CarryBits( r2l1 ) + CarryBits( r1l2 ) + Digits( r1l1 ); + auto a = CarryBits( r1l1 ); + + // Propagate carries between columns + c += CarryBits( d ); + b += CarryBits( c ); + a += CarryBits( b ); + + // Remove the used carries + c = Digits( c ); + b = Digits( b ); + a = Digits( a ); + +#undef CarryBits +#undef Digits + + return { + a << 32 | b, // upper 64 bits + c << 32 | d // lower 64 bits + }; + } + + template + constexpr ExtendedMultResult extendedMult( UInt lhs, UInt rhs ) { + static_assert( std::is_unsigned::value, + "extendedMult can only handle unsigned integers" ); + static_assert( sizeof( UInt ) < sizeof( std::uint64_t ), + "Generic extendedMult can only handle types smaller " + "than uint64_t" ); + using WideType = DoubleWidthUnsignedType_t; + + auto result = WideType( lhs ) * WideType( rhs ); + return { + static_cast( result >> ( CHAR_BIT * sizeof( UInt ) ) ), + static_cast( result & UInt( -1 ) ) }; + } + + + template + std::enable_if_t= sizeof(TargetType), + TargetType> fillBitsFrom(Generator& gen) { + using gresult_type = typename Generator::result_type; + static_assert( std::is_unsigned::value, "Only unsigned integers are supported" ); + static_assert( Generator::min() == 0 && + Generator::max() == static_cast( -1 ), + "Generator must be able to output all numbers in its result type (effectively it must be a random bit generator)" ); + + // We want to return the top bits from a generator, as they are + // usually considered higher quality. + constexpr auto generated_bits = sizeof( gresult_type ) * CHAR_BIT; + constexpr auto return_bits = sizeof( TargetType ) * CHAR_BIT; + + return static_cast( gen() >> + ( generated_bits - return_bits) ); + } + + template + std::enable_if_t fillBitsFrom(Generator& gen) { + using gresult_type = typename Generator::result_type; + static_assert( std::is_unsigned::value, + "Only unsigned integers are supported" ); + static_assert( Generator::min() == 0 && + Generator::max() == static_cast( -1 ), + "Generator must be able to output all numbers in its result type (effectively it must be a random bit generator)" ); + + constexpr auto generated_bits = sizeof( gresult_type ) * CHAR_BIT; + constexpr auto return_bits = sizeof( TargetType ) * CHAR_BIT; + std::size_t filled_bits = 0; + TargetType ret = 0; + do { + ret <<= generated_bits; + ret |= gen(); + filled_bits += generated_bits; + } while ( filled_bits < return_bits ); + + return ret; + } + + /* + * Transposes numbers into unsigned type while keeping their ordering + * + * This means that signed types are changed so that the ordering is + * [INT_MIN, ..., -1, 0, ..., INT_MAX], rather than order we would + * get by simple casting ([0, ..., INT_MAX, INT_MIN, ..., -1]) + */ + template + std::enable_if_t::value, UnsignedType> + transposeToNaturalOrder( UnsignedType in ) { + static_assert( + sizeof( OriginalType ) == sizeof( UnsignedType ), + "reordering requires the same sized types on both sides" ); + static_assert( std::is_unsigned::value, + "Input type must be unsigned" ); + // Assuming 2s complement (standardized in current C++), the + // positive and negative numbers are already internally ordered, + // and their difference is in the top bit. Swapping it orders + // them the desired way. + constexpr auto highest_bit = + UnsignedType( 1 ) << ( sizeof( UnsignedType ) * CHAR_BIT - 1 ); + return static_cast( in ^ highest_bit ); + } + + + + template + std::enable_if_t::value, UnsignedType> + transposeToNaturalOrder(UnsignedType in) { + static_assert( + sizeof( OriginalType ) == sizeof( UnsignedType ), + "reordering requires the same sized types on both sides" ); + static_assert( std::is_unsigned::value, "Input type must be unsigned" ); + // No reordering is needed for unsigned -> unsigned + return in; + } + } // namespace Detail +} // namespace Catch + +#endif // CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED + +namespace Catch { + + namespace Detail { + // Indirection to enable make_unsigned behaviour. + template + struct make_unsigned { + using type = std::make_unsigned_t; + }; + + template <> + struct make_unsigned { + using type = uint8_t; + }; + + template + using make_unsigned_t = typename make_unsigned::type; + } + +/** + * Implementation of uniform distribution on integers. + * + * Unlike `std::uniform_int_distribution`, this implementation supports + * various 1 byte integral types, including bool (but you should not + * actually use it for bools). + * + * The underlying algorithm is based on the one described in "Fast Random + * Integer Generation in an Interval" by Daniel Lemire, but has been + * optimized under the assumption of reuse of the same distribution object. + */ +template +class uniform_integer_distribution { + static_assert(std::is_integral::value, "..."); + + using UnsignedIntegerType = Detail::make_unsigned_t; + + // We store the left range bound converted to internal representation, + // because it will be used in computation in the () operator. + UnsignedIntegerType m_a; + // After initialization, right bound is only used for the b() getter, + // so we keep it in the original type. + IntegerType m_b; + + // How many different values are there in [a, b]. a == b => 1, can be 0 for distribution over all values in the type. + UnsignedIntegerType m_ab_distance; + + // We hoisted this out of the main generation function. Technically, + // this means that using this distribution will be slower than Lemire's + // algorithm if this distribution instance will be used only few times, + // but it will be faster if it is used many times. Since Catch2 uses + // distributions only to implement random generators, we assume that each + // distribution will be reused many times and this is an optimization. + UnsignedIntegerType m_rejection_threshold = 0; + + // Assumes m_b and m_a are already filled + UnsignedIntegerType computeDistance() const { + // This overflows and returns 0 if ua == 0 and ub == TYPE_MAX. + // We handle that later when generating the number. + return transposeTo(m_b) - m_a + 1; + } + + static UnsignedIntegerType computeRejectionThreshold(UnsignedIntegerType ab_distance) { + // distance == 0 means that we will return all possible values from + // the type's range, and that we shouldn't reject anything. + if ( ab_distance == 0 ) { return 0; } + return ( ~ab_distance + 1 ) % ab_distance; + } + + static UnsignedIntegerType transposeTo(IntegerType in) { + return Detail::transposeToNaturalOrder( + static_cast( in ) ); + } + static IntegerType transposeBack(UnsignedIntegerType in) { + return static_cast( + Detail::transposeToNaturalOrder(in) ); + } + +public: + using result_type = IntegerType; + + uniform_integer_distribution( IntegerType a, IntegerType b ): + m_a( transposeTo(a) ), + m_b( b ), + m_ab_distance( computeDistance() ), + m_rejection_threshold( computeRejectionThreshold(m_ab_distance) ) { + assert( a <= b ); + } + + template + result_type operator()( Generator& g ) { + // All possible values of result_type are valid. + if ( m_ab_distance == 0 ) { + return transposeBack( Detail::fillBitsFrom( g ) ); + } + + auto random_number = Detail::fillBitsFrom( g ); + auto emul = Detail::extendedMult( random_number, m_ab_distance ); + // Unlike Lemire's algorithm we skip the ab_distance check, since + // we precomputed the rejection threshold, which is always tighter. + while (emul.lower < m_rejection_threshold) { + random_number = Detail::fillBitsFrom( g ); + emul = Detail::extendedMult( random_number, m_ab_distance ); + } + + return transposeBack(m_a + emul.upper); + } + + result_type a() const { return transposeBack(m_a); } + result_type b() const { return m_b; } +}; + +} // end namespace Catch + +#endif // CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED + + + +#ifndef CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED +#define CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED + + + + +#ifndef CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED +#define CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED + + + +#ifndef CATCH_POLYFILLS_HPP_INCLUDED +#define CATCH_POLYFILLS_HPP_INCLUDED + +namespace Catch { + + bool isnan(float f); + bool isnan(double d); + + float nextafter(float x, float y); + double nextafter(double x, double y); + +} + +#endif // CATCH_POLYFILLS_HPP_INCLUDED + +#include +#include +#include +#include +#include + +namespace Catch { + + namespace Detail { + /** + * Returns the largest magnitude of 1-ULP distance inside the [a, b] range. + * + * Assumes `a < b`. + */ + template + FloatType gamma(FloatType a, FloatType b) { + static_assert( std::is_floating_point::value, + "gamma returns the largest ULP magnitude within " + "floating point range [a, b]. This only makes sense " + "for floating point types" ); + assert( a <= b ); + + const auto gamma_up = Catch::nextafter( a, std::numeric_limits::infinity() ) - a; + const auto gamma_down = b - Catch::nextafter( b, -std::numeric_limits::infinity() ); + + return gamma_up < gamma_down ? gamma_down : gamma_up; + } + + template + struct DistanceTypePicker; + template <> + struct DistanceTypePicker { + using type = std::uint32_t; + }; + template <> + struct DistanceTypePicker { + using type = std::uint64_t; + }; + + template + using DistanceType = typename DistanceTypePicker::type; + +#if defined( __GNUC__ ) || defined( __clang__ ) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + /** + * Computes the number of equi-distant floats in [a, b] + * + * Since not every range can be split into equidistant floats + * exactly, we actually compute ceil(b/distance - a/distance), + * because in those cases we want to overcount. + * + * Uses modified Dekker's FastTwoSum algorithm to handle rounding. + */ + template + DistanceType + count_equidistant_floats( FloatType a, FloatType b, FloatType distance ) { + assert( a <= b ); + // We get distance as gamma for our uniform float distribution, + // so this will round perfectly. + const auto ag = a / distance; + const auto bg = b / distance; + + const auto s = bg - ag; + const auto err = ( std::fabs( a ) <= std::fabs( b ) ) + ? -ag - ( s - bg ) + : bg - ( s + ag ); + const auto ceil_s = static_cast>( std::ceil( s ) ); + + return ( ceil_s != s ) ? ceil_s : ceil_s + ( err > 0 ); + } +#if defined( __GNUC__ ) || defined( __clang__ ) +# pragma GCC diagnostic pop +#endif + + } + +} // end namespace Catch + +#endif // CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED + +#include +#include + +namespace Catch { + + namespace Detail { +#if defined( __GNUC__ ) || defined( __clang__ ) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + // The issue with overflow only happens with maximal ULP and HUGE + // distance, e.g. when generating numbers in [-inf, inf] for given + // type. So we only check for the largest possible ULP in the + // type, and return something that does not overflow to inf in 1 mult. + constexpr std::uint64_t calculate_max_steps_in_one_go(double gamma) { + if ( gamma == 1.99584030953472e+292 ) { return 9007199254740991; } + return static_cast( -1 ); + } + constexpr std::uint32_t calculate_max_steps_in_one_go(float gamma) { + if ( gamma == 2.028241e+31f ) { return 16777215; } + return static_cast( -1 ); + } +#if defined( __GNUC__ ) || defined( __clang__ ) +# pragma GCC diagnostic pop +#endif + } + +/** + * Implementation of uniform distribution on floating point numbers. + * + * Note that we support only `float` and `double` types, because these + * usually mean the same thing across different platform. `long double` + * varies wildly by platform and thus we cannot provide reproducible + * implementation. Also note that we don't implement all parts of + * distribution per standard: this distribution is not serializable, nor + * can the range be arbitrarily reset. + * + * The implementation also uses different approach than the one taken by + * `std::uniform_real_distribution`, where instead of generating a number + * between [0, 1) and then multiplying the range bounds with it, we first + * split the [a, b] range into a set of equidistributed floating point + * numbers, and then use uniform int distribution to pick which one to + * return. + * + * This has the advantage of guaranteeing uniformity (the multiplication + * method loses uniformity due to rounding when multiplying floats), except + * for small non-uniformity at one side of the interval, where we have + * to deal with the fact that not every interval is splittable into + * equidistributed floats. + * + * Based on "Drawing random floating-point numbers from an interval" by + * Frederic Goualard. + */ +template +class uniform_floating_point_distribution { + static_assert(std::is_floating_point::value, "..."); + static_assert(!std::is_same::value, + "We do not support long double due to inconsistent behaviour between platforms"); + + using WidthType = Detail::DistanceType; + + FloatType m_a, m_b; + FloatType m_ulp_magnitude; + WidthType m_floats_in_range; + uniform_integer_distribution m_int_dist; + + // In specific cases, we can overflow into `inf` when computing the + // `steps * g` offset. To avoid this, we don't offset by more than this + // in one multiply + addition. + WidthType m_max_steps_in_one_go; + // We don't want to do the magnitude check every call to `operator()` + bool m_a_has_leq_magnitude; + +public: + using result_type = FloatType; + + uniform_floating_point_distribution( FloatType a, FloatType b ): + m_a( a ), + m_b( b ), + m_ulp_magnitude( Detail::gamma( m_a, m_b ) ), + m_floats_in_range( Detail::count_equidistant_floats( m_a, m_b, m_ulp_magnitude ) ), + m_int_dist(0, m_floats_in_range), + m_max_steps_in_one_go( Detail::calculate_max_steps_in_one_go(m_ulp_magnitude)), + m_a_has_leq_magnitude(std::fabs(m_a) <= std::fabs(m_b)) + { + assert( a <= b ); + } + + template + result_type operator()( Generator& g ) { + WidthType steps = m_int_dist( g ); + if ( m_a_has_leq_magnitude ) { + if ( steps == m_floats_in_range ) { return m_a; } + auto b = m_b; + while (steps > m_max_steps_in_one_go) { + b -= m_max_steps_in_one_go * m_ulp_magnitude; + steps -= m_max_steps_in_one_go; + } + return b - steps * m_ulp_magnitude; + } else { + if ( steps == m_floats_in_range ) { return m_b; } + auto a = m_a; + while (steps > m_max_steps_in_one_go) { + a += m_max_steps_in_one_go * m_ulp_magnitude; + steps -= m_max_steps_in_one_go; + } + return a + steps * m_ulp_magnitude; + } + } + + result_type a() const { return m_a; } + result_type b() const { return m_b; } +}; + +} // end namespace Catch + +#endif // CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED namespace Catch { namespace Generators { @@ -8024,7 +8452,7 @@ namespace Detail { template class RandomFloatingGenerator final : public IGenerator { Catch::SimplePcg32 m_rng; - std::uniform_real_distribution m_dist; + Catch::uniform_floating_point_distribution m_dist; Float m_current_number; public: RandomFloatingGenerator( Float a, Float b, std::uint32_t seed ): @@ -8042,10 +8470,27 @@ public: } }; +template <> +class RandomFloatingGenerator final : public IGenerator { + // We still rely on for this specialization, but we don't + // want to drag it into the header. + struct PImpl; + Catch::Detail::unique_ptr m_pimpl; + long double m_current_number; + +public: + RandomFloatingGenerator( long double a, long double b, std::uint32_t seed ); + + long double const& get() const override { return m_current_number; } + bool next() override; + + ~RandomFloatingGenerator() override; // = default +}; + template class RandomIntegerGenerator final : public IGenerator { Catch::SimplePcg32 m_rng; - std::uniform_int_distribution m_dist; + Catch::uniform_integer_distribution m_dist; Integer m_current_number; public: RandomIntegerGenerator( Integer a, Integer b, std::uint32_t seed ): @@ -8066,14 +8511,6 @@ public: template std::enable_if_t::value, GeneratorWrapper> random(T a, T b) { - static_assert( - !std::is_same::value && - !std::is_same::value && - !std::is_same::value && - !std::is_same::value && - !std::is_same::value && - !std::is_same::value, - "The requested type is not supported by the underlying random distributions from std" ); return GeneratorWrapper( Catch::Detail::make_unique>(a, b, Detail::getSeed()) ); @@ -8186,10 +8623,11 @@ GeneratorWrapper from_range(InputIterator from, InputSentinel to) { return GeneratorWrapper(Catch::Detail::make_unique>(from, to)); } -template -GeneratorWrapper from_range(Container const& cnt) { - return GeneratorWrapper(Catch::Detail::make_unique>(cnt.begin(), cnt.end())); +template +auto from_range(Container const& cnt) { + using std::begin; + using std::end; + return from_range( begin( cnt ), end( cnt ) ); } @@ -8221,6 +8659,232 @@ GeneratorWrapper from_range(Container const& cnt) { +#ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED +#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED + + + +#ifndef CATCH_TEST_RUN_INFO_HPP_INCLUDED +#define CATCH_TEST_RUN_INFO_HPP_INCLUDED + + +namespace Catch { + + struct TestRunInfo { + constexpr TestRunInfo(StringRef _name) : name(_name) {} + StringRef name; + }; + +} // end namespace Catch + +#endif // CATCH_TEST_RUN_INFO_HPP_INCLUDED + +#include +#include +#include +#include + +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 _stream, + ColourMode colourMode, + std::map customOptions ); + + ReporterConfig( ReporterConfig&& ) = default; + ReporterConfig& operator=( ReporterConfig&& ) = default; + ~ReporterConfig(); // = default + + Detail::unique_ptr takeStream() &&; + IConfig const* fullConfig() const; + ColourMode colourMode() const; + std::map const& customOptions() const; + + private: + Detail::unique_ptr m_stream; + IConfig const* m_fullConfig; + ColourMode m_colourMode; + std::map m_customOptions; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector 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 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 const& descriptions) = 0; + //! Writes out the provided listeners descriptions using reporter-specific format + virtual void listListeners(std::vector const& descriptions) = 0; + //! Writes out information about provided tests using reporter-specific format + virtual void listTests(std::vector const& tests) = 0; + //! Writes out information about the provided tags using reporter-specific format + virtual void listTags(std::vector const& tags) = 0; + }; + using IEventListenerPtr = Detail::unique_ptr; + +} // end namespace Catch + +#endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED + + #ifndef CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED #define CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED @@ -8259,9 +8923,55 @@ namespace Catch { #endif // CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED -#ifndef CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED -#define CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED +#ifndef CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED +#define CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED +#include + +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 + + +#ifndef CATCH_INTERFACES_TESTCASE_HPP_INCLUDED +#define CATCH_INTERFACES_TESTCASE_HPP_INCLUDED + +#include + +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 const& getAllInfos() const = 0; + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + +} + +#endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED + +#endif // CATCH_INTERFACES_ALL_HPP_INCLUDED #ifndef CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED @@ -8287,62 +8997,6 @@ namespace Catch { #endif // CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED -#include -#include -#include - -namespace Catch { - - class IConfig; - - class IEventListener; - using IEventListenerPtr = Detail::unique_ptr; - class IReporterFactory; - using IReporterFactoryPtr = Detail::unique_ptr; - struct ReporterConfig; - class EventListenerFactory; - - class IReporterRegistry { - public: - using FactoryMap = std::map; - using Listeners = std::vector>; - - virtual ~IReporterRegistry(); // = default - virtual IEventListenerPtr create( std::string const& name, ReporterConfig&& config ) const = 0; - virtual FactoryMap const& getFactories() const = 0; - virtual Listeners const& getListeners() const = 0; - }; - -} // end namespace Catch - -#endif // CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED - - -#ifndef CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED -#define CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED - -#include - -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 - -#endif // CATCH_INTERFACES_ALL_HPP_INCLUDED - /** \file @@ -8383,6 +9037,7 @@ namespace Catch { #ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED #define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED + #if defined(_MSC_VER) # if _MSC_VER >= 1900 // Visual Studio 2015 or newer # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS @@ -8515,7 +9170,10 @@ namespace Catch { #if defined(__i386__) || defined(__x86_64__) #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ #elif defined(__aarch64__) - #define CATCH_TRAP() __asm__(".inst 0xd43e0000") + #define CATCH_TRAP() __asm__(".inst 0xd43e0000") + #elif defined(__POWERPC__) + #define CATCH_TRAP() __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ) /* NOLINT */ #endif #elif defined(CATCH_PLATFORM_IPHONE) @@ -8670,7 +9328,6 @@ namespace Catch { ~ExceptionTranslatorRegistry() override; void registerTranslator( Detail::unique_ptr&& translator ); std::string translateActiveException() const override; - std::string tryTranslators() const; private: ExceptionTranslators m_translators; @@ -8746,17 +9403,6 @@ namespace Catch { #define CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED - -#ifndef CATCH_POLYFILLS_HPP_INCLUDED -#define CATCH_POLYFILLS_HPP_INCLUDED - -namespace Catch { - bool isnan(float f); - bool isnan(double d); -} - -#endif // CATCH_POLYFILLS_HPP_INCLUDED - #include #include #include @@ -8769,6 +9415,11 @@ namespace Catch { uint32_t convertToBits(float f); uint64_t convertToBits(double d); + // Used when we know we want == comparison of two doubles + // to centralize warning suppression + bool directCompare( float lhs, float rhs ); + bool directCompare( double lhs, double rhs ); + } // end namespace Detail @@ -8865,6 +9516,139 @@ namespace Detail { #endif // CATCH_GETENV_HPP_INCLUDED +#ifndef CATCH_IS_PERMUTATION_HPP_INCLUDED +#define CATCH_IS_PERMUTATION_HPP_INCLUDED + +#include +#include + +namespace Catch { + namespace Detail { + + template + ForwardIter find_sentinel( ForwardIter start, + Sentinel sentinel, + T const& value, + Comparator cmp ) { + while ( start != sentinel ) { + if ( cmp( *start, value ) ) { break; } + ++start; + } + return start; + } + + template + std::ptrdiff_t count_sentinel( ForwardIter start, + Sentinel sentinel, + T const& value, + Comparator cmp ) { + std::ptrdiff_t count = 0; + while ( start != sentinel ) { + if ( cmp( *start, value ) ) { ++count; } + ++start; + } + return count; + } + + template + std::enable_if_t::value, + std::ptrdiff_t> + sentinel_distance( ForwardIter iter, const Sentinel sentinel ) { + std::ptrdiff_t dist = 0; + while ( iter != sentinel ) { + ++iter; + ++dist; + } + return dist; + } + + template + std::ptrdiff_t sentinel_distance( ForwardIter first, + ForwardIter last ) { + return std::distance( first, last ); + } + + template + bool check_element_counts( ForwardIter1 first_1, + const Sentinel1 end_1, + ForwardIter2 first_2, + const Sentinel2 end_2, + Comparator cmp ) { + auto cursor = first_1; + while ( cursor != end_1 ) { + if ( find_sentinel( first_1, cursor, *cursor, cmp ) == + cursor ) { + // we haven't checked this element yet + const auto count_in_range_2 = + count_sentinel( first_2, end_2, *cursor, cmp ); + // Not a single instance in 2nd range, so it cannot be a + // permutation of 1st range + if ( count_in_range_2 == 0 ) { return false; } + + const auto count_in_range_1 = + count_sentinel( cursor, end_1, *cursor, cmp ); + if ( count_in_range_1 != count_in_range_2 ) { + return false; + } + } + + ++cursor; + } + + return true; + } + + template + bool is_permutation( ForwardIter1 first_1, + const Sentinel1 end_1, + ForwardIter2 first_2, + const Sentinel2 end_2, + Comparator cmp ) { + // TODO: no optimization for stronger iterators, because we would also have to constrain on sentinel vs not sentinel types + // TODO: Comparator has to be "both sides", e.g. a == b => b == a + // This skips shared prefix of the two ranges + while (first_1 != end_1 && first_2 != end_2 && cmp(*first_1, *first_2)) { + ++first_1; + ++first_2; + } + + // We need to handle case where at least one of the ranges has no more elements + if (first_1 == end_1 || first_2 == end_2) { + return first_1 == end_1 && first_2 == end_2; + } + + // pair counting is n**2, so we pay linear walk to compare the sizes first + auto dist_1 = sentinel_distance( first_1, end_1 ); + auto dist_2 = sentinel_distance( first_2, end_2 ); + + if (dist_1 != dist_2) { return false; } + + // Since we do not try to handle stronger iterators pair (e.g. + // bidir) optimally, the only thing left to do is to check counts in + // the remaining ranges. + return check_element_counts( first_1, end_1, first_2, end_2, cmp ); + } + + } // namespace Detail +} // namespace Catch + +#endif // CATCH_IS_PERMUTATION_HPP_INCLUDED + + #ifndef CATCH_ISTREAM_HPP_INCLUDED #define CATCH_ISTREAM_HPP_INCLUDED @@ -8912,6 +9696,119 @@ namespace Catch { #endif // CATCH_STREAM_HPP_INCLUDED +#ifndef CATCH_JSONWRITER_HPP_INCLUDED +#define CATCH_JSONWRITER_HPP_INCLUDED + + +#include +#include + +namespace Catch { + class JsonObjectWriter; + class JsonArrayWriter; + + struct JsonUtils { + static void indent( std::ostream& os, std::uint64_t level ); + static void appendCommaNewline( std::ostream& os, + bool& should_comma, + std::uint64_t level ); + }; + + class JsonValueWriter { + public: + JsonValueWriter( std::ostream& os ); + JsonValueWriter( std::ostream& os, std::uint64_t indent_level ); + + JsonObjectWriter writeObject() &&; + JsonArrayWriter writeArray() &&; + + template + void write( T const& value ) && { + writeImpl( value, !std::is_arithmetic::value ); + } + void write( StringRef value ) &&; + void write( bool value ) &&; + + private: + void writeImpl( StringRef value, bool quote ); + + // Without this SFINAE, this overload is a better match + // for `std::string`, `char const*`, `char const[N]` args. + // While it would still work, it would cause code bloat + // and multiple iteration over the strings + template ::value>> + void writeImpl( T const& value, bool quote_value ) { + m_sstream << value; + writeImpl( m_sstream.str(), quote_value ); + } + + std::ostream& m_os; + std::stringstream m_sstream; + std::uint64_t m_indent_level; + }; + + class JsonObjectWriter { + public: + JsonObjectWriter( std::ostream& os ); + JsonObjectWriter( std::ostream& os, std::uint64_t indent_level ); + + JsonObjectWriter( JsonObjectWriter&& source ); + JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete; + + ~JsonObjectWriter(); + + JsonValueWriter write( StringRef key ); + + private: + std::ostream& m_os; + std::uint64_t m_indent_level; + bool m_should_comma = false; + bool m_active = true; + }; + + class JsonArrayWriter { + public: + JsonArrayWriter( std::ostream& os ); + JsonArrayWriter( std::ostream& os, std::uint64_t indent_level ); + + JsonArrayWriter( JsonArrayWriter&& source ); + JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete; + + ~JsonArrayWriter(); + + JsonObjectWriter writeObject(); + JsonArrayWriter writeArray(); + + template + JsonArrayWriter& write( T const& value ) { + return writeImpl( value ); + } + + JsonArrayWriter& write( bool value ); + + private: + template + JsonArrayWriter& writeImpl( T const& value ) { + JsonUtils::appendCommaNewline( + m_os, m_should_comma, m_indent_level + 1 ); + JsonValueWriter{ m_os }.write( value ); + + return *this; + } + + std::ostream& m_os; + std::uint64_t m_indent_level; + bool m_should_comma = false; + bool m_active = true; + }; + +} // namespace Catch + +#endif // CATCH_JSONWRITER_HPP_INCLUDED + + #ifndef CATCH_LEAK_DETECTOR_HPP_INCLUDED #define CATCH_LEAK_DETECTOR_HPP_INCLUDED @@ -9098,28 +9995,45 @@ namespace Catch { #include +#include +#include namespace Catch { - class ReporterRegistry : public IReporterRegistry { + class IEventListener; + using IEventListenerPtr = Detail::unique_ptr; + class IReporterFactory; + using IReporterFactoryPtr = Detail::unique_ptr; + struct ReporterConfig; + class EventListenerFactory; + + class ReporterRegistry { + struct ReporterRegistryImpl; + Detail::unique_ptr m_impl; + public: - ReporterRegistry(); - ~ReporterRegistry() override; // = default, out of line to allow fwd decl + ~ReporterRegistry(); // = default; - IEventListenerPtr create( std::string const& name, ReporterConfig&& config ) const override; + IEventListenerPtr create( std::string const& name, + ReporterConfig&& config ) const; - void registerReporter( std::string const& name, IReporterFactoryPtr factory ); - void registerListener( Detail::unique_ptr factory ); + void registerReporter( std::string const& name, + IReporterFactoryPtr factory ); - FactoryMap const& getFactories() const override; - Listeners const& getListeners() const override; + void + registerListener( Detail::unique_ptr factory ); - private: - FactoryMap m_factories; - Listeners m_listeners; + std::map const& + getFactories() const; + + std::vector> const& + getListeners() const; }; -} + +} // end namespace Catch #endif // CATCH_REPORTER_REGISTRY_HPP_INCLUDED @@ -9143,10 +10057,49 @@ namespace TestCaseTracking { std::string name; SourceLineInfo location; - NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); + NameAndLocation( std::string&& _name, SourceLineInfo const& _location ); friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) { - return lhs.name == rhs.name - && lhs.location == rhs.location; + // This is a very cheap check that should have a very high hit rate. + // If we get to SourceLineInfo::operator==, we will redo it, but the + // cost of repeating is trivial at that point (we will be paying + // multiple strcmp/memcmps at that point). + if ( lhs.location.line != rhs.location.line ) { return false; } + return lhs.name == rhs.name && lhs.location == rhs.location; + } + friend bool operator!=(NameAndLocation const& lhs, + NameAndLocation const& rhs) { + return !( lhs == rhs ); + } + }; + + /** + * This is a variant of `NameAndLocation` that does not own the name string + * + * This avoids extra allocations when trying to locate a tracker by its + * name and location, as long as we make sure that trackers only keep + * around the owning variant. + */ + struct NameAndLocationRef { + StringRef name; + SourceLineInfo location; + + constexpr NameAndLocationRef( StringRef name_, + SourceLineInfo location_ ): + name( name_ ), location( location_ ) {} + + friend bool operator==( NameAndLocation const& lhs, + NameAndLocationRef const& rhs ) { + // This is a very cheap check that should have a very high hit rate. + // If we get to SourceLineInfo::operator==, we will redo it, but the + // cost of repeating is trivial at that point (we will be paying + // multiple strcmp/memcmps at that point). + if ( lhs.location.line != rhs.location.line ) { return false; } + return StringRef( lhs.name ) == rhs.name && + lhs.location == rhs.location; + } + friend bool operator==( NameAndLocationRef const& lhs, + NameAndLocation const& rhs ) { + return rhs == lhs; } }; @@ -9174,8 +10127,8 @@ namespace TestCaseTracking { CycleState m_runState = NotStarted; public: - ITracker( NameAndLocation const& nameAndLoc, ITracker* parent ): - m_nameAndLocation( nameAndLoc ), + ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ): + m_nameAndLocation( CATCH_MOVE(nameAndLoc) ), m_parent( parent ) {} @@ -9195,8 +10148,10 @@ namespace TestCaseTracking { //! Returns true if tracker run to completion (successfully or not) virtual bool isComplete() const = 0; - //! Returns true if tracker run to completion succesfully - bool isSuccessfullyCompleted() const; + //! Returns true if tracker run to completion successfully + bool isSuccessfullyCompleted() const { + return m_runState == CompletedSuccessfully; + } //! Returns true if tracker has started but hasn't been completed bool isOpen() const; //! Returns true iff tracker has started @@ -9214,7 +10169,7 @@ namespace TestCaseTracking { * * Returns nullptr if not found. */ - ITracker* findChild( NameAndLocation const& nameAndLocation ); + ITracker* findChild( NameAndLocationRef const& nameAndLocation ); //! Have any children been added? bool hasChildren() const { return !m_children.empty(); @@ -9255,13 +10210,15 @@ namespace TestCaseTracking { public: ITracker& startRun(); - void endRun(); - void startCycle(); + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } void completeCycle(); bool completedCycle() const; - ITracker& currentTracker(); + ITracker& currentTracker() { return *m_currentTracker; } void setCurrentTracker( ITracker* tracker ); }; @@ -9271,7 +10228,7 @@ namespace TestCaseTracking { TrackerContext& m_ctx; public: - TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ); bool isComplete() const override; @@ -9287,22 +10244,26 @@ namespace TestCaseTracking { class SectionTracker : public TrackerBase { std::vector m_filters; - std::string m_trimmed_name; + // Note that lifetime-wise we piggy back off the name stored in the `ITracker` parent`. + // Currently it allocates owns the name, so this is safe. If it is later refactored + // to not own the name, the name still has to outlive the `ITracker` parent, so + // this should still be safe. + StringRef m_trimmed_name; public: - SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ); bool isSectionTracker() const override; bool isComplete() const override; - static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ); void tryOpen(); void addInitialFilters( std::vector const& filters ); void addNextFilters( std::vector const& filters ); //! Returns filters active in this tracker - std::vector const& getFilters() const; + std::vector const& getFilters() const { return m_filters; } //! Returns whitespace-trimmed name of the tracked section StringRef trimmedName() const; }; @@ -9321,13 +10282,14 @@ using TestCaseTracking::SectionTracker; namespace Catch { - class IMutableContext; class IGeneratorTracker; class IConfig; + class IEventListener; + using IEventListenerPtr = Detail::unique_ptr; /////////////////////////////////////////////////////////////////////////// - class RunContext : public IResultCapture { + class RunContext final : public IResultCapture { public: RunContext( RunContext const& ) = delete; @@ -9356,7 +10318,7 @@ namespace Catch { AssertionReaction& reaction ) override; void handleUnexpectedInflightException ( AssertionInfo const& info, - std::string const& message, + std::string&& message, AssertionReaction& reaction ) override; void handleIncomplete ( AssertionInfo const& info ) override; @@ -9365,12 +10327,22 @@ namespace Catch { ResultWas::OfType resultType, AssertionReaction &reaction ) override; - bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; + void notifyAssertionStarted( AssertionInfo const& info ) override; + bool sectionStarted( StringRef sectionName, + SourceLineInfo const& sectionLineInfo, + Counts& assertions ) override; - void sectionEnded( SectionEndInfo const& endInfo ) override; - void sectionEndedEarly( SectionEndInfo const& endInfo ) override; + void sectionEnded( SectionEndInfo&& endInfo ) override; + void sectionEndedEarly( SectionEndInfo&& endInfo ) override; + + IGeneratorTracker* + acquireGeneratorTracker( StringRef generatorName, + SourceLineInfo const& lineInfo ) override; + IGeneratorTracker* createGeneratorTracker( + StringRef generatorName, + SourceLineInfo lineInfo, + Generators::GeneratorBasePtr&& generator ) override; - auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; void benchmarkPreparing( StringRef name ) override; void benchmarkStarting( BenchmarkInfo const& info ) override; @@ -9380,7 +10352,7 @@ namespace Catch { void pushScopedMessage( MessageInfo const& message ) override; void popScopedMessage( MessageInfo const& message ) override; - void emplaceUnscopedMessage( MessageBuilder const& builder ) override; + void emplaceUnscopedMessage( MessageBuilder&& builder ) override; std::string getCurrentTestName() const override; @@ -9406,7 +10378,7 @@ namespace Catch { void resetAssertionInfo(); bool testForMissingAssertions( Counts& assertions ); - void assertionEnded( AssertionResult const& result ); + void assertionEnded( AssertionResult&& result ); void reportExpr ( AssertionInfo const &info, ResultWas::OfType resultType, @@ -9420,7 +10392,6 @@ namespace Catch { void handleUnfinishedSections(); TestRunInfo m_runInfo; - IMutableContext& m_context; TestCaseHandle const* m_activeTestCase = nullptr; ITracker* m_testCaseTracker = nullptr; Optional m_lastResult; @@ -9568,6 +10539,7 @@ namespace Catch { #define CATCH_STRING_MANIP_HPP_INCLUDED +#include #include #include #include @@ -9676,16 +10648,14 @@ namespace Catch { namespace Catch { - class TestCaseHandle; class IConfig; + class ITestInvoker; + class TestCaseHandle; class TestSpec; std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ); - bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ); - - void enforceNoDuplicateTestCases( std::vector const& functions ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); @@ -9714,18 +10684,6 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////// - class TestInvokerAsFunction final : public ITestInvoker { - using TestType = void(*)(); - TestType m_testAsFunction; - public: - TestInvokerAsFunction(TestType testAsFunction) noexcept: - m_testAsFunction(testAsFunction) {} - - void invoke() const override; - }; - - /////////////////////////////////////////////////////////////////////////// - } // end namespace Catch @@ -9861,7 +10819,7 @@ namespace Catch { // Calculates the length of the current line void calcLength(); - // Returns current indention width + // Returns current indentation width size_t indentSize() const; // Creates an indented and (optionally) suffixed string from @@ -10174,6 +11132,8 @@ namespace Catch { #define CATCH_MATCHERS_IMPL_HPP_INCLUDED +#include + namespace Catch { template @@ -10866,13 +11826,11 @@ namespace Catch { } template - bool match(RangeLike&& rng) const { - using std::begin; using std::end; - - return end(rng) != std::find_if(begin(rng), end(rng), - [&](auto const& elem) { - return m_eq(elem, m_desired); - }); + bool match( RangeLike&& rng ) const { + for ( auto&& elem : rng ) { + if ( m_eq( elem, m_desired ) ) { return true; } + } + return false; } }; @@ -10924,7 +11882,7 @@ namespace Catch { /** * Creates a matcher that checks whether a range contains a specific element. * - * Uses `eq` to do the comparisons + * Uses `eq` to do the comparisons, the element is provided on the rhs */ template ContainsElementMatcher Contains(T&& elem, Equality&& eq) { @@ -10960,6 +11918,32 @@ public: //! Creates a matcher that checks whether a std derived exception has the provided message ExceptionMessageMatcher Message(std::string const& message); +template +class ExceptionMessageMatchesMatcher final + : public MatcherBase { + StringMatcherType m_matcher; + +public: + ExceptionMessageMatchesMatcher( StringMatcherType matcher ): + m_matcher( CATCH_MOVE( matcher ) ) {} + + bool match( std::exception const& ex ) const override { + return m_matcher.match( ex.what() ); + } + + std::string describe() const override { + return " matches \"" + m_matcher.describe() + '"'; + } +}; + +//! Creates a matcher that checks whether a message from an std derived +//! exception matches a provided matcher +template +ExceptionMessageMatchesMatcher +MessageMatches( StringMatcherType&& matcher ) { + return { CATCH_FORWARD( matcher ) }; +} + } // namespace Matchers } // namespace Catch @@ -10987,6 +11971,11 @@ namespace Matchers { double m_margin; }; + //! Creates a matcher that accepts numbers within certain range of target + WithinAbsMatcher WithinAbs( double target, double margin ); + + + class WithinUlpsMatcher final : public MatcherBase { public: WithinUlpsMatcher( double target, @@ -11000,6 +11989,13 @@ namespace Matchers { Detail::FloatingPointKind m_type; }; + //! Creates a matcher that accepts doubles within certain ULP range of target + WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff); + //! Creates a matcher that accepts floats within certain ULP range of target + WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff); + + + // Given IEEE-754 format for floats and doubles, we can assume // that float -> double promotion is lossless. Given this, we can // assume that if we do the standard relative comparison of @@ -11016,13 +12012,6 @@ namespace Matchers { double m_epsilon; }; - //! Creates a matcher that accepts doubles within certain ULP range of target - WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff); - //! Creates a matcher that accepts floats within certain ULP range of target - WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff); - //! Creates a matcher that accepts numbers within certain range of target - WithinAbsMatcher WithinAbs(double target, double margin); - //! Creates a matcher that accepts doubles within certain relative range of target WithinRelMatcher WithinRel(double target, double eps); //! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target @@ -11032,6 +12021,17 @@ namespace Matchers { //! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target WithinRelMatcher WithinRel(float target); + + + class IsNaNMatcher final : public MatcherBase { + public: + IsNaNMatcher() = default; + bool match( double const& matchee ) const override; + std::string describe() const override; + }; + + IsNaNMatcher IsNaN(); + } // namespace Matchers } // namespace Catch @@ -11247,6 +12247,143 @@ namespace Catch { #endif // CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED +#ifndef CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED +#define CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED + + +#include +#include + +namespace Catch { + namespace Matchers { + + /** + * Matcher for checking that an element contains the same + * elements in the same order + */ + template + class RangeEqualsMatcher final : public MatcherGenericBase { + TargetRangeLike m_desired; + Equality m_predicate; + + public: + template + RangeEqualsMatcher( TargetRangeLike2&& range, + Equality2&& predicate ): + m_desired( CATCH_FORWARD( range ) ), + m_predicate( CATCH_FORWARD( predicate ) ) {} + + template + bool match( RangeLike&& rng ) const { + auto rng_start = begin( rng ); + const auto rng_end = end( rng ); + auto target_start = begin( m_desired ); + const auto target_end = end( m_desired ); + + while (rng_start != rng_end && target_start != target_end) { + if (!m_predicate(*rng_start, *target_start)) { + return false; + } + ++rng_start; + ++target_start; + } + return rng_start == rng_end && target_start == target_end; + } + + std::string describe() const override { + return "elements are " + Catch::Detail::stringify( m_desired ); + } + }; + + /** + * Matcher for checking that an element contains the same + * elements (but not necessarily in the same order) + */ + template + class UnorderedRangeEqualsMatcher final : public MatcherGenericBase { + TargetRangeLike m_desired; + Equality m_predicate; + + public: + template + UnorderedRangeEqualsMatcher( TargetRangeLike2&& range, + Equality2&& predicate ): + m_desired( CATCH_FORWARD( range ) ), + m_predicate( CATCH_FORWARD( predicate ) ) {} + + template + bool match( RangeLike&& rng ) const { + using std::begin; + using std::end; + return Catch::Detail::is_permutation( begin( m_desired ), + end( m_desired ), + begin( rng ), + end( rng ), + m_predicate ); + } + + std::string describe() const override { + return "unordered elements are " + + ::Catch::Detail::stringify( m_desired ); + } + }; + + /** + * Creates a matcher that checks if all elements in a range are equal + * to all elements in another range. + * + * Uses `std::equal_to` to do the comparison + */ + template + std::enable_if_t::value, + RangeEqualsMatcher>> + RangeEquals( RangeLike&& range ) { + return { CATCH_FORWARD( range ), std::equal_to<>{} }; + } + + /** + * Creates a matcher that checks if all elements in a range are equal + * to all elements in another range. + * + * Uses to provided predicate `predicate` to do the comparisons + */ + template + RangeEqualsMatcher + RangeEquals( RangeLike&& range, Equality&& predicate ) { + return { CATCH_FORWARD( range ), CATCH_FORWARD( predicate ) }; + } + + /** + * Creates a matcher that checks if all elements in a range are equal + * to all elements in another range, in some permutation + * + * Uses `std::equal_to` to do the comparison + */ + template + std::enable_if_t< + !Detail::is_matcher::value, + UnorderedRangeEqualsMatcher>> + UnorderedRangeEquals( RangeLike&& range ) { + return { CATCH_FORWARD( range ), std::equal_to<>{} }; + } + + /** + * Creates a matcher that checks if all elements in a range are equal + * to all elements in another range, in some permutation. + * + * Uses to provided predicate `predicate` to do the comparisons + */ + template + UnorderedRangeEqualsMatcher + UnorderedRangeEquals( RangeLike&& range, Equality&& predicate ) { + return { CATCH_FORWARD( range ), CATCH_FORWARD( predicate ) }; + } + } // namespace Matchers +} // namespace Catch + +#endif // CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED + + #ifndef CATCH_MATCHERS_STRING_HPP_INCLUDED #define CATCH_MATCHERS_STRING_HPP_INCLUDED @@ -11402,11 +12539,10 @@ namespace Matchers { // - a more general approach would be via a compare template that defaults // to using !=. but could be specialised for, e.g. std::vector etc // - then just call that directly - if (m_comparator.size() != v.size()) - return false; - for (std::size_t i = 0; i < v.size(); ++i) - if (m_comparator[i] != v[i]) - return false; + if ( m_comparator.size() != v.size() ) { return false; } + for ( std::size_t i = 0; i < v.size(); ++i ) { + if ( !( m_comparator[i] == v[i] ) ) { return false; } + } return true; } std::string describe() const override { @@ -11910,7 +13046,7 @@ namespace Catch { void skipTest(TestCaseInfo const&) override {} protected: - //! Should the cumulative base store the assertion expansion for succesful assertions? + //! Should the cumulative base store the assertion expansion for successful assertions? bool m_shouldStoreSuccesfulAssertions = true; //! Should the cumulative base store the assertion expansion for failed assertions? bool m_shouldStoreFailedAssertions = true; @@ -12078,6 +13214,93 @@ namespace Catch { #endif // CATCH_REPORTER_HELPERS_HPP_INCLUDED + +#ifndef CATCH_REPORTER_JSON_HPP_INCLUDED +#define CATCH_REPORTER_JSON_HPP_INCLUDED + + +#include + +namespace Catch { + class JsonReporter : public StreamingReporterBase { + public: + JsonReporter( ReporterConfig&& config ); + + ~JsonReporter() override; + + static std::string getDescription(); + + public: // StreamingReporterBase + void testRunStarting( TestRunInfo const& runInfo ) override; + void testRunEnded( TestRunStats const& runStats ) override; + + void testCaseStarting( TestCaseInfo const& tcInfo ) override; + void testCaseEnded( TestCaseStats const& tcStats ) override; + + void testCasePartialStarting( TestCaseInfo const& tcInfo, + uint64_t index ) override; + void testCasePartialEnded( TestCaseStats const& tcStats, + uint64_t index ) override; + + void sectionStarting( SectionInfo const& sectionInfo ) override; + void sectionEnded( SectionStats const& sectionStats ) override; + + void assertionStarting( AssertionInfo const& assertionInfo ) override; + void assertionEnded( AssertionStats const& assertionStats ) override; + + //void testRunEndedCumulative() override; + + void benchmarkPreparing( StringRef name ) override; + void benchmarkStarting( BenchmarkInfo const& ) override; + void benchmarkEnded( BenchmarkStats<> const& ) override; + void benchmarkFailed( StringRef error ) override; + + void listReporters( + std::vector const& descriptions ) override; + void listListeners( + std::vector const& descriptions ) override; + void listTests( std::vector const& tests ) override; + void listTags( std::vector const& tags ) override; + + private: + Timer m_testCaseTimer; + enum class Writer { + Object, + Array + }; + + JsonArrayWriter& startArray(); + JsonArrayWriter& startArray( StringRef key ); + + JsonObjectWriter& startObject(); + JsonObjectWriter& startObject( StringRef key ); + + void endObject(); + void endArray(); + + bool isInside( Writer writer ); + + void startListing(); + void endListing(); + + // Invariant: + // When m_writers is not empty and its top element is + // - Writer::Object, then m_objectWriters is not be empty + // - Writer::Array, then m_arrayWriters shall not be empty + std::stack m_objectWriters{}; + std::stack m_arrayWriters{}; + std::stack m_writers{}; + + bool m_startedListing = false; + + // std::size_t m_sectionDepth = 0; + // std::size_t m_sectionStarted = 0; + }; +} // namespace Catch + +#endif // CATCH_REPORTER_JSON_HPP_INCLUDED + + #ifndef CATCH_REPORTER_JUNIT_HPP_INCLUDED #define CATCH_REPORTER_JUNIT_HPP_INCLUDED @@ -12217,7 +13440,8 @@ namespace Catch { //! independent on the reporter's concrete type void registerReporterImpl( std::string const& name, IReporterFactoryPtr reporterPtr ); - + //! Actually registers the factory, independent on listener's concrete type + void registerListenerImpl( Detail::unique_ptr listenerFactory ); } // namespace Detail class IEventListener; @@ -12278,7 +13502,7 @@ namespace Catch { public: ListenerRegistrar(StringRef listenerName) { - getMutableRegistryHub().registerListener( Detail::make_unique(listenerName) ); + registerListenerImpl( Detail::make_unique(listenerName) ); } }; } @@ -12299,7 +13523,7 @@ namespace Catch { CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace { \ Catch::ListenerRegistrar INTERNAL_CATCH_UNIQUE_NAME( \ - catch_internal_RegistrarFor )( #listenerType ); \ + catch_internal_RegistrarFor )( #listenerType##_catch_sr ); \ } \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION @@ -12346,7 +13570,7 @@ namespace Catch { void writeRun( TestRunNode const& groupNode ); - void writeTestFile(std::string const& filename, std::vector const& testCaseNodes); + void writeTestFile(StringRef filename, std::vector const& testCaseNodes); void writeTestCase(TestCaseNode const& testCaseNode); diff --git a/fuzzing/NullOStream.cpp b/fuzzing/NullOStream.cpp index 53e0893d..e3a181e8 100644 --- a/fuzzing/NullOStream.cpp +++ b/fuzzing/NullOStream.cpp @@ -1,3 +1,11 @@ + +// 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 "NullOStream.h" void NullOStream::avoidOutOfLineVirtualCompilerWarning() diff --git a/fuzzing/NullOStream.h b/fuzzing/NullOStream.h index e1fe15b0..abbec09c 100644 --- a/fuzzing/NullOStream.h +++ b/fuzzing/NullOStream.h @@ -1,3 +1,11 @@ + +// 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 + #pragma once #include diff --git a/fuzzing/fuzz_TestSpecParser.cpp b/fuzzing/fuzz_TestSpecParser.cpp index af4de406..3aba8c84 100644 --- a/fuzzing/fuzz_TestSpecParser.cpp +++ b/fuzzing/fuzz_TestSpecParser.cpp @@ -1,4 +1,10 @@ -//License: Boost 1.0 + +// 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 //By Paul Dreik 2020 #include diff --git a/fuzzing/fuzz_XmlWriter.cpp b/fuzzing/fuzz_XmlWriter.cpp index f8e5a0d9..70c4ed80 100644 --- a/fuzzing/fuzz_XmlWriter.cpp +++ b/fuzzing/fuzz_XmlWriter.cpp @@ -1,4 +1,10 @@ -//License: Boost 1.0 + +// 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 //By Paul Dreik 2020 #include diff --git a/fuzzing/fuzz_textflow.cpp b/fuzzing/fuzz_textflow.cpp index eafe79fe..7000f420 100644 --- a/fuzzing/fuzz_textflow.cpp +++ b/fuzzing/fuzz_textflow.cpp @@ -1,4 +1,10 @@ -//License: Boost 1.0 + +// 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 //By Paul Dreik 2020 #include diff --git a/meson.build b/meson.build index 0cab573e..1c5b80a1 100644 --- a/meson.build +++ b/meson.build @@ -8,10 +8,12 @@ project( 'catch2', 'cpp', - version: '3.2.1', # CML version placeholder, don't delete + version: '3.5.0', # CML version placeholder, don't delete license: 'BSL-1.0', - meson_version: '>=0.50.0', + meson_version: '>=0.54.1', ) subdir('src/catch2') -subdir('tests') +if get_option('tests') + subdir('tests') +endif diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 00000000..76904873 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +option('tests', type: 'boolean', value: true, description: 'Build the unit tests') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b54c6274..d01aab2d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,6 +21,8 @@ set(BENCHMARK_HEADERS ${SOURCES_DIR}/benchmark/catch_sample_analysis.hpp ${SOURCES_DIR}/benchmark/detail/catch_analyse.hpp ${SOURCES_DIR}/benchmark/detail/catch_benchmark_function.hpp + ${SOURCES_DIR}/benchmark/detail/catch_benchmark_stats.hpp + ${SOURCES_DIR}/benchmark/detail/catch_benchmark_stats_fwd.hpp ${SOURCES_DIR}/benchmark/detail/catch_complete_invoke.hpp ${SOURCES_DIR}/benchmark/detail/catch_estimate_clock.hpp ${SOURCES_DIR}/benchmark/detail/catch_measure.hpp @@ -31,6 +33,7 @@ set(BENCHMARK_HEADERS ) set(BENCHMARK_SOURCES ${SOURCES_DIR}/benchmark/catch_chronometer.cpp + ${SOURCES_DIR}/benchmark/detail/catch_analyse.cpp ${SOURCES_DIR}/benchmark/detail/catch_benchmark_function.cpp ${SOURCES_DIR}/benchmark/detail/catch_run_for_at_least.cpp ${SOURCES_DIR}/benchmark/detail/catch_stats.cpp @@ -39,7 +42,7 @@ set(BENCHMARK_FILES ${BENCHMARK_HEADERS} ${BENCHMARK_SOURCES}) set(IMPL_HEADERS - "${CMAKE_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp" + "${PROJECT_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp" ${SOURCES_DIR}/catch_user_config.hpp.in ${SOURCES_DIR}/catch_all.hpp ${SOURCES_DIR}/catch_approx.hpp @@ -71,6 +74,7 @@ set(IMPL_HEADERS ${SOURCES_DIR}/internal/catch_compiler_capabilities.hpp ${SOURCES_DIR}/internal/catch_config_android_logwrite.hpp ${SOURCES_DIR}/internal/catch_config_counter.hpp + ${SOURCES_DIR}/internal/catch_config_static_analysis_support.hpp ${SOURCES_DIR}/internal/catch_config_uncaught_exceptions.hpp ${SOURCES_DIR}/internal/catch_config_wchar.hpp ${SOURCES_DIR}/internal/catch_console_colour.hpp @@ -88,6 +92,8 @@ set(IMPL_HEADERS ${SOURCES_DIR}/internal/catch_floating_point_helpers.hpp ${SOURCES_DIR}/internal/catch_getenv.hpp ${SOURCES_DIR}/internal/catch_istream.hpp + ${SOURCES_DIR}/internal/catch_is_permutation.hpp + ${SOURCES_DIR}/internal/catch_jsonwriter.hpp ${SOURCES_DIR}/internal/catch_lazy_expr.hpp ${SOURCES_DIR}/internal/catch_leak_detector.hpp ${SOURCES_DIR}/internal/catch_list.hpp @@ -103,6 +109,8 @@ set(IMPL_HEADERS ${SOURCES_DIR}/internal/catch_polyfills.hpp ${SOURCES_DIR}/internal/catch_preprocessor.hpp ${SOURCES_DIR}/internal/catch_preprocessor_remove_parens.hpp + ${SOURCES_DIR}/internal/catch_random_floating_point_helpers.hpp + ${SOURCES_DIR}/internal/catch_random_integer_helpers.hpp ${SOURCES_DIR}/internal/catch_random_number_generator.hpp ${SOURCES_DIR}/internal/catch_random_seed_generation.hpp ${SOURCES_DIR}/internal/catch_reporter_registry.hpp @@ -127,10 +135,13 @@ set(IMPL_HEADERS ${SOURCES_DIR}/internal/catch_test_failure_exception.hpp ${SOURCES_DIR}/internal/catch_test_macro_impl.hpp ${SOURCES_DIR}/internal/catch_test_registry.hpp + ${SOURCES_DIR}/internal/catch_test_run_info.hpp ${SOURCES_DIR}/internal/catch_test_spec_parser.hpp ${SOURCES_DIR}/internal/catch_textflow.hpp ${SOURCES_DIR}/internal/catch_to_string.hpp ${SOURCES_DIR}/internal/catch_uncaught_exceptions.hpp + ${SOURCES_DIR}/internal/catch_uniform_floating_point_distribution.hpp + ${SOURCES_DIR}/internal/catch_uniform_integer_distribution.hpp ${SOURCES_DIR}/internal/catch_unique_name.hpp ${SOURCES_DIR}/internal/catch_unique_ptr.hpp ${SOURCES_DIR}/internal/catch_void_type.hpp @@ -152,6 +163,7 @@ set(IMPL_SOURCES ${SOURCES_DIR}/catch_timer.cpp ${SOURCES_DIR}/catch_tostring.cpp ${SOURCES_DIR}/catch_totals.cpp + ${SOURCES_DIR}/catch_translate_exception.cpp ${SOURCES_DIR}/catch_version.cpp ${SOURCES_DIR}/internal/catch_assertion_handler.cpp ${SOURCES_DIR}/internal/catch_case_insensitive_comparisons.cpp @@ -170,6 +182,7 @@ set(IMPL_SOURCES ${SOURCES_DIR}/internal/catch_floating_point_helpers.cpp ${SOURCES_DIR}/internal/catch_getenv.cpp ${SOURCES_DIR}/internal/catch_istream.cpp + ${SOURCES_DIR}/internal/catch_jsonwriter.cpp ${SOURCES_DIR}/internal/catch_lazy_expr.cpp ${SOURCES_DIR}/internal/catch_leak_detector.cpp ${SOURCES_DIR}/internal/catch_list.cpp @@ -215,8 +228,8 @@ set(INTERFACE_HEADERS ${SOURCES_DIR}/interfaces/catch_interfaces_registry_hub.hpp ${SOURCES_DIR}/interfaces/catch_interfaces_reporter.hpp ${SOURCES_DIR}/interfaces/catch_interfaces_reporter_factory.hpp - ${SOURCES_DIR}/interfaces/catch_interfaces_reporter_registry.hpp ${SOURCES_DIR}/interfaces/catch_interfaces_tag_alias_registry.hpp + ${SOURCES_DIR}/interfaces/catch_interfaces_test_invoker.hpp ${SOURCES_DIR}/interfaces/catch_interfaces_testcase.hpp ) set(INTERFACE_SOURCES @@ -227,7 +240,6 @@ set(INTERFACE_SOURCES ${SOURCES_DIR}/interfaces/catch_interfaces_registry_hub.cpp ${SOURCES_DIR}/interfaces/catch_interfaces_reporter.cpp ${SOURCES_DIR}/interfaces/catch_interfaces_reporter_factory.cpp - ${SOURCES_DIR}/interfaces/catch_interfaces_reporter_registry.cpp ${SOURCES_DIR}/interfaces/catch_interfaces_testcase.cpp ) set(INTERFACE_FILES ${INTERFACE_HEADERS} ${INTERFACE_SOURCES}) @@ -252,6 +264,7 @@ set(MATCHER_HEADERS ${SOURCES_DIR}/matchers/catch_matchers_all.hpp ${SOURCES_DIR}/matchers/catch_matchers_container_properties.hpp ${SOURCES_DIR}/matchers/catch_matchers_contains.hpp + ${SOURCES_DIR}/matchers/catch_matchers_range_equals.hpp ${SOURCES_DIR}/matchers/catch_matchers_exception.hpp ${SOURCES_DIR}/matchers/catch_matchers_floating_point.hpp ${SOURCES_DIR}/matchers/catch_matchers_predicate.hpp @@ -282,6 +295,7 @@ set(REPORTER_HEADERS ${SOURCES_DIR}/reporters/catch_reporter_cumulative_base.hpp ${SOURCES_DIR}/reporters/catch_reporter_event_listener.hpp ${SOURCES_DIR}/reporters/catch_reporter_helpers.hpp + ${SOURCES_DIR}/reporters/catch_reporter_json.hpp ${SOURCES_DIR}/reporters/catch_reporter_junit.hpp ${SOURCES_DIR}/reporters/catch_reporter_multi.hpp ${SOURCES_DIR}/reporters/catch_reporter_registrars.hpp @@ -300,6 +314,7 @@ set(REPORTER_SOURCES ${SOURCES_DIR}/reporters/catch_reporter_cumulative_base.cpp ${SOURCES_DIR}/reporters/catch_reporter_event_listener.cpp ${SOURCES_DIR}/reporters/catch_reporter_helpers.cpp + ${SOURCES_DIR}/reporters/catch_reporter_json.cpp ${SOURCES_DIR}/reporters/catch_reporter_junit.cpp ${SOURCES_DIR}/reporters/catch_reporter_multi.cpp ${SOURCES_DIR}/reporters/catch_reporter_registrars.cpp @@ -321,7 +336,7 @@ set(ALL_FILES ) set(FILTERED_FILES ${ALL_FILES}) -list(REMOVE_ITEM FILTERED_FILES "${CMAKE_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp") +list(REMOVE_ITEM FILTERED_FILES "${PROJECT_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp") source_group( TREE ${SOURCES_DIR} PREFIX sources @@ -329,7 +344,7 @@ source_group( ) source_group("generated headers" FILES - "${CMAKE_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp" + "${PROJECT_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp" ) add_library(Catch2 ${ALL_FILES}) @@ -372,13 +387,13 @@ target_compile_features(Catch2 configure_file( "${SOURCES_DIR}/catch_user_config.hpp.in" - "${CMAKE_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp" + "${PROJECT_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp" ) target_include_directories(Catch2 PUBLIC $ - $ + $ $ ) @@ -426,7 +441,7 @@ if (NOT_SUBPROJECT) install( DIRECTORY "${SOURCES_DIR}" - "${CMAKE_BINARY_DIR}/generated-includes/catch2" # Also install the generated header + "${PROJECT_BINARY_DIR}/generated-includes/catch2" # Also install the generated header DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" FILES_MATCHING @@ -447,7 +462,7 @@ if (CATCH_BUILD_EXAMPLES OR CATCH_BUILD_EXTRA_TESTS) target_include_directories(Catch2_buildall_interface INTERFACE $ - $ + $ $ ) target_compile_definitions(Catch2_buildall_interface @@ -487,12 +502,10 @@ set(CATCH_WARNING_TARGETS ${CATCH_WARNING_TARGETS} PARENT_SCOPE) # so we want to check & warn users if they do this. However, we won't abort # the configuration step so that we don't have to also provide an override. if (BUILD_SHARED_LIBS) - if (MSVC) - set_target_properties(Catch2 Catch2WithMain - PROPERTIES - WINDOWS_EXPORT_ALL_SYMBOLS ON - ) - endif() + set_target_properties(Catch2 Catch2WithMain + PROPERTIES + WINDOWS_EXPORT_ALL_SYMBOLS ON + ) get_target_property(_VisPreset Catch2 CXX_VISIBILITY_PRESET) if (NOT MSVC AND _VisPreset STREQUAL "hidden") diff --git a/src/catch2/benchmark/catch_benchmark.hpp b/src/catch2/benchmark/catch_benchmark.hpp index a2d5c3ea..3db40bb0 100644 --- a/src/catch2/benchmark/catch_benchmark.hpp +++ b/src/catch2/benchmark/catch_benchmark.hpp @@ -10,26 +10,28 @@ #ifndef CATCH_BENCHMARK_HPP_INCLUDED #define CATCH_BENCHMARK_HPP_INCLUDED -#include +#include #include #include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include #include #include #include #include -#include +#include +#include #include -#include #include namespace Catch { @@ -43,16 +45,18 @@ namespace Catch { : fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {} template - ExecutionPlan> prepare(const IConfig &cfg, Environment> env) const { + ExecutionPlan prepare(const IConfig &cfg, Environment env) const { auto min_time = env.clock_resolution.mean * Detail::minimum_ticks; auto run_time = std::max(min_time, std::chrono::duration_cast(cfg.benchmarkWarmupTime())); - auto&& test = Detail::run_for_at_least(std::chrono::duration_cast>(run_time), 1, fun); + auto&& test = Detail::run_for_at_least(std::chrono::duration_cast(run_time), 1, fun); int new_iters = static_cast(std::ceil(min_time * test.iterations / test.elapsed)); - return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations }; + return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast(cfg.benchmarkWarmupTime()), Detail::warmup_iterations }; } template void run() { + static_assert( Clock::is_steady, + "Benchmarking clock should be steady" ); auto const* cfg = getCurrentContext().getConfig(); auto env = Detail::measure_environment(); @@ -64,7 +68,7 @@ namespace Catch { }); BenchmarkInfo info { - name, + CATCH_MOVE(name), plan.estimated_duration.count(), plan.iterations_per_sample, cfg->benchmarkSamples(), @@ -79,10 +83,10 @@ namespace Catch { return plan.template run(*cfg, env); }); - auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); - BenchmarkStats> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance }; + auto analysis = Detail::analyse(*cfg, samples.data(), samples.data() + samples.size()); + BenchmarkStats<> 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) { + } CATCH_CATCH_ANON (TestFailureException const&) { getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr); } CATCH_CATCH_ALL{ getResultCapture().benchmarkFailed(translateActiveException()); diff --git a/src/catch2/benchmark/catch_benchmark_all.hpp b/src/catch2/benchmark/catch_benchmark_all.hpp index eb81f238..56fc7c74 100644 --- a/src/catch2/benchmark/catch_benchmark_all.hpp +++ b/src/catch2/benchmark/catch_benchmark_all.hpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/catch2/benchmark/catch_chronometer.hpp b/src/catch2/benchmark/catch_chronometer.hpp index bce2406b..95498e6b 100644 --- a/src/catch2/benchmark/catch_chronometer.hpp +++ b/src/catch2/benchmark/catch_chronometer.hpp @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -33,7 +32,10 @@ namespace Catch { void start() override { started = Clock::now(); } void finish() override { finished = Clock::now(); } - ClockDuration elapsed() const { return finished - started; } + IDuration elapsed() const { + return std::chrono::duration_cast( + finished - started ); + } TimePoint started; TimePoint finished; diff --git a/src/catch2/benchmark/catch_clock.hpp b/src/catch2/benchmark/catch_clock.hpp index cee46097..4068c4d2 100644 --- a/src/catch2/benchmark/catch_clock.hpp +++ b/src/catch2/benchmark/catch_clock.hpp @@ -11,28 +11,16 @@ #define CATCH_CLOCK_HPP_INCLUDED #include -#include namespace Catch { namespace Benchmark { - template - using ClockDuration = typename Clock::duration; - template - using FloatDuration = std::chrono::duration; + using IDuration = std::chrono::nanoseconds; + using FDuration = std::chrono::duration; template using TimePoint = typename Clock::time_point; using default_clock = std::chrono::steady_clock; - - template - struct now { - TimePoint operator()() const { - return Clock::now(); - } - }; - - using fp_seconds = std::chrono::duration>; } // namespace Benchmark } // namespace Catch diff --git a/src/catch2/benchmark/catch_environment.hpp b/src/catch2/benchmark/catch_environment.hpp index de4d77df..da3f2fa9 100644 --- a/src/catch2/benchmark/catch_environment.hpp +++ b/src/catch2/benchmark/catch_environment.hpp @@ -15,21 +15,13 @@ namespace Catch { namespace Benchmark { - template struct EnvironmentEstimate { - Duration mean; + FDuration mean; OutlierClassification outliers; - - template - operator EnvironmentEstimate() const { - return { mean, outliers }; - } }; - template struct Environment { - using clock_type = Clock; - EnvironmentEstimate> clock_resolution; - EnvironmentEstimate> clock_cost; + EnvironmentEstimate clock_resolution; + EnvironmentEstimate clock_cost; }; } // namespace Benchmark } // namespace Catch diff --git a/src/catch2/benchmark/catch_estimate.hpp b/src/catch2/benchmark/catch_estimate.hpp index be594a18..64383a2e 100644 --- a/src/catch2/benchmark/catch_estimate.hpp +++ b/src/catch2/benchmark/catch_estimate.hpp @@ -12,17 +12,12 @@ namespace Catch { namespace Benchmark { - template + template struct Estimate { - Duration point; - Duration lower_bound; - Duration upper_bound; + Type point; + Type lower_bound; + Type upper_bound; double confidence_interval; - - template - operator Estimate() const { - return { point, lower_bound, upper_bound, confidence_interval }; - } }; } // namespace Benchmark } // namespace Catch diff --git a/src/catch2/benchmark/catch_execution_plan.hpp b/src/catch2/benchmark/catch_execution_plan.hpp index 039de7ee..17ca589f 100644 --- a/src/catch2/benchmark/catch_execution_plan.hpp +++ b/src/catch2/benchmark/catch_execution_plan.hpp @@ -17,38 +17,38 @@ #include #include -#include -#include +#include namespace Catch { namespace Benchmark { - template struct ExecutionPlan { int iterations_per_sample; - Duration estimated_duration; + FDuration estimated_duration; Detail::BenchmarkFunction benchmark; - Duration warmup_time; + FDuration warmup_time; int warmup_iterations; - template - operator ExecutionPlan() const { - return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations }; - } - template - std::vector> run(const IConfig &cfg, Environment> env) const { + std::vector run(const IConfig &cfg, Environment env) const { // warmup a bit - Detail::run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_iterations, Detail::repeat(now{})); + Detail::run_for_at_least( + std::chrono::duration_cast( warmup_time ), + warmup_iterations, + Detail::repeat( []() { return Clock::now(); } ) + ); - std::vector> times; - times.reserve(cfg.benchmarkSamples()); - std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { + std::vector times; + const auto num_samples = cfg.benchmarkSamples(); + times.reserve( num_samples ); + for ( size_t i = 0; i < num_samples; ++i ) { Detail::ChronometerModel model; - this->benchmark(Chronometer(model, iterations_per_sample)); + this->benchmark( Chronometer( model, iterations_per_sample ) ); auto sample_time = model.elapsed() - env.clock_cost.mean; - if (sample_time < FloatDuration::zero()) sample_time = FloatDuration::zero(); - return sample_time / iterations_per_sample; - }); + if ( sample_time < FDuration::zero() ) { + sample_time = FDuration::zero(); + } + times.push_back(sample_time / iterations_per_sample); + } return times; } }; diff --git a/src/catch2/benchmark/catch_optimizer.hpp b/src/catch2/benchmark/catch_optimizer.hpp index 0dbfc145..61e6571f 100644 --- a/src/catch2/benchmark/catch_optimizer.hpp +++ b/src/catch2/benchmark/catch_optimizer.hpp @@ -10,7 +10,7 @@ #ifndef CATCH_OPTIMIZER_HPP_INCLUDED #define CATCH_OPTIMIZER_HPP_INCLUDED -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__) # include // atomic_thread_fence #endif @@ -32,16 +32,23 @@ namespace Catch { namespace Detail { inline void optimizer_barrier() { keep_memory(); } } // namespace Detail -#elif defined(_MSC_VER) +#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 inline void keep_memory(T* p) { // thanks @milleniumbug *reinterpret_cast(p) = *reinterpret_cast(p); } // TODO equivalent keep_memory() +#if defined(_MSVC_VER) #pragma optimize("", on) +#endif namespace Detail { inline void optimizer_barrier() { @@ -63,7 +70,7 @@ namespace Catch { template inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t::value> { - CATCH_FORWARD(fn) (CATCH_FORWARD(args)...); + CATCH_FORWARD((fn)) (CATCH_FORWARD(args)...); } } // namespace Benchmark } // namespace Catch diff --git a/src/catch2/benchmark/catch_sample_analysis.hpp b/src/catch2/benchmark/catch_sample_analysis.hpp index d849d246..aeb87d05 100644 --- a/src/catch2/benchmark/catch_sample_analysis.hpp +++ b/src/catch2/benchmark/catch_sample_analysis.hpp @@ -10,38 +10,20 @@ #ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED #define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED -#include #include #include -#include +#include -#include #include -#include namespace Catch { namespace Benchmark { - template struct SampleAnalysis { - std::vector samples; - Estimate mean; - Estimate standard_deviation; + std::vector samples; + Estimate mean; + Estimate standard_deviation; OutlierClassification outliers; double outlier_variance; - - template - operator SampleAnalysis() const { - std::vector samples2; - samples2.reserve(samples.size()); - std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); - return { - CATCH_MOVE(samples2), - mean, - standard_deviation, - outliers, - outlier_variance, - }; - } }; } // namespace Benchmark } // namespace Catch diff --git a/src/catch2/benchmark/detail/catch_analyse.cpp b/src/catch2/benchmark/detail/catch_analyse.cpp new file mode 100644 index 00000000..7d27daf1 --- /dev/null +++ b/src/catch2/benchmark/detail/catch_analyse.cpp @@ -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 +// Adapted from donated nonius code. + +#include +#include +#include +#include +#include +#include + +#include + +namespace Catch { + namespace Benchmark { + namespace Detail { + SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last) { + if (!cfg.benchmarkNoAnalysis()) { + std::vector samples; + samples.reserve(static_cast(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.data(), + samples.data() + samples.size() ); + auto outliers = Catch::Benchmark::Detail::classify_outliers( + samples.data(), samples.data() + samples.size() ); + + auto wrap_estimate = [](Estimate e) { + return Estimate { + FDuration(e.point), + FDuration(e.lower_bound), + FDuration(e.upper_bound), + e.confidence_interval, + }; + }; + std::vector samples2; + samples2.reserve(samples.size()); + for (auto s : samples) { + samples2.push_back( FDuration( s ) ); + } + + return { + CATCH_MOVE(samples2), + wrap_estimate(analysis.mean), + wrap_estimate(analysis.standard_deviation), + outliers, + analysis.outlier_variance, + }; + } else { + std::vector samples; + samples.reserve(static_cast(last - first)); + + FDuration mean = FDuration(0); + int i = 0; + for (auto it = first; it < last; ++it, ++i) { + samples.push_back(FDuration(*it)); + mean += FDuration(*it); + } + mean /= i; + + return SampleAnalysis{ + CATCH_MOVE(samples), + Estimate{ mean, mean, mean, 0.0 }, + Estimate{ FDuration( 0 ), + FDuration( 0 ), + FDuration( 0 ), + 0.0 }, + OutlierClassification{}, + 0.0 + }; + } + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch diff --git a/src/catch2/benchmark/detail/catch_analyse.hpp b/src/catch2/benchmark/detail/catch_analyse.hpp index 77b0a9d3..5e3f7b0f 100644 --- a/src/catch2/benchmark/detail/catch_analyse.hpp +++ b/src/catch2/benchmark/detail/catch_analyse.hpp @@ -11,68 +11,15 @@ #define CATCH_ANALYSE_HPP_INCLUDED #include -#include #include -#include -#include -#include -#include -#include -#include namespace Catch { + class IConfig; + namespace Benchmark { namespace Detail { - template - SampleAnalysis analyse(const IConfig &cfg, Environment, Iterator first, Iterator last) { - if (!cfg.benchmarkNoAnalysis()) { - std::vector samples; - samples.reserve(static_cast(last - first)); - std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.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 e) { - return Estimate { - Duration(e.point), - Duration(e.lower_bound), - Duration(e.upper_bound), - e.confidence_interval, - }; - }; - std::vector samples2; - samples2.reserve(samples.size()); - std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); - return { - CATCH_MOVE(samples2), - wrap_estimate(analysis.mean), - wrap_estimate(analysis.standard_deviation), - outliers, - analysis.outlier_variance, - }; - } else { - std::vector samples; - samples.reserve(static_cast(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{mean, mean, mean, 0.0}, - Estimate{Duration(0), Duration(0), Duration(0), 0.0}, - OutlierClassification{}, - 0.0 - }; - } - } + SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last); } // namespace Detail } // namespace Benchmark } // namespace Catch diff --git a/src/catch2/benchmark/detail/catch_benchmark_function.hpp b/src/catch2/benchmark/detail/catch_benchmark_function.hpp index 15298258..144e4b6e 100644 --- a/src/catch2/benchmark/detail/catch_benchmark_function.hpp +++ b/src/catch2/benchmark/detail/catch_benchmark_function.hpp @@ -11,7 +11,6 @@ #define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED #include -#include #include #include #include diff --git a/src/catch2/benchmark/detail/catch_benchmark_stats.hpp b/src/catch2/benchmark/detail/catch_benchmark_stats.hpp new file mode 100644 index 00000000..3633bc9f --- /dev/null +++ b/src/catch2/benchmark/detail/catch_benchmark_stats.hpp @@ -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 +#ifndef CATCH_BENCHMARK_STATS_HPP_INCLUDED +#define CATCH_BENCHMARK_STATS_HPP_INCLUDED + +#include +#include +// The fwd decl & default specialization needs to be seen by VS2017 before +// BenchmarkStats itself, or VS2017 will report compilation error. +#include + +#include +#include + +namespace Catch { + + struct BenchmarkInfo { + std::string name; + double estimatedDuration; + int iterations; + unsigned int samples; + unsigned int resamples; + double clockResolution; + double clockCost; + }; + + // We need to keep template parameter for backwards compatibility, + // but we also do not want to use the template paraneter. + template + struct BenchmarkStats { + BenchmarkInfo info; + + std::vector samples; + Benchmark::Estimate mean; + Benchmark::Estimate standardDeviation; + Benchmark::OutlierClassification outliers; + double outlierVariance; + }; + + +} // end namespace Catch + +#endif // CATCH_BENCHMARK_STATS_HPP_INCLUDED diff --git a/src/catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp b/src/catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp new file mode 100644 index 00000000..2ccc25d5 --- /dev/null +++ b/src/catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp @@ -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 + +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 + struct BenchmarkStats; + +} // end namespace Catch + +#endif // CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED diff --git a/src/catch2/benchmark/detail/catch_complete_invoke.hpp b/src/catch2/benchmark/detail/catch_complete_invoke.hpp index 49db413e..4dff4b7e 100644 --- a/src/catch2/benchmark/detail/catch_complete_invoke.hpp +++ b/src/catch2/benchmark/detail/catch_complete_invoke.hpp @@ -10,14 +10,9 @@ #ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED #define CATCH_COMPLETE_INVOKE_HPP_INCLUDED -#include #include -#include -#include #include -#include - namespace Catch { namespace Benchmark { namespace Detail { diff --git a/src/catch2/benchmark/detail/catch_estimate_clock.hpp b/src/catch2/benchmark/detail/catch_estimate_clock.hpp index 907773f2..918484a9 100644 --- a/src/catch2/benchmark/detail/catch_estimate_clock.hpp +++ b/src/catch2/benchmark/detail/catch_estimate_clock.hpp @@ -19,7 +19,6 @@ #include #include -#include #include #include @@ -30,46 +29,49 @@ namespace Catch { std::vector resolution(int k) { std::vector> times; times.reserve(static_cast(k + 1)); - std::generate_n(std::back_inserter(times), k + 1, now{}); + for ( int i = 0; i < k + 1; ++i ) { + times.push_back( Clock::now() ); + } std::vector deltas; deltas.reserve(static_cast(k)); - std::transform(std::next(times.begin()), times.end(), times.begin(), - std::back_inserter(deltas), - [](TimePoint a, TimePoint b) { return static_cast((a - b).count()); }); + for ( size_t idx = 1; idx < times.size(); ++idx ) { + deltas.push_back( static_cast( + ( times[idx] - times[idx - 1] ).count() ) ); + } return deltas; } - const auto warmup_iterations = 10000; - const auto warmup_time = std::chrono::milliseconds(100); - const auto minimum_ticks = 1000; - const auto warmup_seed = 10000; - const auto clock_resolution_estimation_time = std::chrono::milliseconds(500); - const auto clock_cost_estimation_time_limit = std::chrono::seconds(1); - const auto clock_cost_estimation_tick_limit = 100000; - const auto clock_cost_estimation_time = std::chrono::milliseconds(10); - const auto clock_cost_estimation_iterations = 10000; + 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 int warmup() { - return run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_seed, &resolution) + return run_for_at_least(std::chrono::duration_cast(warmup_time), warmup_seed, &resolution) .iterations; } template - EnvironmentEstimate> estimate_clock_resolution(int iterations) { - auto r = run_for_at_least(std::chrono::duration_cast>(clock_resolution_estimation_time), iterations, &resolution) + EnvironmentEstimate estimate_clock_resolution(int iterations) { + auto r = run_for_at_least(std::chrono::duration_cast(clock_resolution_estimation_time), iterations, &resolution) .result; return { - FloatDuration(mean(r.begin(), r.end())), - classify_outliers(r.begin(), r.end()), + FDuration(mean(r.data(), r.data() + r.size())), + classify_outliers(r.data(), r.data() + r.size()), }; } template - EnvironmentEstimate> estimate_clock_cost(FloatDuration resolution) { + EnvironmentEstimate estimate_clock_cost(FDuration resolution) { auto time_limit = (std::min)( resolution * clock_cost_estimation_tick_limit, - FloatDuration(clock_cost_estimation_time_limit)); + FDuration(clock_cost_estimation_time_limit)); auto time_clock = [](int k) { return Detail::measure([k] { for (int i = 0; i < k; ++i) { @@ -80,26 +82,28 @@ namespace Catch { }; time_clock(1); int iters = clock_cost_estimation_iterations; - auto&& r = run_for_at_least(std::chrono::duration_cast>(clock_cost_estimation_time), iters, time_clock); + auto&& r = run_for_at_least(std::chrono::duration_cast(clock_cost_estimation_time), iters, time_clock); std::vector times; int nsamples = static_cast(std::ceil(time_limit / r.elapsed)); times.reserve(static_cast(nsamples)); - std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { - return static_cast((time_clock(r.iterations) / r.iterations).count()); - }); + for ( int s = 0; s < nsamples; ++s ) { + times.push_back( static_cast( + ( time_clock( r.iterations ) / r.iterations ) + .count() ) ); + } return { - FloatDuration(mean(times.begin(), times.end())), - classify_outliers(times.begin(), times.end()), + FDuration(mean(times.data(), times.data() + times.size())), + classify_outliers(times.data(), times.data() + times.size()), }; } template - Environment> measure_environment() { + Environment measure_environment() { #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wexit-time-destructors" #endif - static Catch::Detail::unique_ptr>> env; + static Catch::Detail::unique_ptr env; #if defined(__clang__) # pragma clang diagnostic pop #endif @@ -111,7 +115,7 @@ namespace Catch { auto resolution = Detail::estimate_clock_resolution(iters); auto cost = Detail::estimate_clock_cost(resolution.mean); - env = Catch::Detail::make_unique>>( Environment>{resolution, cost} ); + env = Catch::Detail::make_unique( Environment{resolution, cost} ); return *env; } } // namespace Detail diff --git a/src/catch2/benchmark/detail/catch_measure.hpp b/src/catch2/benchmark/detail/catch_measure.hpp index 388814c1..37494a68 100644 --- a/src/catch2/benchmark/detail/catch_measure.hpp +++ b/src/catch2/benchmark/detail/catch_measure.hpp @@ -10,7 +10,6 @@ #ifndef CATCH_MEASURE_HPP_INCLUDED #define CATCH_MEASURE_HPP_INCLUDED -#include #include #include #include @@ -19,7 +18,7 @@ namespace Catch { namespace Benchmark { namespace Detail { template - TimingOf measure(Fun&& fun, Args&&... args) { + TimingOf measure(Fun&& fun, Args&&... args) { auto start = Clock::now(); auto&& r = Detail::complete_invoke(fun, CATCH_FORWARD(args)...); auto end = Clock::now(); diff --git a/src/catch2/benchmark/detail/catch_run_for_at_least.cpp b/src/catch2/benchmark/detail/catch_run_for_at_least.cpp index 35778b27..3ebdcc05 100644 --- a/src/catch2/benchmark/detail/catch_run_for_at_least.cpp +++ b/src/catch2/benchmark/detail/catch_run_for_at_least.cpp @@ -7,9 +7,10 @@ // SPDX-License-Identifier: BSL-1.0 #include -#include #include +#include + namespace Catch { namespace Benchmark { namespace Detail { diff --git a/src/catch2/benchmark/detail/catch_run_for_at_least.hpp b/src/catch2/benchmark/detail/catch_run_for_at_least.hpp index 976a4b24..4dfa8bbb 100644 --- a/src/catch2/benchmark/detail/catch_run_for_at_least.hpp +++ b/src/catch2/benchmark/detail/catch_run_for_at_least.hpp @@ -24,11 +24,11 @@ namespace Catch { namespace Benchmark { namespace Detail { template - TimingOf measure_one(Fun&& fun, int iters, std::false_type) { + TimingOf measure_one(Fun&& fun, int iters, std::false_type) { return Detail::measure(fun, iters); } template - TimingOf measure_one(Fun&& fun, int iters, std::true_type) { + TimingOf measure_one(Fun&& fun, int iters, std::true_type) { Detail::ChronometerModel meter; auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); @@ -43,8 +43,8 @@ namespace Catch { void throw_optimized_away_error(); template - TimingOf> - run_for_at_least(ClockDuration how_long, + TimingOf> + run_for_at_least(IDuration how_long, const int initial_iterations, Fun&& fun) { auto iters = initial_iterations; diff --git a/src/catch2/benchmark/detail/catch_stats.cpp b/src/catch2/benchmark/detail/catch_stats.cpp index 514ed1f7..2dd2d864 100644 --- a/src/catch2/benchmark/detail/catch_stats.cpp +++ b/src/catch2/benchmark/detail/catch_stats.cpp @@ -10,10 +10,14 @@ #include #include +#include +#include +#include #include +#include #include -#include +#include #include @@ -21,139 +25,204 @@ #include #endif -namespace { +namespace Catch { + namespace Benchmark { + namespace Detail { + namespace { -using Catch::Benchmark::Detail::sample; + template + static sample + resample( URng& rng, + unsigned int resamples, + double const* first, + double const* last, + Estimator& estimator ) { + auto n = static_cast( last - first ); + std::uniform_int_distribution dist( 0, + n - 1 ); - template - sample resample(URng& rng, unsigned int resamples, std::vector::iterator first, std::vector::iterator last, Estimator& estimator) { - auto n = static_cast(last - first); - std::uniform_int_distribution dist(0, n - 1); + sample out; + out.reserve( resamples ); + // We allocate the vector outside the loop to avoid realloc + // per resample + std::vector 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( + dist( rng ) )] ); + } + const auto estimate = + estimator( resampled.data(), resampled.data() + resampled.size() ); + out.push_back( estimate ); + } + std::sort( out.begin(), out.end() ); + return out; + } - sample out; - out.reserve(resamples); - std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] { - std::vector resampled; - resampled.reserve(n); - std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[static_cast(dist(rng))]; }); - return estimator(resampled.begin(), resampled.end()); - }); - std::sort(out.begin(), out.end()); - return out; - } + static double outlier_variance( Estimate mean, + Estimate 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( -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( double const* first, double const* 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 ); + } + + static sample jackknife( double ( *estimator )( double const*, + double const* ), + double* first, + double* last ) { + const auto second = first + 1; + sample results; + results.reserve( static_cast( last - first ) ); + + for ( auto it = first; it != last; ++it ) { + std::iter_swap( it, first ); + results.push_back( estimator( second, last ) ); + } + + return results; + } - 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; - } - - double standard_deviation(std::vector::iterator first, std::vector::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::iterator first, std::vector::iterator last) { + double weighted_average_quantile( int k, + int q, + double* first, + double* last ) { auto count = last - first; double idx = (count - 1) * k / static_cast(q); int j = static_cast(idx); double g = idx - j; std::nth_element(first, first + j, last); auto xj = first[j]; - if ( directCompare( g, 0 ) ) { + if ( Catch::Detail::directCompare( g, 0 ) ) { return xj; } @@ -161,6 +230,48 @@ namespace Catch { return xj + g * (xj1 - xj); } + OutlierClassification + classify_outliers( double const* first, double const* last ) { + std::vector copy( first, last ); + + auto q1 = weighted_average_quantile( 1, 4, copy.data(), copy.data() + copy.size() ); + auto q3 = weighted_average_quantile( 3, 4, copy.data(), copy.data() + copy.size() ); + 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( double const* first, double const* last ) { + auto count = last - first; + double sum = 0.; + while (first != last) { + sum += *first; + ++first; + } + return sum / static_cast(count); + } + + double normal_cdf( double x ) { + return std::erfc( -x / std::sqrt( 2.0 ) ) / 2.0; + } double erfc_inv(double x) { return erf_inv(1.0 - x); @@ -182,50 +293,77 @@ namespace Catch { return result; } + Estimate + bootstrap( double confidence_level, + double* first, + double* last, + sample const& resample, + double ( *estimator )( double const*, double const* ) ) { + auto n_samples = last - first; - double outlier_variance(Estimate mean, Estimate 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; + double point = estimator( first, last ); + // Degenerate case with a single sample + if ( n_samples == 1 ) + return { point, point, point, confidence_level }; - 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(-2. * k0 / (k1 + std::sqrt(det))); + sample jack = jackknife( estimator, first, last ); + double jack_mean = + mean( jack.data(), jack.data() + jack.size() ); + 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( resample.size() ); + double prob_n = + std::count_if( resample.begin(), + resample.end(), + [point]( double x ) { return x < point; } ) / + static_cast( n ); + // degenerate case with uniform samples + if ( Catch::Detail::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( n ) ); }; - - auto var_out = [n, sb2, sg2](double c) { - double nc = n - c; - return (nc / n) * (sb2 - nc * sg2); + 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( (std::max)( cumn( a1 ), 0l ) ); + auto hi = + static_cast( (std::min)( cumn( a2 ), n - 1 ) ); - return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2; + return { point, resample[lo], resample[hi], confidence_level }; } - - bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector::iterator first, std::vector::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(last - first); // seriously, one can't use integral types without hell in C++ - - auto mean = &Detail::mean::iterator>; + bootstrap_analysis analyse_samples(double confidence_level, + unsigned int n_resamples, + double* first, + double* last) { + auto mean = &Detail::mean; auto stddev = &standard_deviation; #if defined(CATCH_CONFIG_USE_ASYNC) - auto Estimate = [=](double(*f)(std::vector::iterator, std::vector::iterator)) { - auto seed = entropy(); + auto Estimate = [=](double(*f)(double const*, double const*)) { + std::random_device rd; + auto seed = rd(); return std::async(std::launch::async, [=] { - std::mt19937 rng(seed); + SimplePcg32 rng( seed ); auto resampled = resample(rng, n_resamples, first, last, f); return bootstrap(confidence_level, first, last, resampled, f); }); @@ -237,9 +375,10 @@ namespace Catch { auto mean_estimate = mean_future.get(); auto stddev_estimate = stddev_future.get(); #else - auto Estimate = [=](double(*f)(std::vector::iterator, std::vector::iterator)) { - auto seed = entropy(); - std::mt19937 rng(seed); + auto Estimate = [=](double(*f)(double const* , double const*)) { + std::random_device rd; + auto seed = rd(); + SimplePcg32 rng( seed ); auto resampled = resample(rng, n_resamples, first, last, f); return bootstrap(confidence_level, first, last, resampled, f); }; @@ -248,6 +387,7 @@ namespace Catch { auto stddev_estimate = Estimate(stddev); #endif // CATCH_USE_ASYNC + auto n = static_cast(last - first); // seriously, one can't use integral types without hell in C++ double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n); return { mean_estimate, stddev_estimate, outlier_variance }; diff --git a/src/catch2/benchmark/detail/catch_stats.hpp b/src/catch2/benchmark/detail/catch_stats.hpp index 4c54ec52..3bea612f 100644 --- a/src/catch2/benchmark/detail/catch_stats.hpp +++ b/src/catch2/benchmark/detail/catch_stats.hpp @@ -13,122 +13,35 @@ #include #include -#include #include -#include -#include -#include namespace Catch { namespace Benchmark { namespace Detail { using sample = std::vector; - // 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, + double* first, + double* last ); - double weighted_average_quantile(int k, int q, std::vector::iterator first, std::vector::iterator last); + OutlierClassification + classify_outliers( double const* first, double const* last ); - template - OutlierClassification classify_outliers(Iterator first, Iterator last) { - std::vector copy(first, last); + double mean( double const* first, double const* 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) { - auto&& 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; - } - - template - double mean(Iterator first, Iterator last) { - auto count = last - first; - double sum = std::accumulate(first, last, 0.); - return sum / static_cast(count); - } - - template - sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { - auto n = static_cast(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 normal_cdf( double x ); double erfc_inv(double x); double normal_quantile(double p); - template - Estimate bootstrap(double confidence_level, Iterator first, 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, sum_cubes; - std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair sqcb, double x) -> std::pair { - auto d = jack_mean - x; - auto d2 = d * d; - auto d3 = d2 * d; - return { sqcb.first + d2, sqcb.second + d3 }; - }); - - double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); - long n = static_cast(resample.size()); - double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / static_cast(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(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((std::max)(cumn(a1), 0l)); - auto hi = static_cast((std::min)(cumn(a2), n - 1)); - - return { point, resample[lo], resample[hi], confidence_level }; - } - - double outlier_variance(Estimate mean, Estimate stddev, int n); + Estimate + bootstrap( double confidence_level, + double* first, + double* last, + sample const& resample, + double ( *estimator )( double const*, double const* ) ); struct bootstrap_analysis { Estimate mean; @@ -136,7 +49,10 @@ namespace Catch { double outlier_variance; }; - bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector::iterator first, std::vector::iterator last); + bootstrap_analysis analyse_samples(double confidence_level, + unsigned int n_resamples, + double* first, + double* last); } // namespace Detail } // namespace Benchmark } // namespace Catch diff --git a/src/catch2/benchmark/detail/catch_timing.hpp b/src/catch2/benchmark/detail/catch_timing.hpp index f5c25571..da567190 100644 --- a/src/catch2/benchmark/detail/catch_timing.hpp +++ b/src/catch2/benchmark/detail/catch_timing.hpp @@ -17,14 +17,14 @@ namespace Catch { namespace Benchmark { - template + template struct Timing { - Duration elapsed; + IDuration elapsed; Result result; int iterations; }; - template - using TimingOf = Timing, Detail::CompleteType_t>>; + template + using TimingOf = Timing>>; } // namespace Benchmark } // namespace Catch diff --git a/src/catch2/catch_all.hpp b/src/catch2/catch_all.hpp index a0bf7605..f2cc8536 100644 --- a/src/catch2/catch_all.hpp +++ b/src/catch2/catch_all.hpp @@ -54,6 +54,8 @@ #include #include #include +#include +#include #include #include #include @@ -70,7 +72,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -85,7 +89,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -110,10 +117,13 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include #include diff --git a/src/catch2/catch_approx.cpp b/src/catch2/catch_approx.cpp index 407586d1..9ad4ce3e 100644 --- a/src/catch2/catch_approx.cpp +++ b/src/catch2/catch_approx.cpp @@ -70,10 +70,10 @@ namespace Catch { } namespace literals { - Approx operator "" _a(long double val) { + Approx operator ""_a(long double val) { return Approx(val); } - Approx operator "" _a(unsigned long long val) { + Approx operator ""_a(unsigned long long val) { return Approx(val); } } // end namespace literals diff --git a/src/catch2/catch_assertion_result.cpp b/src/catch2/catch_assertion_result.cpp index 5b5d3290..61d4fd06 100644 --- a/src/catch2/catch_assertion_result.cpp +++ b/src/catch2/catch_assertion_result.cpp @@ -7,6 +7,7 @@ // SPDX-License-Identifier: BSL-1.0 #include #include +#include namespace Catch { @@ -26,9 +27,9 @@ namespace Catch { return reconstructedExpression; } - AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData&& data ) : m_info( info ), - m_resultData( data ) + m_resultData( CATCH_MOVE(data) ) {} // Result was a success @@ -67,16 +68,15 @@ namespace Catch { } std::string AssertionResult::getExpressionInMacro() const { - std::string expr; - if( m_info.macroName.empty() ) - expr = static_cast(m_info.capturedExpression); - else { - expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); - expr += m_info.macroName; - expr += "( "; - expr += m_info.capturedExpression; - expr += " )"; + if ( m_info.macroName.empty() ) { + return static_cast( 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; } diff --git a/src/catch2/catch_assertion_result.hpp b/src/catch2/catch_assertion_result.hpp index 6829e2f7..48882876 100644 --- a/src/catch2/catch_assertion_result.hpp +++ b/src/catch2/catch_assertion_result.hpp @@ -35,7 +35,7 @@ namespace Catch { class AssertionResult { public: AssertionResult() = delete; - AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + AssertionResult( AssertionInfo const& info, AssertionResultData&& data ); bool isOk() const; bool succeeded() const; diff --git a/src/catch2/catch_config.cpp b/src/catch2/catch_config.cpp index eb4f5ad3..34f50f17 100644 --- a/src/catch2/catch_config.cpp +++ b/src/catch2/catch_config.cpp @@ -105,7 +105,7 @@ namespace Catch { elem = trim(elem); } - // Insert the default reporter if user hasn't asked for a specfic one + // 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 ) diff --git a/src/catch2/catch_message.cpp b/src/catch2/catch_message.cpp index 4ab6ecf5..384f180e 100644 --- a/src/catch2/catch_message.cpp +++ b/src/catch2/catch_message.cpp @@ -19,8 +19,8 @@ namespace Catch { //////////////////////////////////////////////////////////////////////////// - ScopedMessage::ScopedMessage( MessageBuilder const& builder ): - m_info( builder.m_info ) { + ScopedMessage::ScopedMessage( MessageBuilder&& builder ): + m_info( CATCH_MOVE(builder.m_info) ) { m_info.message = builder.m_stream.str(); getResultCapture().pushScopedMessage( m_info ); } @@ -37,7 +37,11 @@ namespace Catch { } - Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { + 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(names[start]))) { ++start; diff --git a/src/catch2/catch_message.hpp b/src/catch2/catch_message.hpp index 4f71f227..05325ee8 100644 --- a/src/catch2/catch_message.hpp +++ b/src/catch2/catch_message.hpp @@ -8,12 +8,13 @@ #ifndef CATCH_MESSAGE_HPP_INCLUDED #define CATCH_MESSAGE_HPP_INCLUDED +#include #include #include #include #include -#include #include +#include #include #include @@ -21,6 +22,7 @@ namespace Catch { struct SourceLineInfo; + class IResultCapture; struct MessageStream { @@ -39,11 +41,10 @@ namespace Catch { ResultWas::OfType type ): m_info(macroName, lineInfo, type) {} - template - MessageBuilder& operator << ( T const& value ) { + MessageBuilder&& operator << ( T const& value ) && { m_stream << value; - return *this; + return CATCH_MOVE(*this); } MessageInfo m_info; @@ -51,7 +52,7 @@ namespace Catch { class ScopedMessage { public: - explicit ScopedMessage( MessageBuilder const& builder ); + explicit ScopedMessage( MessageBuilder&& builder ); ScopedMessage( ScopedMessage& duplicate ) = delete; ScopedMessage( ScopedMessage&& old ) noexcept; ~ScopedMessage(); @@ -62,7 +63,7 @@ namespace Catch { class Capturer { std::vector m_messages; - IResultCapture& m_resultCapture = getResultCapture(); + IResultCapture& m_resultCapture; size_t m_captured = 0; public: Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); @@ -98,7 +99,10 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ - Catch::Capturer varName( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \ + Catch::Capturer varName( macroName##_catch_sr, \ + CATCH_INTERNAL_LINEINFO, \ + Catch::ResultWas::Info, \ + #__VA_ARGS__##_catch_sr ); \ varName.captureValues( 0, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// @@ -110,28 +114,28 @@ namespace Catch { 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) +#if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !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) +#elif defined(CATCH_CONFIG_PREFIX_MESSAGES) && 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) +#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && !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) +#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE) #define INFO( msg ) (void)(0) #define UNSCOPED_INFO( msg ) (void)(0) diff --git a/src/catch2/catch_registry_hub.cpp b/src/catch2/catch_registry_hub.cpp index 243dd2b0..8716db3a 100644 --- a/src/catch2/catch_registry_hub.cpp +++ b/src/catch2/catch_registry_hub.cpp @@ -20,6 +20,9 @@ #include #include #include +#include + +#include namespace Catch { @@ -31,7 +34,7 @@ namespace Catch { public: // IRegistryHub RegistryHub() = default; - IReporterRegistry const& getReporterRegistry() const override { + ReporterRegistry const& getReporterRegistry() const override { return m_reporterRegistry; } ITestCaseRegistry const& getTestCaseRegistry() const override { diff --git a/src/catch2/catch_session.cpp b/src/catch2/catch_session.cpp index 128f21d9..f1ed5f9c 100644 --- a/src/catch2/catch_session.cpp +++ b/src/catch2/catch_session.cpp @@ -13,13 +13,13 @@ #include #include #include -#include #include #include +#include #include #include #include -#include +#include #include #include #include @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -341,6 +342,12 @@ namespace Catch { 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 diff --git a/src/catch2/catch_test_case_info.cpp b/src/catch2/catch_test_case_info.cpp index a6adce0a..e9dad577 100644 --- a/src/catch2/catch_test_case_info.cpp +++ b/src/catch2/catch_test_case_info.cpp @@ -139,12 +139,20 @@ namespace Catch { for (size_t idx = 0; idx < originalTags.size(); ++idx) { auto c = originalTags[idx]; if (c == '[') { - assert(!inTag); + CATCH_ENFORCE( + !inTag, + "Found '[' inside a tag while registering test case '" + << _nameAndTags.name << "' at " << _lineInfo ); + inTag = true; tagStart = idx; } if (c == ']') { - assert(inTag); + CATCH_ENFORCE( + inTag, + "Found unmatched ']' while registering test case '" + << _nameAndTags.name << "' at " << _lineInfo ); + inTag = false; tagEnd = idx; assert(tagStart < tagEnd); @@ -153,7 +161,11 @@ namespace Catch { // 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(), "Empty tags are not allowed"); + 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 @@ -167,8 +179,12 @@ namespace Catch { // the tags. internalAppendTag(tagStr); } - (void)inTag; // Silence "set-but-unused" warning in release mode. } + CATCH_ENFORCE( !inTag, + "Found an unclosed tag while registering test case '" + << _nameAndTags.name << "' at " << _lineInfo ); + + // Add [.] if relevant if (isHidden()) { internalAppendTag("."_sr); diff --git a/src/catch2/catch_test_case_info.hpp b/src/catch2/catch_test_case_info.hpp index ab5ae8b9..5ff3e3e7 100644 --- a/src/catch2/catch_test_case_info.hpp +++ b/src/catch2/catch_test_case_info.hpp @@ -15,6 +15,7 @@ #include +#include #include #include diff --git a/src/catch2/catch_test_macros.hpp b/src/catch2/catch_test_macros.hpp index cce2852f..1088afbe 100644 --- a/src/catch2/catch_test_macros.hpp +++ b/src/catch2/catch_test_macros.hpp @@ -49,6 +49,7 @@ #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) @@ -102,6 +103,7 @@ #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) @@ -146,6 +148,7 @@ #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) @@ -198,6 +201,7 @@ #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) diff --git a/src/catch2/catch_test_spec.cpp b/src/catch2/catch_test_spec.cpp index f27ce99c..f32f9864 100644 --- a/src/catch2/catch_test_spec.cpp +++ b/src/catch2/catch_test_spec.cpp @@ -6,6 +6,8 @@ // SPDX-License-Identifier: BSL-1.0 #include +#include +#include #include #include #include @@ -106,16 +108,18 @@ namespace Catch { return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } ); } - TestSpec::Matches TestSpec::matchesByFilter( std::vector const& testCases, IConfig const& config ) const - { - Matches matches( m_filters.size() ); - std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){ + TestSpec::Matches TestSpec::matchesByFilter( std::vector const& testCases, IConfig const& config ) const { + Matches matches; + matches.reserve( m_filters.size() ); + for ( auto const& filter : m_filters ) { std::vector currentMatches; - for( auto const& test : testCases ) - if( isThrowSafe( test, config ) && filter.matches( test.getTestCaseInfo() ) ) + for ( auto const& test : testCases ) + if ( isThrowSafe( test, config ) && + filter.matches( test.getTestCaseInfo() ) ) currentMatches.emplace_back( &test ); - return FilterMatch{ extractFilterName(filter), currentMatches }; - } ); + matches.push_back( + FilterMatch{ extractFilterName( filter ), currentMatches } ); + } return matches; } diff --git a/src/catch2/catch_tostring.hpp b/src/catch2/catch_tostring.hpp index 904caa7e..f3fb0beb 100644 --- a/src/catch2/catch_tostring.hpp +++ b/src/catch2/catch_tostring.hpp @@ -116,7 +116,6 @@ namespace Catch { } // namespace Detail - // If we decide for C++14, change these to enable_if_ts template struct StringMaker { template @@ -399,6 +398,12 @@ namespace Catch { } } }; + template <> + struct StringMaker { + static std::string convert(const std::nullopt_t&) { + return "{ }"; + } + }; } #endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER diff --git a/src/catch2/catch_totals.cpp b/src/catch2/catch_totals.cpp index a3e2b384..bd1954fb 100644 --- a/src/catch2/catch_totals.cpp +++ b/src/catch2/catch_totals.cpp @@ -14,6 +14,7 @@ namespace Catch { diff.passed = passed - other.passed; diff.failed = failed - other.failed; diff.failedButOk = failedButOk - other.failedButOk; + diff.skipped = skipped - other.skipped; return diff; } @@ -21,14 +22,15 @@ namespace Catch { passed += other.passed; failed += other.failed; failedButOk += other.failedButOk; + skipped += other.skipped; return *this; } std::uint64_t Counts::total() const { - return passed + failed + failedButOk; + return passed + failed + failedButOk + skipped; } bool Counts::allPassed() const { - return failed == 0 && failedButOk == 0; + return failed == 0 && failedButOk == 0 && skipped == 0; } bool Counts::allOk() const { return failed == 0; @@ -53,6 +55,8 @@ namespace Catch { ++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; diff --git a/src/catch2/catch_totals.hpp b/src/catch2/catch_totals.hpp index 8dd360c6..386392c9 100644 --- a/src/catch2/catch_totals.hpp +++ b/src/catch2/catch_totals.hpp @@ -23,6 +23,7 @@ namespace Catch { std::uint64_t passed = 0; std::uint64_t failed = 0; std::uint64_t failedButOk = 0; + std::uint64_t skipped = 0; }; struct Totals { diff --git a/src/catch2/catch_translate_exception.cpp b/src/catch2/catch_translate_exception.cpp new file mode 100644 index 00000000..c4b28944 --- /dev/null +++ b/src/catch2/catch_translate_exception.cpp @@ -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 +#include + +namespace Catch { + namespace Detail { + void registerTranslatorImpl( + Detail::unique_ptr&& translator ) { + getMutableRegistryHub().registerTranslator( + CATCH_MOVE( translator ) ); + } + } // namespace Detail +} // namespace Catch diff --git a/src/catch2/catch_translate_exception.hpp b/src/catch2/catch_translate_exception.hpp index 2dbeb17e..5a4dc5e3 100644 --- a/src/catch2/catch_translate_exception.hpp +++ b/src/catch2/catch_translate_exception.hpp @@ -15,6 +15,10 @@ #include namespace Catch { + namespace Detail { + void registerTranslatorImpl( + Detail::unique_ptr&& translator ); + } class ExceptionTranslatorRegistrar { template @@ -48,9 +52,9 @@ namespace Catch { public: template ExceptionTranslatorRegistrar( std::string(*translateFunction)( T const& ) ) { - getMutableRegistryHub().registerTranslator( - Detail::make_unique>(translateFunction) - ); + Detail::registerTranslatorImpl( + Detail::make_unique>( + translateFunction ) ); } }; diff --git a/src/catch2/catch_user_config.hpp.in b/src/catch2/catch_user_config.hpp.in index 3f6b10e8..10d61937 100644 --- a/src/catch2/catch_user_config.hpp.in +++ b/src/catch2/catch_user_config.hpp.in @@ -169,9 +169,18 @@ #endif +#cmakedefine CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT +#cmakedefine CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + +#if defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) && \ + defined( CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) +# error Cannot force STATIC_ANALYSIS_SUPPORT to both ON and OFF +#endif + + // ------ // Simple toggle defines -// their value is never used and they cannot be overriden +// their value is never used and they cannot be overridden // ------ @@ -189,6 +198,7 @@ #cmakedefine CATCH_CONFIG_FAST_COMPILE #cmakedefine CATCH_CONFIG_NOSTDOUT #cmakedefine CATCH_CONFIG_PREFIX_ALL +#cmakedefine CATCH_CONFIG_PREFIX_MESSAGES #cmakedefine CATCH_CONFIG_WINDOWS_CRTDBG #cmakedefine CATCH_CONFIG_SHARED_LIBRARY diff --git a/src/catch2/catch_version.cpp b/src/catch2/catch_version.cpp index b6b818a0..dbf8b4b2 100644 --- a/src/catch2/catch_version.cpp +++ b/src/catch2/catch_version.cpp @@ -36,7 +36,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 3, 2, 1, "", 0 ); + static Version version( 3, 5, 0, "", 0 ); return version; } diff --git a/src/catch2/catch_version_macros.hpp b/src/catch2/catch_version_macros.hpp index f61d999d..fbe1188c 100644 --- a/src/catch2/catch_version_macros.hpp +++ b/src/catch2/catch_version_macros.hpp @@ -9,7 +9,7 @@ #define CATCH_VERSION_MACROS_HPP_INCLUDED #define CATCH_VERSION_MAJOR 3 -#define CATCH_VERSION_MINOR 2 -#define CATCH_VERSION_PATCH 1 +#define CATCH_VERSION_MINOR 5 +#define CATCH_VERSION_PATCH 0 #endif // CATCH_VERSION_MACROS_HPP_INCLUDED diff --git a/src/catch2/generators/catch_generators.cpp b/src/catch2/generators/catch_generators.cpp index 7cc5aa8a..3514e9f6 100644 --- a/src/catch2/generators/catch_generators.cpp +++ b/src/catch2/generators/catch_generators.cpp @@ -27,9 +27,16 @@ namespace Detail { GeneratorUntypedBase::~GeneratorUntypedBase() = default; - auto acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + 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 diff --git a/src/catch2/generators/catch_generators.hpp b/src/catch2/generators/catch_generators.hpp index 8fc7e58c..117f1901 100644 --- a/src/catch2/generators/catch_generators.hpp +++ b/src/catch2/generators/catch_generators.hpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -204,37 +203,47 @@ namespace Detail { return makeGenerators( value( T( CATCH_FORWARD( val ) ) ), CATCH_FORWARD( moreGenerators )... ); } - auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; + IGeneratorTracker* acquireGeneratorTracker( StringRef generatorName, + SourceLineInfo const& lineInfo ); + IGeneratorTracker* createGeneratorTracker( StringRef generatorName, + SourceLineInfo lineInfo, + GeneratorBasePtr&& generator ); template - // Note: The type after -> is weird, because VS2015 cannot parse - // the expression used in the typedef inside, when it is in - // return type. Yeah. - auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval().get()) { + 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 ); - if (!tracker.hasGenerator()) { - tracker.setGenerator(Catch::Detail::make_unique>(generatorExpression())); + 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>( + generatorExpression() ) ); } - auto const& generator = static_cast const&>( *tracker.getGenerator() ); + auto const& generator = static_cast 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( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + 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( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + 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( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + 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) diff --git a/src/catch2/generators/catch_generators_random.cpp b/src/catch2/generators/catch_generators_random.cpp index 2e3390fd..00a8e634 100644 --- a/src/catch2/generators/catch_generators_random.cpp +++ b/src/catch2/generators/catch_generators_random.cpp @@ -7,7 +7,35 @@ // SPDX-License-Identifier: BSL-1.0 #include - #include -std::uint32_t Catch::Generators::Detail::getSeed() { return sharedRng()(); } +#include + +namespace Catch { + namespace Generators { + namespace Detail { + std::uint32_t getSeed() { return sharedRng()(); } + } // namespace Detail + + struct RandomFloatingGenerator::PImpl { + PImpl( long double a, long double b, uint32_t seed ): + rng( seed ), dist( a, b ) {} + + Catch::SimplePcg32 rng; + std::uniform_real_distribution dist; + }; + + RandomFloatingGenerator::RandomFloatingGenerator( + long double a, long double b, std::uint32_t seed) : + m_pimpl(Catch::Detail::make_unique(a, b, seed)) { + static_cast( next() ); + } + + RandomFloatingGenerator::~RandomFloatingGenerator() = + default; + bool RandomFloatingGenerator::next() { + m_current_number = m_pimpl->dist( m_pimpl->rng ); + return true; + } + } // namespace Generators +} // namespace Catch diff --git a/src/catch2/generators/catch_generators_random.hpp b/src/catch2/generators/catch_generators_random.hpp index bcd4888d..d5f307d4 100644 --- a/src/catch2/generators/catch_generators_random.hpp +++ b/src/catch2/generators/catch_generators_random.hpp @@ -11,8 +11,9 @@ #include #include #include - -#include +#include +#include +#include namespace Catch { namespace Generators { @@ -26,7 +27,7 @@ namespace Detail { template class RandomFloatingGenerator final : public IGenerator { Catch::SimplePcg32 m_rng; - std::uniform_real_distribution m_dist; + Catch::uniform_floating_point_distribution m_dist; Float m_current_number; public: RandomFloatingGenerator( Float a, Float b, std::uint32_t seed ): @@ -44,10 +45,27 @@ public: } }; +template <> +class RandomFloatingGenerator final : public IGenerator { + // We still rely on for this specialization, but we don't + // want to drag it into the header. + struct PImpl; + Catch::Detail::unique_ptr m_pimpl; + long double m_current_number; + +public: + RandomFloatingGenerator( long double a, long double b, std::uint32_t seed ); + + long double const& get() const override { return m_current_number; } + bool next() override; + + ~RandomFloatingGenerator() override; // = default +}; + template class RandomIntegerGenerator final : public IGenerator { Catch::SimplePcg32 m_rng; - std::uniform_int_distribution m_dist; + Catch::uniform_integer_distribution m_dist; Integer m_current_number; public: RandomIntegerGenerator( Integer a, Integer b, std::uint32_t seed ): @@ -68,14 +86,6 @@ public: template std::enable_if_t::value, GeneratorWrapper> random(T a, T b) { - static_assert( - !std::is_same::value && - !std::is_same::value && - !std::is_same::value && - !std::is_same::value && - !std::is_same::value && - !std::is_same::value, - "The requested type is not supported by the underlying random distributions from std" ); return GeneratorWrapper( Catch::Detail::make_unique>(a, b, Detail::getSeed()) ); diff --git a/src/catch2/generators/catch_generators_range.hpp b/src/catch2/generators/catch_generators_range.hpp index 495acb95..b67c1590 100644 --- a/src/catch2/generators/catch_generators_range.hpp +++ b/src/catch2/generators/catch_generators_range.hpp @@ -96,10 +96,11 @@ GeneratorWrapper from_range(InputIterator from, InputSentinel to) { return GeneratorWrapper(Catch::Detail::make_unique>(from, to)); } -template -GeneratorWrapper from_range(Container const& cnt) { - return GeneratorWrapper(Catch::Detail::make_unique>(cnt.begin(), cnt.end())); +template +auto from_range(Container const& cnt) { + using std::begin; + using std::end; + return from_range( begin( cnt ), end( cnt ) ); } diff --git a/src/catch2/interfaces/catch_interfaces_all.hpp b/src/catch2/interfaces/catch_interfaces_all.hpp index 87b746d8..a99fdcdc 100644 --- a/src/catch2/interfaces/catch_interfaces_all.hpp +++ b/src/catch2/interfaces/catch_interfaces_all.hpp @@ -30,8 +30,8 @@ #include #include #include -#include #include +#include #include #endif // CATCH_INTERFACES_ALL_HPP_INCLUDED diff --git a/src/catch2/interfaces/catch_interfaces_capture.hpp b/src/catch2/interfaces/catch_interfaces_capture.hpp index ac25a8c0..a1876a4c 100644 --- a/src/catch2/interfaces/catch_interfaces_capture.hpp +++ b/src/catch2/interfaces/catch_interfaces_capture.hpp @@ -13,6 +13,8 @@ #include #include +#include +#include namespace Catch { @@ -30,19 +32,31 @@ namespace Catch { class IGeneratorTracker; struct BenchmarkInfo; - template > - struct BenchmarkStats; + + namespace Generators { + class GeneratorUntypedBase; + using GeneratorBasePtr = Catch::Detail::unique_ptr; + } + class IResultCapture { public: virtual ~IResultCapture(); - virtual bool sectionStarted( SectionInfo const& sectionInfo, - Counts& assertions ) = 0; - virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; - virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + 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 auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 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; @@ -52,7 +66,7 @@ namespace Catch { virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; - virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0; + virtual void emplaceUnscopedMessage( MessageBuilder&& builder ) = 0; virtual void handleFatalErrorCondition( StringRef message ) = 0; @@ -70,7 +84,7 @@ namespace Catch { AssertionReaction& reaction ) = 0; virtual void handleUnexpectedInflightException ( AssertionInfo const& info, - std::string const& message, + std::string&& message, AssertionReaction& reaction ) = 0; virtual void handleIncomplete ( AssertionInfo const& info ) = 0; diff --git a/src/catch2/interfaces/catch_interfaces_exception.hpp b/src/catch2/interfaces/catch_interfaces_exception.hpp index 9177666a..fcc2a8f9 100644 --- a/src/catch2/interfaces/catch_interfaces_exception.hpp +++ b/src/catch2/interfaces/catch_interfaces_exception.hpp @@ -8,7 +8,6 @@ #ifndef CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED #define CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED -#include #include #include diff --git a/src/catch2/interfaces/catch_interfaces_registry_hub.hpp b/src/catch2/interfaces/catch_interfaces_registry_hub.hpp index 8813b538..113f223e 100644 --- a/src/catch2/interfaces/catch_interfaces_registry_hub.hpp +++ b/src/catch2/interfaces/catch_interfaces_registry_hub.hpp @@ -19,7 +19,7 @@ namespace Catch { class ITestCaseRegistry; class IExceptionTranslatorRegistry; class IExceptionTranslator; - class IReporterRegistry; + class ReporterRegistry; class IReporterFactory; class ITagAliasRegistry; class ITestInvoker; @@ -35,7 +35,7 @@ namespace Catch { public: virtual ~IRegistryHub(); // = default - virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ReporterRegistry const& getReporterRegistry() const = 0; virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; diff --git a/src/catch2/interfaces/catch_interfaces_reporter.cpp b/src/catch2/interfaces/catch_interfaces_reporter.cpp index 0bcf66df..3274bcf5 100644 --- a/src/catch2/interfaces/catch_interfaces_reporter.cpp +++ b/src/catch2/interfaces/catch_interfaces_reporter.cpp @@ -54,24 +54,21 @@ namespace Catch { infoMessages( _infoMessages ), totals( _totals ) { - assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; - 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 << assertionResult.getMessage(); - builder.m_info.message = builder.m_stream.str(); + builder.m_info.message = static_cast(assertionResult.getMessage()); - infoMessages.push_back( builder.m_info ); + infoMessages.push_back( CATCH_MOVE(builder.m_info) ); } } - SectionStats::SectionStats( SectionInfo const& _sectionInfo, + SectionStats::SectionStats( SectionInfo&& _sectionInfo, Counts const& _assertions, double _durationInSeconds, bool _missingAssertions ) - : sectionInfo( _sectionInfo ), + : sectionInfo( CATCH_MOVE(_sectionInfo) ), assertions( _assertions ), durationInSeconds( _durationInSeconds ), missingAssertions( _missingAssertions ) @@ -80,13 +77,13 @@ namespace Catch { TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, + std::string&& _stdOut, + std::string&& _stdErr, bool _aborting ) : testInfo( &_testInfo ), totals( _totals ), - stdOut( _stdOut ), - stdErr( _stdErr ), + stdOut( CATCH_MOVE(_stdOut) ), + stdErr( CATCH_MOVE(_stdErr) ), aborting( _aborting ) {} diff --git a/src/catch2/interfaces/catch_interfaces_reporter.hpp b/src/catch2/interfaces/catch_interfaces_reporter.hpp index 5f286363..b40fce31 100644 --- a/src/catch2/interfaces/catch_interfaces_reporter.hpp +++ b/src/catch2/interfaces/catch_interfaces_reporter.hpp @@ -13,11 +13,10 @@ #include #include #include +#include #include #include -#include -#include - +#include #include #include @@ -57,11 +56,6 @@ namespace Catch { std::map m_customOptions; }; - struct TestRunInfo { - constexpr TestRunInfo(StringRef _name) : name(_name) {} - StringRef name; - }; - struct AssertionStats { AssertionStats( AssertionResult const& _assertionResult, std::vector const& _infoMessages, @@ -78,7 +72,7 @@ namespace Catch { }; struct SectionStats { - SectionStats( SectionInfo const& _sectionInfo, + SectionStats( SectionInfo&& _sectionInfo, Counts const& _assertions, double _durationInSeconds, bool _missingAssertions ); @@ -92,8 +86,8 @@ namespace Catch { struct TestCaseStats { TestCaseStats( TestCaseInfo const& _testInfo, Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, + std::string&& _stdOut, + std::string&& _stdErr, bool _aborting ); TestCaseInfo const * testInfo; @@ -113,45 +107,6 @@ namespace Catch { bool aborting; }; - - struct BenchmarkInfo { - std::string name; - double estimatedDuration; - int iterations; - unsigned int samples; - unsigned int resamples; - double clockResolution; - double clockCost; - }; - - template - struct BenchmarkStats { - BenchmarkInfo info; - - std::vector samples; - Benchmark::Estimate mean; - Benchmark::Estimate standardDeviation; - Benchmark::OutlierClassification outliers; - double outlierVariance; - - template - operator BenchmarkStats() const { - std::vector samples2; - samples2.reserve(samples.size()); - for (auto const& sample : samples) { - samples2.push_back(Duration2(sample)); - } - return { - info, - CATCH_MOVE(samples2), - mean, - standardDeviation, - outliers, - outlierVariance, - }; - } - }; - //! 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. @@ -242,10 +197,15 @@ namespace Catch { */ virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; - //! Called with test cases that are skipped due to the test run aborting + /** + * 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) occured + //! 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 diff --git a/src/catch2/interfaces/catch_interfaces_reporter_registry.hpp b/src/catch2/interfaces/catch_interfaces_reporter_registry.hpp deleted file mode 100644 index 277d1761..00000000 --- a/src/catch2/interfaces/catch_interfaces_reporter_registry.hpp +++ /dev/null @@ -1,42 +0,0 @@ - -// 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_REGISTRY_HPP_INCLUDED -#define CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED - -#include -#include - -#include -#include -#include - -namespace Catch { - - class IConfig; - - class IEventListener; - using IEventListenerPtr = Detail::unique_ptr; - class IReporterFactory; - using IReporterFactoryPtr = Detail::unique_ptr; - struct ReporterConfig; - class EventListenerFactory; - - class IReporterRegistry { - public: - using FactoryMap = std::map; - using Listeners = std::vector>; - - virtual ~IReporterRegistry(); // = default - virtual IEventListenerPtr create( std::string const& name, ReporterConfig&& config ) const = 0; - virtual FactoryMap const& getFactories() const = 0; - virtual Listeners const& getListeners() const = 0; - }; - -} // end namespace Catch - -#endif // CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED diff --git a/src/catch2/interfaces/catch_interfaces_test_invoker.hpp b/src/catch2/interfaces/catch_interfaces_test_invoker.hpp new file mode 100644 index 00000000..3caeff9a --- /dev/null +++ b/src/catch2/interfaces/catch_interfaces_test_invoker.hpp @@ -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 diff --git a/src/catch2/interfaces/catch_interfaces_testcase.cpp b/src/catch2/interfaces/catch_interfaces_testcase.cpp index 5e632ba8..a543116c 100644 --- a/src/catch2/interfaces/catch_interfaces_testcase.cpp +++ b/src/catch2/interfaces/catch_interfaces_testcase.cpp @@ -9,6 +9,5 @@ #include namespace Catch { - ITestInvoker::~ITestInvoker() = default; ITestCaseRegistry::~ITestCaseRegistry() = default; } diff --git a/src/catch2/interfaces/catch_interfaces_testcase.hpp b/src/catch2/interfaces/catch_interfaces_testcase.hpp index 78ee2021..daee8482 100644 --- a/src/catch2/interfaces/catch_interfaces_testcase.hpp +++ b/src/catch2/interfaces/catch_interfaces_testcase.hpp @@ -12,15 +12,7 @@ namespace Catch { - class TestSpec; struct TestCaseInfo; - - class ITestInvoker { - public: - virtual void invoke () const = 0; - virtual ~ITestInvoker(); // = default - }; - class TestCaseHandle; class IConfig; @@ -33,11 +25,6 @@ namespace Catch { virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; - bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ); - bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - } #endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED diff --git a/src/catch2/internal/catch_assertion_handler.cpp b/src/catch2/internal/catch_assertion_handler.cpp index f051314c..e5232f70 100644 --- a/src/catch2/internal/catch_assertion_handler.cpp +++ b/src/catch2/internal/catch_assertion_handler.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include namespace Catch { @@ -24,7 +23,9 @@ namespace Catch { 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 ); @@ -38,7 +39,7 @@ namespace Catch { } void AssertionHandler::complete() { - setCompleted(); + m_completed = true; if( m_reaction.shouldDebugBreak ) { // If you find your debugger stopping you here then go one level up on the @@ -50,9 +51,9 @@ namespace Catch { if (m_reaction.shouldThrow) { throw_test_failure_exception(); } - } - void AssertionHandler::setCompleted() { - m_completed = true; + if ( m_reaction.shouldSkip ) { + throw_test_skip_exception(); + } } void AssertionHandler::handleUnexpectedInflightException() { diff --git a/src/catch2/internal/catch_assertion_handler.hpp b/src/catch2/internal/catch_assertion_handler.hpp index 36b55243..01dd7801 100644 --- a/src/catch2/internal/catch_assertion_handler.hpp +++ b/src/catch2/internal/catch_assertion_handler.hpp @@ -11,17 +11,15 @@ #include #include #include -#include #include namespace Catch { - class IResultCapture; - struct AssertionReaction { bool shouldDebugBreak = false; bool shouldThrow = false; + bool shouldSkip = false; }; class AssertionHandler { @@ -58,7 +56,6 @@ namespace Catch { void handleUnexpectedInflightException(); void complete(); - void setCompleted(); // query auto allowThrows() const -> bool; diff --git a/src/catch2/internal/catch_commandline.cpp b/src/catch2/internal/catch_commandline.cpp index 81aa073c..4ac1847b 100644 --- a/src/catch2/internal/catch_commandline.cpp +++ b/src/catch2/internal/catch_commandline.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -144,7 +144,7 @@ namespace Catch { auto const& reporterSpec = *parsed; - IReporterRegistry::FactoryMap const& factories = + auto const& factories = getRegistryHub().getReporterRegistry().getFactories(); auto result = factories.find( reporterSpec.name() ); diff --git a/src/catch2/internal/catch_compiler_capabilities.hpp b/src/catch2/internal/catch_compiler_capabilities.hpp index d457a4b4..dacae01b 100644 --- a/src/catch2/internal/catch_compiler_capabilities.hpp +++ b/src/catch2/internal/catch_compiler_capabilities.hpp @@ -41,7 +41,7 @@ // Only GCC compiler should be used in this block, so other compilers trying to // mask themselves as GCC should be ignored. -#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) && !defined(__NVCOMPILER) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) @@ -50,20 +50,37 @@ # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ + _Pragma( "GCC diagnostic ignored \"-Wunused-result\"" ) + # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ _Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" ) # define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ _Pragma( "GCC diagnostic ignored \"-Wuseless-cast\"" ) +# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + _Pragma( "GCC diagnostic ignored \"-Wshadow\"" ) + # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) #endif +#if defined(__NVCOMPILER) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "diag push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "diag pop" ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress declared_but_not_referenced" ) +#endif + #if defined(__CUDACC__) && !defined(__clang__) +# ifdef __NVCC_DIAG_PRAGMA_SUPPORT__ +// New pragmas introduced in CUDA 11.5+ # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic pop" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "nv_diag_suppress 177" ) +# else +# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress 177" ) +# endif #endif // clang-cl defines _MSC_VER as well as __clang__, which could cause the @@ -117,6 +134,9 @@ # define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wcomma\"" ) +# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wshadow\"" ) + #endif // __clang__ @@ -136,7 +156,9 @@ //////////////////////////////////////////////////////////////////////////////// // Assume that some platforms do not support getenv. -#if defined(CATCH_PLATFORM_WINDOWS_UWP) || defined(CATCH_PLATFORM_PLAYSTATION) +#if defined( CATCH_PLATFORM_WINDOWS_UWP ) || \ + defined( CATCH_PLATFORM_PLAYSTATION ) || \ + defined( _GAMING_XBOX ) # define CATCH_INTERNAL_CONFIG_NO_GETENV #else # define CATCH_INTERNAL_CONFIG_GETENV @@ -181,8 +203,14 @@ // Visual C++ #if defined(_MSC_VER) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) +// We want to defer to nvcc-specific warning suppression if we are compiled +// with nvcc masquerading for MSVC. +# if !defined( __CUDACC__ ) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + __pragma( warning( push ) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + __pragma( warning( pop ) ) +# endif // Universal Windows platform does not support SEH // Or console colours (or console at all...) @@ -348,6 +376,9 @@ #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS #endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS #endif @@ -357,6 +388,16 @@ #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS #endif +#if !defined( CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif +#if !defined( CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS ) +# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS +#endif +#if !defined( CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS ) +# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS +#endif + // The goal of this macro is to avoid evaluation of the arguments, but // still have the compiler warn on problems inside... @@ -370,13 +411,6 @@ # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if !defined(CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS -#endif #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) #define CATCH_TRY if ((true)) diff --git a/src/catch2/internal/catch_config_counter.hpp b/src/catch2/internal/catch_config_counter.hpp index 23b22324..a482ce34 100644 --- a/src/catch2/internal/catch_config_counter.hpp +++ b/src/catch2/internal/catch_config_counter.hpp @@ -18,6 +18,8 @@ #ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED #define CATCH_CONFIG_COUNTER_HPP_INCLUDED +#include + #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) #define CATCH_INTERNAL_CONFIG_COUNTER #endif diff --git a/src/catch2/internal/catch_config_prefix_messages.hpp b/src/catch2/internal/catch_config_prefix_messages.hpp new file mode 100644 index 00000000..be1e9a96 --- /dev/null +++ b/src/catch2/internal/catch_config_prefix_messages.hpp @@ -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 + +/** \file + * Wrapper for the CATCH_CONFIG_PREFIX_MESSAGES configuration option + * + * CATCH_CONFIG_PREFIX_ALL can be used to avoid clashes with other macros + * by prepending CATCH_. This may not be desirable if the only clashes are with + * logger macros such as INFO and WARN. In this cases + * CATCH_CONFIG_PREFIX_MESSAGES can be used to only prefix a small subset + * of relevant macros. + * + */ + +#ifndef CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED +#define CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED + +#include + +#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_PREFIX_MESSAGES) + #define CATCH_CONFIG_PREFIX_MESSAGES +#endif + +#endif // CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED diff --git a/src/catch2/internal/catch_config_static_analysis_support.hpp b/src/catch2/internal/catch_config_static_analysis_support.hpp new file mode 100644 index 00000000..81bdf39f --- /dev/null +++ b/src/catch2/internal/catch_config_static_analysis_support.hpp @@ -0,0 +1,34 @@ + +// 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 + * Wrapper for the STATIC_ANALYSIS_SUPPORT configuration option + * + * Some of Catch2's macros can be defined differently to work better with + * static analysis tools, like clang-tidy or coverity. + * Currently the main use case is to show that `SECTION`s are executed + * exclusively, and not all in one run of a `TEST_CASE`. + */ + +#ifndef CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED +#define CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED + +#include + +#if defined(__clang_analyzer__) || defined(__COVERITY__) + #define CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT +#endif + +#if defined( CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT ) && \ + !defined( CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) && \ + !defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) +# define CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT +#endif + + +#endif // CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED diff --git a/src/catch2/internal/catch_config_uncaught_exceptions.hpp b/src/catch2/internal/catch_config_uncaught_exceptions.hpp index 5c4cb930..20b1dfca 100644 --- a/src/catch2/internal/catch_config_uncaught_exceptions.hpp +++ b/src/catch2/internal/catch_config_uncaught_exceptions.hpp @@ -17,6 +17,8 @@ #ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED #define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED +#include + #if defined(_MSC_VER) # if _MSC_VER >= 1900 // Visual Studio 2015 or newer # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS diff --git a/src/catch2/internal/catch_config_wchar.hpp b/src/catch2/internal/catch_config_wchar.hpp index 8c758ec4..90d85d05 100644 --- a/src/catch2/internal/catch_config_wchar.hpp +++ b/src/catch2/internal/catch_config_wchar.hpp @@ -17,6 +17,8 @@ #ifndef CATCH_CONFIG_WCHAR_HPP_INCLUDED #define CATCH_CONFIG_WCHAR_HPP_INCLUDED +#include + // We assume that WCHAR should be enabled by default, and only disabled // for a shortlist (so far only DJGPP) of compilers. diff --git a/src/catch2/internal/catch_console_colour.cpp b/src/catch2/internal/catch_console_colour.cpp index 099a6c59..e1238816 100644 --- a/src/catch2/internal/catch_console_colour.cpp +++ b/src/catch2/internal/catch_console_colour.cpp @@ -85,7 +85,7 @@ namespace Catch { namespace { //! A do-nothing implementation of colour, used as fallback for unknown //! platforms, and when the user asks to deactivate all colours. - class NoColourImpl : public ColourImpl { + class NoColourImpl final : public ColourImpl { public: NoColourImpl( IStream* stream ): ColourImpl( stream ) {} @@ -103,7 +103,7 @@ namespace Catch { namespace Catch { namespace { - class Win32ColourImpl : public ColourImpl { + class Win32ColourImpl final : public ColourImpl { public: Win32ColourImpl(IStream* stream): ColourImpl(stream) { @@ -169,7 +169,7 @@ namespace { namespace Catch { namespace { - class ANSIColourImpl : public ColourImpl { + class ANSIColourImpl final : public ColourImpl { public: ANSIColourImpl( IStream* stream ): ColourImpl( stream ) {} diff --git a/src/catch2/internal/catch_console_colour.hpp b/src/catch2/internal/catch_console_colour.hpp index 9aa6a163..d9144315 100644 --- a/src/catch2/internal/catch_console_colour.hpp +++ b/src/catch2/internal/catch_console_colour.hpp @@ -47,6 +47,7 @@ namespace Catch { Error = BrightRed, Success = Green, + Skip = LightGrey, OriginalExpression = Cyan, ReconstructedExpression = BrightYellow, diff --git a/src/catch2/internal/catch_context.cpp b/src/catch2/internal/catch_context.cpp index 17f28509..3b1cc277 100644 --- a/src/catch2/internal/catch_context.cpp +++ b/src/catch2/internal/catch_context.cpp @@ -11,49 +11,27 @@ namespace Catch { - class Context : public IMutableContext, private Detail::NonCopyable { + Context* Context::currentContext = nullptr; - public: // IContext - IResultCapture* getResultCapture() override { - return m_resultCapture; - } - - IConfig const* getConfig() const override { - return m_config; - } - - ~Context() override; - - public: // IMutableContext - void setResultCapture( IResultCapture* resultCapture ) override { - m_resultCapture = resultCapture; - } - void setConfig( IConfig const* config ) override { - m_config = config; - } - - friend IMutableContext& getCurrentMutableContext(); - - private: - IConfig const* m_config = nullptr; - IResultCapture* m_resultCapture = nullptr; - }; - - IMutableContext *IMutableContext::currentContext = nullptr; - - void IMutableContext::createContext() - { + void cleanUpContext() { + delete Context::currentContext; + Context::currentContext = nullptr; + } + void Context::createContext() { currentContext = new Context(); } - void cleanUpContext() { - delete IMutableContext::currentContext; - IMutableContext::currentContext = nullptr; + Context& getCurrentMutableContext() { + if ( !Context::currentContext ) { Context::createContext(); } + // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) + return *Context::currentContext; } - IContext::~IContext() = default; - IMutableContext::~IMutableContext() = default; - Context::~Context() = default; + void Context::setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + + void Context::setConfig( IConfig const* config ) { m_config = config; } SimplePcg32& sharedRng() { static SimplePcg32 s_rng; diff --git a/src/catch2/internal/catch_context.hpp b/src/catch2/internal/catch_context.hpp index a9d1b394..6ccb3b31 100644 --- a/src/catch2/internal/catch_context.hpp +++ b/src/catch2/internal/catch_context.hpp @@ -15,38 +15,31 @@ namespace Catch { class IResultCapture; class IConfig; - class IContext { - public: - virtual ~IContext(); // = default + class Context { + IConfig const* m_config = nullptr; + IResultCapture* m_resultCapture = nullptr; - virtual IResultCapture* getResultCapture() = 0; - virtual IConfig const* getConfig() const = 0; - }; - - class IMutableContext : public IContext { - public: - ~IMutableContext() override; // = default - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setConfig( IConfig const* config ) = 0; - - private: - CATCH_EXPORT static IMutableContext* currentContext; - friend IMutableContext& getCurrentMutableContext(); - friend void cleanUpContext(); + CATCH_EXPORT static Context* currentContext; + friend Context& getCurrentMutableContext(); + friend Context const& getCurrentContext(); static void createContext(); + friend void cleanUpContext(); + + public: + IResultCapture* getResultCapture() const { return m_resultCapture; } + IConfig const* getConfig() const { return m_config; } + void setResultCapture( IResultCapture* resultCapture ); + void setConfig( IConfig const* config ); }; - inline IMutableContext& getCurrentMutableContext() - { - if( !IMutableContext::currentContext ) - IMutableContext::createContext(); - // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) - return *IMutableContext::currentContext; - } + Context& getCurrentMutableContext(); - inline IContext& getCurrentContext() - { - return getCurrentMutableContext(); + inline Context const& getCurrentContext() { + // We duplicate the logic from `getCurrentMutableContext` here, + // to avoid paying the call overhead in debug mode. + if ( !Context::currentContext ) { Context::createContext(); } + // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) + return *Context::currentContext; } void cleanUpContext(); diff --git a/src/catch2/internal/catch_debugger.hpp b/src/catch2/internal/catch_debugger.hpp index 30063d1f..25c5a260 100644 --- a/src/catch2/internal/catch_debugger.hpp +++ b/src/catch2/internal/catch_debugger.hpp @@ -19,7 +19,10 @@ namespace Catch { #if defined(__i386__) || defined(__x86_64__) #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ #elif defined(__aarch64__) - #define CATCH_TRAP() __asm__(".inst 0xd43e0000") + #define CATCH_TRAP() __asm__(".inst 0xd43e0000") + #elif defined(__POWERPC__) + #define CATCH_TRAP() __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ) /* NOLINT */ #endif #elif defined(CATCH_PLATFORM_IPHONE) diff --git a/src/catch2/internal/catch_enum_values_registry.cpp b/src/catch2/internal/catch_enum_values_registry.cpp index 7e8bf5e5..a94b6088 100644 --- a/src/catch2/internal/catch_enum_values_registry.cpp +++ b/src/catch2/internal/catch_enum_values_registry.cpp @@ -39,7 +39,7 @@ namespace Catch { return parsed; } - EnumInfo::~EnumInfo() {} + EnumInfo::~EnumInfo() = default; StringRef EnumInfo::lookup( int value ) const { for( auto const& valueToName : m_values ) { diff --git a/src/catch2/internal/catch_exception_translator_registry.cpp b/src/catch2/internal/catch_exception_translator_registry.cpp index 2a240a9b..1eb61147 100644 --- a/src/catch2/internal/catch_exception_translator_registry.cpp +++ b/src/catch2/internal/catch_exception_translator_registry.cpp @@ -11,10 +11,27 @@ #include #include +#include + namespace Catch { - ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + namespace { + static std::string tryTranslators( + std::vector< + Detail::unique_ptr> const& translators ) { + if ( translators.empty() ) { + std::rethrow_exception( std::current_exception() ); + } else { + return translators[0]->translate( translators.begin() + 1, + translators.end() ); + } + } + } +#endif //!defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + + ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() = default; void ExceptionTranslatorRegistry::registerTranslator( Detail::unique_ptr&& translator ) { m_translators.push_back( CATCH_MOVE( translator ) ); @@ -37,13 +54,16 @@ namespace Catch { // First we try user-registered translators. If none of them can // handle the exception, it will be rethrown handled by our defaults. try { - return tryTranslators(); + return tryTranslators(m_translators); } // To avoid having to handle TFE explicitly everywhere, we just // rethrow it so that it goes back up the caller. catch( TestFailureException& ) { std::rethrow_exception(std::current_exception()); } + catch( TestSkipException& ) { + std::rethrow_exception(std::current_exception()); + } catch( std::exception const& ex ) { return ex.what(); } @@ -58,23 +78,10 @@ namespace Catch { } } - std::string ExceptionTranslatorRegistry::tryTranslators() const { - if (m_translators.empty()) { - std::rethrow_exception(std::current_exception()); - } else { - return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end()); - } - } - #else // ^^ Exceptions are enabled // Exceptions are disabled vv std::string ExceptionTranslatorRegistry::translateActiveException() const { CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); } - - std::string ExceptionTranslatorRegistry::tryTranslators() const { - CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); - } #endif - } diff --git a/src/catch2/internal/catch_exception_translator_registry.hpp b/src/catch2/internal/catch_exception_translator_registry.hpp index 2aafa684..3123e93d 100644 --- a/src/catch2/internal/catch_exception_translator_registry.hpp +++ b/src/catch2/internal/catch_exception_translator_registry.hpp @@ -21,7 +21,6 @@ namespace Catch { ~ExceptionTranslatorRegistry() override; void registerTranslator( Detail::unique_ptr&& translator ); std::string translateActiveException() const override; - std::string tryTranslators() const; private: ExceptionTranslators m_translators; diff --git a/src/catch2/internal/catch_floating_point_helpers.cpp b/src/catch2/internal/catch_floating_point_helpers.cpp index e30ee434..9631ed6d 100644 --- a/src/catch2/internal/catch_floating_point_helpers.cpp +++ b/src/catch2/internal/catch_floating_point_helpers.cpp @@ -27,6 +27,17 @@ namespace Catch { return i; } +#if defined( __GNUC__ ) || defined( __clang__ ) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + bool directCompare( float lhs, float rhs ) { return lhs == rhs; } + bool directCompare( double lhs, double rhs ) { return lhs == rhs; } +#if defined( __GNUC__ ) || defined( __clang__ ) +# pragma GCC diagnostic pop +#endif + + } // end namespace Detail } // end namespace Catch diff --git a/src/catch2/internal/catch_floating_point_helpers.hpp b/src/catch2/internal/catch_floating_point_helpers.hpp index ca883c61..b2143726 100644 --- a/src/catch2/internal/catch_floating_point_helpers.hpp +++ b/src/catch2/internal/catch_floating_point_helpers.hpp @@ -22,6 +22,11 @@ namespace Catch { uint32_t convertToBits(float f); uint64_t convertToBits(double d); + // Used when we know we want == comparison of two doubles + // to centralize warning suppression + bool directCompare( float lhs, float rhs ); + bool directCompare( double lhs, double rhs ); + } // end namespace Detail diff --git a/src/catch2/internal/catch_is_permutation.hpp b/src/catch2/internal/catch_is_permutation.hpp new file mode 100644 index 00000000..708053d3 --- /dev/null +++ b/src/catch2/internal/catch_is_permutation.hpp @@ -0,0 +1,138 @@ + +// 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_IS_PERMUTATION_HPP_INCLUDED +#define CATCH_IS_PERMUTATION_HPP_INCLUDED + +#include +#include + +namespace Catch { + namespace Detail { + + template + ForwardIter find_sentinel( ForwardIter start, + Sentinel sentinel, + T const& value, + Comparator cmp ) { + while ( start != sentinel ) { + if ( cmp( *start, value ) ) { break; } + ++start; + } + return start; + } + + template + std::ptrdiff_t count_sentinel( ForwardIter start, + Sentinel sentinel, + T const& value, + Comparator cmp ) { + std::ptrdiff_t count = 0; + while ( start != sentinel ) { + if ( cmp( *start, value ) ) { ++count; } + ++start; + } + return count; + } + + template + std::enable_if_t::value, + std::ptrdiff_t> + sentinel_distance( ForwardIter iter, const Sentinel sentinel ) { + std::ptrdiff_t dist = 0; + while ( iter != sentinel ) { + ++iter; + ++dist; + } + return dist; + } + + template + std::ptrdiff_t sentinel_distance( ForwardIter first, + ForwardIter last ) { + return std::distance( first, last ); + } + + template + bool check_element_counts( ForwardIter1 first_1, + const Sentinel1 end_1, + ForwardIter2 first_2, + const Sentinel2 end_2, + Comparator cmp ) { + auto cursor = first_1; + while ( cursor != end_1 ) { + if ( find_sentinel( first_1, cursor, *cursor, cmp ) == + cursor ) { + // we haven't checked this element yet + const auto count_in_range_2 = + count_sentinel( first_2, end_2, *cursor, cmp ); + // Not a single instance in 2nd range, so it cannot be a + // permutation of 1st range + if ( count_in_range_2 == 0 ) { return false; } + + const auto count_in_range_1 = + count_sentinel( cursor, end_1, *cursor, cmp ); + if ( count_in_range_1 != count_in_range_2 ) { + return false; + } + } + + ++cursor; + } + + return true; + } + + template + bool is_permutation( ForwardIter1 first_1, + const Sentinel1 end_1, + ForwardIter2 first_2, + const Sentinel2 end_2, + Comparator cmp ) { + // TODO: no optimization for stronger iterators, because we would also have to constrain on sentinel vs not sentinel types + // TODO: Comparator has to be "both sides", e.g. a == b => b == a + // This skips shared prefix of the two ranges + while (first_1 != end_1 && first_2 != end_2 && cmp(*first_1, *first_2)) { + ++first_1; + ++first_2; + } + + // We need to handle case where at least one of the ranges has no more elements + if (first_1 == end_1 || first_2 == end_2) { + return first_1 == end_1 && first_2 == end_2; + } + + // pair counting is n**2, so we pay linear walk to compare the sizes first + auto dist_1 = sentinel_distance( first_1, end_1 ); + auto dist_2 = sentinel_distance( first_2, end_2 ); + + if (dist_1 != dist_2) { return false; } + + // Since we do not try to handle stronger iterators pair (e.g. + // bidir) optimally, the only thing left to do is to check counts in + // the remaining ranges. + return check_element_counts( first_1, end_1, first_2, end_2, cmp ); + } + + } // namespace Detail +} // namespace Catch + +#endif // CATCH_IS_PERMUTATION_HPP_INCLUDED diff --git a/src/catch2/internal/catch_istream.cpp b/src/catch2/internal/catch_istream.cpp index 489396ec..bf0f66e4 100644 --- a/src/catch2/internal/catch_istream.cpp +++ b/src/catch2/internal/catch_istream.cpp @@ -24,7 +24,7 @@ namespace Catch { namespace Detail { namespace { template - class StreamBufImpl : public std::streambuf { + class StreamBufImpl final : public std::streambuf { char data[bufferSize]; WriterF m_writer; @@ -72,7 +72,7 @@ namespace Detail { /////////////////////////////////////////////////////////////////////////// - class FileStream : public IStream { + class FileStream final : public IStream { std::ofstream m_ofs; public: FileStream( std::string const& filename ) { @@ -89,7 +89,7 @@ namespace Detail { /////////////////////////////////////////////////////////////////////////// - class CoutStream : public IStream { + class CoutStream final : public IStream { std::ostream m_os; public: // Store the streambuf from cout up-front because @@ -118,7 +118,7 @@ namespace Detail { /////////////////////////////////////////////////////////////////////////// - class DebugOutStream : public IStream { + class DebugOutStream final : public IStream { Detail::unique_ptr> m_streamBuf; std::ostream m_os; public: diff --git a/src/catch2/internal/catch_jsonwriter.cpp b/src/catch2/internal/catch_jsonwriter.cpp new file mode 100644 index 00000000..ff65a9d3 --- /dev/null +++ b/src/catch2/internal/catch_jsonwriter.cpp @@ -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 +#include +#include + +namespace Catch { + void JsonUtils::indent( std::ostream& os, std::uint64_t level ) { + for ( std::uint64_t i = 0; i < level; ++i ) { + os << " "; + } + } + void JsonUtils::appendCommaNewline( std::ostream& os, + bool& should_comma, + std::uint64_t level ) { + if ( should_comma ) { os << ','; } + should_comma = true; + os << '\n'; + indent( os, level ); + } + + JsonObjectWriter::JsonObjectWriter( std::ostream& os ): + JsonObjectWriter{ os, 0 } {} + + JsonObjectWriter::JsonObjectWriter( std::ostream& os, + std::uint64_t indent_level ): + m_os{ os }, m_indent_level{ indent_level } { + m_os << '{'; + } + JsonObjectWriter::JsonObjectWriter( JsonObjectWriter&& source ): + m_os{ source.m_os }, + m_indent_level{ source.m_indent_level }, + m_should_comma{ source.m_should_comma }, + m_active{ source.m_active } { + source.m_active = false; + } + + JsonObjectWriter::~JsonObjectWriter() { + if ( !m_active ) { return; } + + m_os << '\n'; + JsonUtils::indent( m_os, m_indent_level ); + m_os << '}'; + } + + JsonValueWriter JsonObjectWriter::write( StringRef key ) { + JsonUtils::appendCommaNewline( + m_os, m_should_comma, m_indent_level + 1 ); + + m_os << '"' << key << "\": "; + return JsonValueWriter{ m_os, m_indent_level + 1 }; + } + + JsonArrayWriter::JsonArrayWriter( std::ostream& os ): + JsonArrayWriter{ os, 0 } {} + JsonArrayWriter::JsonArrayWriter( std::ostream& os, + std::uint64_t indent_level ): + m_os{ os }, m_indent_level{ indent_level } { + m_os << '['; + } + JsonArrayWriter::JsonArrayWriter( JsonArrayWriter&& source ): + m_os{ source.m_os }, + m_indent_level{ source.m_indent_level }, + m_should_comma{ source.m_should_comma }, + m_active{ source.m_active } { + source.m_active = false; + } + JsonArrayWriter::~JsonArrayWriter() { + if ( !m_active ) { return; } + + m_os << '\n'; + JsonUtils::indent( m_os, m_indent_level ); + m_os << ']'; + } + + JsonObjectWriter JsonArrayWriter::writeObject() { + JsonUtils::appendCommaNewline( + m_os, m_should_comma, m_indent_level + 1 ); + return JsonObjectWriter{ m_os, m_indent_level + 1 }; + } + + JsonArrayWriter JsonArrayWriter::writeArray() { + JsonUtils::appendCommaNewline( + m_os, m_should_comma, m_indent_level + 1 ); + return JsonArrayWriter{ m_os, m_indent_level + 1 }; + } + + JsonArrayWriter& JsonArrayWriter::write( bool value ) { + return writeImpl( value ); + } + + JsonValueWriter::JsonValueWriter( std::ostream& os ): + JsonValueWriter{ os, 0 } {} + + JsonValueWriter::JsonValueWriter( std::ostream& os, + std::uint64_t indent_level ): + m_os{ os }, m_indent_level{ indent_level } {} + + JsonObjectWriter JsonValueWriter::writeObject() && { + return JsonObjectWriter{ m_os, m_indent_level }; + } + + JsonArrayWriter JsonValueWriter::writeArray() && { + return JsonArrayWriter{ m_os, m_indent_level }; + } + + void JsonValueWriter::write( Catch::StringRef value ) && { + writeImpl( value, true ); + } + + void JsonValueWriter::write( bool value ) && { + writeImpl( value ? "true"_sr : "false"_sr, false ); + } + + void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) { + if ( quote ) { m_os << '"'; } + for (char c : value) { + // Escape list taken from https://www.json.org/json-en.html, + // string definition. + // Note that while forward slash _can_ be escaped, it does + // not have to be, if JSON is not further embedded somewhere + // where forward slash is meaningful. + if ( c == '"' ) { + m_os << "\\\""; + } else if ( c == '\\' ) { + m_os << "\\\\"; + } else if ( c == '\b' ) { + m_os << "\\b"; + } else if ( c == '\f' ) { + m_os << "\\f"; + } else if ( c == '\n' ) { + m_os << "\\n"; + } else if ( c == '\r' ) { + m_os << "\\r"; + } else if ( c == '\t' ) { + m_os << "\\t"; + } else { + m_os << c; + } + } + if ( quote ) { m_os << '"'; } + } + +} // namespace Catch diff --git a/src/catch2/internal/catch_jsonwriter.hpp b/src/catch2/internal/catch_jsonwriter.hpp new file mode 100644 index 00000000..59c044e4 --- /dev/null +++ b/src/catch2/internal/catch_jsonwriter.hpp @@ -0,0 +1,120 @@ + +// 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_JSONWRITER_HPP_INCLUDED +#define CATCH_JSONWRITER_HPP_INCLUDED + +#include +#include + +#include +#include + +namespace Catch { + class JsonObjectWriter; + class JsonArrayWriter; + + struct JsonUtils { + static void indent( std::ostream& os, std::uint64_t level ); + static void appendCommaNewline( std::ostream& os, + bool& should_comma, + std::uint64_t level ); + }; + + class JsonValueWriter { + public: + JsonValueWriter( std::ostream& os ); + JsonValueWriter( std::ostream& os, std::uint64_t indent_level ); + + JsonObjectWriter writeObject() &&; + JsonArrayWriter writeArray() &&; + + template + void write( T const& value ) && { + writeImpl( value, !std::is_arithmetic::value ); + } + void write( StringRef value ) &&; + void write( bool value ) &&; + + private: + void writeImpl( StringRef value, bool quote ); + + // Without this SFINAE, this overload is a better match + // for `std::string`, `char const*`, `char const[N]` args. + // While it would still work, it would cause code bloat + // and multiple iteration over the strings + template ::value>> + void writeImpl( T const& value, bool quote_value ) { + m_sstream << value; + writeImpl( m_sstream.str(), quote_value ); + } + + std::ostream& m_os; + std::stringstream m_sstream; + std::uint64_t m_indent_level; + }; + + class JsonObjectWriter { + public: + JsonObjectWriter( std::ostream& os ); + JsonObjectWriter( std::ostream& os, std::uint64_t indent_level ); + + JsonObjectWriter( JsonObjectWriter&& source ); + JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete; + + ~JsonObjectWriter(); + + JsonValueWriter write( StringRef key ); + + private: + std::ostream& m_os; + std::uint64_t m_indent_level; + bool m_should_comma = false; + bool m_active = true; + }; + + class JsonArrayWriter { + public: + JsonArrayWriter( std::ostream& os ); + JsonArrayWriter( std::ostream& os, std::uint64_t indent_level ); + + JsonArrayWriter( JsonArrayWriter&& source ); + JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete; + + ~JsonArrayWriter(); + + JsonObjectWriter writeObject(); + JsonArrayWriter writeArray(); + + template + JsonArrayWriter& write( T const& value ) { + return writeImpl( value ); + } + + JsonArrayWriter& write( bool value ); + + private: + template + JsonArrayWriter& writeImpl( T const& value ) { + JsonUtils::appendCommaNewline( + m_os, m_should_comma, m_indent_level + 1 ); + JsonValueWriter{ m_os }.write( value ); + + return *this; + } + + std::ostream& m_os; + std::uint64_t m_indent_level; + bool m_should_comma = false; + bool m_active = true; + }; + +} // namespace Catch + +#endif // CATCH_JSONWRITER_HPP_INCLUDED diff --git a/src/catch2/internal/catch_leak_detector.cpp b/src/catch2/internal/catch_leak_detector.cpp index 7389eaf7..691bc772 100644 --- a/src/catch2/internal/catch_leak_detector.cpp +++ b/src/catch2/internal/catch_leak_detector.cpp @@ -29,7 +29,7 @@ namespace Catch { #else // ^^ Windows crt debug heap enabled // Windows crt debug heap disabled vv - Catch::LeakDetector::LeakDetector() {} + Catch::LeakDetector::LeakDetector() = default; #endif // CATCH_CONFIG_WINDOWS_CRTDBG diff --git a/src/catch2/internal/catch_list.cpp b/src/catch2/internal/catch_list.cpp index 263781d6..97e4c593 100644 --- a/src/catch2/internal/catch_list.cpp +++ b/src/catch2/internal/catch_list.cpp @@ -9,9 +9,9 @@ #include #include -#include -#include #include +#include +#include #include #include @@ -54,7 +54,7 @@ namespace Catch { void listReporters(IEventListener& reporter) { std::vector descriptions; - IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + auto const& factories = getRegistryHub().getReporterRegistry().getFactories(); descriptions.reserve(factories.size()); for (auto const& fac : factories) { descriptions.push_back({ fac.first, fac.second->getDescription() }); diff --git a/src/catch2/internal/catch_message_info.hpp b/src/catch2/internal/catch_message_info.hpp index d2658429..1ef43fda 100644 --- a/src/catch2/internal/catch_message_info.hpp +++ b/src/catch2/internal/catch_message_info.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include diff --git a/src/catch2/internal/catch_optional.hpp b/src/catch2/internal/catch_optional.hpp index ac3714ee..d1e953ad 100644 --- a/src/catch2/internal/catch_optional.hpp +++ b/src/catch2/internal/catch_optional.hpp @@ -8,6 +8,8 @@ #ifndef CATCH_OPTIONAL_HPP_INCLUDED #define CATCH_OPTIONAL_HPP_INCLUDED +#include + #include namespace Catch { @@ -16,35 +18,50 @@ namespace Catch { template class Optional { public: - Optional() : nullableValue( nullptr ) {} - Optional( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Optional( Optional const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) - {} + Optional(): nullableValue( nullptr ) {} + ~Optional() { reset(); } - ~Optional() { + Optional( T const& _value ): + nullableValue( new ( storage ) T( _value ) ) {} + Optional( T&& _value ): + nullableValue( new ( storage ) T( CATCH_MOVE( _value ) ) ) {} + + Optional& operator=( T const& _value ) { reset(); + nullableValue = new ( storage ) T( _value ); + return *this; + } + Optional& operator=( T&& _value ) { + reset(); + nullableValue = new ( storage ) T( CATCH_MOVE( _value ) ); + return *this; } - Optional& operator= ( Optional const& _other ) { - if( &_other != this ) { + Optional( Optional const& _other ): + nullableValue( _other ? new ( storage ) T( *_other ) : nullptr ) {} + Optional( Optional&& _other ): + nullableValue( _other ? new ( storage ) T( CATCH_MOVE( *_other ) ) + : nullptr ) {} + + Optional& operator=( Optional const& _other ) { + if ( &_other != this ) { reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); + if ( _other ) { nullableValue = new ( storage ) T( *_other ); } } return *this; } - Optional& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); + Optional& operator=( Optional&& _other ) { + if ( &_other != this ) { + reset(); + if ( _other ) { + nullableValue = new ( storage ) T( CATCH_MOVE( *_other ) ); + } + } return *this; } void reset() { - if( nullableValue ) - nullableValue->~T(); + if ( nullableValue ) { nullableValue->~T(); } nullableValue = nullptr; } @@ -91,7 +108,7 @@ namespace Catch { } private: - T *nullableValue; + T* nullableValue; alignas(alignof(T)) char storage[sizeof(T)]; }; diff --git a/src/catch2/internal/catch_parse_numbers.cpp b/src/catch2/internal/catch_parse_numbers.cpp index 390b8c87..d949ac19 100644 --- a/src/catch2/internal/catch_parse_numbers.cpp +++ b/src/catch2/internal/catch_parse_numbers.cpp @@ -6,12 +6,12 @@ // SPDX-License-Identifier: BSL-1.0 -#include - #include +#include #include #include +#include namespace Catch { @@ -39,11 +39,14 @@ namespace Catch { return {}; } return static_cast(ret); - } CATCH_CATCH_ANON( std::exception const& ) { - // There was a larger issue with the input, e.g. the parsed - // number would be too large to fit within ull. - return {}; } + CATCH_CATCH_ANON( std::invalid_argument const& ) { + // no conversion could be performed + } + CATCH_CATCH_ANON( std::out_of_range const& ) { + // the input does not fit into an unsigned long long + } + return {}; } } // namespace Catch diff --git a/src/catch2/internal/catch_polyfills.cpp b/src/catch2/internal/catch_polyfills.cpp index 96efad5d..776c2243 100644 --- a/src/catch2/internal/catch_polyfills.cpp +++ b/src/catch2/internal/catch_polyfills.cpp @@ -31,4 +31,12 @@ namespace Catch { } #endif +#if !defined( CATCH_CONFIG_GLOBAL_NEXTAFTER ) + float nextafter( float x, float y ) { return std::nextafter( x, y ); } + double nextafter( double x, double y ) { return std::nextafter( x, y ); } +#else + float nextafter( float x, float y ) { return ::nextafterf( x, y ); } + double nextafter( double x, double y ) { return ::nextafter( x, y ); } +#endif + } // end namespace Catch diff --git a/src/catch2/internal/catch_polyfills.hpp b/src/catch2/internal/catch_polyfills.hpp index 23a9332b..4503f8f2 100644 --- a/src/catch2/internal/catch_polyfills.hpp +++ b/src/catch2/internal/catch_polyfills.hpp @@ -9,8 +9,13 @@ #define CATCH_POLYFILLS_HPP_INCLUDED namespace Catch { + bool isnan(float f); bool isnan(double d); + + float nextafter(float x, float y); + double nextafter(double x, double y); + } #endif // CATCH_POLYFILLS_HPP_INCLUDED diff --git a/src/catch2/internal/catch_preprocessor_internal_stringify.hpp b/src/catch2/internal/catch_preprocessor_internal_stringify.hpp new file mode 100644 index 00000000..2fd64e1c --- /dev/null +++ b/src/catch2/internal/catch_preprocessor_internal_stringify.hpp @@ -0,0 +1,19 @@ + +// 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_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED +#define CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED + +#include + +#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) + #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr +#else + #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr +#endif + +#endif // CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED diff --git a/src/catch2/internal/catch_random_floating_point_helpers.hpp b/src/catch2/internal/catch_random_floating_point_helpers.hpp new file mode 100644 index 00000000..c59c0539 --- /dev/null +++ b/src/catch2/internal/catch_random_floating_point_helpers.hpp @@ -0,0 +1,94 @@ + +// 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_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED +#define CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED + +#include + +#include +#include +#include +#include +#include + +namespace Catch { + + namespace Detail { + /** + * Returns the largest magnitude of 1-ULP distance inside the [a, b] range. + * + * Assumes `a < b`. + */ + template + FloatType gamma(FloatType a, FloatType b) { + static_assert( std::is_floating_point::value, + "gamma returns the largest ULP magnitude within " + "floating point range [a, b]. This only makes sense " + "for floating point types" ); + assert( a <= b ); + + const auto gamma_up = Catch::nextafter( a, std::numeric_limits::infinity() ) - a; + const auto gamma_down = b - Catch::nextafter( b, -std::numeric_limits::infinity() ); + + return gamma_up < gamma_down ? gamma_down : gamma_up; + } + + template + struct DistanceTypePicker; + template <> + struct DistanceTypePicker { + using type = std::uint32_t; + }; + template <> + struct DistanceTypePicker { + using type = std::uint64_t; + }; + + template + using DistanceType = typename DistanceTypePicker::type; + +#if defined( __GNUC__ ) || defined( __clang__ ) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + /** + * Computes the number of equi-distant floats in [a, b] + * + * Since not every range can be split into equidistant floats + * exactly, we actually compute ceil(b/distance - a/distance), + * because in those cases we want to overcount. + * + * Uses modified Dekker's FastTwoSum algorithm to handle rounding. + */ + template + DistanceType + count_equidistant_floats( FloatType a, FloatType b, FloatType distance ) { + assert( a <= b ); + // We get distance as gamma for our uniform float distribution, + // so this will round perfectly. + const auto ag = a / distance; + const auto bg = b / distance; + + const auto s = bg - ag; + const auto err = ( std::fabs( a ) <= std::fabs( b ) ) + ? -ag - ( s - bg ) + : bg - ( s + ag ); + const auto ceil_s = static_cast>( std::ceil( s ) ); + + return ( ceil_s != s ) ? ceil_s : ceil_s + ( err > 0 ); + } +#if defined( __GNUC__ ) || defined( __clang__ ) +# pragma GCC diagnostic pop +#endif + + } + +} // end namespace Catch + +#endif // CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED diff --git a/src/catch2/internal/catch_random_integer_helpers.hpp b/src/catch2/internal/catch_random_integer_helpers.hpp new file mode 100644 index 00000000..1c450f05 --- /dev/null +++ b/src/catch2/internal/catch_random_integer_helpers.hpp @@ -0,0 +1,202 @@ + +// 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_RANDOM_INTEGER_HELPERS_HPP_INCLUDED +#define CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + namespace Detail { + + template + struct SizedUnsignedType; +#define SizedUnsignedTypeHelper( TYPE ) \ + template <> \ + struct SizedUnsignedType { \ + using type = TYPE; \ + } + + SizedUnsignedTypeHelper( std::uint8_t ); + SizedUnsignedTypeHelper( std::uint16_t ); + SizedUnsignedTypeHelper( std::uint32_t ); + SizedUnsignedTypeHelper( std::uint64_t ); +#undef SizedUnsignedTypeHelper + + template + using SizedUnsignedType_t = typename SizedUnsignedType::type; + + template + using DoubleWidthUnsignedType_t = SizedUnsignedType_t<2 * sizeof( T )>; + + template + struct ExtendedMultResult { + T upper; + T lower; + friend bool operator==( ExtendedMultResult const& lhs, + ExtendedMultResult const& rhs ) { + return lhs.upper == rhs.upper && lhs.lower == rhs.lower; + } + }; + + // Returns 128 bit result of multiplying lhs and rhs + constexpr ExtendedMultResult + extendedMult( std::uint64_t lhs, std::uint64_t rhs ) { + // We use the simple long multiplication approach for + // correctness, we can use platform specific builtins + // for performance later. + + // Split the lhs and rhs into two 32bit "digits", so that we can + // do 64 bit arithmetic to handle carry bits. + // 32b 32b 32b 32b + // lhs L1 L2 + // * rhs R1 R2 + // ------------------------ + // | R2 * L2 | + // | R2 * L1 | + // | R1 * L2 | + // | R1 * L1 | + // ------------------------- + // | a | b | c | d | + +#define CarryBits( x ) ( x >> 32 ) +#define Digits( x ) ( x & 0xFF'FF'FF'FF ) + + auto r2l2 = Digits( rhs ) * Digits( lhs ); + auto r2l1 = Digits( rhs ) * CarryBits( lhs ); + auto r1l2 = CarryBits( rhs ) * Digits( lhs ); + auto r1l1 = CarryBits( rhs ) * CarryBits( lhs ); + + // Sum to columns first + auto d = Digits( r2l2 ); + auto c = CarryBits( r2l2 ) + Digits( r2l1 ) + Digits( r1l2 ); + auto b = CarryBits( r2l1 ) + CarryBits( r1l2 ) + Digits( r1l1 ); + auto a = CarryBits( r1l1 ); + + // Propagate carries between columns + c += CarryBits( d ); + b += CarryBits( c ); + a += CarryBits( b ); + + // Remove the used carries + c = Digits( c ); + b = Digits( b ); + a = Digits( a ); + +#undef CarryBits +#undef Digits + + return { + a << 32 | b, // upper 64 bits + c << 32 | d // lower 64 bits + }; + } + + template + constexpr ExtendedMultResult extendedMult( UInt lhs, UInt rhs ) { + static_assert( std::is_unsigned::value, + "extendedMult can only handle unsigned integers" ); + static_assert( sizeof( UInt ) < sizeof( std::uint64_t ), + "Generic extendedMult can only handle types smaller " + "than uint64_t" ); + using WideType = DoubleWidthUnsignedType_t; + + auto result = WideType( lhs ) * WideType( rhs ); + return { + static_cast( result >> ( CHAR_BIT * sizeof( UInt ) ) ), + static_cast( result & UInt( -1 ) ) }; + } + + + template + std::enable_if_t= sizeof(TargetType), + TargetType> fillBitsFrom(Generator& gen) { + using gresult_type = typename Generator::result_type; + static_assert( std::is_unsigned::value, "Only unsigned integers are supported" ); + static_assert( Generator::min() == 0 && + Generator::max() == static_cast( -1 ), + "Generator must be able to output all numbers in its result type (effectively it must be a random bit generator)" ); + + // We want to return the top bits from a generator, as they are + // usually considered higher quality. + constexpr auto generated_bits = sizeof( gresult_type ) * CHAR_BIT; + constexpr auto return_bits = sizeof( TargetType ) * CHAR_BIT; + + return static_cast( gen() >> + ( generated_bits - return_bits) ); + } + + template + std::enable_if_t fillBitsFrom(Generator& gen) { + using gresult_type = typename Generator::result_type; + static_assert( std::is_unsigned::value, + "Only unsigned integers are supported" ); + static_assert( Generator::min() == 0 && + Generator::max() == static_cast( -1 ), + "Generator must be able to output all numbers in its result type (effectively it must be a random bit generator)" ); + + constexpr auto generated_bits = sizeof( gresult_type ) * CHAR_BIT; + constexpr auto return_bits = sizeof( TargetType ) * CHAR_BIT; + std::size_t filled_bits = 0; + TargetType ret = 0; + do { + ret <<= generated_bits; + ret |= gen(); + filled_bits += generated_bits; + } while ( filled_bits < return_bits ); + + return ret; + } + + /* + * Transposes numbers into unsigned type while keeping their ordering + * + * This means that signed types are changed so that the ordering is + * [INT_MIN, ..., -1, 0, ..., INT_MAX], rather than order we would + * get by simple casting ([0, ..., INT_MAX, INT_MIN, ..., -1]) + */ + template + std::enable_if_t::value, UnsignedType> + transposeToNaturalOrder( UnsignedType in ) { + static_assert( + sizeof( OriginalType ) == sizeof( UnsignedType ), + "reordering requires the same sized types on both sides" ); + static_assert( std::is_unsigned::value, + "Input type must be unsigned" ); + // Assuming 2s complement (standardized in current C++), the + // positive and negative numbers are already internally ordered, + // and their difference is in the top bit. Swapping it orders + // them the desired way. + constexpr auto highest_bit = + UnsignedType( 1 ) << ( sizeof( UnsignedType ) * CHAR_BIT - 1 ); + return static_cast( in ^ highest_bit ); + } + + + + template + std::enable_if_t::value, UnsignedType> + transposeToNaturalOrder(UnsignedType in) { + static_assert( + sizeof( OriginalType ) == sizeof( UnsignedType ), + "reordering requires the same sized types on both sides" ); + static_assert( std::is_unsigned::value, "Input type must be unsigned" ); + // No reordering is needed for unsigned -> unsigned + return in; + } + } // namespace Detail +} // namespace Catch + +#endif // CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED diff --git a/src/catch2/internal/catch_random_seed_generation.cpp b/src/catch2/internal/catch_random_seed_generation.cpp index 40c468cb..fdc3fa19 100644 --- a/src/catch2/internal/catch_random_seed_generation.cpp +++ b/src/catch2/internal/catch_random_seed_generation.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -21,10 +22,10 @@ namespace Catch { return static_cast( std::time( nullptr ) ); case GenerateFrom::Default: - case GenerateFrom::RandomDevice: - // In theory, a platform could have random_device that returns just - // 16 bits. That is still some randomness, so we don't care too much - return static_cast( std::random_device{}() ); + case GenerateFrom::RandomDevice: { + std::random_device rd; + return Detail::fillBitsFrom( rd ); + } default: CATCH_ERROR("Unknown generation method"); diff --git a/src/catch2/internal/catch_reporter_registry.cpp b/src/catch2/internal/catch_reporter_registry.cpp index 4c0c44f4..cea8c4dc 100644 --- a/src/catch2/internal/catch_reporter_registry.cpp +++ b/src/catch2/internal/catch_reporter_registry.cpp @@ -5,61 +5,87 @@ // https://www.boost.org/LICENSE_1_0.txt) // SPDX-License-Identifier: BSL-1.0 -#include -#include +#include +#include +#include +#include #include #include #include +#include #include +#include #include #include #include #include -#include -#include namespace Catch { + struct ReporterRegistry::ReporterRegistryImpl { + std::vector> listeners; + std::map + factories; + }; - ReporterRegistry::ReporterRegistry() { + ReporterRegistry::ReporterRegistry(): + m_impl( Detail::make_unique() ) { // Because it is impossible to move out of initializer list, // we have to add the elements manually - m_factories["Automake"] = Detail::make_unique>(); - m_factories["compact"] = Detail::make_unique>(); - m_factories["console"] = Detail::make_unique>(); - m_factories["JUnit"] = Detail::make_unique>(); - m_factories["SonarQube"] = Detail::make_unique>(); - m_factories["TAP"] = Detail::make_unique>(); - m_factories["TeamCity"] = Detail::make_unique>(); - m_factories["XML"] = Detail::make_unique>(); + m_impl->factories["Automake"] = + Detail::make_unique>(); + m_impl->factories["compact"] = + Detail::make_unique>(); + m_impl->factories["console"] = + Detail::make_unique>(); + m_impl->factories["JUnit"] = + Detail::make_unique>(); + m_impl->factories["SonarQube"] = + Detail::make_unique>(); + m_impl->factories["TAP"] = + Detail::make_unique>(); + m_impl->factories["TeamCity"] = + Detail::make_unique>(); + m_impl->factories["XML"] = + Detail::make_unique>(); + m_impl->factories["JSON"] = + Detail::make_unique>(); } ReporterRegistry::~ReporterRegistry() = default; - - IEventListenerPtr ReporterRegistry::create( std::string const& name, ReporterConfig&& config ) const { - auto it = m_factories.find( name ); - if( it == m_factories.end() ) - return nullptr; - return it->second->create( CATCH_MOVE(config) ); + IEventListenerPtr + ReporterRegistry::create( std::string const& name, + ReporterConfig&& config ) const { + auto it = m_impl->factories.find( name ); + if ( it == m_impl->factories.end() ) return nullptr; + return it->second->create( CATCH_MOVE( config ) ); } - void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr factory ) { + void ReporterRegistry::registerReporter( std::string const& name, + IReporterFactoryPtr factory ) { CATCH_ENFORCE( name.find( "::" ) == name.npos, - "'::' is not allowed in reporter name: '" + name + '\'' ); - auto ret = m_factories.emplace(name, CATCH_MOVE(factory)); - CATCH_ENFORCE( ret.second, "reporter using '" + name + "' as name was already registered" ); + "'::' is not allowed in reporter name: '" + name + + '\'' ); + auto ret = m_impl->factories.emplace( name, CATCH_MOVE( factory ) ); + CATCH_ENFORCE( ret.second, + "reporter using '" + name + + "' as name was already registered" ); } void ReporterRegistry::registerListener( Detail::unique_ptr factory ) { - m_listeners.push_back( CATCH_MOVE(factory) ); + m_impl->listeners.push_back( CATCH_MOVE( factory ) ); } - IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { - return m_factories; - } - IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { - return m_listeners; + std::map const& + ReporterRegistry::getFactories() const { + return m_impl->factories; } -} + std::vector> const& + ReporterRegistry::getListeners() const { + return m_impl->listeners; + } +} // namespace Catch diff --git a/src/catch2/internal/catch_reporter_registry.hpp b/src/catch2/internal/catch_reporter_registry.hpp index 5577b9ef..92a88927 100644 --- a/src/catch2/internal/catch_reporter_registry.hpp +++ b/src/catch2/internal/catch_reporter_registry.hpp @@ -8,31 +8,48 @@ #ifndef CATCH_REPORTER_REGISTRY_HPP_INCLUDED #define CATCH_REPORTER_REGISTRY_HPP_INCLUDED -#include -#include +#include +#include #include +#include +#include namespace Catch { - class ReporterRegistry : public IReporterRegistry { + class IEventListener; + using IEventListenerPtr = Detail::unique_ptr; + class IReporterFactory; + using IReporterFactoryPtr = Detail::unique_ptr; + struct ReporterConfig; + class EventListenerFactory; + + class ReporterRegistry { + struct ReporterRegistryImpl; + Detail::unique_ptr m_impl; + public: - ReporterRegistry(); - ~ReporterRegistry() override; // = default, out of line to allow fwd decl + ~ReporterRegistry(); // = default; - IEventListenerPtr create( std::string const& name, ReporterConfig&& config ) const override; + IEventListenerPtr create( std::string const& name, + ReporterConfig&& config ) const; - void registerReporter( std::string const& name, IReporterFactoryPtr factory ); - void registerListener( Detail::unique_ptr factory ); + void registerReporter( std::string const& name, + IReporterFactoryPtr factory ); - FactoryMap const& getFactories() const override; - Listeners const& getListeners() const override; + void + registerListener( Detail::unique_ptr factory ); - private: - FactoryMap m_factories; - Listeners m_listeners; + std::map const& + getFactories() const; + + std::vector> const& + getListeners() const; }; -} + +} // end namespace Catch #endif // CATCH_REPORTER_REGISTRY_HPP_INCLUDED diff --git a/src/catch2/internal/catch_reporter_spec_parser.cpp b/src/catch2/internal/catch_reporter_spec_parser.cpp index f6591d9a..8b88b170 100644 --- a/src/catch2/internal/catch_reporter_spec_parser.cpp +++ b/src/catch2/internal/catch_reporter_spec_parser.cpp @@ -21,9 +21,9 @@ namespace Catch { }; kvPair splitKVPair(StringRef kvString) { - auto splitPos = static_cast( std::distance( - kvString.begin(), - std::find( kvString.begin(), kvString.end(), '=' ) ) ); + auto splitPos = static_cast( + std::find( kvString.begin(), kvString.end(), '=' ) - + kvString.begin() ); return { kvString.substr( 0, splitPos ), kvString.substr( splitPos + 1, kvString.size() ) }; diff --git a/src/catch2/internal/catch_result_type.hpp b/src/catch2/internal/catch_result_type.hpp index faf0683d..e66afaff 100644 --- a/src/catch2/internal/catch_result_type.hpp +++ b/src/catch2/internal/catch_result_type.hpp @@ -16,6 +16,8 @@ namespace Catch { Ok = 0, Info = 1, Warning = 2, + // TODO: Should explicit skip be considered "not OK" (cf. isOk)? I.e., should it have the failure bit? + ExplicitSkip = 4, FailureBit = 0x10, diff --git a/src/catch2/internal/catch_run_context.cpp b/src/catch2/internal/catch_run_context.cpp index d2e8fb8c..e568100d 100644 --- a/src/catch2/internal/catch_run_context.cpp +++ b/src/catch2/internal/catch_run_context.cpp @@ -8,8 +8,9 @@ #include #include -#include #include +#include +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include @@ -26,149 +28,152 @@ namespace Catch { namespace Generators { - struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { - GeneratorBasePtr m_generator; + namespace { + struct GeneratorTracker final : TestCaseTracking::TrackerBase, + IGeneratorTracker { + GeneratorBasePtr m_generator; - GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( nameAndLocation, ctx, parent ) - {} - ~GeneratorTracker() override; + GeneratorTracker( + TestCaseTracking::NameAndLocation&& nameAndLocation, + TrackerContext& ctx, + ITracker* parent ): + TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ) {} + ~GeneratorTracker() override = default; - static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { - GeneratorTracker* tracker; + static GeneratorTracker* + acquire( TrackerContext& ctx, + TestCaseTracking::NameAndLocationRef const& + nameAndLocation ) { + GeneratorTracker* tracker; - ITracker& currentTracker = ctx.currentTracker(); - // Under specific circumstances, the generator we want - // to acquire is also the current tracker. If this is - // the case, we have to avoid looking through current - // tracker's children, and instead return the current - // tracker. - // A case where this check is important is e.g. - // for (int i = 0; i < 5; ++i) { - // int n = GENERATE(1, 2); - // } - // - // without it, the code above creates 5 nested generators. - if ( currentTracker.nameAndLocation() == nameAndLocation ) { - auto thisTracker = - currentTracker.parent()->findChild( nameAndLocation ); - assert( thisTracker ); - assert( thisTracker->isGeneratorTracker() ); - tracker = static_cast( thisTracker ); - } else if ( ITracker* childTracker = - currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isGeneratorTracker() ); - tracker = static_cast( childTracker ); - } else { - auto newTracker = - Catch::Detail::make_unique( - nameAndLocation, ctx, ¤tTracker ); - tracker = newTracker.get(); - currentTracker.addChild( CATCH_MOVE(newTracker) ); + ITracker& currentTracker = ctx.currentTracker(); + // Under specific circumstances, the generator we want + // to acquire is also the current tracker. If this is + // the case, we have to avoid looking through current + // tracker's children, and instead return the current + // tracker. + // A case where this check is important is e.g. + // for (int i = 0; i < 5; ++i) { + // int n = GENERATE(1, 2); + // } + // + // without it, the code above creates 5 nested generators. + if ( currentTracker.nameAndLocation() == nameAndLocation ) { + auto thisTracker = currentTracker.parent()->findChild( + nameAndLocation ); + assert( thisTracker ); + assert( thisTracker->isGeneratorTracker() ); + tracker = static_cast( thisTracker ); + } else if ( ITracker* childTracker = + currentTracker.findChild( + nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isGeneratorTracker() ); + tracker = + static_cast( childTracker ); + } else { + return nullptr; + } + + if ( !tracker->isComplete() ) { tracker->open(); } + + return tracker; } - if( !tracker->isComplete() ) { - tracker->open(); + // TrackerBase interface + bool isGeneratorTracker() const override { return true; } + auto hasGenerator() const -> bool override { + return !!m_generator; } - - return *tracker; - } - - // TrackerBase interface - bool isGeneratorTracker() const override { return true; } - auto hasGenerator() const -> bool override { - return !!m_generator; - } - void close() override { - TrackerBase::close(); - // If a generator has a child (it is followed by a section) - // and none of its children have started, then we must wait - // until later to start consuming its values. - // This catches cases where `GENERATE` is placed between two - // `SECTION`s. - // **The check for m_children.empty cannot be removed**. - // doing so would break `GENERATE` _not_ followed by `SECTION`s. - const bool should_wait_for_child = [&]() { - // No children -> nobody to wait for - if ( m_children.empty() ) { - return false; - } - // If at least one child started executing, don't wait - if ( std::find_if( - m_children.begin(), - m_children.end(), - []( TestCaseTracking::ITrackerPtr const& tracker ) { - return tracker->hasStarted(); - } ) != m_children.end() ) { - return false; - } - - // No children have started. We need to check if they _can_ - // start, and thus we should wait for them, or they cannot - // start (due to filters), and we shouldn't wait for them - ITracker* parent = m_parent; - // This is safe: there is always at least one section - // tracker in a test case tracking tree - while ( !parent->isSectionTracker() ) { - parent = parent->parent(); - } - assert( parent && - "Missing root (test case) level section" ); - - auto const& parentSection = - static_cast( *parent ); - auto const& filters = parentSection.getFilters(); - // No filters -> no restrictions on running sections - if ( filters.empty() ) { - return true; - } - - for ( auto const& child : m_children ) { - if ( child->isSectionTracker() && - std::find( - filters.begin(), - filters.end(), - static_cast( *child ) - .trimmedName() ) != filters.end() ) { - return true; + void close() override { + TrackerBase::close(); + // If a generator has a child (it is followed by a section) + // and none of its children have started, then we must wait + // until later to start consuming its values. + // This catches cases where `GENERATE` is placed between two + // `SECTION`s. + // **The check for m_children.empty cannot be removed**. + // doing so would break `GENERATE` _not_ followed by + // `SECTION`s. + const bool should_wait_for_child = [&]() { + // No children -> nobody to wait for + if ( m_children.empty() ) { return false; } + // If at least one child started executing, don't wait + if ( std::find_if( + m_children.begin(), + m_children.end(), + []( TestCaseTracking::ITrackerPtr const& + tracker ) { + return tracker->hasStarted(); + } ) != m_children.end() ) { + return false; } + + // No children have started. We need to check if they + // _can_ start, and thus we should wait for them, or + // they cannot start (due to filters), and we shouldn't + // wait for them + ITracker* parent = m_parent; + // This is safe: there is always at least one section + // tracker in a test case tracking tree + while ( !parent->isSectionTracker() ) { + parent = parent->parent(); + } + assert( parent && + "Missing root (test case) level section" ); + + auto const& parentSection = + static_cast( *parent ); + auto const& filters = parentSection.getFilters(); + // No filters -> no restrictions on running sections + if ( filters.empty() ) { return true; } + + for ( auto const& child : m_children ) { + if ( child->isSectionTracker() && + std::find( filters.begin(), + filters.end(), + static_cast( + *child ) + .trimmedName() ) != + filters.end() ) { + return true; + } + } + return false; + }(); + + // This check is a bit tricky, because m_generator->next() + // has a side-effect, where it consumes generator's current + // value, but we do not want to invoke the side-effect if + // this generator is still waiting for any child to start. + assert( m_generator && "Tracker without generator" ); + if ( should_wait_for_child || + ( m_runState == CompletedSuccessfully && + m_generator->countedNext() ) ) { + m_children.clear(); + m_runState = Executing; } - return false; - }(); - - // This check is a bit tricky, because m_generator->next() - // has a side-effect, where it consumes generator's current - // value, but we do not want to invoke the side-effect if - // this generator is still waiting for any child to start. - if ( should_wait_for_child || - ( m_runState == CompletedSuccessfully && - m_generator->countedNext() ) ) { - m_children.clear(); - m_runState = Executing; } - } - // IGeneratorTracker interface - auto getGenerator() const -> GeneratorBasePtr const& override { - return m_generator; - } - void setGenerator( GeneratorBasePtr&& generator ) override { - m_generator = CATCH_MOVE( generator ); - } - }; - GeneratorTracker::~GeneratorTracker() = default; + // IGeneratorTracker interface + auto getGenerator() const -> GeneratorBasePtr const& override { + return m_generator; + } + void setGenerator( GeneratorBasePtr&& generator ) override { + m_generator = CATCH_MOVE( generator ); + } + }; + } // namespace } RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter) : m_runInfo(_config->name()), - m_context(getCurrentMutableContext()), m_config(_config), m_reporter(CATCH_MOVE(reporter)), m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) { - m_context.setResultCapture(this); + getCurrentMutableContext().setResultCapture( this ); m_reporter->testRunStarting(m_runInfo); } @@ -179,13 +184,8 @@ namespace Catch { Totals RunContext::runTest(TestCaseHandle const& testCase) { const Totals prevTotals = m_totals; - std::string redirectedCout; - std::string redirectedCerr; - auto const& testInfo = testCase.getTestCaseInfo(); - m_reporter->testCaseStarting(testInfo); - m_activeTestCase = &testCase; @@ -227,9 +227,11 @@ namespace Catch { seedRng( *m_config ); uint64_t testRuns = 0; + std::string redirectedCout; + std::string redirectedCerr; do { m_trackerContext.startCycle(); - m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); + m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo)); m_reporter->testCasePartialStarting(testInfo, testRuns); @@ -240,7 +242,7 @@ namespace Catch { redirectedCerr += oneRunCerr; const auto singleRunTotals = m_totals.delta(beforeRunTotals); - auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, oneRunCout, oneRunCerr, aborting()); + auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting()); m_reporter->testCasePartialEnded(statsForOneRun, testRuns); ++testRuns; @@ -255,8 +257,8 @@ namespace Catch { m_totals.testCases += deltaTotals.testCases; m_reporter->testCaseEnded(TestCaseStats(testInfo, deltaTotals, - redirectedCout, - redirectedCerr, + CATCH_MOVE(redirectedCout), + CATCH_MOVE(redirectedCerr), aborting())); m_activeTestCase = nullptr; @@ -266,10 +268,13 @@ namespace Catch { } - void RunContext::assertionEnded(AssertionResult const & result) { + void RunContext::assertionEnded(AssertionResult&& result) { if (result.getResultType() == ResultWas::Ok) { m_totals.assertions.passed++; m_lastAssertionPassed = true; + } else if (result.getResultType() == ResultWas::ExplicitSkip) { + m_totals.assertions.skipped++; + m_lastAssertionPassed = true; } else if (!result.succeeded()) { m_lastAssertionPassed = false; if (result.isOk()) { @@ -285,24 +290,37 @@ namespace Catch { m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)); - if (result.getResultType() != ResultWas::Warning) + if ( result.getResultType() != ResultWas::Warning ) { m_messageScopes.clear(); + } - // Reset working state - resetAssertionInfo(); - m_lastResult = result; + // Reset working state. assertion info will be reset after + // populateReaction is run if it is needed + m_lastResult = CATCH_MOVE( result ); } void RunContext::resetAssertionInfo() { m_lastAssertionInfo.macroName = StringRef(); m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; + m_lastAssertionInfo.resultDisposition = ResultDisposition::Normal; } - bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { - ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); + void RunContext::notifyAssertionStarted( AssertionInfo const& info ) { + m_reporter->assertionStarting( info ); + } + + bool RunContext::sectionStarted( StringRef sectionName, + SourceLineInfo const& sectionLineInfo, + Counts& assertions ) { + ITracker& sectionTracker = + SectionTracker::acquire( m_trackerContext, + TestCaseTracking::NameAndLocationRef( + sectionName, sectionLineInfo ) ); + if (!sectionTracker.isOpen()) return false; m_activeSections.push_back(§ionTracker); + SectionInfo sectionInfo( sectionLineInfo, static_cast(sectionName) ); m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; m_reporter->sectionStarting(sectionInfo); @@ -311,14 +329,39 @@ namespace Catch { return true; } - auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + IGeneratorTracker* + RunContext::acquireGeneratorTracker( StringRef generatorName, + SourceLineInfo const& lineInfo ) { using namespace Generators; - GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext, - TestCaseTracking::NameAndLocation( static_cast(generatorName), lineInfo ) ); + GeneratorTracker* tracker = GeneratorTracker::acquire( + m_trackerContext, + TestCaseTracking::NameAndLocationRef( + generatorName, lineInfo ) ); m_lastAssertionInfo.lineInfo = lineInfo; return tracker; } + IGeneratorTracker* RunContext::createGeneratorTracker( + StringRef generatorName, + SourceLineInfo lineInfo, + Generators::GeneratorBasePtr&& generator ) { + + auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast( generatorName ), lineInfo ); + auto& currentTracker = m_trackerContext.currentTracker(); + assert( + currentTracker.nameAndLocation() != nameAndLoc && + "Trying to create tracker for a genreator that already has one" ); + + auto newTracker = Catch::Detail::make_unique( + CATCH_MOVE(nameAndLoc), m_trackerContext, ¤tTracker ); + auto ret = newTracker.get(); + currentTracker.addChild( CATCH_MOVE( newTracker ) ); + + ret->setGenerator( CATCH_MOVE( generator ) ); + ret->open(); + return ret; + } + bool RunContext::testForMissingAssertions(Counts& assertions) { if (assertions.total() != 0) return false; @@ -331,7 +374,7 @@ namespace Catch { return true; } - void RunContext::sectionEnded(SectionEndInfo const & endInfo) { + void RunContext::sectionEnded(SectionEndInfo&& endInfo) { Counts assertions = m_totals.assertions - endInfo.prevAssertions; bool missingAssertions = testForMissingAssertions(assertions); @@ -340,19 +383,20 @@ namespace Catch { m_activeSections.pop_back(); } - m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); + m_reporter->sectionEnded(SectionStats(CATCH_MOVE(endInfo.sectionInfo), assertions, endInfo.durationInSeconds, missingAssertions)); m_messages.clear(); m_messageScopes.clear(); } - void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { - if (m_unfinishedSections.empty()) + void RunContext::sectionEndedEarly(SectionEndInfo&& endInfo) { + if ( m_unfinishedSections.empty() ) { m_activeSections.back()->fail(); - else + } else { m_activeSections.back()->close(); + } m_activeSections.pop_back(); - m_unfinishedSections.push_back(endInfo); + m_unfinishedSections.push_back(CATCH_MOVE(endInfo)); } void RunContext::benchmarkPreparing( StringRef name ) { @@ -376,8 +420,8 @@ namespace Catch { m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); } - void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) { - m_messageScopes.emplace_back( builder ); + void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) { + m_messageScopes.emplace_back( CATCH_MOVE(builder) ); } std::string RunContext::getCurrentTestName() const { @@ -402,9 +446,10 @@ namespace Catch { // Instead, fake a result data. AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); tempResult.message = static_cast(message); - AssertionResult result(m_lastAssertionInfo, tempResult); + AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult)); - assertionEnded(result); + assertionEnded(CATCH_MOVE(result) ); + resetAssertionInfo(); handleUnfinishedSections(); @@ -414,7 +459,7 @@ namespace Catch { Counts assertions; assertions.failed = 1; - SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); + SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, false); m_reporter->sectionEnded(testCaseSectionStats); auto const& testInfo = m_activeTestCase->getTestCaseInfo(); @@ -475,6 +520,8 @@ namespace Catch { duration = timer.getElapsedSeconds(); } CATCH_CATCH_ANON (TestFailureException&) { // This just means the test was aborted due to failure + } CATCH_CATCH_ANON (TestSkipException&) { + // This just means the test was explicitly skipped } CATCH_CATCH_ALL { // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions // are reported without translation at the point of origin. @@ -491,7 +538,7 @@ namespace Catch { m_messages.clear(); m_messageScopes.clear(); - SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); + SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions); m_reporter->sectionEnded(testCaseSectionStats); } @@ -515,7 +562,7 @@ namespace Catch { itEnd = m_unfinishedSections.rend(); it != itEnd; ++it) - sectionEnded(*it); + sectionEnded(CATCH_MOVE(*it)); m_unfinishedSections.clear(); } @@ -524,8 +571,6 @@ namespace Catch { ITransientExpression const& expr, AssertionReaction& reaction ) { - m_reporter->assertionStarting( info ); - bool negated = isFalseTest( info.resultDisposition ); bool result = expr.getResult() != negated; @@ -541,6 +586,7 @@ namespace Catch { reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); populateReaction( reaction ); } + resetAssertionInfo(); } void RunContext::reportExpr( AssertionInfo const &info, @@ -551,10 +597,10 @@ namespace Catch { m_lastAssertionInfo = info; AssertionResultData data( resultType, LazyExpression( negated ) ); - AssertionResult assertionResult{ info, data }; + AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; - assertionEnded( assertionResult ); + assertionEnded( CATCH_MOVE(assertionResult) ); } void RunContext::handleMessage( @@ -563,16 +609,23 @@ namespace Catch { StringRef message, AssertionReaction& reaction ) { - m_reporter->assertionStarting( info ); - m_lastAssertionInfo = info; AssertionResultData data( resultType, LazyExpression( false ) ); data.message = static_cast(message); - AssertionResult assertionResult{ m_lastAssertionInfo, data }; - assertionEnded( assertionResult ); - if( !assertionResult.isOk() ) + AssertionResult assertionResult{ m_lastAssertionInfo, + CATCH_MOVE( data ) }; + + const auto isOk = assertionResult.isOk(); + assertionEnded( CATCH_MOVE(assertionResult) ); + if ( !isOk ) { populateReaction( reaction ); + } else if ( resultType == ResultWas::ExplicitSkip ) { + // TODO: Need to handle this explicitly, as ExplicitSkip is + // considered "OK" + reaction.shouldSkip = true; + } + resetAssertionInfo(); } void RunContext::handleUnexpectedExceptionNotThrown( AssertionInfo const& info, @@ -583,16 +636,17 @@ namespace Catch { void RunContext::handleUnexpectedInflightException( AssertionInfo const& info, - std::string const& message, + std::string&& message, AssertionReaction& reaction ) { m_lastAssertionInfo = info; AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); - data.message = message; - AssertionResult assertionResult{ info, data }; - assertionEnded( assertionResult ); + data.message = CATCH_MOVE(message); + AssertionResult assertionResult{ info, CATCH_MOVE(data) }; + assertionEnded( CATCH_MOVE(assertionResult) ); populateReaction( reaction ); + resetAssertionInfo(); } void RunContext::populateReaction( AssertionReaction& reaction ) { @@ -603,12 +657,14 @@ namespace Catch { void RunContext::handleIncomplete( AssertionInfo const& info ) { + using namespace std::string_literals; m_lastAssertionInfo = info; AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); - data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; - AssertionResult assertionResult{ info, data }; - assertionEnded( assertionResult ); + data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s; + AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; + assertionEnded( CATCH_MOVE(assertionResult) ); + resetAssertionInfo(); } void RunContext::handleNonExpr( AssertionInfo const &info, @@ -618,11 +674,12 @@ namespace Catch { m_lastAssertionInfo = info; AssertionResultData data( resultType, LazyExpression( false ) ); - AssertionResult assertionResult{ info, data }; - assertionEnded( assertionResult ); + AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; - if( !assertionResult.isOk() ) - populateReaction( reaction ); + const auto isOk = assertionResult.isOk(); + assertionEnded( CATCH_MOVE(assertionResult) ); + if ( !isOk ) { populateReaction( reaction ); } + resetAssertionInfo(); } diff --git a/src/catch2/internal/catch_run_context.hpp b/src/catch2/internal/catch_run_context.hpp index ab20db57..c749304d 100644 --- a/src/catch2/internal/catch_run_context.hpp +++ b/src/catch2/internal/catch_run_context.hpp @@ -8,8 +8,9 @@ #ifndef CATCH_RUN_CONTEXT_HPP_INCLUDED #define CATCH_RUN_CONTEXT_HPP_INCLUDED -#include +#include #include +#include #include #include #include @@ -24,13 +25,14 @@ namespace Catch { - class IMutableContext; class IGeneratorTracker; class IConfig; + class IEventListener; + using IEventListenerPtr = Detail::unique_ptr; /////////////////////////////////////////////////////////////////////////// - class RunContext : public IResultCapture { + class RunContext final : public IResultCapture { public: RunContext( RunContext const& ) = delete; @@ -59,7 +61,7 @@ namespace Catch { AssertionReaction& reaction ) override; void handleUnexpectedInflightException ( AssertionInfo const& info, - std::string const& message, + std::string&& message, AssertionReaction& reaction ) override; void handleIncomplete ( AssertionInfo const& info ) override; @@ -68,12 +70,22 @@ namespace Catch { ResultWas::OfType resultType, AssertionReaction &reaction ) override; - bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; + void notifyAssertionStarted( AssertionInfo const& info ) override; + bool sectionStarted( StringRef sectionName, + SourceLineInfo const& sectionLineInfo, + Counts& assertions ) override; - void sectionEnded( SectionEndInfo const& endInfo ) override; - void sectionEndedEarly( SectionEndInfo const& endInfo ) override; + void sectionEnded( SectionEndInfo&& endInfo ) override; + void sectionEndedEarly( SectionEndInfo&& endInfo ) override; + + IGeneratorTracker* + acquireGeneratorTracker( StringRef generatorName, + SourceLineInfo const& lineInfo ) override; + IGeneratorTracker* createGeneratorTracker( + StringRef generatorName, + SourceLineInfo lineInfo, + Generators::GeneratorBasePtr&& generator ) override; - auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; void benchmarkPreparing( StringRef name ) override; void benchmarkStarting( BenchmarkInfo const& info ) override; @@ -83,7 +95,7 @@ namespace Catch { void pushScopedMessage( MessageInfo const& message ) override; void popScopedMessage( MessageInfo const& message ) override; - void emplaceUnscopedMessage( MessageBuilder const& builder ) override; + void emplaceUnscopedMessage( MessageBuilder&& builder ) override; std::string getCurrentTestName() const override; @@ -109,7 +121,7 @@ namespace Catch { void resetAssertionInfo(); bool testForMissingAssertions( Counts& assertions ); - void assertionEnded( AssertionResult const& result ); + void assertionEnded( AssertionResult&& result ); void reportExpr ( AssertionInfo const &info, ResultWas::OfType resultType, @@ -123,7 +135,6 @@ namespace Catch { void handleUnfinishedSections(); TestRunInfo m_runInfo; - IMutableContext& m_context; TestCaseHandle const* m_activeTestCase = nullptr; ITracker* m_testCaseTracker = nullptr; Optional m_lastResult; diff --git a/src/catch2/internal/catch_section.cpp b/src/catch2/internal/catch_section.cpp index ca2e5d8c..061732b1 100644 --- a/src/catch2/internal/catch_section.cpp +++ b/src/catch2/internal/catch_section.cpp @@ -15,7 +15,7 @@ namespace Catch { Section::Section( SectionInfo&& info ): m_info( CATCH_MOVE( info ) ), m_sectionIncluded( - getResultCapture().sectionStarted( m_info, m_assertions ) ) { + getResultCapture().sectionStarted( m_info.name, m_info.lineInfo, m_assertions ) ) { // Non-"included" sections will not use the timing information // anyway, so don't bother with the potential syscall. if (m_sectionIncluded) { @@ -23,13 +23,31 @@ namespace Catch { } } + Section::Section( SourceLineInfo const& _lineInfo, + StringRef _name, + const char* const ): + m_info( { "invalid", static_cast( -1 ) }, std::string{} ), + m_sectionIncluded( + getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) { + // We delay initialization the SectionInfo member until we know + // this section needs it, so we avoid allocating std::string for name. + // We also delay timer start to avoid the potential syscall unless we + // will actually use the result. + if ( m_sectionIncluded ) { + m_info.name = static_cast( _name ); + m_info.lineInfo = _lineInfo; + m_timer.start(); + } + } + Section::~Section() { if( m_sectionIncluded ) { - SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; - if( uncaught_exceptions() ) - getResultCapture().sectionEndedEarly( endInfo ); - else - getResultCapture().sectionEnded( endInfo ); + SectionEndInfo endInfo{ CATCH_MOVE(m_info), m_assertions, m_timer.getElapsedSeconds() }; + if ( uncaught_exceptions() ) { + getResultCapture().sectionEndedEarly( CATCH_MOVE(endInfo) ); + } else { + getResultCapture().sectionEnded( CATCH_MOVE( endInfo ) ); + } } } diff --git a/src/catch2/internal/catch_section.hpp b/src/catch2/internal/catch_section.hpp index abd12192..8c894eeb 100644 --- a/src/catch2/internal/catch_section.hpp +++ b/src/catch2/internal/catch_section.hpp @@ -9,6 +9,7 @@ #define CATCH_SECTION_HPP_INCLUDED #include +#include #include #include #include @@ -20,6 +21,9 @@ namespace Catch { class Section : Detail::NonCopyable { public: Section( SectionInfo&& info ); + Section( SourceLineInfo const& _lineInfo, + StringRef _name, + const char* const = nullptr ); ~Section(); // This indicates whether the section should be executed or not @@ -35,16 +39,62 @@ namespace Catch { } // end namespace Catch -#define INTERNAL_CATCH_SECTION( ... ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT) +# define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \ + catch_internal_Section ) = \ + Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \ + catch_internal_Section ) = \ + Catch::SectionInfo( \ + CATCH_INTERNAL_LINEINFO, \ + ( Catch::ReusableStringStream() << __VA_ARGS__ ) \ + .str() ) ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +#else + +// These section definitions imply that at most one section at one level +// will be intered (because only one section's __LINE__ can be equal to +// the dummy `catchInternalSectionHint` variable from `TEST_CASE`). + +namespace Catch { + namespace Detail { + // Intentionally without linkage, as it should only be used as a dummy + // symbol for static analysis. + int GetNewSectionHint(); + } // namespace Detail +} // namespace Catch + + +# define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \ + catchInternalSectionHint, \ + catchInternalSectionHint = Catch::Detail::GetNewSectionHint(); \ + catchInternalPreviousSectionHint == __LINE__ ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \ + catchInternalSectionHint, \ + catchInternalSectionHint = Catch::Detail::GetNewSectionHint(); \ + catchInternalPreviousSectionHint == __LINE__ ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +#endif -#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #endif // CATCH_SECTION_HPP_INCLUDED diff --git a/src/catch2/internal/catch_stream_end_stop.hpp b/src/catch2/internal/catch_stream_end_stop.hpp index 61379f20..66d678cf 100644 --- a/src/catch2/internal/catch_stream_end_stop.hpp +++ b/src/catch2/internal/catch_stream_end_stop.hpp @@ -17,10 +17,10 @@ namespace Catch { // as well as // << stuff +StreamEndStop struct StreamEndStop { - StringRef operator+() const { return StringRef(); } + constexpr StringRef operator+() const { return StringRef(); } template - friend T const& operator+( T const& value, StreamEndStop ) { + constexpr friend T const& operator+( T const& value, StreamEndStop ) { return value; } }; diff --git a/src/catch2/internal/catch_string_manip.cpp b/src/catch2/internal/catch_string_manip.cpp index cb96dd4f..0c889ca1 100644 --- a/src/catch2/internal/catch_string_manip.cpp +++ b/src/catch2/internal/catch_string_manip.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -32,9 +31,9 @@ namespace Catch { return s.find( infix ) != std::string::npos; } void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), []( char c ) { - return toLower( c ); - } ); + for ( char& c : s ) { + c = toLower( c ); + } } std::string toLower( std::string const& s ) { std::string lc = s; diff --git a/src/catch2/internal/catch_string_manip.hpp b/src/catch2/internal/catch_string_manip.hpp index 8630b56a..dc0c552c 100644 --- a/src/catch2/internal/catch_string_manip.hpp +++ b/src/catch2/internal/catch_string_manip.hpp @@ -10,6 +10,7 @@ #include +#include #include #include #include diff --git a/src/catch2/internal/catch_stringref.cpp b/src/catch2/internal/catch_stringref.cpp index 668ff297..232498eb 100644 --- a/src/catch2/internal/catch_stringref.cpp +++ b/src/catch2/internal/catch_stringref.cpp @@ -17,10 +17,6 @@ namespace Catch { : StringRef( rawChars, std::strlen(rawChars) ) {} - auto StringRef::operator == ( StringRef other ) const noexcept -> bool { - return m_size == other.m_size - && (std::memcmp( m_start, other.m_start, m_size ) == 0); - } bool StringRef::operator<(StringRef rhs) const noexcept { if (m_size < rhs.m_size) { diff --git a/src/catch2/internal/catch_stringref.hpp b/src/catch2/internal/catch_stringref.hpp index bd8971bc..99bb9a98 100644 --- a/src/catch2/internal/catch_stringref.hpp +++ b/src/catch2/internal/catch_stringref.hpp @@ -13,6 +13,8 @@ #include #include +#include + namespace Catch { /// A non-owning string class (similar to the forthcoming std::string_view) @@ -49,7 +51,10 @@ namespace Catch { } public: // operators - auto operator == ( StringRef other ) const noexcept -> bool; + auto operator == ( StringRef other ) const noexcept -> bool { + return m_size == other.m_size + && (std::memcmp( m_start, other.m_start, m_size ) == 0); + } auto operator != (StringRef other) const noexcept -> bool { return !(*this == other); } diff --git a/src/catch2/internal/catch_tag_alias_registry.cpp b/src/catch2/internal/catch_tag_alias_registry.cpp index b7c6b9ec..4fd0d557 100644 --- a/src/catch2/internal/catch_tag_alias_registry.cpp +++ b/src/catch2/internal/catch_tag_alias_registry.cpp @@ -13,7 +13,7 @@ namespace Catch { - TagAliasRegistry::~TagAliasRegistry() {} + TagAliasRegistry::~TagAliasRegistry() = default; TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { auto it = m_registry.find( alias ); diff --git a/src/catch2/internal/catch_template_test_registry.hpp b/src/catch2/internal/catch_template_test_registry.hpp index 88599f32..0ea354bc 100644 --- a/src/catch2/internal/catch_template_test_registry.hpp +++ b/src/catch2/internal/catch_template_test_registry.hpp @@ -181,7 +181,7 @@ void reg_tests() { \ size_t index = 0; \ using expander = size_t[]; \ - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ } \ };\ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ @@ -316,7 +316,7 @@ void reg_tests(){\ size_t index = 0;\ using expander = size_t[];\ - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ }\ };\ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ diff --git a/src/catch2/internal/catch_test_case_registry_impl.cpp b/src/catch2/internal/catch_test_case_registry_impl.cpp index 4b3d2e47..f1702979 100644 --- a/src/catch2/internal/catch_test_case_registry_impl.cpp +++ b/src/catch2/internal/catch_test_case_registry_impl.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,38 @@ namespace Catch { + namespace { + static void enforceNoDuplicateTestCases( + std::vector const& tests ) { + auto testInfoCmp = []( TestCaseInfo const* lhs, + TestCaseInfo const* rhs ) { + return *lhs < *rhs; + }; + std::set seenTests( + testInfoCmp ); + for ( auto const& test : tests ) { + const auto infoPtr = &test.getTestCaseInfo(); + const auto prev = seenTests.insert( infoPtr ); + CATCH_ENFORCE( prev.second, + "error: test case \"" + << infoPtr->name << "\", with tags \"" + << infoPtr->tagsAsString() + << "\" already defined.\n" + << "\tFirst seen at " + << ( *prev.first )->lineInfo << "\n" + << "\tRedefined at " << infoPtr->lineInfo ); + } + } + + static bool matchTest( TestCaseHandle const& testCase, + TestSpec const& testSpec, + IConfig const& config ) { + return testSpec.matches( testCase.getTestCaseInfo() ) && + isThrowSafe( testCase, config ); + } + + } // end unnamed namespace + std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { switch (config.runOrder()) { case TestRunOrder::Declared: @@ -79,29 +112,6 @@ namespace Catch { return !testCase.getTestCaseInfo().throws() || config.allowThrows(); } - bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ) { - return testSpec.matches( testCase.getTestCaseInfo() ) && isThrowSafe( testCase, config ); - } - - void - enforceNoDuplicateTestCases( std::vector const& tests ) { - auto testInfoCmp = []( TestCaseInfo const* lhs, - TestCaseInfo const* rhs ) { - return *lhs < *rhs; - }; - std::set seenTests(testInfoCmp); - for ( auto const& test : tests ) { - const auto infoPtr = &test.getTestCaseInfo(); - const auto prev = seenTests.insert( infoPtr ); - CATCH_ENFORCE( - prev.second, - "error: test case \"" << infoPtr->name << "\", with tags \"" - << infoPtr->tagsAsString() << "\" already defined.\n" - << "\tFirst seen at " << ( *prev.first )->lineInfo << "\n" - << "\tRedefined at " << infoPtr->lineInfo ); - } - } - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { std::vector filtered; filtered.reserve( testCases.size() ); @@ -142,11 +152,4 @@ namespace Catch { return m_sortedFunctions; } - - - /////////////////////////////////////////////////////////////////////////// - void TestInvokerAsFunction::invoke() const { - m_testAsFunction(); - } - } // end namespace Catch diff --git a/src/catch2/internal/catch_test_case_registry_impl.hpp b/src/catch2/internal/catch_test_case_registry_impl.hpp index 228dbb79..a4a27ed1 100644 --- a/src/catch2/internal/catch_test_case_registry_impl.hpp +++ b/src/catch2/internal/catch_test_case_registry_impl.hpp @@ -8,23 +8,22 @@ #ifndef CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED #define CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED -#include +#include #include +#include #include namespace Catch { - class TestCaseHandle; class IConfig; + class ITestInvoker; + class TestCaseHandle; class TestSpec; std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ); - bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ); - - void enforceNoDuplicateTestCases( std::vector const& functions ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); @@ -53,18 +52,6 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////// - class TestInvokerAsFunction final : public ITestInvoker { - using TestType = void(*)(); - TestType m_testAsFunction; - public: - TestInvokerAsFunction(TestType testAsFunction) noexcept: - m_testAsFunction(testAsFunction) {} - - void invoke() const override; - }; - - /////////////////////////////////////////////////////////////////////////// - } // end namespace Catch diff --git a/src/catch2/internal/catch_test_case_tracker.cpp b/src/catch2/internal/catch_test_case_tracker.cpp index e230fac1..1470b91c 100644 --- a/src/catch2/internal/catch_test_case_tracker.cpp +++ b/src/catch2/internal/catch_test_case_tracker.cpp @@ -22,8 +22,8 @@ namespace Catch { namespace TestCaseTracking { - NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) - : name( _name ), + NameAndLocation::NameAndLocation( std::string&& _name, SourceLineInfo const& _location ) + : name( CATCH_MOVE(_name) ), location( _location ) {} @@ -38,14 +38,17 @@ namespace TestCaseTracking { m_children.push_back( CATCH_MOVE(child) ); } - ITracker* ITracker::findChild( NameAndLocation const& nameAndLocation ) { + ITracker* ITracker::findChild( NameAndLocationRef const& nameAndLocation ) { auto it = std::find_if( m_children.begin(), m_children.end(), [&nameAndLocation]( ITrackerPtr const& tracker ) { - return tracker->nameAndLocation().location == - nameAndLocation.location && - tracker->nameAndLocation().name == nameAndLocation.name; + auto const& tnameAndLoc = tracker->nameAndLocation(); + if ( tnameAndLoc.location.line != + nameAndLocation.location.line ) { + return false; + } + return tnameAndLoc == nameAndLocation; } ); return ( it != m_children.end() ) ? it->get() : nullptr; } @@ -53,10 +56,6 @@ namespace TestCaseTracking { bool ITracker::isSectionTracker() const { return false; } bool ITracker::isGeneratorTracker() const { return false; } - bool ITracker::isSuccessfullyCompleted() const { - return m_runState == CompletedSuccessfully; - } - bool ITracker::isOpen() const { return m_runState != NotStarted && !isComplete(); } @@ -83,16 +82,6 @@ namespace TestCaseTracking { return *m_rootTracker; } - void TrackerContext::endRun() { - m_rootTracker.reset(); - m_currentTracker = nullptr; - m_runState = NotStarted; - } - - void TrackerContext::startCycle() { - m_currentTracker = m_rootTracker.get(); - m_runState = Executing; - } void TrackerContext::completeCycle() { m_runState = CompletedCycle; } @@ -100,16 +89,13 @@ namespace TestCaseTracking { bool TrackerContext::completedCycle() const { return m_runState == CompletedCycle; } - ITracker& TrackerContext::currentTracker() { - return *m_currentTracker; - } void TrackerContext::setCurrentTracker( ITracker* tracker ) { m_currentTracker = tracker; } - TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ): - ITracker(nameAndLocation, parent), + TrackerBase::TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ): + ITracker(CATCH_MOVE(nameAndLocation), parent), m_ctx( ctx ) {} @@ -169,13 +155,14 @@ namespace TestCaseTracking { m_ctx.setCurrentTracker( this ); } - SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( nameAndLocation, ctx, parent ), - m_trimmed_name(trim(nameAndLocation.name)) + SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ), + m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name))) { if( parent ) { - while( !parent->isSectionTracker() ) + while ( !parent->isSectionTracker() ) { parent = parent->parent(); + } SectionTracker& parentSection = static_cast( *parent ); addNextFilters( parentSection.m_filters ); @@ -195,24 +182,30 @@ namespace TestCaseTracking { bool SectionTracker::isSectionTracker() const { return true; } - SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { - SectionTracker* section; + SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ) { + SectionTracker* tracker; ITracker& currentTracker = ctx.currentTracker(); if ( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isSectionTracker() ); - section = static_cast( childTracker ); + tracker = static_cast( childTracker ); } else { - auto newSection = Catch::Detail::make_unique( - nameAndLocation, ctx, ¤tTracker ); - section = newSection.get(); - currentTracker.addChild( CATCH_MOVE( newSection ) ); + auto newTracker = Catch::Detail::make_unique( + NameAndLocation{ static_cast(nameAndLocation.name), + nameAndLocation.location }, + ctx, + ¤tTracker ); + tracker = newTracker.get(); + currentTracker.addChild( CATCH_MOVE( newTracker ) ); } - if( !ctx.completedCycle() ) - section->tryOpen(); - return *section; + + if ( !ctx.completedCycle() ) { + tracker->tryOpen(); + } + + return *tracker; } void SectionTracker::tryOpen() { @@ -233,10 +226,6 @@ namespace TestCaseTracking { m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); } - std::vector const& SectionTracker::getFilters() const { - return m_filters; - } - StringRef SectionTracker::trimmedName() const { return m_trimmed_name; } diff --git a/src/catch2/internal/catch_test_case_tracker.hpp b/src/catch2/internal/catch_test_case_tracker.hpp index 005b1d8e..50278c91 100644 --- a/src/catch2/internal/catch_test_case_tracker.hpp +++ b/src/catch2/internal/catch_test_case_tracker.hpp @@ -22,10 +22,49 @@ namespace TestCaseTracking { std::string name; SourceLineInfo location; - NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); + NameAndLocation( std::string&& _name, SourceLineInfo const& _location ); friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) { - return lhs.name == rhs.name - && lhs.location == rhs.location; + // This is a very cheap check that should have a very high hit rate. + // If we get to SourceLineInfo::operator==, we will redo it, but the + // cost of repeating is trivial at that point (we will be paying + // multiple strcmp/memcmps at that point). + if ( lhs.location.line != rhs.location.line ) { return false; } + return lhs.name == rhs.name && lhs.location == rhs.location; + } + friend bool operator!=(NameAndLocation const& lhs, + NameAndLocation const& rhs) { + return !( lhs == rhs ); + } + }; + + /** + * This is a variant of `NameAndLocation` that does not own the name string + * + * This avoids extra allocations when trying to locate a tracker by its + * name and location, as long as we make sure that trackers only keep + * around the owning variant. + */ + struct NameAndLocationRef { + StringRef name; + SourceLineInfo location; + + constexpr NameAndLocationRef( StringRef name_, + SourceLineInfo location_ ): + name( name_ ), location( location_ ) {} + + friend bool operator==( NameAndLocation const& lhs, + NameAndLocationRef const& rhs ) { + // This is a very cheap check that should have a very high hit rate. + // If we get to SourceLineInfo::operator==, we will redo it, but the + // cost of repeating is trivial at that point (we will be paying + // multiple strcmp/memcmps at that point). + if ( lhs.location.line != rhs.location.line ) { return false; } + return StringRef( lhs.name ) == rhs.name && + lhs.location == rhs.location; + } + friend bool operator==( NameAndLocationRef const& lhs, + NameAndLocation const& rhs ) { + return rhs == lhs; } }; @@ -53,8 +92,8 @@ namespace TestCaseTracking { CycleState m_runState = NotStarted; public: - ITracker( NameAndLocation const& nameAndLoc, ITracker* parent ): - m_nameAndLocation( nameAndLoc ), + ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ): + m_nameAndLocation( CATCH_MOVE(nameAndLoc) ), m_parent( parent ) {} @@ -74,8 +113,10 @@ namespace TestCaseTracking { //! Returns true if tracker run to completion (successfully or not) virtual bool isComplete() const = 0; - //! Returns true if tracker run to completion succesfully - bool isSuccessfullyCompleted() const; + //! Returns true if tracker run to completion successfully + bool isSuccessfullyCompleted() const { + return m_runState == CompletedSuccessfully; + } //! Returns true if tracker has started but hasn't been completed bool isOpen() const; //! Returns true iff tracker has started @@ -93,7 +134,7 @@ namespace TestCaseTracking { * * Returns nullptr if not found. */ - ITracker* findChild( NameAndLocation const& nameAndLocation ); + ITracker* findChild( NameAndLocationRef const& nameAndLocation ); //! Have any children been added? bool hasChildren() const { return !m_children.empty(); @@ -134,13 +175,15 @@ namespace TestCaseTracking { public: ITracker& startRun(); - void endRun(); - void startCycle(); + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } void completeCycle(); bool completedCycle() const; - ITracker& currentTracker(); + ITracker& currentTracker() { return *m_currentTracker; } void setCurrentTracker( ITracker* tracker ); }; @@ -150,7 +193,7 @@ namespace TestCaseTracking { TrackerContext& m_ctx; public: - TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ); bool isComplete() const override; @@ -166,22 +209,26 @@ namespace TestCaseTracking { class SectionTracker : public TrackerBase { std::vector m_filters; - std::string m_trimmed_name; + // Note that lifetime-wise we piggy back off the name stored in the `ITracker` parent`. + // Currently it allocates owns the name, so this is safe. If it is later refactored + // to not own the name, the name still has to outlive the `ITracker` parent, so + // this should still be safe. + StringRef m_trimmed_name; public: - SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ); bool isSectionTracker() const override; bool isComplete() const override; - static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ); void tryOpen(); void addInitialFilters( std::vector const& filters ); void addNextFilters( std::vector const& filters ); //! Returns filters active in this tracker - std::vector const& getFilters() const; + std::vector const& getFilters() const { return m_filters; } //! Returns whitespace-trimmed name of the tracked section StringRef trimmedName() const; }; diff --git a/src/catch2/internal/catch_test_failure_exception.cpp b/src/catch2/internal/catch_test_failure_exception.cpp index c1edff3c..8ea31313 100644 --- a/src/catch2/internal/catch_test_failure_exception.cpp +++ b/src/catch2/internal/catch_test_failure_exception.cpp @@ -20,4 +20,12 @@ namespace Catch { #endif } + void throw_test_skip_exception() { +#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) + throw Catch::TestSkipException(); +#else + CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" ); +#endif + } + } // namespace Catch diff --git a/src/catch2/internal/catch_test_failure_exception.hpp b/src/catch2/internal/catch_test_failure_exception.hpp index 810a81c9..1ef88364 100644 --- a/src/catch2/internal/catch_test_failure_exception.hpp +++ b/src/catch2/internal/catch_test_failure_exception.hpp @@ -12,6 +12,8 @@ namespace Catch { //! Used to signal that an assertion macro failed struct TestFailureException{}; + //! Used to signal that the remainder of a test should be skipped + struct TestSkipException {}; /** * Outlines throwing of `TestFailureException` into a single TU @@ -20,6 +22,13 @@ namespace Catch { */ [[noreturn]] void throw_test_failure_exception(); + /** + * Outlines throwing of `TestSkipException` into a single TU + * + * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers. + */ + [[noreturn]] void throw_test_skip_exception(); + } // namespace Catch #endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED diff --git a/src/catch2/internal/catch_test_macro_impl.hpp b/src/catch2/internal/catch_test_macro_impl.hpp index 1b4ea8e7..59c851e8 100644 --- a/src/catch2/internal/catch_test_macro_impl.hpp +++ b/src/catch2/internal/catch_test_macro_impl.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -22,12 +23,6 @@ #if !defined(CATCH_CONFIG_DISABLE) -#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) - #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ -#else - #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" -#endif - #if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) /////////////////////////////////////////////////////////////////////////////// @@ -39,7 +34,7 @@ #else // CATCH_CONFIG_FAST_COMPILE #define INTERNAL_CATCH_TRY try -#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } +#define INTERNAL_CATCH_CATCH( handler ) catch(...) { (handler).handleUnexpectedInflightException(); } #endif @@ -95,6 +90,7 @@ if( catchAssertionHandler.allowThrows() ) \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(__VA_ARGS__); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ @@ -115,6 +111,7 @@ if( catchAssertionHandler.allowThrows() ) \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(expr); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ @@ -141,6 +138,7 @@ if( catchAssertionHandler.allowThrows() ) \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(__VA_ARGS__); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ diff --git a/src/catch2/internal/catch_test_registry.cpp b/src/catch2/internal/catch_test_registry.cpp index 9769ed03..e9c999fe 100644 --- a/src/catch2/internal/catch_test_registry.cpp +++ b/src/catch2/internal/catch_test_registry.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -17,9 +16,10 @@ #include namespace Catch { + ITestInvoker::~ITestInvoker() = default; namespace { - StringRef extractClassName( StringRef classOrMethodName ) { + static StringRef extractClassName( StringRef classOrMethodName ) { if ( !startsWith( classOrMethodName, '&' ) ) { return classOrMethodName; } @@ -46,6 +46,18 @@ namespace Catch { static_cast( startIdx ), static_cast( classNameSize ) ); } + + class TestInvokerAsFunction final : public ITestInvoker { + using TestType = void ( * )(); + TestType m_testAsFunction; + + public: + TestInvokerAsFunction( TestType testAsFunction ) noexcept: + m_testAsFunction( testAsFunction ) {} + + void invoke() const override { m_testAsFunction(); } + }; + } // namespace Detail::unique_ptr makeTestInvoker( void(*testAsFunction)() ) { diff --git a/src/catch2/internal/catch_test_registry.hpp b/src/catch2/internal/catch_test_registry.hpp index 5329a1e9..7766fe11 100644 --- a/src/catch2/internal/catch_test_registry.hpp +++ b/src/catch2/internal/catch_test_registry.hpp @@ -8,9 +8,10 @@ #ifndef CATCH_TEST_REGISTRY_HPP_INCLUDED #define CATCH_TEST_REGISTRY_HPP_INCLUDED +#include #include #include -#include +#include #include #include #include @@ -72,25 +73,55 @@ struct AutoReg : Detail::NonCopyable { void TestName::test() #endif + +#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT) + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + namespace{ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__ ) - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + + +// Dummy registrator for the dumy test case macros +namespace Catch { + namespace Detail { + struct DummyUse { + DummyUse( void ( * )( int ) ); + }; + } // namespace Detail +} // namespace Catch + +// Note that both the presence of the argument and its exact name are +// necessary for the section support. + +// We provide a shadowed variable so that a `SECTION` inside non-`TEST_CASE` +// tests can compile. The redefined `TEST_CASE` shadows this with param. +static int catchInternalSectionHint = 0; + +# define INTERNAL_CATCH_TESTCASE2( fname ) \ + static void fname( int ); \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + static const Catch::Detail::DummyUse INTERNAL_CATCH_UNIQUE_NAME( \ + dummyUser )( &(fname) ); \ + CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + static void fname( [[maybe_unused]] int catchInternalSectionHint ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +# define INTERNAL_CATCH_TESTCASE( ... ) \ + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( dummyFunction ) ) + + +#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ @@ -101,13 +132,33 @@ struct AutoReg : Detail::NonCopyable { struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ void test(); \ }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \ + Catch::makeTestInvoker( &TestName::test ), \ + CATCH_INTERNAL_LINEINFO, \ + #ClassName##_catch_sr, \ + Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ } \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + namespace { \ + const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \ + Catch::makeTestInvoker( &QualifiedMethod ), \ + CATCH_INTERNAL_LINEINFO, \ + "&" #QualifiedMethod##_catch_sr, \ + Catch::NameAndTags{ __VA_ARGS__ } ); \ + } /* NOLINT */ \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ do { \ diff --git a/src/catch2/internal/catch_test_run_info.hpp b/src/catch2/internal/catch_test_run_info.hpp new file mode 100644 index 00000000..90357b0a --- /dev/null +++ b/src/catch2/internal/catch_test_run_info.hpp @@ -0,0 +1,22 @@ + +// 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_RUN_INFO_HPP_INCLUDED +#define CATCH_TEST_RUN_INFO_HPP_INCLUDED + +#include + +namespace Catch { + + struct TestRunInfo { + constexpr TestRunInfo(StringRef _name) : name(_name) {} + StringRef name; + }; + +} // end namespace Catch + +#endif // CATCH_TEST_RUN_INFO_HPP_INCLUDED diff --git a/src/catch2/internal/catch_test_spec_parser.cpp b/src/catch2/internal/catch_test_spec_parser.cpp index bae25475..d6e4cb58 100644 --- a/src/catch2/internal/catch_test_spec_parser.cpp +++ b/src/catch2/internal/catch_test_spec_parser.cpp @@ -221,10 +221,8 @@ namespace Catch { token.erase(token.begin()); if (m_exclusion) { m_currentFilter.m_forbidden.emplace_back(Detail::make_unique(".", m_substring)); - m_currentFilter.m_forbidden.emplace_back(Detail::make_unique(token, m_substring)); } else { m_currentFilter.m_required.emplace_back(Detail::make_unique(".", m_substring)); - m_currentFilter.m_required.emplace_back(Detail::make_unique(token, m_substring)); } } if (m_exclusion) { diff --git a/src/catch2/internal/catch_textflow.hpp b/src/catch2/internal/catch_textflow.hpp index ceac675d..0776ab92 100644 --- a/src/catch2/internal/catch_textflow.hpp +++ b/src/catch2/internal/catch_textflow.hpp @@ -59,7 +59,7 @@ namespace Catch { // Calculates the length of the current line void calcLength(); - // Returns current indention width + // Returns current indentation width size_t indentSize() const; // Creates an indented and (optionally) suffixed string from diff --git a/src/catch2/internal/catch_uniform_floating_point_distribution.hpp b/src/catch2/internal/catch_uniform_floating_point_distribution.hpp new file mode 100644 index 00000000..23d03b43 --- /dev/null +++ b/src/catch2/internal/catch_uniform_floating_point_distribution.hpp @@ -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_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED +#define CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED + +#include +#include + +#include +#include + +namespace Catch { + + namespace Detail { +#if defined( __GNUC__ ) || defined( __clang__ ) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + // The issue with overflow only happens with maximal ULP and HUGE + // distance, e.g. when generating numbers in [-inf, inf] for given + // type. So we only check for the largest possible ULP in the + // type, and return something that does not overflow to inf in 1 mult. + constexpr std::uint64_t calculate_max_steps_in_one_go(double gamma) { + if ( gamma == 1.99584030953472e+292 ) { return 9007199254740991; } + return static_cast( -1 ); + } + constexpr std::uint32_t calculate_max_steps_in_one_go(float gamma) { + if ( gamma == 2.028241e+31f ) { return 16777215; } + return static_cast( -1 ); + } +#if defined( __GNUC__ ) || defined( __clang__ ) +# pragma GCC diagnostic pop +#endif + } + +/** + * Implementation of uniform distribution on floating point numbers. + * + * Note that we support only `float` and `double` types, because these + * usually mean the same thing across different platform. `long double` + * varies wildly by platform and thus we cannot provide reproducible + * implementation. Also note that we don't implement all parts of + * distribution per standard: this distribution is not serializable, nor + * can the range be arbitrarily reset. + * + * The implementation also uses different approach than the one taken by + * `std::uniform_real_distribution`, where instead of generating a number + * between [0, 1) and then multiplying the range bounds with it, we first + * split the [a, b] range into a set of equidistributed floating point + * numbers, and then use uniform int distribution to pick which one to + * return. + * + * This has the advantage of guaranteeing uniformity (the multiplication + * method loses uniformity due to rounding when multiplying floats), except + * for small non-uniformity at one side of the interval, where we have + * to deal with the fact that not every interval is splittable into + * equidistributed floats. + * + * Based on "Drawing random floating-point numbers from an interval" by + * Frederic Goualard. + */ +template +class uniform_floating_point_distribution { + static_assert(std::is_floating_point::value, "..."); + static_assert(!std::is_same::value, + "We do not support long double due to inconsistent behaviour between platforms"); + + using WidthType = Detail::DistanceType; + + FloatType m_a, m_b; + FloatType m_ulp_magnitude; + WidthType m_floats_in_range; + uniform_integer_distribution m_int_dist; + + // In specific cases, we can overflow into `inf` when computing the + // `steps * g` offset. To avoid this, we don't offset by more than this + // in one multiply + addition. + WidthType m_max_steps_in_one_go; + // We don't want to do the magnitude check every call to `operator()` + bool m_a_has_leq_magnitude; + +public: + using result_type = FloatType; + + uniform_floating_point_distribution( FloatType a, FloatType b ): + m_a( a ), + m_b( b ), + m_ulp_magnitude( Detail::gamma( m_a, m_b ) ), + m_floats_in_range( Detail::count_equidistant_floats( m_a, m_b, m_ulp_magnitude ) ), + m_int_dist(0, m_floats_in_range), + m_max_steps_in_one_go( Detail::calculate_max_steps_in_one_go(m_ulp_magnitude)), + m_a_has_leq_magnitude(std::fabs(m_a) <= std::fabs(m_b)) + { + assert( a <= b ); + } + + template + result_type operator()( Generator& g ) { + WidthType steps = m_int_dist( g ); + if ( m_a_has_leq_magnitude ) { + if ( steps == m_floats_in_range ) { return m_a; } + auto b = m_b; + while (steps > m_max_steps_in_one_go) { + b -= m_max_steps_in_one_go * m_ulp_magnitude; + steps -= m_max_steps_in_one_go; + } + return b - steps * m_ulp_magnitude; + } else { + if ( steps == m_floats_in_range ) { return m_b; } + auto a = m_a; + while (steps > m_max_steps_in_one_go) { + a += m_max_steps_in_one_go * m_ulp_magnitude; + steps -= m_max_steps_in_one_go; + } + return a + steps * m_ulp_magnitude; + } + } + + result_type a() const { return m_a; } + result_type b() const { return m_b; } +}; + +} // end namespace Catch + +#endif // CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED diff --git a/src/catch2/internal/catch_uniform_integer_distribution.hpp b/src/catch2/internal/catch_uniform_integer_distribution.hpp new file mode 100644 index 00000000..3b623579 --- /dev/null +++ b/src/catch2/internal/catch_uniform_integer_distribution.hpp @@ -0,0 +1,126 @@ + +// 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_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED +#define CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED + +#include + +namespace Catch { + + namespace Detail { + // Indirection to enable make_unsigned behaviour. + template + struct make_unsigned { + using type = std::make_unsigned_t; + }; + + template <> + struct make_unsigned { + using type = uint8_t; + }; + + template + using make_unsigned_t = typename make_unsigned::type; + } + +/** + * Implementation of uniform distribution on integers. + * + * Unlike `std::uniform_int_distribution`, this implementation supports + * various 1 byte integral types, including bool (but you should not + * actually use it for bools). + * + * The underlying algorithm is based on the one described in "Fast Random + * Integer Generation in an Interval" by Daniel Lemire, but has been + * optimized under the assumption of reuse of the same distribution object. + */ +template +class uniform_integer_distribution { + static_assert(std::is_integral::value, "..."); + + using UnsignedIntegerType = Detail::make_unsigned_t; + + // We store the left range bound converted to internal representation, + // because it will be used in computation in the () operator. + UnsignedIntegerType m_a; + // After initialization, right bound is only used for the b() getter, + // so we keep it in the original type. + IntegerType m_b; + + // How many different values are there in [a, b]. a == b => 1, can be 0 for distribution over all values in the type. + UnsignedIntegerType m_ab_distance; + + // We hoisted this out of the main generation function. Technically, + // this means that using this distribution will be slower than Lemire's + // algorithm if this distribution instance will be used only few times, + // but it will be faster if it is used many times. Since Catch2 uses + // distributions only to implement random generators, we assume that each + // distribution will be reused many times and this is an optimization. + UnsignedIntegerType m_rejection_threshold = 0; + + // Assumes m_b and m_a are already filled + UnsignedIntegerType computeDistance() const { + // This overflows and returns 0 if ua == 0 and ub == TYPE_MAX. + // We handle that later when generating the number. + return transposeTo(m_b) - m_a + 1; + } + + static UnsignedIntegerType computeRejectionThreshold(UnsignedIntegerType ab_distance) { + // distance == 0 means that we will return all possible values from + // the type's range, and that we shouldn't reject anything. + if ( ab_distance == 0 ) { return 0; } + return ( ~ab_distance + 1 ) % ab_distance; + } + + static UnsignedIntegerType transposeTo(IntegerType in) { + return Detail::transposeToNaturalOrder( + static_cast( in ) ); + } + static IntegerType transposeBack(UnsignedIntegerType in) { + return static_cast( + Detail::transposeToNaturalOrder(in) ); + } + +public: + using result_type = IntegerType; + + uniform_integer_distribution( IntegerType a, IntegerType b ): + m_a( transposeTo(a) ), + m_b( b ), + m_ab_distance( computeDistance() ), + m_rejection_threshold( computeRejectionThreshold(m_ab_distance) ) { + assert( a <= b ); + } + + template + result_type operator()( Generator& g ) { + // All possible values of result_type are valid. + if ( m_ab_distance == 0 ) { + return transposeBack( Detail::fillBitsFrom( g ) ); + } + + auto random_number = Detail::fillBitsFrom( g ); + auto emul = Detail::extendedMult( random_number, m_ab_distance ); + // Unlike Lemire's algorithm we skip the ab_distance check, since + // we precomputed the rejection threshold, which is always tighter. + while (emul.lower < m_rejection_threshold) { + random_number = Detail::fillBitsFrom( g ); + emul = Detail::extendedMult( random_number, m_ab_distance ); + } + + return transposeBack(m_a + emul.upper); + } + + result_type a() const { return transposeBack(m_a); } + result_type b() const { return m_b; } +}; + +} // end namespace Catch + +#endif // CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED diff --git a/src/catch2/internal/catch_xmlwriter.cpp b/src/catch2/internal/catch_xmlwriter.cpp index d3bc6303..6c1d45df 100644 --- a/src/catch2/internal/catch_xmlwriter.cpp +++ b/src/catch2/internal/catch_xmlwriter.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include diff --git a/src/catch2/matchers/catch_matchers_all.hpp b/src/catch2/matchers/catch_matchers_all.hpp index eadf7082..83fe5386 100644 --- a/src/catch2/matchers/catch_matchers_all.hpp +++ b/src/catch2/matchers/catch_matchers_all.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/src/catch2/matchers/catch_matchers_contains.hpp b/src/catch2/matchers/catch_matchers_contains.hpp index e298cab7..877d6924 100644 --- a/src/catch2/matchers/catch_matchers_contains.hpp +++ b/src/catch2/matchers/catch_matchers_contains.hpp @@ -33,13 +33,11 @@ namespace Catch { } template - bool match(RangeLike&& rng) const { - using std::begin; using std::end; - - return end(rng) != std::find_if(begin(rng), end(rng), - [&](auto const& elem) { - return m_eq(elem, m_desired); - }); + bool match( RangeLike&& rng ) const { + for ( auto&& elem : rng ) { + if ( m_eq( elem, m_desired ) ) { return true; } + } + return false; } }; @@ -91,7 +89,7 @@ namespace Catch { /** * Creates a matcher that checks whether a range contains a specific element. * - * Uses `eq` to do the comparisons + * Uses `eq` to do the comparisons, the element is provided on the rhs */ template ContainsElementMatcher Contains(T&& elem, Equality&& eq) { diff --git a/src/catch2/matchers/catch_matchers_exception.hpp b/src/catch2/matchers/catch_matchers_exception.hpp index 27e1b932..e7c3a636 100644 --- a/src/catch2/matchers/catch_matchers_exception.hpp +++ b/src/catch2/matchers/catch_matchers_exception.hpp @@ -29,6 +29,32 @@ public: //! Creates a matcher that checks whether a std derived exception has the provided message ExceptionMessageMatcher Message(std::string const& message); +template +class ExceptionMessageMatchesMatcher final + : public MatcherBase { + StringMatcherType m_matcher; + +public: + ExceptionMessageMatchesMatcher( StringMatcherType matcher ): + m_matcher( CATCH_MOVE( matcher ) ) {} + + bool match( std::exception const& ex ) const override { + return m_matcher.match( ex.what() ); + } + + std::string describe() const override { + return " matches \"" + m_matcher.describe() + '"'; + } +}; + +//! Creates a matcher that checks whether a message from an std derived +//! exception matches a provided matcher +template +ExceptionMessageMatchesMatcher +MessageMatches( StringMatcherType&& matcher ) { + return { CATCH_FORWARD( matcher ) }; +} + } // namespace Matchers } // namespace Catch diff --git a/src/catch2/matchers/catch_matchers_floating_point.cpp b/src/catch2/matchers/catch_matchers_floating_point.cpp index 719fb51f..206332ef 100644 --- a/src/catch2/matchers/catch_matchers_floating_point.cpp +++ b/src/catch2/matchers/catch_matchers_floating_point.cpp @@ -38,26 +38,11 @@ namespace { return ulpDist <= maxUlpDiff; } -#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) - - float nextafter(float x, float y) { - return ::nextafterf(x, y); - } - - double nextafter(double x, double y) { - return ::nextafter(x, y); - } - -#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^ template FP step(FP start, FP direction, uint64_t steps) { for (uint64_t i = 0; i < steps; ++i) { -#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) start = Catch::nextafter(start, direction); -#else - start = std::nextafter(start, direction); -#endif } return start; } @@ -225,5 +210,17 @@ WithinRelMatcher WithinRel(float target) { } -} // namespace Matchers + +bool IsNaNMatcher::match( double const& matchee ) const { + return std::isnan( matchee ); +} + +std::string IsNaNMatcher::describe() const { + using namespace std::string_literals; + return "is NaN"s; +} + +IsNaNMatcher IsNaN() { return IsNaNMatcher(); } + + } // namespace Matchers } // namespace Catch diff --git a/src/catch2/matchers/catch_matchers_floating_point.hpp b/src/catch2/matchers/catch_matchers_floating_point.hpp index abdaf159..76816633 100644 --- a/src/catch2/matchers/catch_matchers_floating_point.hpp +++ b/src/catch2/matchers/catch_matchers_floating_point.hpp @@ -27,6 +27,11 @@ namespace Matchers { double m_margin; }; + //! Creates a matcher that accepts numbers within certain range of target + WithinAbsMatcher WithinAbs( double target, double margin ); + + + class WithinUlpsMatcher final : public MatcherBase { public: WithinUlpsMatcher( double target, @@ -40,6 +45,13 @@ namespace Matchers { Detail::FloatingPointKind m_type; }; + //! Creates a matcher that accepts doubles within certain ULP range of target + WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff); + //! Creates a matcher that accepts floats within certain ULP range of target + WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff); + + + // Given IEEE-754 format for floats and doubles, we can assume // that float -> double promotion is lossless. Given this, we can // assume that if we do the standard relative comparison of @@ -56,13 +68,6 @@ namespace Matchers { double m_epsilon; }; - //! Creates a matcher that accepts doubles within certain ULP range of target - WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff); - //! Creates a matcher that accepts floats within certain ULP range of target - WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff); - //! Creates a matcher that accepts numbers within certain range of target - WithinAbsMatcher WithinAbs(double target, double margin); - //! Creates a matcher that accepts doubles within certain relative range of target WithinRelMatcher WithinRel(double target, double eps); //! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target @@ -72,6 +77,17 @@ namespace Matchers { //! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target WithinRelMatcher WithinRel(float target); + + + class IsNaNMatcher final : public MatcherBase { + public: + IsNaNMatcher() = default; + bool match( double const& matchee ) const override; + std::string describe() const override; + }; + + IsNaNMatcher IsNaN(); + } // namespace Matchers } // namespace Catch diff --git a/src/catch2/matchers/catch_matchers_range_equals.hpp b/src/catch2/matchers/catch_matchers_range_equals.hpp new file mode 100644 index 00000000..95b781a4 --- /dev/null +++ b/src/catch2/matchers/catch_matchers_range_equals.hpp @@ -0,0 +1,144 @@ + +// 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_MATCHERS_RANGE_EQUALS_HPP_INCLUDED +#define CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED + +#include +#include + +#include +#include + +namespace Catch { + namespace Matchers { + + /** + * Matcher for checking that an element contains the same + * elements in the same order + */ + template + class RangeEqualsMatcher final : public MatcherGenericBase { + TargetRangeLike m_desired; + Equality m_predicate; + + public: + template + RangeEqualsMatcher( TargetRangeLike2&& range, + Equality2&& predicate ): + m_desired( CATCH_FORWARD( range ) ), + m_predicate( CATCH_FORWARD( predicate ) ) {} + + template + bool match( RangeLike&& rng ) const { + auto rng_start = begin( rng ); + const auto rng_end = end( rng ); + auto target_start = begin( m_desired ); + const auto target_end = end( m_desired ); + + while (rng_start != rng_end && target_start != target_end) { + if (!m_predicate(*rng_start, *target_start)) { + return false; + } + ++rng_start; + ++target_start; + } + return rng_start == rng_end && target_start == target_end; + } + + std::string describe() const override { + return "elements are " + Catch::Detail::stringify( m_desired ); + } + }; + + /** + * Matcher for checking that an element contains the same + * elements (but not necessarily in the same order) + */ + template + class UnorderedRangeEqualsMatcher final : public MatcherGenericBase { + TargetRangeLike m_desired; + Equality m_predicate; + + public: + template + UnorderedRangeEqualsMatcher( TargetRangeLike2&& range, + Equality2&& predicate ): + m_desired( CATCH_FORWARD( range ) ), + m_predicate( CATCH_FORWARD( predicate ) ) {} + + template + bool match( RangeLike&& rng ) const { + using std::begin; + using std::end; + return Catch::Detail::is_permutation( begin( m_desired ), + end( m_desired ), + begin( rng ), + end( rng ), + m_predicate ); + } + + std::string describe() const override { + return "unordered elements are " + + ::Catch::Detail::stringify( m_desired ); + } + }; + + /** + * Creates a matcher that checks if all elements in a range are equal + * to all elements in another range. + * + * Uses `std::equal_to` to do the comparison + */ + template + std::enable_if_t::value, + RangeEqualsMatcher>> + RangeEquals( RangeLike&& range ) { + return { CATCH_FORWARD( range ), std::equal_to<>{} }; + } + + /** + * Creates a matcher that checks if all elements in a range are equal + * to all elements in another range. + * + * Uses to provided predicate `predicate` to do the comparisons + */ + template + RangeEqualsMatcher + RangeEquals( RangeLike&& range, Equality&& predicate ) { + return { CATCH_FORWARD( range ), CATCH_FORWARD( predicate ) }; + } + + /** + * Creates a matcher that checks if all elements in a range are equal + * to all elements in another range, in some permutation + * + * Uses `std::equal_to` to do the comparison + */ + template + std::enable_if_t< + !Detail::is_matcher::value, + UnorderedRangeEqualsMatcher>> + UnorderedRangeEquals( RangeLike&& range ) { + return { CATCH_FORWARD( range ), std::equal_to<>{} }; + } + + /** + * Creates a matcher that checks if all elements in a range are equal + * to all elements in another range, in some permutation. + * + * Uses to provided predicate `predicate` to do the comparisons + */ + template + UnorderedRangeEqualsMatcher + UnorderedRangeEquals( RangeLike&& range, Equality&& predicate ) { + return { CATCH_FORWARD( range ), CATCH_FORWARD( predicate ) }; + } + } // namespace Matchers +} // namespace Catch + +#endif // CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED diff --git a/src/catch2/matchers/catch_matchers_vector.hpp b/src/catch2/matchers/catch_matchers_vector.hpp index 9a4b024f..fffbfdf6 100644 --- a/src/catch2/matchers/catch_matchers_vector.hpp +++ b/src/catch2/matchers/catch_matchers_vector.hpp @@ -85,11 +85,10 @@ namespace Matchers { // - a more general approach would be via a compare template that defaults // to using !=. but could be specialised for, e.g. std::vector etc // - then just call that directly - if (m_comparator.size() != v.size()) - return false; - for (std::size_t i = 0; i < v.size(); ++i) - if (m_comparator[i] != v[i]) - return false; + if ( m_comparator.size() != v.size() ) { return false; } + for ( std::size_t i = 0; i < v.size(); ++i ) { + if ( !( m_comparator[i] == v[i] ) ) { return false; } + } return true; } std::string describe() const override { diff --git a/src/catch2/matchers/internal/catch_matchers_impl.hpp b/src/catch2/matchers/internal/catch_matchers_impl.hpp index 12455bfe..2ee9f0c0 100644 --- a/src/catch2/matchers/internal/catch_matchers_impl.hpp +++ b/src/catch2/matchers/internal/catch_matchers_impl.hpp @@ -8,9 +8,14 @@ #ifndef CATCH_MATCHERS_IMPL_HPP_INCLUDED #define CATCH_MATCHERS_IMPL_HPP_INCLUDED -#include +#include +#include +#include +#include #include +#include + namespace Catch { template diff --git a/src/catch2/meson.build b/src/catch2/meson.build index b32f72d2..4b9f3e8e 100644 --- a/src/catch2/meson.build +++ b/src/catch2/meson.build @@ -32,6 +32,8 @@ benchmark_headers = [ 'benchmark/catch_sample_analysis.hpp', 'benchmark/detail/catch_analyse.hpp', 'benchmark/detail/catch_benchmark_function.hpp', + 'benchmark/detail/catch_benchmark_stats.hpp', + 'benchmark/detail/catch_benchmark_stats_fwd.hpp', 'benchmark/detail/catch_complete_invoke.hpp', 'benchmark/detail/catch_estimate_clock.hpp', 'benchmark/detail/catch_measure.hpp', @@ -43,6 +45,7 @@ benchmark_headers = [ benchmark_sources = files( 'benchmark/catch_chronometer.cpp', + 'benchmark/detail/catch_analyse.cpp', 'benchmark/detail/catch_benchmark_function.cpp', 'benchmark/detail/catch_run_for_at_least.cpp', 'benchmark/detail/catch_stats.cpp', @@ -64,8 +67,8 @@ internal_headers = [ 'interfaces/catch_interfaces_registry_hub.hpp', 'interfaces/catch_interfaces_reporter.hpp', 'interfaces/catch_interfaces_reporter_factory.hpp', - 'interfaces/catch_interfaces_reporter_registry.hpp', 'interfaces/catch_interfaces_tag_alias_registry.hpp', + 'interfaces/catch_interfaces_test_invoker.hpp', 'interfaces/catch_interfaces_testcase.hpp', 'internal/catch_assertion_handler.hpp', 'internal/catch_case_insensitive_comparisons.hpp', @@ -76,6 +79,7 @@ internal_headers = [ 'internal/catch_compiler_capabilities.hpp', 'internal/catch_config_android_logwrite.hpp', 'internal/catch_config_counter.hpp', + 'internal/catch_config_static_analysis_support.hpp', 'internal/catch_config_uncaught_exceptions.hpp', 'internal/catch_config_wchar.hpp', 'internal/catch_console_colour.hpp', @@ -93,6 +97,8 @@ internal_headers = [ 'internal/catch_floating_point_helpers.hpp', 'internal/catch_getenv.hpp', 'internal/catch_istream.hpp', + 'internal/catch_is_permutation.hpp', + 'internal/catch_jsonwriter.hpp', 'internal/catch_lazy_expr.hpp', 'internal/catch_leak_detector.hpp', 'internal/catch_list.hpp', @@ -107,7 +113,10 @@ internal_headers = [ 'internal/catch_platform.hpp', 'internal/catch_polyfills.hpp', 'internal/catch_preprocessor.hpp', + 'internal/catch_preprocessor_internal_stringify.hpp', 'internal/catch_preprocessor_remove_parens.hpp', + 'internal/catch_random_floating_point_helpers.hpp', + 'internal/catch_random_integer_helpers.hpp', 'internal/catch_random_number_generator.hpp', 'internal/catch_random_seed_generation.hpp', 'internal/catch_reporter_registry.hpp', @@ -132,10 +141,13 @@ internal_headers = [ 'internal/catch_test_failure_exception.hpp', 'internal/catch_test_macro_impl.hpp', 'internal/catch_test_registry.hpp', + 'internal/catch_test_run_info.hpp', 'internal/catch_test_spec_parser.hpp', 'internal/catch_textflow.hpp', 'internal/catch_to_string.hpp', 'internal/catch_uncaught_exceptions.hpp', + 'internal/catch_uniform_floating_point_distribution.hpp', + 'internal/catch_uniform_integer_distribution.hpp', 'internal/catch_unique_name.hpp', 'internal/catch_unique_ptr.hpp', 'internal/catch_void_type.hpp', @@ -150,6 +162,7 @@ internal_headers = [ 'matchers/catch_matchers_floating_point.hpp', 'matchers/catch_matchers_predicate.hpp', 'matchers/catch_matchers_quantifiers.hpp', + 'matchers/catch_matchers_range_equals.hpp', 'matchers/catch_matchers_string.hpp', 'matchers/catch_matchers_templated.hpp', 'matchers/catch_matchers_vector.hpp', @@ -188,7 +201,6 @@ internal_sources = files( 'interfaces/catch_interfaces_registry_hub.cpp', 'interfaces/catch_interfaces_reporter.cpp', 'interfaces/catch_interfaces_reporter_factory.cpp', - 'interfaces/catch_interfaces_reporter_registry.cpp', 'interfaces/catch_interfaces_testcase.cpp', 'internal/catch_assertion_handler.cpp', 'internal/catch_case_insensitive_comparisons.cpp', @@ -207,6 +219,7 @@ internal_sources = files( 'internal/catch_floating_point_helpers.cpp', 'internal/catch_getenv.cpp', 'internal/catch_istream.cpp', + 'internal/catch_jsonwriter.cpp', 'internal/catch_lazy_expr.cpp', 'internal/catch_leak_detector.cpp', 'internal/catch_list.cpp', @@ -261,6 +274,7 @@ internal_sources = files( 'catch_timer.cpp', 'catch_tostring.cpp', 'catch_totals.cpp', + 'catch_translate_exception.cpp', 'catch_version.cpp', ) @@ -272,6 +286,7 @@ reporter_headers = [ 'reporters/catch_reporter_cumulative_base.hpp', 'reporters/catch_reporter_event_listener.hpp', 'reporters/catch_reporter_helpers.hpp', + 'reporters/catch_reporter_json.hpp', 'reporters/catch_reporter_junit.hpp', 'reporters/catch_reporter_multi.hpp', 'reporters/catch_reporter_registrars.hpp', @@ -291,6 +306,7 @@ reporter_sources = files( 'reporters/catch_reporter_cumulative_base.cpp', 'reporters/catch_reporter_event_listener.cpp', 'reporters/catch_reporter_helpers.cpp', + 'reporters/catch_reporter_json.cpp', 'reporters/catch_reporter_junit.cpp', 'reporters/catch_reporter_multi.cpp', 'reporters/catch_reporter_registrars.cpp', diff --git a/src/catch2/reporters/catch_reporter_automake.cpp b/src/catch2/reporters/catch_reporter_automake.cpp index 0660d092..5e506a6b 100644 --- a/src/catch2/reporters/catch_reporter_automake.cpp +++ b/src/catch2/reporters/catch_reporter_automake.cpp @@ -12,12 +12,14 @@ namespace Catch { - AutomakeReporter::~AutomakeReporter() {} + AutomakeReporter::~AutomakeReporter() = default; void AutomakeReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR. m_stream << ":test-result: "; - if (_testCaseStats.totals.assertions.allPassed()) { + if ( _testCaseStats.totals.testCases.skipped > 0 ) { + m_stream << "SKIP"; + } else if (_testCaseStats.totals.assertions.allPassed()) { m_stream << "PASS"; } else if (_testCaseStats.totals.assertions.allOk()) { m_stream << "XFAIL"; diff --git a/src/catch2/reporters/catch_reporter_automake.hpp b/src/catch2/reporters/catch_reporter_automake.hpp index 3475a1fd..a639428c 100644 --- a/src/catch2/reporters/catch_reporter_automake.hpp +++ b/src/catch2/reporters/catch_reporter_automake.hpp @@ -8,7 +8,6 @@ #ifndef CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED #define CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED -#include #include #include diff --git a/src/catch2/reporters/catch_reporter_compact.cpp b/src/catch2/reporters/catch_reporter_compact.cpp index d8088457..0f855944 100644 --- a/src/catch2/reporters/catch_reporter_compact.cpp +++ b/src/catch2/reporters/catch_reporter_compact.cpp @@ -105,6 +105,11 @@ public: printIssue("explicitly"); printRemainingMessages(Colour::None); break; + case ResultWas::ExplicitSkip: + printResultType(Colour::Skip, "skipped"_sr); + printMessage(); + printRemainingMessages(); + break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: @@ -166,7 +171,7 @@ private: return; const auto itEnd = messages.cend(); - const auto N = static_cast(std::distance(itMessage, itEnd)); + const auto N = static_cast(itEnd - itMessage); stream << colourImpl->guardColour( colour ) << " with " << pluralise( N, "message"_sr ) << ':'; @@ -187,7 +192,7 @@ private: private: std::ostream& stream; AssertionResult const& result; - std::vector messages; + std::vector const& messages; std::vector::const_iterator itMessage; bool printInfoMessages; ColourImpl* colourImpl; @@ -220,7 +225,7 @@ private: // Drop out if result was successful and we're not printing those if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) + if( result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip ) return; printInfoMessages = false; } @@ -244,6 +249,6 @@ private: StreamingReporterBase::testRunEnded( _testRunStats ); } - CompactReporter::~CompactReporter() {} + CompactReporter::~CompactReporter() = default; } // end namespace Catch diff --git a/src/catch2/reporters/catch_reporter_console.cpp b/src/catch2/reporters/catch_reporter_console.cpp index 0edb121e..bbde5ec9 100644 --- a/src/catch2/reporters/catch_reporter_console.cpp +++ b/src/catch2/reporters/catch_reporter_console.cpp @@ -51,7 +51,6 @@ public: stats(_stats), result(_stats.assertionResult), colour(Colour::None), - message(result.getMessage()), messages(_stats.infoMessages), colourImpl(colourImpl_), printInfoMessages(_printInfoMessages) { @@ -60,10 +59,10 @@ public: colour = Colour::Success; passOrFail = "PASSED"_sr; //if( result.hasMessage() ) - if (_stats.infoMessages.size() == 1) - messageLabel = "with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "with messages"; + if (messages.size() == 1) + messageLabel = "with message"_sr; + if (messages.size() > 1) + messageLabel = "with messages"_sr; break; case ResultWas::ExpressionFailed: if (result.isOk()) { @@ -73,43 +72,57 @@ public: colour = Colour::Error; passOrFail = "FAILED"_sr; } - if (_stats.infoMessages.size() == 1) - messageLabel = "with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "with messages"; + if (messages.size() == 1) + messageLabel = "with message"_sr; + if (messages.size() > 1) + messageLabel = "with messages"_sr; break; case ResultWas::ThrewException: colour = Colour::Error; passOrFail = "FAILED"_sr; - messageLabel = "due to unexpected exception with "; - if (_stats.infoMessages.size() == 1) - messageLabel += "message"; - if (_stats.infoMessages.size() > 1) - messageLabel += "messages"; + // todo switch + switch (messages.size()) { case 0: + messageLabel = "due to unexpected exception with "_sr; + break; + case 1: + messageLabel = "due to unexpected exception with message"_sr; + break; + default: + messageLabel = "due to unexpected exception with messages"_sr; + break; + } break; case ResultWas::FatalErrorCondition: colour = Colour::Error; passOrFail = "FAILED"_sr; - messageLabel = "due to a fatal error condition"; + messageLabel = "due to a fatal error condition"_sr; break; case ResultWas::DidntThrowException: colour = Colour::Error; passOrFail = "FAILED"_sr; - messageLabel = "because no exception was thrown where one was expected"; + messageLabel = "because no exception was thrown where one was expected"_sr; break; case ResultWas::Info: - messageLabel = "info"; + messageLabel = "info"_sr; break; case ResultWas::Warning: - messageLabel = "warning"; + messageLabel = "warning"_sr; break; case ResultWas::ExplicitFailure: passOrFail = "FAILED"_sr; colour = Colour::Error; - if (_stats.infoMessages.size() == 1) - messageLabel = "explicitly with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "explicitly with messages"; + if (messages.size() == 1) + messageLabel = "explicitly with message"_sr; + if (messages.size() > 1) + messageLabel = "explicitly with messages"_sr; + break; + case ResultWas::ExplicitSkip: + colour = Colour::Skip; + passOrFail = "SKIPPED"_sr; + if (messages.size() == 1) + messageLabel = "explicitly with message"_sr; + if (messages.size() > 1) + messageLabel = "explicitly with messages"_sr; break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: @@ -173,9 +186,8 @@ private: AssertionResult const& result; Colour::Code colour; StringRef passOrFail; - std::string messageLabel; - std::string message; - std::vector messages; + StringRef messageLabel; + std::vector const& messages; ColourImpl* colourImpl; bool printInfoMessages; }; @@ -185,13 +197,16 @@ std::size_t makeRatio( std::uint64_t number, std::uint64_t total ) { return (ratio == 0 && number > 0) ? 1 : static_cast(ratio); } -std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { - if (i > j && i > k) +std::size_t& +findMax( std::size_t& i, std::size_t& j, std::size_t& k, std::size_t& l ) { + if (i > j && i > k && i > l) return i; - else if (j > k) + else if (j > k && j > l) return j; - else + else if (k > l) return k; + else + return l; } enum class Justification { Left, Right }; @@ -203,6 +218,7 @@ struct ColumnInfo { }; struct ColumnBreak {}; struct RowBreak {}; +struct OutputFlush {}; class Duration { enum class Unit { @@ -319,12 +335,12 @@ public: } template - friend TablePrinter& operator << (TablePrinter& tp, T const& value) { + friend TablePrinter& operator<< (TablePrinter& tp, T const& value) { tp.m_oss << value; return tp; } - friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { + friend TablePrinter& operator<< (TablePrinter& tp, ColumnBreak) { auto colStr = tp.m_oss.str(); const auto strSize = colStr.size(); tp.m_oss.str(""); @@ -346,13 +362,18 @@ public: return tp; } - friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { + friend TablePrinter& operator<< (TablePrinter& tp, RowBreak) { if (tp.m_currentColumn > 0) { tp.m_os << '\n'; tp.m_currentColumn = -1; } return tp; } + + friend TablePrinter& operator<<(TablePrinter& tp, OutputFlush) { + tp.m_os << std::flush; + return tp; + } }; ConsoleReporter::ConsoleReporter(ReporterConfig&& config): @@ -374,7 +395,7 @@ ConsoleReporter::ConsoleReporter(ReporterConfig&& config): { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left }, { "samples mean std dev", 14, Justification::Right }, { "iterations low mean low std dev", 14, Justification::Right }, - { "estimated high mean high std dev", 14, Justification::Right } + { "est run time high mean high std dev", 14, Justification::Right } }; } }())) {} @@ -400,7 +421,8 @@ void ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); // Drop out if result was successful but we're not printing them. - if (!includeResults && result.getResultType() != ResultWas::Warning) + // TODO: Make configurable whether skips should be printed + if (!includeResults && result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip) return; lazyPrint(); @@ -457,8 +479,11 @@ void ConsoleReporter::benchmarkPreparing( StringRef name ) { void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { (*m_tablePrinter) << info.samples << ColumnBreak() << info.iterations << ColumnBreak(); - if (!m_config->benchmarkNoAnalysis()) - (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak(); + if ( !m_config->benchmarkNoAnalysis() ) { + ( *m_tablePrinter ) + << Duration( info.estimatedDuration ) << ColumnBreak(); + } + ( *m_tablePrinter ) << OutputFlush{}; } void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) { if (m_config->benchmarkNoAnalysis()) @@ -603,10 +628,11 @@ void ConsoleReporter::printTotalsDivider(Totals const& totals) { std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); - while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) - findMax(failedRatio, failedButOkRatio, passedRatio)++; + std::size_t skippedRatio = makeRatio(totals.testCases.skipped, totals.testCases.total()); + while (failedRatio + failedButOkRatio + passedRatio + skippedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)++; while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) - findMax(failedRatio, failedButOkRatio, passedRatio)--; + findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)--; m_stream << m_colour->guardColour( Colour::Error ) << std::string( failedRatio, '=' ) @@ -619,6 +645,8 @@ void ConsoleReporter::printTotalsDivider(Totals const& totals) { m_stream << m_colour->guardColour( Colour::Success ) << std::string( passedRatio, '=' ); } + m_stream << m_colour->guardColour( Colour::Skip ) + << std::string( skippedRatio, '=' ); } else { m_stream << m_colour->guardColour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH - 1, '=' ); diff --git a/src/catch2/reporters/catch_reporter_cumulative_base.cpp b/src/catch2/reporters/catch_reporter_cumulative_base.cpp index effd98b7..5e106326 100644 --- a/src/catch2/reporters/catch_reporter_cumulative_base.cpp +++ b/src/catch2/reporters/catch_reporter_cumulative_base.cpp @@ -70,7 +70,8 @@ namespace Catch { void CumulativeReporterBase::sectionStarting( SectionInfo const& sectionInfo ) { - SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + // We need a copy, because SectionStats expect to take ownership + SectionStats incompleteStats( SectionInfo(sectionInfo), Counts(), 0, false ); SectionNode* node; if ( m_sectionStack.empty() ) { if ( !m_rootSection ) { diff --git a/src/catch2/reporters/catch_reporter_cumulative_base.hpp b/src/catch2/reporters/catch_reporter_cumulative_base.hpp index cdff9991..267b39fd 100644 --- a/src/catch2/reporters/catch_reporter_cumulative_base.hpp +++ b/src/catch2/reporters/catch_reporter_cumulative_base.hpp @@ -8,7 +8,6 @@ #ifndef CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED #define CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED -#include #include #include #include @@ -125,7 +124,7 @@ namespace Catch { void skipTest(TestCaseInfo const&) override {} protected: - //! Should the cumulative base store the assertion expansion for succesful assertions? + //! Should the cumulative base store the assertion expansion for successful assertions? bool m_shouldStoreSuccesfulAssertions = true; //! Should the cumulative base store the assertion expansion for failed assertions? bool m_shouldStoreFailedAssertions = true; diff --git a/src/catch2/reporters/catch_reporter_helpers.cpp b/src/catch2/reporters/catch_reporter_helpers.cpp index f6aa6fc5..ffb32ffb 100644 --- a/src/catch2/reporters/catch_reporter_helpers.cpp +++ b/src/catch2/reporters/catch_reporter_helpers.cpp @@ -316,15 +316,22 @@ namespace Catch { } std::vector columns; + // Don't include "skipped assertions" in total count + const auto totalAssertionCount = + totals.assertions.total() - totals.assertions.skipped; columns.push_back( SummaryColumn( "", Colour::None ) .addRow( totals.testCases.total() ) - .addRow( totals.assertions.total() ) ); + .addRow( totalAssertionCount ) ); columns.push_back( SummaryColumn( "passed", Colour::Success ) .addRow( totals.testCases.passed ) .addRow( totals.assertions.passed ) ); columns.push_back( SummaryColumn( "failed", Colour::ResultError ) .addRow( totals.testCases.failed ) .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "skipped", Colour::Skip ) + .addRow( totals.testCases.skipped ) + // Don't print "skipped assertions" + .addRow( 0 ) ); columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) .addRow( totals.testCases.failedButOk ) diff --git a/src/catch2/reporters/catch_reporter_json.cpp b/src/catch2/reporters/catch_reporter_json.cpp new file mode 100644 index 00000000..1f0db8b0 --- /dev/null +++ b/src/catch2/reporters/catch_reporter_json.cpp @@ -0,0 +1,372 @@ + +// 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 +#include +#include +#include +#include +#include +#include + +namespace Catch { + namespace { + void writeSourceInfo( JsonObjectWriter& writer, + SourceLineInfo const& sourceInfo ) { + auto source_location_writer = + writer.write( "source-location"_sr ).writeObject(); + source_location_writer.write( "filename"_sr ) + .write( sourceInfo.file ); + source_location_writer.write( "line"_sr ).write( sourceInfo.line ); + } + + void writeTags( JsonArrayWriter writer, std::vector const& tags ) { + for ( auto const& tag : tags ) { + writer.write( tag.original ); + } + } + + void writeProperties( JsonArrayWriter writer, + TestCaseInfo const& info ) { + if ( info.isHidden() ) { writer.write( "is-hidden"_sr ); } + if ( info.okToFail() ) { writer.write( "ok-to-fail"_sr ); } + if ( info.expectedToFail() ) { + writer.write( "expected-to-fail"_sr ); + } + if ( info.throws() ) { writer.write( "throws"_sr ); } + } + + } // namespace + + JsonReporter::JsonReporter( ReporterConfig&& config ): + StreamingReporterBase{ CATCH_MOVE( config ) } { + + m_preferences.shouldRedirectStdOut = true; + // TBD: Do we want to report all assertions? XML reporter does + // not, but for machine-parseable reporters I think the answer + // should be yes. + m_preferences.shouldReportAllAssertions = true; + + m_objectWriters.emplace( m_stream ); + m_writers.emplace( Writer::Object ); + auto& writer = m_objectWriters.top(); + + writer.write( "version"_sr ).write( 1 ); + + { + auto metadata_writer = writer.write( "metadata"_sr ).writeObject(); + metadata_writer.write( "name"_sr ).write( m_config->name() ); + metadata_writer.write( "rng-seed"_sr ).write( m_config->rngSeed() ); + metadata_writer.write( "catch2-version"_sr ) + .write( libraryVersion() ); + if ( m_config->testSpec().hasFilters() ) { + metadata_writer.write( "filters"_sr ) + .write( m_config->testSpec() ); + } + } + } + + JsonReporter::~JsonReporter() { + endListing(); + // TODO: Ensure this closes the top level object, add asserts + assert( m_writers.size() == 1 && "Only the top level object should be open" ); + assert( m_writers.top() == Writer::Object ); + endObject(); + m_stream << '\n' << std::flush; + assert( m_writers.empty() ); + } + + JsonArrayWriter& JsonReporter::startArray() { + m_arrayWriters.emplace( m_arrayWriters.top().writeArray() ); + m_writers.emplace( Writer::Array ); + return m_arrayWriters.top(); + } + JsonArrayWriter& JsonReporter::startArray( StringRef key ) { + m_arrayWriters.emplace( + m_objectWriters.top().write( key ).writeArray() ); + m_writers.emplace( Writer::Array ); + return m_arrayWriters.top(); + } + + JsonObjectWriter& JsonReporter::startObject() { + m_objectWriters.emplace( m_arrayWriters.top().writeObject() ); + m_writers.emplace( Writer::Object ); + return m_objectWriters.top(); + } + JsonObjectWriter& JsonReporter::startObject( StringRef key ) { + m_objectWriters.emplace( + m_objectWriters.top().write( key ).writeObject() ); + m_writers.emplace( Writer::Object ); + return m_objectWriters.top(); + } + + void JsonReporter::endObject() { + assert( isInside( Writer::Object ) ); + m_objectWriters.pop(); + m_writers.pop(); + } + void JsonReporter::endArray() { + assert( isInside( Writer::Array ) ); + m_arrayWriters.pop(); + m_writers.pop(); + } + + bool JsonReporter::isInside( Writer writer ) { + return !m_writers.empty() && m_writers.top() == writer; + } + + void JsonReporter::startListing() { + if ( !m_startedListing ) { startObject( "listings"_sr ); } + m_startedListing = true; + } + void JsonReporter::endListing() { + if ( m_startedListing ) { endObject(); } + m_startedListing = false; + } + + std::string JsonReporter::getDescription() { + return "Outputs listings as JSON. Test listing is Work-in-Progress!"; + } + + void JsonReporter::testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + endListing(); + + assert( isInside( Writer::Object ) ); + startObject( "test-run"_sr ); + startArray( "test-cases"_sr ); + } + + static void writeCounts( JsonObjectWriter&& writer, Counts const& counts ) { + writer.write( "passed"_sr ).write( counts.passed ); + writer.write( "failed"_sr ).write( counts.failed ); + writer.write( "fail-but-ok"_sr ).write( counts.failedButOk ); + writer.write( "skipped"_sr ).write( counts.skipped ); + } + + void JsonReporter::testRunEnded(TestRunStats const& runStats) { + assert( isInside( Writer::Array ) ); + // End "test-cases" + endArray(); + + { + auto totals = + m_objectWriters.top().write( "totals"_sr ).writeObject(); + writeCounts( totals.write( "assertions"_sr ).writeObject(), + runStats.totals.assertions ); + writeCounts( totals.write( "test-cases"_sr ).writeObject(), + runStats.totals.testCases ); + } + + // End the "test-run" object + endObject(); + } + + void JsonReporter::testCaseStarting( TestCaseInfo const& tcInfo ) { + StreamingReporterBase::testCaseStarting( tcInfo ); + + assert( isInside( Writer::Array ) && + "We should be in the 'test-cases' array" ); + startObject(); + // "test-info" prelude + { + auto testInfo = + m_objectWriters.top().write( "test-info"_sr ).writeObject(); + // TODO: handle testName vs className!! + testInfo.write( "name"_sr ).write( tcInfo.name ); + writeSourceInfo(testInfo, tcInfo.lineInfo); + writeTags( testInfo.write( "tags"_sr ).writeArray(), tcInfo.tags ); + writeProperties( testInfo.write( "properties"_sr ).writeArray(), + tcInfo ); + } + + + // Start the array for individual test runs (testCasePartial pairs) + startArray( "runs"_sr ); + } + + void JsonReporter::testCaseEnded( TestCaseStats const& tcStats ) { + StreamingReporterBase::testCaseEnded( tcStats ); + + // We need to close the 'runs' array before finishing the test case + assert( isInside( Writer::Array ) ); + endArray(); + + { + auto totals = + m_objectWriters.top().write( "totals"_sr ).writeObject(); + writeCounts( totals.write( "assertions"_sr ).writeObject(), + tcStats.totals.assertions ); + // We do not write the test case totals, because there will always be just one test case here. + // TODO: overall "result" -> success, skip, fail here? Or in partial result? + } + // We do not write out stderr/stdout, because we instead wrote those out in partial runs + + // TODO: aborting? + + // And we also close this test case's object + assert( isInside( Writer::Object ) ); + endObject(); + } + + void JsonReporter::testCasePartialStarting( TestCaseInfo const& /*tcInfo*/, + uint64_t index ) { + startObject(); + m_objectWriters.top().write( "run-idx"_sr ).write( index ); + startArray( "path"_sr ); + // TODO: we want to delay most of the printing to the 'root' section + // TODO: childSection key name? + } + + void JsonReporter::testCasePartialEnded( TestCaseStats const& tcStats, + uint64_t /*index*/ ) { + // Fixme: the top level section handles this. + //// path object + endArray(); + if ( !tcStats.stdOut.empty() ) { + m_objectWriters.top() + .write( "captured-stdout"_sr ) + .write( tcStats.stdOut ); + } + if ( !tcStats.stdErr.empty() ) { + m_objectWriters.top() + .write( "captured-stderr"_sr ) + .write( tcStats.stdErr ); + } + { + auto totals = + m_objectWriters.top().write( "totals"_sr ).writeObject(); + writeCounts( totals.write( "assertions"_sr ).writeObject(), + tcStats.totals.assertions ); + // We do not write the test case totals, because there will + // always be just one test case here. + // TODO: overall "result" -> success, skip, fail here? Or in + // partial result? + } + // TODO: aborting? + // run object + endObject(); + } + + void JsonReporter::sectionStarting( SectionInfo const& sectionInfo ) { + assert( isInside( Writer::Array ) && + "Section should always start inside an object" ); + // We want to nest top level sections, even though it shares name + // and source loc with the TEST_CASE + auto& sectionObject = startObject(); + sectionObject.write( "kind"_sr ).write( "section"_sr ); + sectionObject.write( "name"_sr ).write( sectionInfo.name ); + writeSourceInfo( m_objectWriters.top(), sectionInfo.lineInfo ); + + + // TBD: Do we want to create this event lazily? It would become + // rather complex, but we could do it, and it would look + // better for empty sections. OTOH, empty sections should + // be rare. + startArray( "path"_sr ); + } + void JsonReporter::sectionEnded( SectionStats const& /*sectionStats */) { + // End the subpath array + endArray(); + // TODO: metadata + // TODO: what info do we have here? + + // End the section object + endObject(); + } + + void JsonReporter::assertionStarting( AssertionInfo const& /*assertionInfo*/ ) {} + void JsonReporter::assertionEnded( AssertionStats const& assertionStats ) { + // TODO: There is lot of different things to handle here, but + // we can fill it in later, after we show that the basic + // outline and streaming reporter impl works well enough. + //if ( !m_config->includeSuccessfulResults() + // && assertionStats.assertionResult.isOk() ) { + // return; + //} + assert( isInside( Writer::Array ) ); + auto assertionObject = m_arrayWriters.top().writeObject(); + + assertionObject.write( "kind"_sr ).write( "assertion"_sr ); + writeSourceInfo( assertionObject, + assertionStats.assertionResult.getSourceInfo() ); + assertionObject.write( "status"_sr ) + .write( assertionStats.assertionResult.isOk() ); + // TODO: handling of result. + // TODO: messages + // TODO: totals? + } + + + void JsonReporter::benchmarkPreparing( StringRef name ) { (void)name; } + void JsonReporter::benchmarkStarting( BenchmarkInfo const& ) {} + void JsonReporter::benchmarkEnded( BenchmarkStats<> const& ) {} + void JsonReporter::benchmarkFailed( StringRef error ) { (void)error; } + + void JsonReporter::listReporters( + std::vector const& descriptions ) { + startListing(); + + auto writer = + m_objectWriters.top().write( "reporters"_sr ).writeArray(); + for ( auto const& desc : descriptions ) { + auto desc_writer = writer.writeObject(); + desc_writer.write( "name"_sr ).write( desc.name ); + desc_writer.write( "description"_sr ).write( desc.description ); + } + } + void JsonReporter::listListeners( + std::vector const& descriptions ) { + startListing(); + + auto writer = + m_objectWriters.top().write( "listeners"_sr ).writeArray(); + + for ( auto const& desc : descriptions ) { + auto desc_writer = writer.writeObject(); + desc_writer.write( "name"_sr ).write( desc.name ); + desc_writer.write( "description"_sr ).write( desc.description ); + } + } + void JsonReporter::listTests( std::vector const& tests ) { + startListing(); + + auto writer = m_objectWriters.top().write( "tests"_sr ).writeArray(); + + for ( auto const& test : tests ) { + auto desc_writer = writer.writeObject(); + auto const& info = test.getTestCaseInfo(); + + desc_writer.write( "name"_sr ).write( info.name ); + desc_writer.write( "class-name"_sr ).write( info.className ); + { + auto tag_writer = desc_writer.write( "tags"_sr ).writeArray(); + for ( auto const& tag : info.tags ) { + tag_writer.write( tag.original ); + } + } + writeSourceInfo( desc_writer, info.lineInfo ); + } + } + void JsonReporter::listTags( std::vector const& tags ) { + startListing(); + + auto writer = m_objectWriters.top().write( "tags"_sr ).writeArray(); + for ( auto const& tag : tags ) { + auto tag_writer = writer.writeObject(); + { + auto aliases_writer = + tag_writer.write( "aliases"_sr ).writeArray(); + for ( auto alias : tag.spellings ) { + aliases_writer.write( alias ); + } + } + tag_writer.write( "count"_sr ).write( tag.count ); + } + } +} // namespace Catch diff --git a/src/catch2/reporters/catch_reporter_json.hpp b/src/catch2/reporters/catch_reporter_json.hpp new file mode 100644 index 00000000..c938ca39 --- /dev/null +++ b/src/catch2/reporters/catch_reporter_json.hpp @@ -0,0 +1,95 @@ + +// 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_REPORTER_JSON_HPP_INCLUDED +#define CATCH_REPORTER_JSON_HPP_INCLUDED + +#include +#include +#include + +#include + +namespace Catch { + class JsonReporter : public StreamingReporterBase { + public: + JsonReporter( ReporterConfig&& config ); + + ~JsonReporter() override; + + static std::string getDescription(); + + public: // StreamingReporterBase + void testRunStarting( TestRunInfo const& runInfo ) override; + void testRunEnded( TestRunStats const& runStats ) override; + + void testCaseStarting( TestCaseInfo const& tcInfo ) override; + void testCaseEnded( TestCaseStats const& tcStats ) override; + + void testCasePartialStarting( TestCaseInfo const& tcInfo, + uint64_t index ) override; + void testCasePartialEnded( TestCaseStats const& tcStats, + uint64_t index ) override; + + void sectionStarting( SectionInfo const& sectionInfo ) override; + void sectionEnded( SectionStats const& sectionStats ) override; + + void assertionStarting( AssertionInfo const& assertionInfo ) override; + void assertionEnded( AssertionStats const& assertionStats ) override; + + //void testRunEndedCumulative() override; + + void benchmarkPreparing( StringRef name ) override; + void benchmarkStarting( BenchmarkInfo const& ) override; + void benchmarkEnded( BenchmarkStats<> const& ) override; + void benchmarkFailed( StringRef error ) override; + + void listReporters( + std::vector const& descriptions ) override; + void listListeners( + std::vector const& descriptions ) override; + void listTests( std::vector const& tests ) override; + void listTags( std::vector const& tags ) override; + + private: + Timer m_testCaseTimer; + enum class Writer { + Object, + Array + }; + + JsonArrayWriter& startArray(); + JsonArrayWriter& startArray( StringRef key ); + + JsonObjectWriter& startObject(); + JsonObjectWriter& startObject( StringRef key ); + + void endObject(); + void endArray(); + + bool isInside( Writer writer ); + + void startListing(); + void endListing(); + + // Invariant: + // When m_writers is not empty and its top element is + // - Writer::Object, then m_objectWriters is not be empty + // - Writer::Array, then m_arrayWriters shall not be empty + std::stack m_objectWriters{}; + std::stack m_arrayWriters{}; + std::stack m_writers{}; + + bool m_startedListing = false; + + // std::size_t m_sectionDepth = 0; + // std::size_t m_sectionStarted = 0; + }; +} // namespace Catch + +#endif // CATCH_REPORTER_JSON_HPP_INCLUDED diff --git a/src/catch2/reporters/catch_reporter_junit.cpp b/src/catch2/reporters/catch_reporter_junit.cpp index 837d0489..fc5cae34 100644 --- a/src/catch2/reporters/catch_reporter_junit.cpp +++ b/src/catch2/reporters/catch_reporter_junit.cpp @@ -33,6 +33,8 @@ namespace Catch { gmtime_s(&timeInfo, &rawtime); #elif defined (CATCH_PLATFORM_PLAYSTATION) gmtime_s(&rawtime, &timeInfo); +#elif defined (__IAR_SYSTEMS_ICC__) + timeInfo = *std::gmtime(&rawtime); #else gmtime_r(&rawtime, &timeInfo); #endif @@ -132,6 +134,7 @@ namespace Catch { xml.writeAttribute( "name"_sr, stats.runInfo.name ); xml.writeAttribute( "errors"_sr, unexpectedExceptions ); xml.writeAttribute( "failures"_sr, stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "skipped"_sr, stats.totals.assertions.skipped ); xml.writeAttribute( "tests"_sr, stats.totals.assertions.total() ); xml.writeAttribute( "hostname"_sr, "tbd"_sr ); // !TBD if( m_config->showDurations() == ShowDurations::Never ) @@ -244,7 +247,8 @@ namespace Catch { void JunitReporter::writeAssertion( AssertionStats const& stats ) { AssertionResult const& result = stats.assertionResult; - if( !result.isOk() ) { + if ( !result.isOk() || + result.getResultType() == ResultWas::ExplicitSkip ) { std::string elementName; switch( result.getResultType() ) { case ResultWas::ThrewException: @@ -256,7 +260,9 @@ namespace Catch { case ResultWas::DidntThrowException: elementName = "failure"; break; - + case ResultWas::ExplicitSkip: + elementName = "skipped"; + break; // We should never see these here: case ResultWas::Info: case ResultWas::Warning: @@ -274,7 +280,9 @@ namespace Catch { xml.writeAttribute( "type"_sr, result.getTestMacroName() ); ReusableStringStream rss; - if (stats.totals.assertions.total() > 0) { + if ( result.getResultType() == ResultWas::ExplicitSkip ) { + rss << "SKIPPED\n"; + } else { rss << "FAILED" << ":\n"; if (result.hasExpression()) { rss << " "; @@ -285,11 +293,9 @@ namespace Catch { rss << "with expansion:\n"; rss << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n'; } - } else { - rss << '\n'; } - if( !result.getMessage().empty() ) + if( result.hasMessage() ) rss << result.getMessage() << '\n'; for( auto const& msg : stats.infoMessages ) if( msg.type == ResultWas::Info ) diff --git a/src/catch2/reporters/catch_reporter_multi.cpp b/src/catch2/reporters/catch_reporter_multi.cpp index ebf28b64..531902be 100644 --- a/src/catch2/reporters/catch_reporter_multi.cpp +++ b/src/catch2/reporters/catch_reporter_multi.cpp @@ -114,7 +114,6 @@ namespace Catch { } } - // The return value indicates if the messages buffer should be cleared: void MultiReporter::assertionEnded( AssertionStats const& assertionStats ) { const bool reportByDefault = assertionStats.assertionResult.getResultType() != ResultWas::Ok || diff --git a/src/catch2/reporters/catch_reporter_registrars.cpp b/src/catch2/reporters/catch_reporter_registrars.cpp index a9787ce5..2a3ac957 100644 --- a/src/catch2/reporters/catch_reporter_registrars.cpp +++ b/src/catch2/reporters/catch_reporter_registrars.cpp @@ -8,6 +8,7 @@ #include +#include #include namespace Catch { @@ -26,5 +27,10 @@ namespace Catch { } } + void registerListenerImpl( Detail::unique_ptr listenerFactory ) { + getMutableRegistryHub().registerListener( CATCH_MOVE(listenerFactory) ); + } + + } // namespace Detail } // namespace Catch diff --git a/src/catch2/reporters/catch_reporter_registrars.hpp b/src/catch2/reporters/catch_reporter_registrars.hpp index fe8cf1ec..a93963f0 100644 --- a/src/catch2/reporters/catch_reporter_registrars.hpp +++ b/src/catch2/reporters/catch_reporter_registrars.hpp @@ -8,8 +8,6 @@ #ifndef CATCH_REPORTER_REGISTRARS_HPP_INCLUDED #define CATCH_REPORTER_REGISTRARS_HPP_INCLUDED -#include -#include #include #include #include @@ -36,7 +34,8 @@ namespace Catch { //! independent on the reporter's concrete type void registerReporterImpl( std::string const& name, IReporterFactoryPtr reporterPtr ); - + //! Actually registers the factory, independent on listener's concrete type + void registerListenerImpl( Detail::unique_ptr listenerFactory ); } // namespace Detail class IEventListener; @@ -97,7 +96,7 @@ namespace Catch { public: ListenerRegistrar(StringRef listenerName) { - getMutableRegistryHub().registerListener( Detail::make_unique(listenerName) ); + registerListenerImpl( Detail::make_unique(listenerName) ); } }; } @@ -118,7 +117,7 @@ namespace Catch { CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace { \ Catch::ListenerRegistrar INTERNAL_CATCH_UNIQUE_NAME( \ - catch_internal_RegistrarFor )( #listenerType ); \ + catch_internal_RegistrarFor )( #listenerType##_catch_sr ); \ } \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION diff --git a/src/catch2/reporters/catch_reporter_sonarqube.cpp b/src/catch2/reporters/catch_reporter_sonarqube.cpp index 365979f4..9c391b1f 100644 --- a/src/catch2/reporters/catch_reporter_sonarqube.cpp +++ b/src/catch2/reporters/catch_reporter_sonarqube.cpp @@ -40,7 +40,7 @@ namespace Catch { } void SonarQubeReporter::writeRun( TestRunNode const& runNode ) { - std::map> testsPerFile; + std::map> testsPerFile; for ( auto const& child : runNode.children ) { testsPerFile[child->value.testInfo->lineInfo.file].push_back( @@ -52,7 +52,7 @@ namespace Catch { } } - void SonarQubeReporter::writeTestFile(std::string const& filename, std::vector const& testCaseNodes) { + void SonarQubeReporter::writeTestFile(StringRef filename, std::vector const& testCaseNodes) { XmlWriter::ScopedElement e = xml.scopedElement("file"); xml.writeAttribute("path"_sr, filename); @@ -97,7 +97,8 @@ namespace Catch { void SonarQubeReporter::writeAssertion(AssertionStats const& stats, bool okToFail) { AssertionResult const& result = stats.assertionResult; - if (!result.isOk()) { + if ( !result.isOk() || + result.getResultType() == ResultWas::ExplicitSkip ) { std::string elementName; if (okToFail) { elementName = "skipped"; @@ -108,15 +109,13 @@ namespace Catch { elementName = "error"; break; case ResultWas::ExplicitFailure: - elementName = "failure"; - break; case ResultWas::ExpressionFailed: - elementName = "failure"; - break; case ResultWas::DidntThrowException: elementName = "failure"; break; - + case ResultWas::ExplicitSkip: + elementName = "skipped"; + break; // We should never see these here: case ResultWas::Info: case ResultWas::Warning: @@ -136,7 +135,9 @@ namespace Catch { xml.writeAttribute("message"_sr, messageRss.str()); ReusableStringStream textRss; - if (stats.totals.assertions.total() > 0) { + if ( result.getResultType() == ResultWas::ExplicitSkip ) { + textRss << "SKIPPED\n"; + } else { textRss << "FAILED:\n"; if (result.hasExpression()) { textRss << '\t' << result.getExpressionInMacro() << '\n'; @@ -146,7 +147,7 @@ namespace Catch { } } - if (!result.getMessage().empty()) + if (result.hasMessage()) textRss << result.getMessage() << '\n'; for (auto const& msg : stats.infoMessages) diff --git a/src/catch2/reporters/catch_reporter_sonarqube.hpp b/src/catch2/reporters/catch_reporter_sonarqube.hpp index bc8f0332..cad6deec 100644 --- a/src/catch2/reporters/catch_reporter_sonarqube.hpp +++ b/src/catch2/reporters/catch_reporter_sonarqube.hpp @@ -41,7 +41,7 @@ namespace Catch { void writeRun( TestRunNode const& groupNode ); - void writeTestFile(std::string const& filename, std::vector const& testCaseNodes); + void writeTestFile(StringRef filename, std::vector const& testCaseNodes); void writeTestCase(TestCaseNode const& testCaseNode); diff --git a/src/catch2/reporters/catch_reporter_streaming_base.hpp b/src/catch2/reporters/catch_reporter_streaming_base.hpp index 13672a28..5448000c 100644 --- a/src/catch2/reporters/catch_reporter_streaming_base.hpp +++ b/src/catch2/reporters/catch_reporter_streaming_base.hpp @@ -8,7 +8,6 @@ #ifndef CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED #define CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED -#include #include #include diff --git a/src/catch2/reporters/catch_reporter_tap.cpp b/src/catch2/reporters/catch_reporter_tap.cpp index 59f8fb8b..67d406fb 100644 --- a/src/catch2/reporters/catch_reporter_tap.cpp +++ b/src/catch2/reporters/catch_reporter_tap.cpp @@ -14,7 +14,6 @@ #include #include -#include #include namespace Catch { @@ -100,6 +99,12 @@ namespace Catch { printIssue("explicitly"_sr); printRemainingMessages(Colour::None); break; + case ResultWas::ExplicitSkip: + printResultType(tapPassedString); + printIssue(" # SKIP"_sr); + printMessage(); + printRemainingMessages(); + break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: @@ -159,7 +164,7 @@ namespace Catch { // using messages.end() directly (or auto) yields compilation error: std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast(std::distance(itMessage, itEnd)); + const std::size_t N = static_cast(itEnd - itMessage); stream << colourImpl->guardColour( colour ) << " with " << pluralise( N, "message"_sr ) << ':'; @@ -178,7 +183,7 @@ namespace Catch { private: std::ostream& stream; AssertionResult const& result; - std::vector messages; + std::vector const& messages; std::vector::const_iterator itMessage; bool printInfoMessages; std::size_t counter; diff --git a/src/catch2/reporters/catch_reporter_teamcity.cpp b/src/catch2/reporters/catch_reporter_teamcity.cpp index 1d002c27..38aa55a6 100644 --- a/src/catch2/reporters/catch_reporter_teamcity.cpp +++ b/src/catch2/reporters/catch_reporter_teamcity.cpp @@ -45,7 +45,7 @@ namespace Catch { } // end anonymous namespace - TeamCityReporter::~TeamCityReporter() {} + TeamCityReporter::~TeamCityReporter() = default; void TeamCityReporter::testRunStarting( TestRunInfo const& runInfo ) { m_stream << "##teamcity[testSuiteStarted name='" << escape( runInfo.name ) @@ -59,7 +59,8 @@ namespace Catch { void TeamCityReporter::assertionEnded(AssertionStats const& assertionStats) { AssertionResult const& result = assertionStats.assertionResult; - if (!result.isOk()) { + if ( !result.isOk() || + result.getResultType() == ResultWas::ExplicitSkip ) { ReusableStringStream msg; if (!m_headerPrintedForThisSection) @@ -84,6 +85,9 @@ namespace Catch { case ResultWas::ExplicitFailure: msg << "explicit failure"; break; + case ResultWas::ExplicitSkip: + msg << "explicit skip"; + break; // We shouldn't get here because of the isOk() test case ResultWas::Ok: @@ -111,18 +115,16 @@ namespace Catch { " " << result.getExpandedExpression() << '\n'; } - if (currentTestCaseInfo->okToFail()) { + if ( result.getResultType() == ResultWas::ExplicitSkip ) { + m_stream << "##teamcity[testIgnored"; + } else if ( currentTestCaseInfo->okToFail() ) { msg << "- failure ignore as test marked as 'ok to fail'\n"; - m_stream << "##teamcity[testIgnored" - << " name='" << escape(currentTestCaseInfo->name) << '\'' - << " message='" << escape(msg.str()) << '\'' - << "]\n"; + m_stream << "##teamcity[testIgnored"; } else { - m_stream << "##teamcity[testFailed" - << " name='" << escape(currentTestCaseInfo->name) << '\'' - << " message='" << escape(msg.str()) << '\'' - << "]\n"; + m_stream << "##teamcity[testFailed"; } + m_stream << " name='" << escape( currentTestCaseInfo->name ) << '\'' + << " message='" << escape( msg.str() ) << '\'' << "]\n"; } m_stream.flush(); } diff --git a/src/catch2/reporters/catch_reporter_xml.cpp b/src/catch2/reporters/catch_reporter_xml.cpp index 57fa1cab..35a3028e 100644 --- a/src/catch2/reporters/catch_reporter_xml.cpp +++ b/src/catch2/reporters/catch_reporter_xml.cpp @@ -56,7 +56,7 @@ namespace Catch { m_xml.startElement("Catch2TestRun") .writeAttribute("name"_sr, m_config->name()) .writeAttribute("rng-seed"_sr, m_config->rngSeed()) - .writeAttribute("xml-format-version"_sr, 2) + .writeAttribute("xml-format-version"_sr, 3) .writeAttribute("catch2-version"_sr, libraryVersion()); if ( m_config->testSpec().hasFilters() ) { m_xml.writeAttribute( "filters"_sr, m_config->testSpec() ); @@ -66,7 +66,7 @@ namespace Catch { void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ) - .writeAttribute( "name"_sr, trim( testInfo.name ) ) + .writeAttribute( "name"_sr, trim( StringRef(testInfo.name) ) ) .writeAttribute( "tags"_sr, testInfo.tagsAsString() ); writeSourceInfo( testInfo.lineInfo ); @@ -80,7 +80,7 @@ namespace Catch { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) - .writeAttribute( "name"_sr, trim( sectionInfo.name ) ); + .writeAttribute( "name"_sr, trim( StringRef(sectionInfo.name) ) ); writeSourceInfo( sectionInfo.lineInfo ); m_xml.ensureTagClosed(); } @@ -98,19 +98,22 @@ namespace Catch { // Print any info messages in tags. for( auto const& msg : assertionStats.infoMessages ) { if( msg.type == ResultWas::Info && includeResults ) { - m_xml.scopedElement( "Info" ) - .writeText( msg.message ); + auto t = m_xml.scopedElement( "Info" ); + writeSourceInfo( msg.lineInfo ); + t.writeText( msg.message ); } else if ( msg.type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( msg.message ); + auto t = m_xml.scopedElement( "Warning" ); + writeSourceInfo( msg.lineInfo ); + t.writeText( msg.message ); } } } // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) + if ( !includeResults && result.getResultType() != ResultWas::Warning && + result.getResultType() != ResultWas::ExplicitSkip ) { return; - + } // Print the expression if there is one. if( result.hasExpression() ) { @@ -153,6 +156,12 @@ namespace Catch { m_xml.writeText( result.getMessage() ); m_xml.endElement(); break; + case ResultWas::ExplicitSkip: + m_xml.startElement( "Skip" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; default: break; } @@ -163,15 +172,18 @@ namespace Catch { void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { StreamingReporterBase::sectionEnded( sectionStats ); - if( --m_sectionDepth > 0 ) { - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); - e.writeAttribute( "successes"_sr, sectionStats.assertions.passed ); - e.writeAttribute( "failures"_sr, sectionStats.assertions.failed ); - e.writeAttribute( "expectedFailures"_sr, sectionStats.assertions.failedButOk ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds"_sr, sectionStats.durationInSeconds ); + if ( --m_sectionDepth > 0 ) { + { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes"_sr, sectionStats.assertions.passed ); + e.writeAttribute( "failures"_sr, sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures"_sr, sectionStats.assertions.failedButOk ); + e.writeAttribute( "skipped"_sr, sectionStats.assertions.skipped > 0 ); + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds"_sr, sectionStats.durationInSeconds ); + } + // Ends assertion tag m_xml.endElement(); } } @@ -180,14 +192,14 @@ namespace Catch { StreamingReporterBase::testCaseEnded( testCaseStats ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); e.writeAttribute( "success"_sr, testCaseStats.totals.assertions.allOk() ); + e.writeAttribute( "skips"_sr, testCaseStats.totals.assertions.skipped ); if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() ); - if( !testCaseStats.stdOut.empty() ) - m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline ); + m_xml.scopedElement( "StdOut" ).writeText( trim( StringRef(testCaseStats.stdOut) ), XmlFormatting::Newline ); if( !testCaseStats.stdErr.empty() ) - m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline ); + m_xml.scopedElement( "StdErr" ).writeText( trim( StringRef(testCaseStats.stdErr) ), XmlFormatting::Newline ); m_xml.endElement(); } @@ -197,11 +209,13 @@ namespace Catch { m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes"_sr, testRunStats.totals.assertions.passed ) .writeAttribute( "failures"_sr, testRunStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures"_sr, testRunStats.totals.assertions.failedButOk ); + .writeAttribute( "expectedFailures"_sr, testRunStats.totals.assertions.failedButOk ) + .writeAttribute( "skips"_sr, testRunStats.totals.assertions.skipped ); m_xml.scopedElement( "OverallResultsCases") .writeAttribute( "successes"_sr, testRunStats.totals.testCases.passed ) .writeAttribute( "failures"_sr, testRunStats.totals.testCases.failed ) - .writeAttribute( "expectedFailures"_sr, testRunStats.totals.testCases.failedButOk ); + .writeAttribute( "expectedFailures"_sr, testRunStats.totals.testCases.failedButOk ) + .writeAttribute( "skips"_sr, testRunStats.totals.testCases.skipped ); m_xml.endElement(); } @@ -220,26 +234,23 @@ namespace Catch { } void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { - m_xml.startElement("mean") + m_xml.scopedElement("mean") .writeAttribute("value"_sr, benchmarkStats.mean.point.count()) .writeAttribute("lowerBound"_sr, benchmarkStats.mean.lower_bound.count()) .writeAttribute("upperBound"_sr, benchmarkStats.mean.upper_bound.count()) .writeAttribute("ci"_sr, benchmarkStats.mean.confidence_interval); - m_xml.endElement(); - m_xml.startElement("standardDeviation") + m_xml.scopedElement("standardDeviation") .writeAttribute("value"_sr, benchmarkStats.standardDeviation.point.count()) .writeAttribute("lowerBound"_sr, benchmarkStats.standardDeviation.lower_bound.count()) .writeAttribute("upperBound"_sr, benchmarkStats.standardDeviation.upper_bound.count()) .writeAttribute("ci"_sr, benchmarkStats.standardDeviation.confidence_interval); - m_xml.endElement(); - m_xml.startElement("outliers") + m_xml.scopedElement("outliers") .writeAttribute("variance"_sr, benchmarkStats.outlierVariance) .writeAttribute("lowMild"_sr, benchmarkStats.outliers.low_mild) .writeAttribute("lowSevere"_sr, benchmarkStats.outliers.low_severe) .writeAttribute("highMild"_sr, benchmarkStats.outliers.high_mild) .writeAttribute("highSevere"_sr, benchmarkStats.outliers.high_severe); m_xml.endElement(); - m_xml.endElement(); } void XmlReporter::benchmarkFailed(StringRef error) { diff --git a/src/catch2/reporters/catch_reporters_all.hpp b/src/catch2/reporters/catch_reporters_all.hpp index 16f7bd70..5c713fe1 100644 --- a/src/catch2/reporters/catch_reporters_all.hpp +++ b/src/catch2/reporters/catch_reporters_all.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b40fbceb..d3ab14a7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -77,6 +77,8 @@ endif(MSVC) #Temporary workaround # Please keep these ordered alphabetically set(TEST_SOURCES ${SELF_TEST_DIR}/TestRegistrations.cpp + ${SELF_TEST_DIR}/IntrospectiveTests/Algorithms.tests.cpp + ${SELF_TEST_DIR}/IntrospectiveTests/AssertionHandler.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/Clara.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/CmdLine.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/CmdLineHelpers.tests.cpp @@ -84,7 +86,9 @@ set(TEST_SOURCES ${SELF_TEST_DIR}/IntrospectiveTests/Details.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/FloatingPoint.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/GeneratorsImpl.tests.cpp + ${SELF_TEST_DIR}/IntrospectiveTests/Integer.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/InternalBenchmark.tests.cpp + ${SELF_TEST_DIR}/IntrospectiveTests/Json.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/Parse.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/PartTracker.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/RandomNumberGeneration.tests.cpp @@ -116,6 +120,7 @@ set(TEST_SOURCES ${SELF_TEST_DIR}/UsageTests/Generators.tests.cpp ${SELF_TEST_DIR}/UsageTests/Message.tests.cpp ${SELF_TEST_DIR}/UsageTests/Misc.tests.cpp + ${SELF_TEST_DIR}/UsageTests/Skip.tests.cpp ${SELF_TEST_DIR}/UsageTests/ToStringByte.tests.cpp ${SELF_TEST_DIR}/UsageTests/ToStringChrono.tests.cpp ${SELF_TEST_DIR}/UsageTests/ToStringGeneral.tests.cpp @@ -133,6 +138,7 @@ set(TEST_SOURCES set(TEST_HEADERS ${SELF_TEST_DIR}/helpers/parse_test_spec.hpp + ${SELF_TEST_DIR}/helpers/range_test_helpers.hpp ${SELF_TEST_DIR}/helpers/type_with_lit_0_comparisons.hpp ) @@ -272,6 +278,10 @@ add_test(NAME TestSpecs::OverrideFailureWithNoMatchedTests COMMAND $ "___nonexistent_test___" --allow-running-no-tests ) +add_test(NAME TestSpecs::OverrideAllSkipFailure + COMMAND $ "tests can be skipped dynamically at runtime" --allow-running-no-tests +) + add_test(NAME TestSpecs::NonMatchingTestSpecIsRoundTrippable COMMAND $ Tracker, "this test does not exist" "[nor does this tag]" ) @@ -615,6 +625,18 @@ if (CATCH_ENABLE_CONFIGURE_TESTS) endforeach() endif() +if (CATCH_ENABLE_CMAKE_HELPER_TESTS) + add_test(NAME "CMakeHelper::DiscoverTests" + COMMAND + "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_LIST_DIR}/TestScripts/DiscoverTests/VerifyRegistration.py" "${CATCH_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" + ) + set_tests_properties("CMakeHelper::DiscoverTests" + PROPERTIES + COST 240 + LABELS "uses-python" + ) +endif() + foreach (reporterName # "Automake" - the simple .trs format does not support any kind of comments/metadata "compact" "console" @@ -622,7 +644,8 @@ foreach (reporterName # "Automake" - the simple .trs format does not support any "SonarQube" "TAP" # "TeamCity" - does not seem to support test suite-level metadata/comments - "XML") + "XML" + "JSON") add_test(NAME "Reporters:Filters:${reporterName}" COMMAND @@ -632,6 +655,8 @@ foreach (reporterName # "Automake" - the simple .trs format does not support any # Different regex for these two reporters, because the commas end up xml-escaped if (reporterName MATCHES "JUnit|XML") set(testCaseNameFormat ""CaseInsensitiveLess is case insensitive"") + elseif(reporterName MATCHES "JSON") + set(testCaseNameFormat "\\\\\"CaseInsensitiveLess is case insensitive\\\\\"") else() set(testCaseNameFormat "\"CaseInsensitiveLess is case insensitive\"") endif() diff --git a/tests/ExtraTests/CMakeLists.txt b/tests/ExtraTests/CMakeLists.txt index d5b27fba..2a810e25 100644 --- a/tests/ExtraTests/CMakeLists.txt +++ b/tests/ExtraTests/CMakeLists.txt @@ -468,6 +468,17 @@ set_tests_properties( ) +add_executable(AssertionStartingEventGoesBeforeAssertionIsEvaluated + X20-AssertionStartingEventGoesBeforeAssertionIsEvaluated.cpp +) +target_link_libraries(AssertionStartingEventGoesBeforeAssertionIsEvaluated + PRIVATE Catch2::Catch2WithMain +) +add_test( + NAME ReporterEvents::AssertionStartingHappensBeforeAssertionIsEvaluated + COMMAND $ +) + #add_executable(DebugBreakMacros ${TESTS_DIR}/X12-CustomDebugBreakMacro.cpp) #target_link_libraries(DebugBreakMacros Catch2) #add_test(NAME DebugBreakMacros COMMAND DebugBreakMacros --break) @@ -488,15 +499,32 @@ set_tests_properties(TestSpecs::EmptySpecWithNoTestsFails PROPERTIES WILL_FAIL ON ) + add_test( NAME TestSpecs::OverrideFailureWithEmptySpec COMMAND $ --allow-running-no-tests ) + add_test( NAME List::Listeners::WorksWithoutRegisteredListeners COMMAND $ --list-listeners ) + + +add_executable(AllSkipped ${TESTS_DIR}/X93-AllSkipped.cpp) +target_link_libraries(AllSkipped PRIVATE Catch2::Catch2WithMain) + +add_test( + NAME TestSpecs::SkippingAllTestsFails + COMMAND $ +) +set_tests_properties(TestSpecs::SkippingAllTestsFails + PROPERTIES + WILL_FAIL ON +) + set( EXTRA_TEST_BINARIES + AllSkipped PrefixedMacros DisabledMacros DisabledExceptions-DefaultHandler diff --git a/tests/ExtraTests/X20-AssertionStartingEventGoesBeforeAssertionIsEvaluated.cpp b/tests/ExtraTests/X20-AssertionStartingEventGoesBeforeAssertionIsEvaluated.cpp new file mode 100644 index 00000000..6f44bf69 --- /dev/null +++ b/tests/ExtraTests/X20-AssertionStartingEventGoesBeforeAssertionIsEvaluated.cpp @@ -0,0 +1,77 @@ + +// 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 + * Registers an event listener to increments counter of assertionStarting events. + * + * Different assertion macros then check that the counter is at expected + * value when they are evaluated. + */ + +#include +#include +#include +#include + +namespace { + + static size_t assertion_starting_events_seen = 0; + + class AssertionStartingListener : public Catch::EventListenerBase { + public: + AssertionStartingListener( Catch::IConfig const* config ): + EventListenerBase( config ) {} + + void assertionStarting( Catch::AssertionInfo const& ) override { + ++assertion_starting_events_seen; + } + }; + + static bool f1() { + return assertion_starting_events_seen == 1; + } + + static void f2() { + if ( assertion_starting_events_seen != 2 ) { throw 1; } + } + + static void f3() { + if ( assertion_starting_events_seen == 3 ) { throw 1; } + } + + static bool f4() { return assertion_starting_events_seen == 4; } + + static void f5() { throw assertion_starting_events_seen; } + +} // anonymous namespace + +CATCH_REGISTER_LISTENER( AssertionStartingListener ) + +TEST_CASE() { + // **IMPORTANT** + // The order of assertions below matters. + REQUIRE( f1() ); + REQUIRE_NOTHROW( f2() ); + REQUIRE_THROWS( f3() ); + REQUIRE_THAT( f4(), + Catch::Matchers::Predicate( []( bool b ) { return b; } ) ); + REQUIRE_THROWS_MATCHES( + f5(), size_t, Catch::Matchers::Predicate( []( size_t i ) { + return i == 5; + } ) ); + + CAPTURE( assertion_starting_events_seen ); // **not** an assertion + INFO( "some info msg" ); // **not** an assertion + WARN( "warning! warning!" ); // assertion-like message + SUCCEED(); // assertion-like message + + // We skip FAIL/SKIP and so on, which fail the test. + + // This require will also increment the count once + REQUIRE( assertion_starting_events_seen == 8 ); +} diff --git a/src/catch2/interfaces/catch_interfaces_reporter_registry.cpp b/tests/ExtraTests/X93-AllSkipped.cpp similarity index 51% rename from src/catch2/interfaces/catch_interfaces_reporter_registry.cpp rename to tests/ExtraTests/X93-AllSkipped.cpp index f620cbc8..8e7d0afe 100644 --- a/src/catch2/interfaces/catch_interfaces_reporter_registry.cpp +++ b/tests/ExtraTests/X93-AllSkipped.cpp @@ -6,8 +6,11 @@ // SPDX-License-Identifier: BSL-1.0 -#include +#include -namespace Catch { - IReporterRegistry::~IReporterRegistry() = default; +TEST_CASE( "this test case is being skipped" ) { SKIP(); } + +TEST_CASE( "all sections in this test case are being skipped" ) { + SECTION( "A" ) { SKIP(); } + SECTION( "B" ) { SKIP(); } } diff --git a/tests/SelfTest/Baselines/automake.sw.approved.txt b/tests/SelfTest/Baselines/automake.sw.approved.txt index e29de92b..88c23e17 100644 --- a/tests/SelfTest/Baselines/automake.sw.approved.txt +++ b/tests/SelfTest/Baselines/automake.sw.approved.txt @@ -25,6 +25,7 @@ Nor would this :test-result: PASS #1954 - 7 arg template test case sig compiles - 5, 3, 1, 1, 1, 0, 0 :test-result: PASS #2152 - ULP checks between differently signed values were wrong - double :test-result: PASS #2152 - ULP checks between differently signed values were wrong - float +:test-result: XFAIL #2615 - Throwing in constructor generator fails test case but does not abort :test-result: XFAIL #748 - captures with unexpected exceptions :test-result: PASS #809 :test-result: PASS #833 @@ -129,8 +130,8 @@ Nor would this :test-result: FAIL Custom std-exceptions can be custom translated :test-result: PASS Default scale is invisible to comparison :test-result: PASS Directly creating an EnumInfo +:test-result: SKIP Empty generators can SKIP in constructor :test-result: PASS Empty stream name opens cout stream -:test-result: PASS Empty tag is not allowed :test-result: FAIL EndsWith string matcher :test-result: PASS Enums can quickly have stringification enabled using REGISTER_ENUM :test-result: PASS Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM @@ -142,6 +143,7 @@ Nor would this :test-result: PASS Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified :test-result: FAIL Exception matchers that fail :test-result: PASS Exception matchers that succeed +:test-result: PASS Exception message can be matched :test-result: PASS Exception messages can be tested for :test-result: PASS Exceptions matchers :test-result: FAIL Expected exceptions that don't throw or unexpected exceptions fail the test @@ -149,8 +151,10 @@ Nor would this :test-result: FAIL FAIL does not require an argument :test-result: FAIL FAIL_CHECK does not abort the test :test-result: PASS Factorials are computed +:test-result: PASS Filter generator throws exception for empty generator :test-result: PASS Floating point matchers: double :test-result: PASS Floating point matchers: float +:test-result: PASS GENERATE can combine literals and generators :test-result: PASS Generators -- adapters :test-result: PASS Generators -- simple :test-result: PASS Generators internals @@ -159,12 +163,16 @@ Nor would this :test-result: PASS Hashers with same seed produce same hash :test-result: PASS Hashing different test cases produces different result :test-result: PASS Hashing test case produces same hash across multiple calls +:test-result: FAIL INFO and UNSCOPED_INFO can stream multiple arguments :test-result: FAIL INFO and WARN do not abort tests :test-result: FAIL INFO gets logged on failure :test-result: FAIL INFO gets logged on failure, even if captured before successful assertions :test-result: FAIL INFO is reset for each loop +:test-result: XFAIL Incomplete AssertionHandler :test-result: XFAIL Inequality checks that should fail :test-result: PASS Inequality checks that should succeed +:test-result: PASS JsonWriter +:test-result: PASS JsonWriter escapes charaters in strings properly :test-result: PASS Lambdas in assertions :test-result: PASS Less-than inequalities with different epsilons :test-result: PASS ManuallyRegistered @@ -262,12 +270,15 @@ Message from section two :test-result: PASS Testing checked-if :test-result: XFAIL Testing checked-if 2 :test-result: XFAIL Testing checked-if 3 +:test-result: XFAIL Testing checked-if 4 +:test-result: XFAIL Testing checked-if 5 :test-result: FAIL The NO_FAIL macro reports a failure but does not fail the test :test-result: PASS The default listing implementation write to provided stream :test-result: FAIL This test 'should' fail but doesn't :test-result: FAIL Thrown string literals are translated :test-result: PASS Tracker :test-result: PASS Trim strings +:test-result: PASS Type conversions of RangeEquals and similar :test-result: FAIL Unexpected exceptions can be translated :test-result: PASS Upcasting special member functions :test-result: PASS Usage of AllMatch range matcher @@ -276,6 +287,8 @@ Message from section two :test-result: PASS Usage of AnyTrue range matcher :test-result: PASS Usage of NoneMatch range matcher :test-result: PASS Usage of NoneTrue range matcher +:test-result: PASS Usage of RangeEquals range matcher +:test-result: PASS Usage of UnorderedRangeEquals range matcher :test-result: PASS Usage of the SizeIs range matcher :test-result: PASS Use a custom approx :test-result: PASS Variadic macros @@ -296,6 +309,7 @@ Message from section two :test-result: PASS X/level/1/b :test-result: PASS XmlEncode :test-result: PASS XmlWriter writes boolean attributes as true/false +:test-result: SKIP a succeeding test can still be skipped :test-result: PASS analyse no analysis :test-result: PASS array -> toString :test-result: PASS benchmark function call @@ -308,10 +322,14 @@ Message from section two :test-result: PASS comparisons between const int variables :test-result: PASS comparisons between int variables :test-result: PASS convertToBits +:test-result: SKIP dynamic skipping works with generators :test-result: PASS empty tags are not allowed :test-result: PASS erfc_inv :test-result: PASS estimate_clock_resolution :test-result: PASS even more nested SECTION tests +:test-result: XFAIL failed assertions before SKIP cause test case to fail +:test-result: XFAIL failing for some generator values causes entire test case to fail +:test-result: XFAIL failing in some unskipped sections causes entire test case to fail :test-result: FAIL first tag loose text artifact :test-result: FAIL has printf @@ -330,6 +348,10 @@ loose text artifact :test-result: FAIL mix info, unscoped info and warning :test-result: FAIL more nested SECTION tests :test-result: PASS nested SECTION tests +a! +b1! +! +:test-result: FAIL nested sections can be skipped dynamically at runtime :test-result: PASS non streamable - with conv. op :test-result: PASS non-copyable objects :test-result: PASS normal_cdf @@ -351,9 +373,11 @@ loose text artifact :test-result: PASS run_for_at_least, chronometer :test-result: PASS run_for_at_least, int :test-result: FAIL second tag +:test-result: SKIP sections can be skipped dynamically at runtime :test-result: FAIL send a single char to INFO :test-result: FAIL sends information to INFO :test-result: PASS shortened hide tags are split apart +:test-result: SKIP skipped tests can optionally provide a reason :test-result: PASS splitString :test-result: FAIL stacks unscoped info in loops :test-result: PASS startsWith @@ -375,6 +399,7 @@ loose text artifact :test-result: PASS strlen3 :test-result: PASS tables :test-result: PASS tags with dots in later positions are not parsed as hidden +:test-result: SKIP tests can be skipped dynamically at runtime :test-result: FAIL thrown std::strings are translated :test-result: PASS toString on const wchar_t const pointer returns the string contents :test-result: PASS toString on const wchar_t pointer returns the string contents @@ -390,6 +415,7 @@ loose text artifact :test-result: PASS tuple :test-result: PASS tuple,tuple<>,float> :test-result: PASS uniform samples +:test-result: PASS uniform_integer_distribution can return the bounds :test-result: PASS unique_ptr reimplementation: basic functionality :test-result: PASS vec> -> toString :test-result: PASS vector -> toString diff --git a/tests/SelfTest/Baselines/automake.sw.multi.approved.txt b/tests/SelfTest/Baselines/automake.sw.multi.approved.txt index 3ac53920..a37b1a2b 100644 --- a/tests/SelfTest/Baselines/automake.sw.multi.approved.txt +++ b/tests/SelfTest/Baselines/automake.sw.multi.approved.txt @@ -23,6 +23,7 @@ :test-result: PASS #1954 - 7 arg template test case sig compiles - 5, 3, 1, 1, 1, 0, 0 :test-result: PASS #2152 - ULP checks between differently signed values were wrong - double :test-result: PASS #2152 - ULP checks between differently signed values were wrong - float +:test-result: XFAIL #2615 - Throwing in constructor generator fails test case but does not abort :test-result: XFAIL #748 - captures with unexpected exceptions :test-result: PASS #809 :test-result: PASS #833 @@ -127,8 +128,8 @@ :test-result: FAIL Custom std-exceptions can be custom translated :test-result: PASS Default scale is invisible to comparison :test-result: PASS Directly creating an EnumInfo +:test-result: SKIP Empty generators can SKIP in constructor :test-result: PASS Empty stream name opens cout stream -:test-result: PASS Empty tag is not allowed :test-result: FAIL EndsWith string matcher :test-result: PASS Enums can quickly have stringification enabled using REGISTER_ENUM :test-result: PASS Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM @@ -140,6 +141,7 @@ :test-result: PASS Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified :test-result: FAIL Exception matchers that fail :test-result: PASS Exception matchers that succeed +:test-result: PASS Exception message can be matched :test-result: PASS Exception messages can be tested for :test-result: PASS Exceptions matchers :test-result: FAIL Expected exceptions that don't throw or unexpected exceptions fail the test @@ -147,8 +149,10 @@ :test-result: FAIL FAIL does not require an argument :test-result: FAIL FAIL_CHECK does not abort the test :test-result: PASS Factorials are computed +:test-result: PASS Filter generator throws exception for empty generator :test-result: PASS Floating point matchers: double :test-result: PASS Floating point matchers: float +:test-result: PASS GENERATE can combine literals and generators :test-result: PASS Generators -- adapters :test-result: PASS Generators -- simple :test-result: PASS Generators internals @@ -157,12 +161,16 @@ :test-result: PASS Hashers with same seed produce same hash :test-result: PASS Hashing different test cases produces different result :test-result: PASS Hashing test case produces same hash across multiple calls +:test-result: FAIL INFO and UNSCOPED_INFO can stream multiple arguments :test-result: FAIL INFO and WARN do not abort tests :test-result: FAIL INFO gets logged on failure :test-result: FAIL INFO gets logged on failure, even if captured before successful assertions :test-result: FAIL INFO is reset for each loop +:test-result: XFAIL Incomplete AssertionHandler :test-result: XFAIL Inequality checks that should fail :test-result: PASS Inequality checks that should succeed +:test-result: PASS JsonWriter +:test-result: PASS JsonWriter escapes charaters in strings properly :test-result: PASS Lambdas in assertions :test-result: PASS Less-than inequalities with different epsilons :test-result: PASS ManuallyRegistered @@ -255,12 +263,15 @@ :test-result: PASS Testing checked-if :test-result: XFAIL Testing checked-if 2 :test-result: XFAIL Testing checked-if 3 +:test-result: XFAIL Testing checked-if 4 +:test-result: XFAIL Testing checked-if 5 :test-result: FAIL The NO_FAIL macro reports a failure but does not fail the test :test-result: PASS The default listing implementation write to provided stream :test-result: FAIL This test 'should' fail but doesn't :test-result: FAIL Thrown string literals are translated :test-result: PASS Tracker :test-result: PASS Trim strings +:test-result: PASS Type conversions of RangeEquals and similar :test-result: FAIL Unexpected exceptions can be translated :test-result: PASS Upcasting special member functions :test-result: PASS Usage of AllMatch range matcher @@ -269,6 +280,8 @@ :test-result: PASS Usage of AnyTrue range matcher :test-result: PASS Usage of NoneMatch range matcher :test-result: PASS Usage of NoneTrue range matcher +:test-result: PASS Usage of RangeEquals range matcher +:test-result: PASS Usage of UnorderedRangeEquals range matcher :test-result: PASS Usage of the SizeIs range matcher :test-result: PASS Use a custom approx :test-result: PASS Variadic macros @@ -289,6 +302,7 @@ :test-result: PASS X/level/1/b :test-result: PASS XmlEncode :test-result: PASS XmlWriter writes boolean attributes as true/false +:test-result: SKIP a succeeding test can still be skipped :test-result: PASS analyse no analysis :test-result: PASS array -> toString :test-result: PASS benchmark function call @@ -301,10 +315,14 @@ :test-result: PASS comparisons between const int variables :test-result: PASS comparisons between int variables :test-result: PASS convertToBits +:test-result: SKIP dynamic skipping works with generators :test-result: PASS empty tags are not allowed :test-result: PASS erfc_inv :test-result: PASS estimate_clock_resolution :test-result: PASS even more nested SECTION tests +:test-result: XFAIL failed assertions before SKIP cause test case to fail +:test-result: XFAIL failing for some generator values causes entire test case to fail +:test-result: XFAIL failing in some unskipped sections causes entire test case to fail :test-result: FAIL first tag :test-result: FAIL has printf :test-result: PASS is_unary_function @@ -322,6 +340,7 @@ :test-result: FAIL mix info, unscoped info and warning :test-result: FAIL more nested SECTION tests :test-result: PASS nested SECTION tests +:test-result: FAIL nested sections can be skipped dynamically at runtime :test-result: PASS non streamable - with conv. op :test-result: PASS non-copyable objects :test-result: PASS normal_cdf @@ -343,9 +362,11 @@ :test-result: PASS run_for_at_least, chronometer :test-result: PASS run_for_at_least, int :test-result: FAIL second tag +:test-result: SKIP sections can be skipped dynamically at runtime :test-result: FAIL send a single char to INFO :test-result: FAIL sends information to INFO :test-result: PASS shortened hide tags are split apart +:test-result: SKIP skipped tests can optionally provide a reason :test-result: PASS splitString :test-result: FAIL stacks unscoped info in loops :test-result: PASS startsWith @@ -367,6 +388,7 @@ :test-result: PASS strlen3 :test-result: PASS tables :test-result: PASS tags with dots in later positions are not parsed as hidden +:test-result: SKIP tests can be skipped dynamically at runtime :test-result: FAIL thrown std::strings are translated :test-result: PASS toString on const wchar_t const pointer returns the string contents :test-result: PASS toString on const wchar_t pointer returns the string contents @@ -382,6 +404,7 @@ :test-result: PASS tuple :test-result: PASS tuple,tuple<>,float> :test-result: PASS uniform samples +:test-result: PASS uniform_integer_distribution can return the bounds :test-result: PASS unique_ptr reimplementation: basic functionality :test-result: PASS vec> -> toString :test-result: PASS vector -> toString diff --git a/tests/SelfTest/Baselines/compact.sw.approved.txt b/tests/SelfTest/Baselines/compact.sw.approved.txt index 5073c080..0669fdbb 100644 --- a/tests/SelfTest/Baselines/compact.sw.approved.txt +++ b/tests/SelfTest/Baselines/compact.sw.approved.txt @@ -84,6 +84,7 @@ Matchers.tests.cpp:: passed: smallest_non_zero, WithinULP( -smalles Matchers.tests.cpp:: passed: smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) for: 0.0 not is within 1 ULPs of -4.9406564584124654e-324 ([-9.8813129168249309e-324, -0.0000000000000000e+00]) Matchers.tests.cpp:: passed: smallest_non_zero, WithinULP( -smallest_non_zero, 2 ) for: 0.0f is within 2 ULPs of -1.40129846e-45f ([-4.20389539e-45, 1.40129846e-45]) Matchers.tests.cpp:: passed: smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) for: 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0.00000000e+00]) +Generators.tests.cpp:: failed: unexpected exception with message: 'failure to init' Exception.tests.cpp:: failed: unexpected exception with message: 'answer := 42' with 1 message: 'expected exception' Exception.tests.cpp:: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception' Exception.tests.cpp:: passed: thisThrows() with 1 message: 'answer := 42' @@ -330,7 +331,7 @@ MatchersRanges.tests.cpp:: passed: inner_lists_are_empty.front(), I MatchersRanges.tests.cpp:: passed: has_empty{}, !IsEmpty() for: {?} not is empty MatchersRanges.tests.cpp:: passed: unrelated::ADL_empty{}, IsEmpty() for: {?} is empty Message.tests.cpp:: passed: with 7 messages: 'a := 1' and 'b := 2' and 'c := 3' and 'a + b := 3' and 'a+b := 3' and 'c > b := true' and 'a == 1 := true' -Message.tests.cpp:: passed: with 7 messages: 'std::vector{1, 2, 3}[0, 1, 2] := 3' and 'std::vector{1, 2, 3}[(0, 1)] := 2' and 'std::vector{1, 2, 3}[0] := 1' and '(helper_1436{12, -12}) := { 12, -12 }' and '(helper_1436(-12, 12)) := { -12, 12 }' and '(1, 2) := 2' and '(2, 3) := 3' +Message.tests.cpp:: passed: with 7 messages: 'custom_index_op{1, 2, 3}[0, 1, 2] := 0' and 'custom_index_op{1, 2, 3}[(0, 1)] := 0' and 'custom_index_op{1, 2, 3}[0] := 0' and '(helper_1436{12, -12}) := { 12, -12 }' and '(helper_1436(-12, 12)) := { -12, 12 }' and '(1, 2) := 2' and '(2, 3) := 3' Message.tests.cpp:: passed: with 11 messages: '("comma, in string", "escaped, \", ") := "escaped, ", "' and '"single quote in string,'," := "single quote in string,',"' and '"some escapes, \\,\\\\" := "some escapes, \,\\"' and '"some, ), unmatched, } prenheses {[<" := "some, ), unmatched, } prenheses {[<"' and ''"' := '"'' and ''\'' := '''' and '',' := ','' and ''}' := '}'' and '')' := ')'' and ''(' := '('' and ''{' := '{'' ToStringGeneral.tests.cpp:: passed: true with 1 message: 'i := 2' ToStringGeneral.tests.cpp:: passed: true with 1 message: '3' @@ -519,8 +520,8 @@ ToString.tests.cpp:: passed: enumInfo->lookup(1) == "Value2" for: V ToString.tests.cpp:: passed: enumInfo->lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **} == "{** unexpected enum value **}" +Skip.tests.cpp:: skipped: 'This generator is empty' Stream.tests.cpp:: passed: Catch::makeStream( "" )->isConsole() for: true -Tag.tests.cpp:: passed: Catch::TestCaseInfo( "", { "fake test name", "[]" }, dummySourceLineInfo ) Matchers.tests.cpp:: failed: testStringForMatching(), EndsWith( "Substring" ) for: "this string contains 'abc' as a substring" ends with: "Substring" Matchers.tests.cpp:: failed: testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: "this" (case insensitive) EnumToString.tests.cpp:: passed: stringify( EnumClass3::Value1 ) == "Value1" for: "Value1" == "Value1" @@ -572,6 +573,10 @@ Matchers.tests.cpp:: failed: throwsSpecialException( 3 ), SpecialEx Matchers.tests.cpp:: failed: throwsSpecialException( 4 ), SpecialException, ExceptionMatcher{ 1 } for: SpecialException::what special exception has value of 1 Matchers.tests.cpp:: passed: throwsSpecialException( 1 ), SpecialException, ExceptionMatcher{ 1 } for: SpecialException::what special exception has value of 1 Matchers.tests.cpp:: passed: throwsSpecialException( 2 ), SpecialException, ExceptionMatcher{ 2 } for: SpecialException::what special exception has value of 2 +Matchers.tests.cpp:: passed: throwsDerivedException(), DerivedException, MessageMatches( StartsWith( "Derived" ) ) for: DerivedException::what matches "starts with: "Derived"" +Matchers.tests.cpp:: passed: throwsDerivedException(), DerivedException, MessageMatches( EndsWith( "::what" ) ) for: DerivedException::what matches "ends with: "::what"" +Matchers.tests.cpp:: passed: throwsDerivedException(), DerivedException, MessageMatches( !StartsWith( "::what" ) ) for: DerivedException::what matches "not starts with: "::what"" +Matchers.tests.cpp:: passed: throwsSpecialException( 2 ), SpecialException, MessageMatches( StartsWith( "Special" ) ) for: SpecialException::what matches "starts with: "Special"" Exception.tests.cpp:: passed: thisThrows(), "expected exception" for: "expected exception" equals: "expected exception" Exception.tests.cpp:: passed: thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expected exception" (case insensitive) Exception.tests.cpp:: passed: thisThrows(), StartsWith( "expected" ) for: "expected exception" starts with: "expected" @@ -594,6 +599,7 @@ Misc.tests.cpp:: passed: Factorial(1) == 1 for: 1 == 1 Misc.tests.cpp:: passed: Factorial(2) == 2 for: 2 == 2 Misc.tests.cpp:: passed: Factorial(3) == 6 for: 6 == 6 Misc.tests.cpp:: passed: Factorial(10) == 3628800 for: 3628800 (0x) == 3628800 (0x) +GeneratorsImpl.tests.cpp:: passed: filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException Matchers.tests.cpp:: passed: 10., WithinRel( 11.1, 0.1 ) for: 10.0 and 11.1 are within 10% of each other Matchers.tests.cpp:: passed: 10., !WithinRel( 11.2, 0.1 ) for: 10.0 not and 11.2 are within 10% of each other Matchers.tests.cpp:: passed: 1., !WithinRel( 0., 0.99 ) for: 1.0 not and 0 are within 99% of each other @@ -623,6 +629,7 @@ Matchers.tests.cpp:: passed: WithinULP( 1., 0 ) Matchers.tests.cpp:: passed: WithinRel( 1., 0. ) Matchers.tests.cpp:: passed: WithinRel( 1., -0.2 ), std::domain_error Matchers.tests.cpp:: passed: WithinRel( 1., 1. ), std::domain_error +Matchers.tests.cpp:: passed: 1., !IsNaN() for: 1.0 not is NaN Matchers.tests.cpp:: passed: 10.f, WithinRel( 11.1f, 0.1f ) for: 10.0f and 11.1 are within 10% of each other Matchers.tests.cpp:: passed: 10.f, !WithinRel( 11.2f, 0.1f ) for: 10.0f not and 11.2 are within 10% of each other Matchers.tests.cpp:: passed: 1.f, !WithinRel( 0.f, 0.99f ) for: 1.0f not and 0 are within 99% of each other @@ -655,6 +662,11 @@ Matchers.tests.cpp:: passed: WithinULP( 1.f, static_cast( Matchers.tests.cpp:: passed: WithinRel( 1.f, 0.f ) Matchers.tests.cpp:: passed: WithinRel( 1.f, -0.2f ), std::domain_error Matchers.tests.cpp:: passed: WithinRel( 1.f, 1.f ), std::domain_error +Matchers.tests.cpp:: passed: 1., !IsNaN() for: 1.0 not is NaN +Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 +Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 +Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 +Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 @@ -936,6 +948,7 @@ TestCaseInfoHasher.tests.cpp:: passed: h( dummy1 ) != h( dummy2 ) f TestCaseInfoHasher.tests.cpp:: passed: h( dummy ) == h( dummy ) for: 3422778688 (0x) == 3422778688 (0x) +Message.tests.cpp:: failed: explicitly with 3 messages: 'This info has multiple parts.' and 'This unscoped info has multiple parts.' and 'Show infos!' Message.tests.cpp:: warning: 'this is a message' with 1 message: 'this is a warning' Message.tests.cpp:: failed: a == 1 for: 2 == 1 with 2 messages: 'this message should be logged' and 'so should this' Message.tests.cpp:: passed: a == 2 for: 2 == 2 with 1 message: 'this message may be logged later' @@ -953,6 +966,7 @@ Message.tests.cpp:: passed: i < 10 for: 7 < 10 with 2 messages: 'cu Message.tests.cpp:: passed: i < 10 for: 8 < 10 with 2 messages: 'current counter 8' and 'i := 8' Message.tests.cpp:: passed: i < 10 for: 9 < 10 with 2 messages: 'current counter 9' and 'i := 9' Message.tests.cpp:: failed: i < 10 for: 10 < 10 with 2 messages: 'current counter 10' and 'i := 10' +AssertionHandler.tests.cpp:: failed: unexpected exception with message: 'Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE'; expression was: Dummy Condition.tests.cpp:: failed: data.int_seven != 7 for: 7 != 7 Condition.tests.cpp:: failed: data.float_nine_point_one != Approx( 9.1f ) for: 9.1f != Approx( 9.1000003815 ) Condition.tests.cpp:: failed: data.double_pi != Approx( 3.1415926535 ) for: 3.1415926535 != Approx( 3.1415926535 ) @@ -969,6 +983,91 @@ Condition.tests.cpp:: passed: data.str_hello != "goodbye" for: "hel Condition.tests.cpp:: passed: data.str_hello != "hell" for: "hello" != "hell" Condition.tests.cpp:: passed: data.str_hello != "hello1" for: "hello" != "hello1" Condition.tests.cpp:: passed: data.str_hello.size() != 6 for: 5 != 6 +Json.tests.cpp:: passed: stream.str() == "" for: "" == "" +Json.tests.cpp:: passed: stream.str() == "{\n}" for: "{ +}" +== +"{ +}" +Json.tests.cpp:: passed: stream.str(), ContainsSubstring( "\"int\": 1," ) && ContainsSubstring( "\"double\": 1.5," ) && ContainsSubstring( "\"true\": true," ) && ContainsSubstring( "\"false\": false," ) && ContainsSubstring( "\"string\": \"this is a string\"," ) && ContainsSubstring( "\"array\": [\n 1,\n 2\n ]\n}" ) for: "{ + "int": 1, + "double": 1.5, + "true": true, + "false": false, + "string": "this is a string", + "array": [ + 1, + 2 + ] +}" ( contains: ""int": 1," and contains: ""double": 1.5," and contains: ""true": true," and contains: ""false": false," and contains: ""string": "this is a string"," and contains: ""array": [ + 1, + 2 + ] +}" ) +Json.tests.cpp:: passed: stream.str(), ContainsSubstring( "\"empty_object\": {\n }," ) && ContainsSubstring( "\"fully_object\": {\n \"key\": 1\n }" ) for: "{ + "empty_object": { + }, + "fully_object": { + "key": 1 + } +}" ( contains: ""empty_object": { + }," and contains: ""fully_object": { + "key": 1 + }" ) +Json.tests.cpp:: passed: stream.str() == "[\n]" for: "[ +]" +== +"[ +]" +Json.tests.cpp:: passed: stream.str() == "[\n 1,\n 1.5,\n true,\n false,\n \"this is a string\",\n {\n \"object\": 42\n },\n [\n \"array\",\n 42.5\n ]\n]" for: "[ + 1, + 1.5, + true, + false, + "this is a string", + { + "object": 42 + }, + [ + "array", + 42.5 + ] +]" +== +"[ + 1, + 1.5, + true, + false, + "this is a string", + { + "object": 42 + }, + [ + "array", + 42.5 + ] +]" +Json.tests.cpp:: passed: stream.str() == "{\n}" for: "{ +}" +== +"{ +}" +Json.tests.cpp:: passed: stream.str() == "[\n]" for: "[ +]" +== +"[ +]" +Json.tests.cpp:: passed: stream.str() == "\"custom\"" for: ""custom"" == ""custom"" +Json.tests.cpp:: passed: sstream.str() == "\"\\\"\"" for: ""\""" == ""\""" +Json.tests.cpp:: passed: sstream.str() == "\"\\\\\"" for: ""\\"" == ""\\"" +Json.tests.cpp:: passed: sstream.str() == "\"/\"" for: ""/"" == ""/"" +Json.tests.cpp:: passed: sstream.str() == "\"\\b\"" for: ""\b"" == ""\b"" +Json.tests.cpp:: passed: sstream.str() == "\"\\f\"" for: ""\f"" == ""\f"" +Json.tests.cpp:: passed: sstream.str() == "\"\\n\"" for: ""\n"" == ""\n"" +Json.tests.cpp:: passed: sstream.str() == "\"\\r\"" for: ""\r"" == ""\r"" +Json.tests.cpp:: passed: sstream.str() == "\"\\t\"" for: ""\t"" == ""\t"" +Json.tests.cpp:: passed: sstream.str() == "\"\\\\/\\t\\r\\n\"" for: ""\\/\t\r\n"" == ""\\/\t\r\n"" Compilation.tests.cpp:: passed: []() { return true; }() for: true Approx.tests.cpp:: passed: d <= Approx( 1.24 ) for: 1.23 <= Approx( 1.24 ) Approx.tests.cpp:: passed: d <= Approx( 1.23 ) for: 1.23 <= Approx( 1.23 ) @@ -1333,6 +1432,60 @@ Reporters.tests.cpp:: passed: listingString, ContainsSubstring( "fa " ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: console' Reporters.tests.cpp:: passed: !(factories.empty()) for: !false +Reporters.tests.cpp:: passed: listingString, ContainsSubstring("fakeTag"s) for: "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "tags": [ + { + "aliases": [ + "fakeTag" + ], + "count": 1 + } + ]" contains: "fakeTag" with 1 message: 'Tested reporter: JSON' +Reporters.tests.cpp:: passed: !(factories.empty()) for: !false +Reporters.tests.cpp:: passed: listingString, ContainsSubstring("fake reporter"s) for: "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "reporters": [ + { + "name": "fake reporter", + "description": "fake description" + } + ]" contains: "fake reporter" with 1 message: 'Tested reporter: JSON' +Reporters.tests.cpp:: passed: !(factories.empty()) for: !false +Reporters.tests.cpp:: passed: listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) for: "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "tests": [ + { + "name": "fake test name", + "class-name": "", + "tags": [ + "fakeTestTag" + ], + "source-location": { + "filename": "fake-file.cpp", + "line": 123456789 + } + } + ]" ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: JSON' +Reporters.tests.cpp:: passed: !(factories.empty()) for: !false Reporters.tests.cpp:: passed: listingString, ContainsSubstring("fakeTag"s) for: " All available tags: 1 [fakeTag] @@ -1742,6 +1895,10 @@ Misc.tests.cpp:: passed: true Misc.tests.cpp:: failed: explicitly Misc.tests.cpp:: failed - but was ok: false Misc.tests.cpp:: failed: explicitly +Misc.tests.cpp:: passed: true +Misc.tests.cpp:: failed: unexpected exception with message: 'Uncaught exception should fail!'; expression was: {Unknown expression after the reported line} +Misc.tests.cpp:: failed - but was ok: false +Misc.tests.cpp:: failed: unexpected exception with message: 'Uncaught exception should fail!'; expression was: {Unknown expression after the reported line} Message.tests.cpp:: failed - but was ok: 1 == 2 Reporters.tests.cpp:: passed: listingString, ContainsSubstring("[fakeTag]"s) for: "All available tags: 1 [fakeTag] @@ -1855,6 +2012,23 @@ There is no extra whitespace here StringManip.tests.cpp:: passed: trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace) for: There is no extra whitespace here == There is no extra whitespace here +MatchersRanges.tests.cpp:: passed: array_int_a, RangeEquals( c_array ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_int_a, UnorderedRangeEquals( c_array ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_int_3, !RangeEquals( array_int_4 ) for: { 1, 2, 3 } not elements are { 1, 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: array_int_3, !UnorderedRangeEquals( array_int_4 ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: array_int_a, RangeEquals( vector_char_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_int_a, UnorderedRangeEquals( vector_char_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: with 1 message: 'ContainerIsRandomAccess( array_int_a ) != ContainerIsRandomAccess( list_char_a )' +MatchersRanges.tests.cpp:: passed: array_int_a, RangeEquals( list_char_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_int_a, UnorderedRangeEquals( list_char_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: vector_int_a, RangeEquals( vector_char_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: vector_int_a, UnorderedRangeEquals( vector_char_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: vector_int_a, !RangeEquals( vector_char_b ) for: { 1, 2, 3 } not elements are { 1, 2, 2 } +MatchersRanges.tests.cpp:: passed: vector_int_a, !UnorderedRangeEquals( vector_char_b ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 2 } +MatchersRanges.tests.cpp:: passed: a, !RangeEquals( b ) for: { 1, 2, 3 } not elements are { 3, 2, 1 } +MatchersRanges.tests.cpp:: passed: a, UnorderedRangeEquals( b ) for: { 1, 2, 3 } unordered elements are { 3, 2, 1 } +MatchersRanges.tests.cpp:: passed: vector_a, RangeEquals( array_a_plus_1, close_enough ) for: { 1, 2, 3 } elements are { 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: vector_a, UnorderedRangeEquals( array_a_plus_1, close_enough ) for: { 1, 2, 3 } unordered elements are { 2, 3, 4 } Exception.tests.cpp:: failed: unexpected exception with message: '3.14' UniquePtr.tests.cpp:: passed: bptr->i == 3 for: 3 == 3 UniquePtr.tests.cpp:: passed: bptr->i == 3 for: 3 == 3 @@ -1960,6 +2134,38 @@ MatchersRanges.tests.cpp:: passed: mocked.m_derefed[1] for: true MatchersRanges.tests.cpp:: passed: mocked.m_derefed[2] for: true MatchersRanges.tests.cpp:: passed: !(mocked.m_derefed[3]) for: !false MatchersRanges.tests.cpp:: passed: !(mocked.m_derefed[4]) for: !false +MatchersRanges.tests.cpp:: passed: empty_vector, RangeEquals( empty_vector ) for: { } elements are { } +MatchersRanges.tests.cpp:: passed: empty_vector, !RangeEquals( non_empty_vector ) for: { } not elements are { 1 } +MatchersRanges.tests.cpp:: passed: non_empty_vector, !RangeEquals( empty_vector ) for: { 1 } not elements are { } +MatchersRanges.tests.cpp:: passed: non_empty_array, RangeEquals( non_empty_array ) for: { 1 } elements are { 1 } +MatchersRanges.tests.cpp:: passed: array_a, RangeEquals( array_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_a, !RangeEquals( array_b ) for: { 1, 2, 3 } not elements are { 2, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_a, !RangeEquals( array_c ) for: { 1, 2, 3 } not elements are { 1, 2, 2 } +MatchersRanges.tests.cpp:: passed: vector_a, !RangeEquals( vector_b ) for: { 1, 2, 3 } not elements are { 1, 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: vector_a, RangeEquals( vector_a_plus_1, close_enough ) for: { 1, 2, 3 } elements are { 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: vector_a, !RangeEquals( vector_b, close_enough ) for: { 1, 2, 3 } not elements are { 3, 3, 4 } +MatchersRanges.tests.cpp:: passed: needs_adl1, RangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 } +MatchersRanges.tests.cpp:: passed: needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) for: { 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 } +MatchersRanges.tests.cpp:: passed: mocked1, !RangeEquals( arr ) for: { 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 } +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[0] for: true +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[1] for: true +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[2] for: true +MatchersRanges.tests.cpp:: passed: !(mocked1.m_derefed[3]) for: !false +MatchersRanges.tests.cpp:: passed: mocked1, RangeEquals( arr ) for: { 1, 2, 3, 4 } elements are { 1, 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[0] for: true +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[1] for: true +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[2] for: true +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[3] for: true +MatchersRanges.tests.cpp:: passed: empty_vector, UnorderedRangeEquals( empty_vector ) for: { } unordered elements are { } +MatchersRanges.tests.cpp:: passed: empty_vector, !UnorderedRangeEquals( non_empty_vector ) for: { } not unordered elements are { 1 } +MatchersRanges.tests.cpp:: passed: non_empty_vector, !UnorderedRangeEquals( empty_vector ) for: { 1 } not unordered elements are { } +MatchersRanges.tests.cpp:: passed: non_empty_array, UnorderedRangeEquals( non_empty_array ) for: { 1 } unordered elements are { 1 } +MatchersRanges.tests.cpp:: passed: array_a, UnorderedRangeEquals( array_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_a, !UnorderedRangeEquals( array_b ) for: { 1, 2, 3 } not unordered elements are { 2, 2, 3 } +MatchersRanges.tests.cpp:: passed: vector_a, !UnorderedRangeEquals( vector_b ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: vector_a, UnorderedRangeEquals( vector_a_plus_1, close_enough ) for: { 1, 10, 20 } unordered elements are { 11, 21, 2 } +MatchersRanges.tests.cpp:: passed: vector_a, !UnorderedRangeEquals( vector_b, close_enough ) for: { 1, 10, 21 } not unordered elements are { 11, 21, 3 } +MatchersRanges.tests.cpp:: passed: needs_adl1, UnorderedRangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 } MatchersRanges.tests.cpp:: passed: empty_vec, SizeIs(0) for: { } has size == 0 MatchersRanges.tests.cpp:: passed: empty_vec, !SizeIs(2) for: { } not has size == 2 MatchersRanges.tests.cpp:: passed: empty_vec, SizeIs(Lt(2)) for: { } size matches is less than 2 @@ -2056,6 +2262,8 @@ Xml.tests.cpp:: passed: encode( "[\x7F]" ) == "[\\x7F]" for: "[\x7F Xml.tests.cpp:: passed: stream.str(), ContainsSubstring(R"(attr1="true")") && ContainsSubstring(R"(attr2="false")") for: " " ( contains: "attr1="true"" and contains: "attr2="false"" ) +Skip.tests.cpp:: passed: +Skip.tests.cpp:: skipped: InternalBenchmark.tests.cpp:: passed: analysis.mean.point.count() == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: analysis.mean.lower_bound.count() == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: analysis.mean.upper_bound.count() == 23 for: 23.0 == 23 @@ -2145,6 +2353,9 @@ FloatingPoint.tests.cpp:: passed: convertToBits( -0. ) == ( 1ULL << 9223372036854775808 (0x) FloatingPoint.tests.cpp:: passed: convertToBits( std::numeric_limits::denorm_min() ) == 1 for: 1 == 1 FloatingPoint.tests.cpp:: passed: convertToBits( std::numeric_limits::denorm_min() ) == 1 for: 1 == 1 +Skip.tests.cpp:: skipped: 'skipping because answer = 41' +Skip.tests.cpp:: passed: +Skip.tests.cpp:: skipped: 'skipping because answer = 43' Tag.tests.cpp:: passed: Catch::TestCaseInfo("", { "test with an empty tag", "[]" }, dummySourceLineInfo) InternalBenchmark.tests.cpp:: passed: erfc_inv(1.103560) == Approx(-0.09203687623843015) for: -0.0920368762 == Approx( -0.0920368762 ) InternalBenchmark.tests.cpp:: passed: erfc_inv(1.067400) == Approx(-0.05980291115763361) for: -0.0598029112 == Approx( -0.0598029112 ) @@ -2154,6 +2365,14 @@ InternalBenchmark.tests.cpp:: passed: res.outliers.total() == 0 for Misc.tests.cpp:: passed: Misc.tests.cpp:: passed: Misc.tests.cpp:: passed: +Skip.tests.cpp:: failed: 3 == 4 +Skip.tests.cpp:: skipped: +Skip.tests.cpp:: failed: explicitly +Skip.tests.cpp:: skipped: +Skip.tests.cpp:: failed: explicitly +Skip.tests.cpp:: skipped: +Skip.tests.cpp:: skipped: +Skip.tests.cpp:: failed: explicitly loose text artifact Clara.tests.cpp:: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function::value' Clara.tests.cpp:: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function::value' @@ -2211,6 +2430,10 @@ Misc.tests.cpp:: passed: a < b for: 1 < 2 Misc.tests.cpp:: passed: a != b for: 1 != 2 Misc.tests.cpp:: passed: b != a for: 2 != 1 Misc.tests.cpp:: passed: a != b for: 1 != 2 +a! +b1! +Skip.tests.cpp:: skipped: +! Tricky.tests.cpp:: passed: s == "7" for: "7" == "7" Tricky.tests.cpp:: passed: ti == typeid(int) for: {?} == {?} InternalBenchmark.tests.cpp:: passed: normal_cdf(0.000000) == Approx(0.50000000000000000) for: 0.5 == Approx( 0.5 ) @@ -2295,9 +2518,13 @@ InternalBenchmark.tests.cpp:: passed: x >= old_x for: 128 >= 64 InternalBenchmark.tests.cpp:: passed: Timing.elapsed >= time for: 128 ns >= 100 ns InternalBenchmark.tests.cpp:: passed: Timing.result == Timing.iterations + 17 for: 145 == 145 InternalBenchmark.tests.cpp:: passed: Timing.iterations >= time.count() for: 128 >= 100 +Skip.tests.cpp:: passed: +Skip.tests.cpp:: skipped: +Skip.tests.cpp:: passed: Misc.tests.cpp:: failed: false with 1 message: '3' Message.tests.cpp:: failed: false with 2 messages: 'hi' and 'i := 7' Tag.tests.cpp:: passed: testcase.tags, VectorContains( Tag( "magic-tag" ) ) && VectorContains( Tag( "."_catch_sr ) ) for: { {?}, {?} } ( Contains: {?} and Contains: {?} ) +Skip.tests.cpp:: skipped: 'skipping because answer = 43' StringManip.tests.cpp:: passed: splitStringRef("", ','), Equals(std::vector()) for: { } Equals: { } StringManip.tests.cpp:: passed: splitStringRef("abc", ','), Equals(std::vector{"abc"}) for: { abc } Equals: { abc } StringManip.tests.cpp:: passed: splitStringRef("abc,def", ','), Equals(std::vector{"abc", "def"}) for: { abc, def } Equals: { abc, def } @@ -2363,6 +2590,7 @@ Generators.tests.cpp:: passed: strlen(std::get<0>(data)) == static_ Generators.tests.cpp:: passed: strlen(std::get<0>(data)) == static_cast(std::get<1>(data)) for: 6 == 6 Tag.tests.cpp:: passed: testcase.tags.size() == 1 for: 1 == 1 Tag.tests.cpp:: passed: testcase.tags[0].original == "magic.tag"_catch_sr for: magic.tag == magic.tag +Skip.tests.cpp:: skipped: Exception.tests.cpp:: failed: unexpected exception with message: 'Why would you throw a std::string?' Misc.tests.cpp:: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load"" Misc.tests.cpp:: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load"" @@ -2394,6 +2622,8 @@ InternalBenchmark.tests.cpp:: passed: e.point == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: e.upper_bound == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: e.lower_bound == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: e.confidence_interval == 0.95 for: 0.95 == 0.95 +RandomNumberGeneration.tests.cpp:: passed: dist.a() == -10 for: -10 == -10 +RandomNumberGeneration.tests.cpp:: passed: dist.b() == 10 for: 10 == 10 UniquePtr.tests.cpp:: passed: !(ptr) for: !{?} UniquePtr.tests.cpp:: passed: ptr.get() == 0 for: 0 == 0 UniquePtr.tests.cpp:: passed: ptr for: {?} @@ -2459,7 +2689,7 @@ InternalBenchmark.tests.cpp:: passed: med == 18. for: 18.0 == 18.0 InternalBenchmark.tests.cpp:: passed: q3 == 23. for: 23.0 == 23.0 Misc.tests.cpp:: passed: Misc.tests.cpp:: passed: -test cases: 394 | 304 passed | 83 failed | 7 failed as expected -assertions: 2159 | 1989 passed | 143 failed | 27 failed as expected +test cases: 417 | 312 passed | 85 failed | 6 skipped | 14 failed as expected +assertions: 2260 | 2079 passed | 146 failed | 35 failed as expected diff --git a/tests/SelfTest/Baselines/compact.sw.multi.approved.txt b/tests/SelfTest/Baselines/compact.sw.multi.approved.txt index af348dda..214fef74 100644 --- a/tests/SelfTest/Baselines/compact.sw.multi.approved.txt +++ b/tests/SelfTest/Baselines/compact.sw.multi.approved.txt @@ -82,6 +82,7 @@ Matchers.tests.cpp:: passed: smallest_non_zero, WithinULP( -smalles Matchers.tests.cpp:: passed: smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) for: 0.0 not is within 1 ULPs of -4.9406564584124654e-324 ([-9.8813129168249309e-324, -0.0000000000000000e+00]) Matchers.tests.cpp:: passed: smallest_non_zero, WithinULP( -smallest_non_zero, 2 ) for: 0.0f is within 2 ULPs of -1.40129846e-45f ([-4.20389539e-45, 1.40129846e-45]) Matchers.tests.cpp:: passed: smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) for: 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0.00000000e+00]) +Generators.tests.cpp:: failed: unexpected exception with message: 'failure to init' Exception.tests.cpp:: failed: unexpected exception with message: 'answer := 42' with 1 message: 'expected exception' Exception.tests.cpp:: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception' Exception.tests.cpp:: passed: thisThrows() with 1 message: 'answer := 42' @@ -328,7 +329,7 @@ MatchersRanges.tests.cpp:: passed: inner_lists_are_empty.front(), I MatchersRanges.tests.cpp:: passed: has_empty{}, !IsEmpty() for: {?} not is empty MatchersRanges.tests.cpp:: passed: unrelated::ADL_empty{}, IsEmpty() for: {?} is empty Message.tests.cpp:: passed: with 7 messages: 'a := 1' and 'b := 2' and 'c := 3' and 'a + b := 3' and 'a+b := 3' and 'c > b := true' and 'a == 1 := true' -Message.tests.cpp:: passed: with 7 messages: 'std::vector{1, 2, 3}[0, 1, 2] := 3' and 'std::vector{1, 2, 3}[(0, 1)] := 2' and 'std::vector{1, 2, 3}[0] := 1' and '(helper_1436{12, -12}) := { 12, -12 }' and '(helper_1436(-12, 12)) := { -12, 12 }' and '(1, 2) := 2' and '(2, 3) := 3' +Message.tests.cpp:: passed: with 7 messages: 'custom_index_op{1, 2, 3}[0, 1, 2] := 0' and 'custom_index_op{1, 2, 3}[(0, 1)] := 0' and 'custom_index_op{1, 2, 3}[0] := 0' and '(helper_1436{12, -12}) := { 12, -12 }' and '(helper_1436(-12, 12)) := { -12, 12 }' and '(1, 2) := 2' and '(2, 3) := 3' Message.tests.cpp:: passed: with 11 messages: '("comma, in string", "escaped, \", ") := "escaped, ", "' and '"single quote in string,'," := "single quote in string,',"' and '"some escapes, \\,\\\\" := "some escapes, \,\\"' and '"some, ), unmatched, } prenheses {[<" := "some, ), unmatched, } prenheses {[<"' and ''"' := '"'' and ''\'' := '''' and '',' := ','' and ''}' := '}'' and '')' := ')'' and ''(' := '('' and ''{' := '{'' ToStringGeneral.tests.cpp:: passed: true with 1 message: 'i := 2' ToStringGeneral.tests.cpp:: passed: true with 1 message: '3' @@ -517,8 +518,8 @@ ToString.tests.cpp:: passed: enumInfo->lookup(1) == "Value2" for: V ToString.tests.cpp:: passed: enumInfo->lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **} == "{** unexpected enum value **}" +Skip.tests.cpp:: skipped: 'This generator is empty' Stream.tests.cpp:: passed: Catch::makeStream( "" )->isConsole() for: true -Tag.tests.cpp:: passed: Catch::TestCaseInfo( "", { "fake test name", "[]" }, dummySourceLineInfo ) Matchers.tests.cpp:: failed: testStringForMatching(), EndsWith( "Substring" ) for: "this string contains 'abc' as a substring" ends with: "Substring" Matchers.tests.cpp:: failed: testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: "this" (case insensitive) EnumToString.tests.cpp:: passed: stringify( EnumClass3::Value1 ) == "Value1" for: "Value1" == "Value1" @@ -570,6 +571,10 @@ Matchers.tests.cpp:: failed: throwsSpecialException( 3 ), SpecialEx Matchers.tests.cpp:: failed: throwsSpecialException( 4 ), SpecialException, ExceptionMatcher{ 1 } for: SpecialException::what special exception has value of 1 Matchers.tests.cpp:: passed: throwsSpecialException( 1 ), SpecialException, ExceptionMatcher{ 1 } for: SpecialException::what special exception has value of 1 Matchers.tests.cpp:: passed: throwsSpecialException( 2 ), SpecialException, ExceptionMatcher{ 2 } for: SpecialException::what special exception has value of 2 +Matchers.tests.cpp:: passed: throwsDerivedException(), DerivedException, MessageMatches( StartsWith( "Derived" ) ) for: DerivedException::what matches "starts with: "Derived"" +Matchers.tests.cpp:: passed: throwsDerivedException(), DerivedException, MessageMatches( EndsWith( "::what" ) ) for: DerivedException::what matches "ends with: "::what"" +Matchers.tests.cpp:: passed: throwsDerivedException(), DerivedException, MessageMatches( !StartsWith( "::what" ) ) for: DerivedException::what matches "not starts with: "::what"" +Matchers.tests.cpp:: passed: throwsSpecialException( 2 ), SpecialException, MessageMatches( StartsWith( "Special" ) ) for: SpecialException::what matches "starts with: "Special"" Exception.tests.cpp:: passed: thisThrows(), "expected exception" for: "expected exception" equals: "expected exception" Exception.tests.cpp:: passed: thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expected exception" (case insensitive) Exception.tests.cpp:: passed: thisThrows(), StartsWith( "expected" ) for: "expected exception" starts with: "expected" @@ -592,6 +597,7 @@ Misc.tests.cpp:: passed: Factorial(1) == 1 for: 1 == 1 Misc.tests.cpp:: passed: Factorial(2) == 2 for: 2 == 2 Misc.tests.cpp:: passed: Factorial(3) == 6 for: 6 == 6 Misc.tests.cpp:: passed: Factorial(10) == 3628800 for: 3628800 (0x) == 3628800 (0x) +GeneratorsImpl.tests.cpp:: passed: filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException Matchers.tests.cpp:: passed: 10., WithinRel( 11.1, 0.1 ) for: 10.0 and 11.1 are within 10% of each other Matchers.tests.cpp:: passed: 10., !WithinRel( 11.2, 0.1 ) for: 10.0 not and 11.2 are within 10% of each other Matchers.tests.cpp:: passed: 1., !WithinRel( 0., 0.99 ) for: 1.0 not and 0 are within 99% of each other @@ -621,6 +627,7 @@ Matchers.tests.cpp:: passed: WithinULP( 1., 0 ) Matchers.tests.cpp:: passed: WithinRel( 1., 0. ) Matchers.tests.cpp:: passed: WithinRel( 1., -0.2 ), std::domain_error Matchers.tests.cpp:: passed: WithinRel( 1., 1. ), std::domain_error +Matchers.tests.cpp:: passed: 1., !IsNaN() for: 1.0 not is NaN Matchers.tests.cpp:: passed: 10.f, WithinRel( 11.1f, 0.1f ) for: 10.0f and 11.1 are within 10% of each other Matchers.tests.cpp:: passed: 10.f, !WithinRel( 11.2f, 0.1f ) for: 10.0f not and 11.2 are within 10% of each other Matchers.tests.cpp:: passed: 1.f, !WithinRel( 0.f, 0.99f ) for: 1.0f not and 0 are within 99% of each other @@ -653,6 +660,11 @@ Matchers.tests.cpp:: passed: WithinULP( 1.f, static_cast( Matchers.tests.cpp:: passed: WithinRel( 1.f, 0.f ) Matchers.tests.cpp:: passed: WithinRel( 1.f, -0.2f ), std::domain_error Matchers.tests.cpp:: passed: WithinRel( 1.f, 1.f ), std::domain_error +Matchers.tests.cpp:: passed: 1., !IsNaN() for: 1.0 not is NaN +Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 +Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 +Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 +Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 Generators.tests.cpp:: passed: i % 2 == 0 for: 0 == 0 @@ -934,6 +946,7 @@ TestCaseInfoHasher.tests.cpp:: passed: h( dummy1 ) != h( dummy2 ) f TestCaseInfoHasher.tests.cpp:: passed: h( dummy ) == h( dummy ) for: 3422778688 (0x) == 3422778688 (0x) +Message.tests.cpp:: failed: explicitly with 3 messages: 'This info has multiple parts.' and 'This unscoped info has multiple parts.' and 'Show infos!' Message.tests.cpp:: warning: 'this is a message' with 1 message: 'this is a warning' Message.tests.cpp:: failed: a == 1 for: 2 == 1 with 2 messages: 'this message should be logged' and 'so should this' Message.tests.cpp:: passed: a == 2 for: 2 == 2 with 1 message: 'this message may be logged later' @@ -951,6 +964,7 @@ Message.tests.cpp:: passed: i < 10 for: 7 < 10 with 2 messages: 'cu Message.tests.cpp:: passed: i < 10 for: 8 < 10 with 2 messages: 'current counter 8' and 'i := 8' Message.tests.cpp:: passed: i < 10 for: 9 < 10 with 2 messages: 'current counter 9' and 'i := 9' Message.tests.cpp:: failed: i < 10 for: 10 < 10 with 2 messages: 'current counter 10' and 'i := 10' +AssertionHandler.tests.cpp:: failed: unexpected exception with message: 'Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE'; expression was: Dummy Condition.tests.cpp:: failed: data.int_seven != 7 for: 7 != 7 Condition.tests.cpp:: failed: data.float_nine_point_one != Approx( 9.1f ) for: 9.1f != Approx( 9.1000003815 ) Condition.tests.cpp:: failed: data.double_pi != Approx( 3.1415926535 ) for: 3.1415926535 != Approx( 3.1415926535 ) @@ -967,6 +981,91 @@ Condition.tests.cpp:: passed: data.str_hello != "goodbye" for: "hel Condition.tests.cpp:: passed: data.str_hello != "hell" for: "hello" != "hell" Condition.tests.cpp:: passed: data.str_hello != "hello1" for: "hello" != "hello1" Condition.tests.cpp:: passed: data.str_hello.size() != 6 for: 5 != 6 +Json.tests.cpp:: passed: stream.str() == "" for: "" == "" +Json.tests.cpp:: passed: stream.str() == "{\n}" for: "{ +}" +== +"{ +}" +Json.tests.cpp:: passed: stream.str(), ContainsSubstring( "\"int\": 1," ) && ContainsSubstring( "\"double\": 1.5," ) && ContainsSubstring( "\"true\": true," ) && ContainsSubstring( "\"false\": false," ) && ContainsSubstring( "\"string\": \"this is a string\"," ) && ContainsSubstring( "\"array\": [\n 1,\n 2\n ]\n}" ) for: "{ + "int": 1, + "double": 1.5, + "true": true, + "false": false, + "string": "this is a string", + "array": [ + 1, + 2 + ] +}" ( contains: ""int": 1," and contains: ""double": 1.5," and contains: ""true": true," and contains: ""false": false," and contains: ""string": "this is a string"," and contains: ""array": [ + 1, + 2 + ] +}" ) +Json.tests.cpp:: passed: stream.str(), ContainsSubstring( "\"empty_object\": {\n }," ) && ContainsSubstring( "\"fully_object\": {\n \"key\": 1\n }" ) for: "{ + "empty_object": { + }, + "fully_object": { + "key": 1 + } +}" ( contains: ""empty_object": { + }," and contains: ""fully_object": { + "key": 1 + }" ) +Json.tests.cpp:: passed: stream.str() == "[\n]" for: "[ +]" +== +"[ +]" +Json.tests.cpp:: passed: stream.str() == "[\n 1,\n 1.5,\n true,\n false,\n \"this is a string\",\n {\n \"object\": 42\n },\n [\n \"array\",\n 42.5\n ]\n]" for: "[ + 1, + 1.5, + true, + false, + "this is a string", + { + "object": 42 + }, + [ + "array", + 42.5 + ] +]" +== +"[ + 1, + 1.5, + true, + false, + "this is a string", + { + "object": 42 + }, + [ + "array", + 42.5 + ] +]" +Json.tests.cpp:: passed: stream.str() == "{\n}" for: "{ +}" +== +"{ +}" +Json.tests.cpp:: passed: stream.str() == "[\n]" for: "[ +]" +== +"[ +]" +Json.tests.cpp:: passed: stream.str() == "\"custom\"" for: ""custom"" == ""custom"" +Json.tests.cpp:: passed: sstream.str() == "\"\\\"\"" for: ""\""" == ""\""" +Json.tests.cpp:: passed: sstream.str() == "\"\\\\\"" for: ""\\"" == ""\\"" +Json.tests.cpp:: passed: sstream.str() == "\"/\"" for: ""/"" == ""/"" +Json.tests.cpp:: passed: sstream.str() == "\"\\b\"" for: ""\b"" == ""\b"" +Json.tests.cpp:: passed: sstream.str() == "\"\\f\"" for: ""\f"" == ""\f"" +Json.tests.cpp:: passed: sstream.str() == "\"\\n\"" for: ""\n"" == ""\n"" +Json.tests.cpp:: passed: sstream.str() == "\"\\r\"" for: ""\r"" == ""\r"" +Json.tests.cpp:: passed: sstream.str() == "\"\\t\"" for: ""\t"" == ""\t"" +Json.tests.cpp:: passed: sstream.str() == "\"\\\\/\\t\\r\\n\"" for: ""\\/\t\r\n"" == ""\\/\t\r\n"" Compilation.tests.cpp:: passed: []() { return true; }() for: true Approx.tests.cpp:: passed: d <= Approx( 1.24 ) for: 1.23 <= Approx( 1.24 ) Approx.tests.cpp:: passed: d <= Approx( 1.23 ) for: 1.23 <= Approx( 1.23 ) @@ -1331,6 +1430,60 @@ Reporters.tests.cpp:: passed: listingString, ContainsSubstring( "fa " ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: console' Reporters.tests.cpp:: passed: !(factories.empty()) for: !false +Reporters.tests.cpp:: passed: listingString, ContainsSubstring("fakeTag"s) for: "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "tags": [ + { + "aliases": [ + "fakeTag" + ], + "count": 1 + } + ]" contains: "fakeTag" with 1 message: 'Tested reporter: JSON' +Reporters.tests.cpp:: passed: !(factories.empty()) for: !false +Reporters.tests.cpp:: passed: listingString, ContainsSubstring("fake reporter"s) for: "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "reporters": [ + { + "name": "fake reporter", + "description": "fake description" + } + ]" contains: "fake reporter" with 1 message: 'Tested reporter: JSON' +Reporters.tests.cpp:: passed: !(factories.empty()) for: !false +Reporters.tests.cpp:: passed: listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) for: "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "tests": [ + { + "name": "fake test name", + "class-name": "", + "tags": [ + "fakeTestTag" + ], + "source-location": { + "filename": "fake-file.cpp", + "line": 123456789 + } + } + ]" ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: JSON' +Reporters.tests.cpp:: passed: !(factories.empty()) for: !false Reporters.tests.cpp:: passed: listingString, ContainsSubstring("fakeTag"s) for: " All available tags: 1 [fakeTag] @@ -1735,6 +1888,10 @@ Misc.tests.cpp:: passed: true Misc.tests.cpp:: failed: explicitly Misc.tests.cpp:: failed - but was ok: false Misc.tests.cpp:: failed: explicitly +Misc.tests.cpp:: passed: true +Misc.tests.cpp:: failed: unexpected exception with message: 'Uncaught exception should fail!'; expression was: {Unknown expression after the reported line} +Misc.tests.cpp:: failed - but was ok: false +Misc.tests.cpp:: failed: unexpected exception with message: 'Uncaught exception should fail!'; expression was: {Unknown expression after the reported line} Message.tests.cpp:: failed - but was ok: 1 == 2 Reporters.tests.cpp:: passed: listingString, ContainsSubstring("[fakeTag]"s) for: "All available tags: 1 [fakeTag] @@ -1848,6 +2005,23 @@ There is no extra whitespace here StringManip.tests.cpp:: passed: trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace) for: There is no extra whitespace here == There is no extra whitespace here +MatchersRanges.tests.cpp:: passed: array_int_a, RangeEquals( c_array ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_int_a, UnorderedRangeEquals( c_array ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_int_3, !RangeEquals( array_int_4 ) for: { 1, 2, 3 } not elements are { 1, 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: array_int_3, !UnorderedRangeEquals( array_int_4 ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: array_int_a, RangeEquals( vector_char_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_int_a, UnorderedRangeEquals( vector_char_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: with 1 message: 'ContainerIsRandomAccess( array_int_a ) != ContainerIsRandomAccess( list_char_a )' +MatchersRanges.tests.cpp:: passed: array_int_a, RangeEquals( list_char_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_int_a, UnorderedRangeEquals( list_char_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: vector_int_a, RangeEquals( vector_char_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: vector_int_a, UnorderedRangeEquals( vector_char_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: vector_int_a, !RangeEquals( vector_char_b ) for: { 1, 2, 3 } not elements are { 1, 2, 2 } +MatchersRanges.tests.cpp:: passed: vector_int_a, !UnorderedRangeEquals( vector_char_b ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 2 } +MatchersRanges.tests.cpp:: passed: a, !RangeEquals( b ) for: { 1, 2, 3 } not elements are { 3, 2, 1 } +MatchersRanges.tests.cpp:: passed: a, UnorderedRangeEquals( b ) for: { 1, 2, 3 } unordered elements are { 3, 2, 1 } +MatchersRanges.tests.cpp:: passed: vector_a, RangeEquals( array_a_plus_1, close_enough ) for: { 1, 2, 3 } elements are { 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: vector_a, UnorderedRangeEquals( array_a_plus_1, close_enough ) for: { 1, 2, 3 } unordered elements are { 2, 3, 4 } Exception.tests.cpp:: failed: unexpected exception with message: '3.14' UniquePtr.tests.cpp:: passed: bptr->i == 3 for: 3 == 3 UniquePtr.tests.cpp:: passed: bptr->i == 3 for: 3 == 3 @@ -1953,6 +2127,38 @@ MatchersRanges.tests.cpp:: passed: mocked.m_derefed[1] for: true MatchersRanges.tests.cpp:: passed: mocked.m_derefed[2] for: true MatchersRanges.tests.cpp:: passed: !(mocked.m_derefed[3]) for: !false MatchersRanges.tests.cpp:: passed: !(mocked.m_derefed[4]) for: !false +MatchersRanges.tests.cpp:: passed: empty_vector, RangeEquals( empty_vector ) for: { } elements are { } +MatchersRanges.tests.cpp:: passed: empty_vector, !RangeEquals( non_empty_vector ) for: { } not elements are { 1 } +MatchersRanges.tests.cpp:: passed: non_empty_vector, !RangeEquals( empty_vector ) for: { 1 } not elements are { } +MatchersRanges.tests.cpp:: passed: non_empty_array, RangeEquals( non_empty_array ) for: { 1 } elements are { 1 } +MatchersRanges.tests.cpp:: passed: array_a, RangeEquals( array_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_a, !RangeEquals( array_b ) for: { 1, 2, 3 } not elements are { 2, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_a, !RangeEquals( array_c ) for: { 1, 2, 3 } not elements are { 1, 2, 2 } +MatchersRanges.tests.cpp:: passed: vector_a, !RangeEquals( vector_b ) for: { 1, 2, 3 } not elements are { 1, 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: vector_a, RangeEquals( vector_a_plus_1, close_enough ) for: { 1, 2, 3 } elements are { 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: vector_a, !RangeEquals( vector_b, close_enough ) for: { 1, 2, 3 } not elements are { 3, 3, 4 } +MatchersRanges.tests.cpp:: passed: needs_adl1, RangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 } +MatchersRanges.tests.cpp:: passed: needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) for: { 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 } +MatchersRanges.tests.cpp:: passed: mocked1, !RangeEquals( arr ) for: { 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 } +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[0] for: true +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[1] for: true +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[2] for: true +MatchersRanges.tests.cpp:: passed: !(mocked1.m_derefed[3]) for: !false +MatchersRanges.tests.cpp:: passed: mocked1, RangeEquals( arr ) for: { 1, 2, 3, 4 } elements are { 1, 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[0] for: true +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[1] for: true +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[2] for: true +MatchersRanges.tests.cpp:: passed: mocked1.m_derefed[3] for: true +MatchersRanges.tests.cpp:: passed: empty_vector, UnorderedRangeEquals( empty_vector ) for: { } unordered elements are { } +MatchersRanges.tests.cpp:: passed: empty_vector, !UnorderedRangeEquals( non_empty_vector ) for: { } not unordered elements are { 1 } +MatchersRanges.tests.cpp:: passed: non_empty_vector, !UnorderedRangeEquals( empty_vector ) for: { 1 } not unordered elements are { } +MatchersRanges.tests.cpp:: passed: non_empty_array, UnorderedRangeEquals( non_empty_array ) for: { 1 } unordered elements are { 1 } +MatchersRanges.tests.cpp:: passed: array_a, UnorderedRangeEquals( array_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +MatchersRanges.tests.cpp:: passed: array_a, !UnorderedRangeEquals( array_b ) for: { 1, 2, 3 } not unordered elements are { 2, 2, 3 } +MatchersRanges.tests.cpp:: passed: vector_a, !UnorderedRangeEquals( vector_b ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } +MatchersRanges.tests.cpp:: passed: vector_a, UnorderedRangeEquals( vector_a_plus_1, close_enough ) for: { 1, 10, 20 } unordered elements are { 11, 21, 2 } +MatchersRanges.tests.cpp:: passed: vector_a, !UnorderedRangeEquals( vector_b, close_enough ) for: { 1, 10, 21 } not unordered elements are { 11, 21, 3 } +MatchersRanges.tests.cpp:: passed: needs_adl1, UnorderedRangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 } MatchersRanges.tests.cpp:: passed: empty_vec, SizeIs(0) for: { } has size == 0 MatchersRanges.tests.cpp:: passed: empty_vec, !SizeIs(2) for: { } not has size == 2 MatchersRanges.tests.cpp:: passed: empty_vec, SizeIs(Lt(2)) for: { } size matches is less than 2 @@ -2049,6 +2255,8 @@ Xml.tests.cpp:: passed: encode( "[\x7F]" ) == "[\\x7F]" for: "[\x7F Xml.tests.cpp:: passed: stream.str(), ContainsSubstring(R"(attr1="true")") && ContainsSubstring(R"(attr2="false")") for: " " ( contains: "attr1="true"" and contains: "attr2="false"" ) +Skip.tests.cpp:: passed: +Skip.tests.cpp:: skipped: InternalBenchmark.tests.cpp:: passed: analysis.mean.point.count() == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: analysis.mean.lower_bound.count() == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: analysis.mean.upper_bound.count() == 23 for: 23.0 == 23 @@ -2138,6 +2346,9 @@ FloatingPoint.tests.cpp:: passed: convertToBits( -0. ) == ( 1ULL << 9223372036854775808 (0x) FloatingPoint.tests.cpp:: passed: convertToBits( std::numeric_limits::denorm_min() ) == 1 for: 1 == 1 FloatingPoint.tests.cpp:: passed: convertToBits( std::numeric_limits::denorm_min() ) == 1 for: 1 == 1 +Skip.tests.cpp:: skipped: 'skipping because answer = 41' +Skip.tests.cpp:: passed: +Skip.tests.cpp:: skipped: 'skipping because answer = 43' Tag.tests.cpp:: passed: Catch::TestCaseInfo("", { "test with an empty tag", "[]" }, dummySourceLineInfo) InternalBenchmark.tests.cpp:: passed: erfc_inv(1.103560) == Approx(-0.09203687623843015) for: -0.0920368762 == Approx( -0.0920368762 ) InternalBenchmark.tests.cpp:: passed: erfc_inv(1.067400) == Approx(-0.05980291115763361) for: -0.0598029112 == Approx( -0.0598029112 ) @@ -2147,6 +2358,14 @@ InternalBenchmark.tests.cpp:: passed: res.outliers.total() == 0 for Misc.tests.cpp:: passed: Misc.tests.cpp:: passed: Misc.tests.cpp:: passed: +Skip.tests.cpp:: failed: 3 == 4 +Skip.tests.cpp:: skipped: +Skip.tests.cpp:: failed: explicitly +Skip.tests.cpp:: skipped: +Skip.tests.cpp:: failed: explicitly +Skip.tests.cpp:: skipped: +Skip.tests.cpp:: skipped: +Skip.tests.cpp:: failed: explicitly Clara.tests.cpp:: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function::value' Clara.tests.cpp:: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function::value' Clara.tests.cpp:: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function::value' @@ -2203,6 +2422,7 @@ Misc.tests.cpp:: passed: a < b for: 1 < 2 Misc.tests.cpp:: passed: a != b for: 1 != 2 Misc.tests.cpp:: passed: b != a for: 2 != 1 Misc.tests.cpp:: passed: a != b for: 1 != 2 +Skip.tests.cpp:: skipped: Tricky.tests.cpp:: passed: s == "7" for: "7" == "7" Tricky.tests.cpp:: passed: ti == typeid(int) for: {?} == {?} InternalBenchmark.tests.cpp:: passed: normal_cdf(0.000000) == Approx(0.50000000000000000) for: 0.5 == Approx( 0.5 ) @@ -2287,9 +2507,13 @@ InternalBenchmark.tests.cpp:: passed: x >= old_x for: 128 >= 64 InternalBenchmark.tests.cpp:: passed: Timing.elapsed >= time for: 128 ns >= 100 ns InternalBenchmark.tests.cpp:: passed: Timing.result == Timing.iterations + 17 for: 145 == 145 InternalBenchmark.tests.cpp:: passed: Timing.iterations >= time.count() for: 128 >= 100 +Skip.tests.cpp:: passed: +Skip.tests.cpp:: skipped: +Skip.tests.cpp:: passed: Misc.tests.cpp:: failed: false with 1 message: '3' Message.tests.cpp:: failed: false with 2 messages: 'hi' and 'i := 7' Tag.tests.cpp:: passed: testcase.tags, VectorContains( Tag( "magic-tag" ) ) && VectorContains( Tag( "."_catch_sr ) ) for: { {?}, {?} } ( Contains: {?} and Contains: {?} ) +Skip.tests.cpp:: skipped: 'skipping because answer = 43' StringManip.tests.cpp:: passed: splitStringRef("", ','), Equals(std::vector()) for: { } Equals: { } StringManip.tests.cpp:: passed: splitStringRef("abc", ','), Equals(std::vector{"abc"}) for: { abc } Equals: { abc } StringManip.tests.cpp:: passed: splitStringRef("abc,def", ','), Equals(std::vector{"abc", "def"}) for: { abc, def } Equals: { abc, def } @@ -2355,6 +2579,7 @@ Generators.tests.cpp:: passed: strlen(std::get<0>(data)) == static_ Generators.tests.cpp:: passed: strlen(std::get<0>(data)) == static_cast(std::get<1>(data)) for: 6 == 6 Tag.tests.cpp:: passed: testcase.tags.size() == 1 for: 1 == 1 Tag.tests.cpp:: passed: testcase.tags[0].original == "magic.tag"_catch_sr for: magic.tag == magic.tag +Skip.tests.cpp:: skipped: Exception.tests.cpp:: failed: unexpected exception with message: 'Why would you throw a std::string?' Misc.tests.cpp:: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load"" Misc.tests.cpp:: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load"" @@ -2386,6 +2611,8 @@ InternalBenchmark.tests.cpp:: passed: e.point == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: e.upper_bound == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: e.lower_bound == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: e.confidence_interval == 0.95 for: 0.95 == 0.95 +RandomNumberGeneration.tests.cpp:: passed: dist.a() == -10 for: -10 == -10 +RandomNumberGeneration.tests.cpp:: passed: dist.b() == 10 for: 10 == 10 UniquePtr.tests.cpp:: passed: !(ptr) for: !{?} UniquePtr.tests.cpp:: passed: ptr.get() == 0 for: 0 == 0 UniquePtr.tests.cpp:: passed: ptr for: {?} @@ -2451,7 +2678,7 @@ InternalBenchmark.tests.cpp:: passed: med == 18. for: 18.0 == 18.0 InternalBenchmark.tests.cpp:: passed: q3 == 23. for: 23.0 == 23.0 Misc.tests.cpp:: passed: Misc.tests.cpp:: passed: -test cases: 394 | 304 passed | 83 failed | 7 failed as expected -assertions: 2159 | 1989 passed | 143 failed | 27 failed as expected +test cases: 417 | 312 passed | 85 failed | 6 skipped | 14 failed as expected +assertions: 2260 | 2079 passed | 146 failed | 35 failed as expected diff --git a/tests/SelfTest/Baselines/console.std.approved.txt b/tests/SelfTest/Baselines/console.std.approved.txt index 5ad8447a..25426256 100644 --- a/tests/SelfTest/Baselines/console.std.approved.txt +++ b/tests/SelfTest/Baselines/console.std.approved.txt @@ -27,6 +27,16 @@ Tricky.tests.cpp:: FAILED: explicitly with message: 1514 +------------------------------------------------------------------------------- +#2615 - Throwing in constructor generator fails test case but does not abort +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: FAILED: +due to unexpected exception with message: + failure to init + ------------------------------------------------------------------------------- #748 - captures with unexpected exceptions outside assertions @@ -373,6 +383,16 @@ Exception.tests.cpp:: FAILED: due to unexpected exception with message: custom std exception +------------------------------------------------------------------------------- +Empty generators can SKIP in constructor +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: +explicitly with message: + This generator is empty + ------------------------------------------------------------------------------- EndsWith string matcher ------------------------------------------------------------------------------- @@ -579,6 +599,18 @@ explicitly with message: Message.tests.cpp:: warning: This message appears in the output +------------------------------------------------------------------------------- +INFO and UNSCOPED_INFO can stream multiple arguments +------------------------------------------------------------------------------- +Message.tests.cpp: +............................................................................... + +Message.tests.cpp:: FAILED: +explicitly with messages: + This info has multiple parts. + This unscoped info has multiple parts. + Show infos! + ------------------------------------------------------------------------------- INFO and WARN do not abort tests ------------------------------------------------------------------------------- @@ -639,6 +671,17 @@ with messages: current counter 10 i := 10 +------------------------------------------------------------------------------- +Incomplete AssertionHandler +------------------------------------------------------------------------------- +AssertionHandler.tests.cpp: +............................................................................... + +AssertionHandler.tests.cpp:: FAILED: + REQUIRE( Dummy ) +due to unexpected exception with message: + Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE + ------------------------------------------------------------------------------- Inequality checks that should fail ------------------------------------------------------------------------------- @@ -977,6 +1020,28 @@ Misc.tests.cpp: Misc.tests.cpp:: FAILED: +------------------------------------------------------------------------------- +Testing checked-if 4 +------------------------------------------------------------------------------- +Misc.tests.cpp: +............................................................................... + +Misc.tests.cpp:: FAILED: + {Unknown expression after the reported line} +due to unexpected exception with message: + Uncaught exception should fail! + +------------------------------------------------------------------------------- +Testing checked-if 5 +------------------------------------------------------------------------------- +Misc.tests.cpp: +............................................................................... + +Misc.tests.cpp:: FAILED: + {Unknown expression after the reported line} +due to unexpected exception with message: + Uncaught exception should fail! + ------------------------------------------------------------------------------- Thrown string literals are translated ------------------------------------------------------------------------------- @@ -1164,6 +1229,14 @@ Exception.tests.cpp:: FAILED: due to unexpected exception with message: unexpected exception +------------------------------------------------------------------------------- +a succeeding test can still be skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + ------------------------------------------------------------------------------- checkedElse, failing ------------------------------------------------------------------------------- @@ -1186,6 +1259,87 @@ Misc.tests.cpp:: FAILED: with expansion: false +------------------------------------------------------------------------------- +dynamic skipping works with generators +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: +explicitly with message: + skipping because answer = 41 + +------------------------------------------------------------------------------- +dynamic skipping works with generators +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: +explicitly with message: + skipping because answer = 43 + +------------------------------------------------------------------------------- +failed assertions before SKIP cause test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: FAILED: + CHECK( 3 == 4 ) + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +failing for some generator values causes entire test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: FAILED: + +------------------------------------------------------------------------------- +failing for some generator values causes entire test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +failing for some generator values causes entire test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: FAILED: + +------------------------------------------------------------------------------- +failing for some generator values causes entire test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +failing in some unskipped sections causes entire test case to fail + skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +failing in some unskipped sections causes entire test case to fail + not skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: FAILED: + loose text artifact ------------------------------------------------------------------------------- just failure @@ -1304,6 +1458,19 @@ Misc.tests.cpp:: FAILED: with expansion: 1 == 2 +a! +b1! +------------------------------------------------------------------------------- +nested sections can be skipped dynamically at runtime + B + B2 +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +! ------------------------------------------------------------------------------- not prints unscoped info from previous failures ------------------------------------------------------------------------------- @@ -1338,6 +1505,15 @@ Message.tests.cpp:: FAILED: with message: this SHOULD be seen only ONCE +------------------------------------------------------------------------------- +sections can be skipped dynamically at runtime + skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + ------------------------------------------------------------------------------- send a single char to INFO ------------------------------------------------------------------------------- @@ -1361,6 +1537,16 @@ with messages: hi i := 7 +------------------------------------------------------------------------------- +skipped tests can optionally provide a reason +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: +explicitly with message: + skipping because answer = 43 + ------------------------------------------------------------------------------- stacks unscoped info in loops ------------------------------------------------------------------------------- @@ -1383,6 +1569,14 @@ with messages: 5 6 +------------------------------------------------------------------------------- +tests can be skipped dynamically at runtime +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + ------------------------------------------------------------------------------- thrown std::strings are translated ------------------------------------------------------------------------------- @@ -1394,6 +1588,6 @@ due to unexpected exception with message: Why would you throw a std::string? =============================================================================== -test cases: 394 | 318 passed | 69 failed | 7 failed as expected -assertions: 2144 | 1989 passed | 128 failed | 27 failed as expected +test cases: 417 | 326 passed | 70 failed | 7 skipped | 14 failed as expected +assertions: 2243 | 2079 passed | 129 failed | 35 failed as expected diff --git a/tests/SelfTest/Baselines/console.sw.approved.txt b/tests/SelfTest/Baselines/console.sw.approved.txt index 1ef94ee5..077b7bf7 100644 --- a/tests/SelfTest/Baselines/console.sw.approved.txt +++ b/tests/SelfTest/Baselines/console.sw.approved.txt @@ -761,6 +761,16 @@ with expansion: 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0. 00000000e+00]) +------------------------------------------------------------------------------- +#2615 - Throwing in constructor generator fails test case but does not abort +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: FAILED: +due to unexpected exception with message: + failure to init + ------------------------------------------------------------------------------- #748 - captures with unexpected exceptions outside assertions @@ -2730,9 +2740,9 @@ Message.tests.cpp: Message.tests.cpp:: PASSED: with messages: - std::vector{1, 2, 3}[0, 1, 2] := 3 - std::vector{1, 2, 3}[(0, 1)] := 2 - std::vector{1, 2, 3}[0] := 1 + custom_index_op{1, 2, 3}[0, 1, 2] := 0 + custom_index_op{1, 2, 3}[(0, 1)] := 0 + custom_index_op{1, 2, 3}[0] := 0 (helper_1436{12, -12}) := { 12, -12 } (helper_1436(-12, 12)) := { -12, 12 } (1, 2) := 2 @@ -3946,6 +3956,16 @@ with expansion: == "{** unexpected enum value **}" +------------------------------------------------------------------------------- +Empty generators can SKIP in constructor +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: +explicitly with message: + This generator is empty + ------------------------------------------------------------------------------- Empty stream name opens cout stream ------------------------------------------------------------------------------- @@ -3957,15 +3977,6 @@ Stream.tests.cpp:: PASSED: with expansion: true -------------------------------------------------------------------------------- -Empty tag is not allowed -------------------------------------------------------------------------------- -Tag.tests.cpp: -............................................................................... - -Tag.tests.cpp:: PASSED: - REQUIRE_THROWS( Catch::TestCaseInfo( "", { "fake test name", "[]" }, dummySourceLineInfo ) ) - ------------------------------------------------------------------------------- EndsWith string matcher ------------------------------------------------------------------------------- @@ -4282,6 +4293,32 @@ Matchers.tests.cpp:: PASSED: with expansion: SpecialException::what special exception has value of 2 +------------------------------------------------------------------------------- +Exception message can be matched +------------------------------------------------------------------------------- +Matchers.tests.cpp: +............................................................................... + +Matchers.tests.cpp:: PASSED: + REQUIRE_THROWS_MATCHES( throwsDerivedException(), DerivedException, MessageMatches( StartsWith( "Derived" ) ) ) +with expansion: + DerivedException::what matches "starts with: "Derived"" + +Matchers.tests.cpp:: PASSED: + REQUIRE_THROWS_MATCHES( throwsDerivedException(), DerivedException, MessageMatches( EndsWith( "::what" ) ) ) +with expansion: + DerivedException::what matches "ends with: "::what"" + +Matchers.tests.cpp:: PASSED: + REQUIRE_THROWS_MATCHES( throwsDerivedException(), DerivedException, MessageMatches( !StartsWith( "::what" ) ) ) +with expansion: + DerivedException::what matches "not starts with: "::what"" + +Matchers.tests.cpp:: PASSED: + REQUIRE_THROWS_MATCHES( throwsSpecialException( 2 ), SpecialException, MessageMatches( StartsWith( "Special" ) ) ) +with expansion: + SpecialException::what matches "starts with: "Special"" + ------------------------------------------------------------------------------- Exception messages can be tested for exact match @@ -4441,6 +4478,15 @@ Misc.tests.cpp:: PASSED: with expansion: 3628800 (0x) == 3628800 (0x) +------------------------------------------------------------------------------- +Filter generator throws exception for empty generator +------------------------------------------------------------------------------- +GeneratorsImpl.tests.cpp: +............................................................................... + +GeneratorsImpl.tests.cpp:: PASSED: + REQUIRE_THROWS_AS( filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException ) + ------------------------------------------------------------------------------- Floating point matchers: double Relative @@ -4626,6 +4672,18 @@ Matchers.tests.cpp:: PASSED: Matchers.tests.cpp:: PASSED: REQUIRE_THROWS_AS( WithinRel( 1., 1. ), std::domain_error ) +------------------------------------------------------------------------------- +Floating point matchers: double + IsNaN +------------------------------------------------------------------------------- +Matchers.tests.cpp: +............................................................................... + +Matchers.tests.cpp:: PASSED: + REQUIRE_THAT( 1., !IsNaN() ) +with expansion: + 1.0 not is NaN + ------------------------------------------------------------------------------- Floating point matchers: float Relative @@ -4819,6 +4877,62 @@ Matchers.tests.cpp:: PASSED: Matchers.tests.cpp:: PASSED: REQUIRE_THROWS_AS( WithinRel( 1.f, 1.f ), std::domain_error ) +------------------------------------------------------------------------------- +Floating point matchers: float + IsNaN +------------------------------------------------------------------------------- +Matchers.tests.cpp: +............................................................................... + +Matchers.tests.cpp:: PASSED: + REQUIRE_THAT( 1., !IsNaN() ) +with expansion: + 1.0 not is NaN + +------------------------------------------------------------------------------- +GENERATE can combine literals and generators +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i % 2 == 0 ) +with expansion: + 0 == 0 + +------------------------------------------------------------------------------- +GENERATE can combine literals and generators +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i % 2 == 0 ) +with expansion: + 0 == 0 + +------------------------------------------------------------------------------- +GENERATE can combine literals and generators +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i % 2 == 0 ) +with expansion: + 0 == 0 + +------------------------------------------------------------------------------- +GENERATE can combine literals and generators +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i % 2 == 0 ) +with expansion: + 0 == 0 + ------------------------------------------------------------------------------- Generators -- adapters Filtering by predicate @@ -6912,6 +7026,18 @@ with expansion: == 3422778688 (0x) +------------------------------------------------------------------------------- +INFO and UNSCOPED_INFO can stream multiple arguments +------------------------------------------------------------------------------- +Message.tests.cpp: +............................................................................... + +Message.tests.cpp:: FAILED: +explicitly with messages: + This info has multiple parts. + This unscoped info has multiple parts. + Show infos! + ------------------------------------------------------------------------------- INFO and WARN do not abort tests ------------------------------------------------------------------------------- @@ -7073,6 +7199,17 @@ with messages: current counter 10 i := 10 +------------------------------------------------------------------------------- +Incomplete AssertionHandler +------------------------------------------------------------------------------- +AssertionHandler.tests.cpp: +............................................................................... + +AssertionHandler.tests.cpp:: FAILED: + REQUIRE( Dummy ) +due to unexpected exception with message: + Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE + ------------------------------------------------------------------------------- Inequality checks that should fail ------------------------------------------------------------------------------- @@ -7165,6 +7302,291 @@ Condition.tests.cpp:: PASSED: with expansion: 5 != 6 +------------------------------------------------------------------------------- +JsonWriter + Newly constructed JsonWriter does nothing +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "" ) +with expansion: + "" == "" + +------------------------------------------------------------------------------- +JsonWriter + Calling writeObject will create an empty pair of braces +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "{\n}" ) +with expansion: + "{ + }" + == + "{ + }" + +------------------------------------------------------------------------------- +JsonWriter + Calling writeObject with key will create an object to write the value +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE_THAT( stream.str(), ContainsSubstring( "\"int\": 1," ) && ContainsSubstring( "\"double\": 1.5," ) && ContainsSubstring( "\"true\": true," ) && ContainsSubstring( "\"false\": false," ) && ContainsSubstring( "\"string\": \"this is a string\"," ) && ContainsSubstring( "\"array\": [\n 1,\n 2\n ]\n}" ) ) +with expansion: + "{ + "int": 1, + "double": 1.5, + "true": true, + "false": false, + "string": "this is a string", + "array": [ + 1, + 2 + ] + }" ( contains: ""int": 1," and contains: ""double": 1.5," and contains: + ""true": true," and contains: ""false": false," and contains: ""string": + "this is a string"," and contains: ""array": [ + 1, + 2 + ] + }" ) + +------------------------------------------------------------------------------- +JsonWriter + nesting objects +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE_THAT( stream.str(), ContainsSubstring( "\"empty_object\": {\n }," ) && ContainsSubstring( "\"fully_object\": {\n \"key\": 1\n }" ) ) +with expansion: + "{ + "empty_object": { + }, + "fully_object": { + "key": 1 + } + }" ( contains: ""empty_object": { + }," and contains: ""fully_object": { + "key": 1 + }" ) + +------------------------------------------------------------------------------- +JsonWriter + Calling writeArray will create an empty pair of braces +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "[\n]" ) +with expansion: + "[ + ]" + == + "[ + ]" + +------------------------------------------------------------------------------- +JsonWriter + Calling writeArray creates array to write the values to +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "[\n 1,\n 1.5,\n true,\n false,\n \"this is a string\",\n {\n \"object\": 42\n },\n [\n \"array\",\n 42.5\n ]\n]" ) +with expansion: + "[ + 1, + 1.5, + true, + false, + "this is a string", + { + "object": 42 + }, + [ + "array", + 42.5 + ] + ]" + == + "[ + 1, + 1.5, + true, + false, + "this is a string", + { + "object": 42 + }, + [ + "array", + 42.5 + ] + ]" + +------------------------------------------------------------------------------- +JsonWriter + Moved from JsonObjectWriter shall not insert superfluous brace +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "{\n}" ) +with expansion: + "{ + }" + == + "{ + }" + +------------------------------------------------------------------------------- +JsonWriter + Moved from JsonArrayWriter shall not insert superfluous bracket +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "[\n]" ) +with expansion: + "[ + ]" + == + "[ + ]" + +------------------------------------------------------------------------------- +JsonWriter + Custom class shall be quoted +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "\"custom\"" ) +with expansion: + ""custom"" == ""custom"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + Quote in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\\"\"" ) +with expansion: + ""\""" == ""\""" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + Backslash in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\\\\"" ) +with expansion: + ""\\"" == ""\\"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + Forward slash in a string is **not** escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"/\"" ) +with expansion: + ""/"" == ""/"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + Backspace in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\b\"" ) +with expansion: + ""\b"" == ""\b"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + Formfeed in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\f\"" ) +with expansion: + ""\f"" == ""\f"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + linefeed in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\n\"" ) +with expansion: + ""\n"" == ""\n"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + carriage return in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\r\"" ) +with expansion: + ""\r"" == ""\r"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + tab in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\t\"" ) +with expansion: + ""\t"" == ""\t"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + combination of characters is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\\\/\\t\\r\\n\"" ) +with expansion: + ""\\/\t\r\n"" == ""\\/\t\r\n"" + ------------------------------------------------------------------------------- Lambdas in assertions ------------------------------------------------------------------------------- @@ -9663,6 +10085,129 @@ Reporter's write listings to provided stream Reporters.tests.cpp: ............................................................................... +Reporters.tests.cpp:: PASSED: + REQUIRE_FALSE( factories.empty() ) +with expansion: + !false + +------------------------------------------------------------------------------- +Reporter's write listings to provided stream + JSON reporter lists tags +------------------------------------------------------------------------------- +Reporters.tests.cpp: +............................................................................... + +Reporters.tests.cpp:: PASSED: + REQUIRE_THAT( listingString, ContainsSubstring("fakeTag"s) ) +with expansion: + "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "tags": [ + { + "aliases": [ + "fakeTag" + ], + "count": 1 + } + ]" contains: "fakeTag" +with message: + Tested reporter: JSON + +------------------------------------------------------------------------------- +Reporter's write listings to provided stream +------------------------------------------------------------------------------- +Reporters.tests.cpp: +............................................................................... + +Reporters.tests.cpp:: PASSED: + REQUIRE_FALSE( factories.empty() ) +with expansion: + !false + +------------------------------------------------------------------------------- +Reporter's write listings to provided stream + JSON reporter lists reporters +------------------------------------------------------------------------------- +Reporters.tests.cpp: +............................................................................... + +Reporters.tests.cpp:: PASSED: + REQUIRE_THAT( listingString, ContainsSubstring("fake reporter"s) ) +with expansion: + "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "reporters": [ + { + "name": "fake reporter", + "description": "fake description" + } + ]" contains: "fake reporter" +with message: + Tested reporter: JSON + +------------------------------------------------------------------------------- +Reporter's write listings to provided stream +------------------------------------------------------------------------------- +Reporters.tests.cpp: +............................................................................... + +Reporters.tests.cpp:: PASSED: + REQUIRE_FALSE( factories.empty() ) +with expansion: + !false + +------------------------------------------------------------------------------- +Reporter's write listings to provided stream + JSON reporter lists tests +------------------------------------------------------------------------------- +Reporters.tests.cpp: +............................................................................... + +Reporters.tests.cpp:: PASSED: + REQUIRE_THAT( listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) ) +with expansion: + "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "tests": [ + { + "name": "fake test name", + "class-name": "", + "tags": [ + "fakeTestTag" + ], + "source-location": { + "filename": "fake-file.cpp", + "line": 123456789 + } + } + ]" ( contains: "fake test name" and contains: "fakeTestTag" ) +with message: + Tested reporter: JSON + +------------------------------------------------------------------------------- +Reporter's write listings to provided stream +------------------------------------------------------------------------------- +Reporters.tests.cpp: +............................................................................... + Reporters.tests.cpp:: PASSED: REQUIRE_FALSE( factories.empty() ) with expansion: @@ -12452,6 +12997,34 @@ Misc.tests.cpp:: FAILED - but was ok: Misc.tests.cpp:: FAILED: +------------------------------------------------------------------------------- +Testing checked-if 4 +------------------------------------------------------------------------------- +Misc.tests.cpp: +............................................................................... + +Misc.tests.cpp:: PASSED: + CHECKED_ELSE( true ) + +Misc.tests.cpp:: FAILED: + {Unknown expression after the reported line} +due to unexpected exception with message: + Uncaught exception should fail! + +------------------------------------------------------------------------------- +Testing checked-if 5 +------------------------------------------------------------------------------- +Misc.tests.cpp: +............................................................................... + +Misc.tests.cpp:: FAILED - but was ok: + CHECKED_ELSE( false ) + +Misc.tests.cpp:: FAILED: + {Unknown expression after the reported line} +due to unexpected exception with message: + Uncaught exception should fail! + ------------------------------------------------------------------------------- The NO_FAIL macro reports a failure but does not fail the test ------------------------------------------------------------------------------- @@ -13072,6 +13645,154 @@ with expansion: == There is no extra whitespace here +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Container conversions + Two equal containers of different container types +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_a, RangeEquals( c_array ) ) +with expansion: + { 1, 2, 3 } elements are { 1, 2, 3 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_a, UnorderedRangeEquals( c_array ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Container conversions + Two equal containers of different container types (differ in array N) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_3, !RangeEquals( array_int_4 ) ) +with expansion: + { 1, 2, 3 } not elements are { 1, 2, 3, 4 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_3, !UnorderedRangeEquals( array_int_4 ) ) +with expansion: + { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Container conversions + Two equal containers of different container types and value types +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_a, RangeEquals( vector_char_a ) ) +with expansion: + { 1, 2, 3 } elements are { 1, 2, 3 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_a, UnorderedRangeEquals( vector_char_a ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Container conversions + Two equal containers, one random access, one not +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: +with message: + ContainerIsRandomAccess( array_int_a ) != ContainerIsRandomAccess( + list_char_a ) + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_a, RangeEquals( list_char_a ) ) +with expansion: + { 1, 2, 3 } elements are { 1, 2, 3 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_a, UnorderedRangeEquals( list_char_a ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Value type + Two equal containers of different value types +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_int_a, RangeEquals( vector_char_a ) ) +with expansion: + { 1, 2, 3 } elements are { 1, 2, 3 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_int_a, UnorderedRangeEquals( vector_char_a ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Value type + Two non-equal containers of different value types +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_int_a, !RangeEquals( vector_char_b ) ) +with expansion: + { 1, 2, 3 } not elements are { 1, 2, 2 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_int_a, !UnorderedRangeEquals( vector_char_b ) ) +with expansion: + { 1, 2, 3 } not unordered elements are { 1, 2, 2 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Ranges with begin that needs ADL +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( a, !RangeEquals( b ) ) +with expansion: + { 1, 2, 3 } not elements are { 3, 2, 1 } + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( a, UnorderedRangeEquals( b ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 3, 2, 1 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Custom predicate + Two equal non-empty containers (close enough) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, RangeEquals( array_a_plus_1, close_enough ) ) +with expansion: + { 1, 2, 3 } elements are { 2, 3, 4 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, UnorderedRangeEquals( array_a_plus_1, close_enough ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 2, 3, 4 } + ------------------------------------------------------------------------------- Unexpected exceptions can be translated ------------------------------------------------------------------------------- @@ -13243,7 +13964,7 @@ with expansion: ------------------------------------------------------------------------------- Usage of AllTrue range matcher Basic usage - One false evalutes to false + One false evaluates to false ------------------------------------------------------------------------------- MatchersRanges.tests.cpp: ............................................................................... @@ -13282,7 +14003,7 @@ with expansion: ------------------------------------------------------------------------------- Usage of AllTrue range matcher Contained type is convertible to bool - One false evalutes to false + One false evaluates to false ------------------------------------------------------------------------------- MatchersRanges.tests.cpp: ............................................................................... @@ -13518,7 +14239,7 @@ with expansion: ------------------------------------------------------------------------------- Usage of AnyTrue range matcher Basic usage - One true evalutes to true + One true evaluates to true ------------------------------------------------------------------------------- MatchersRanges.tests.cpp: ............................................................................... @@ -13557,7 +14278,7 @@ with expansion: ------------------------------------------------------------------------------- Usage of AnyTrue range matcher Contained type is convertible to bool - One true evalutes to true + One true evaluates to true ------------------------------------------------------------------------------- MatchersRanges.tests.cpp: ............................................................................... @@ -13793,7 +14514,7 @@ with expansion: ------------------------------------------------------------------------------- Usage of NoneTrue range matcher Basic usage - One true evalutes to false + One true evaluates to false ------------------------------------------------------------------------------- MatchersRanges.tests.cpp: ............................................................................... @@ -13832,7 +14553,7 @@ with expansion: ------------------------------------------------------------------------------- Usage of NoneTrue range matcher Contained type is convertible to bool - One true evalutes to false + One true evaluates to false ------------------------------------------------------------------------------- MatchersRanges.tests.cpp: ............................................................................... @@ -13931,6 +14652,324 @@ MatchersRanges.tests.cpp:: PASSED: with expansion: !false +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Basic usage + Empty container matches empty container +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( empty_vector, RangeEquals( empty_vector ) ) +with expansion: + { } elements are { } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Basic usage + Empty container does not match non-empty container +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( empty_vector, !RangeEquals( non_empty_vector ) ) +with expansion: + { } not elements are { 1 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( non_empty_vector, !RangeEquals( empty_vector ) ) +with expansion: + { 1 } not elements are { } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Basic usage + Two equal 1-length non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( non_empty_array, RangeEquals( non_empty_array ) ) +with expansion: + { 1 } elements are { 1 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Basic usage + Two equal-sized, equal, non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_a, RangeEquals( array_a ) ) +with expansion: + { 1, 2, 3 } elements are { 1, 2, 3 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Basic usage + Two equal-sized, non-equal, non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_a, !RangeEquals( array_b ) ) +with expansion: + { 1, 2, 3 } not elements are { 2, 2, 3 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_a, !RangeEquals( array_c ) ) +with expansion: + { 1, 2, 3 } not elements are { 1, 2, 2 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Basic usage + Two non-equal-sized, non-empty containers (with same first elements) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, !RangeEquals( vector_b ) ) +with expansion: + { 1, 2, 3 } not elements are { 1, 2, 3, 4 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Custom predicate + Two equal non-empty containers (close enough) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, RangeEquals( vector_a_plus_1, close_enough ) ) +with expansion: + { 1, 2, 3 } elements are { 2, 3, 4 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Custom predicate + Two non-equal non-empty containers (close enough) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, !RangeEquals( vector_b, close_enough ) ) +with expansion: + { 1, 2, 3 } not elements are { 3, 3, 4 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Ranges that need ADL begin/end +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl2 ) ) +with expansion: + { 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 } + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) ) +with expansion: + { 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Check short-circuiting behaviour + Check short-circuits on failure +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( mocked1, !RangeEquals( arr ) ) +with expansion: + { 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 } + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[0] ) +with expansion: + true + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[1] ) +with expansion: + true + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[2] ) +with expansion: + true + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_FALSE( mocked1.m_derefed[3] ) +with expansion: + !false + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Check short-circuiting behaviour + All elements are checked on success +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( mocked1, RangeEquals( arr ) ) +with expansion: + { 1, 2, 3, 4 } elements are { 1, 2, 3, 4 } + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[0] ) +with expansion: + true + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[1] ) +with expansion: + true + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[2] ) +with expansion: + true + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[3] ) +with expansion: + true + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Basic usage + Empty container matches empty container +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( empty_vector, UnorderedRangeEquals( empty_vector ) ) +with expansion: + { } unordered elements are { } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Basic usage + Empty container does not match non-empty container +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( empty_vector, !UnorderedRangeEquals( non_empty_vector ) ) +with expansion: + { } not unordered elements are { 1 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( non_empty_vector, !UnorderedRangeEquals( empty_vector ) ) +with expansion: + { 1 } not unordered elements are { } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Basic usage + Two equal 1-length non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( non_empty_array, UnorderedRangeEquals( non_empty_array ) ) +with expansion: + { 1 } unordered elements are { 1 } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Basic usage + Two equal-sized, equal, non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_a, UnorderedRangeEquals( array_a ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Basic usage + Two equal-sized, non-equal, non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_a, !UnorderedRangeEquals( array_b ) ) +with expansion: + { 1, 2, 3 } not unordered elements are { 2, 2, 3 } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Basic usage + Two non-equal-sized, non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, !UnorderedRangeEquals( vector_b ) ) +with expansion: + { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Custom predicate + Two equal non-empty containers (close enough) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, UnorderedRangeEquals( vector_a_plus_1, close_enough ) ) +with expansion: + { 1, 10, 20 } unordered elements are { 11, 21, 2 } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Custom predicate + Two non-equal non-empty containers (close enough) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, !UnorderedRangeEquals( vector_b, close_enough ) ) +with expansion: + { 1, 10, 21 } not unordered elements are { 11, 21, 3 } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Ranges that need ADL begin/end +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( needs_adl1, UnorderedRangeEquals( needs_adl2 ) ) +with expansion: + { 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 } + ------------------------------------------------------------------------------- Usage of the SizeIs range matcher Some with stdlib containers @@ -14633,6 +15672,16 @@ with expansion: " ( contains: "attr1="true"" and contains: "attr2="false"" ) +------------------------------------------------------------------------------- +a succeeding test can still be skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: PASSED: + +Skip.tests.cpp:: SKIPPED: + ------------------------------------------------------------------------------- analyse no analysis ------------------------------------------------------------------------------- @@ -15178,6 +16227,34 @@ FloatingPoint.tests.cpp:: PASSED: with expansion: 1 == 1 +------------------------------------------------------------------------------- +dynamic skipping works with generators +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: +explicitly with message: + skipping because answer = 41 + +------------------------------------------------------------------------------- +dynamic skipping works with generators +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: PASSED: + +------------------------------------------------------------------------------- +dynamic skipping works with generators +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: +explicitly with message: + skipping because answer = 43 + ------------------------------------------------------------------------------- empty tags are not allowed ------------------------------------------------------------------------------- @@ -15253,6 +16330,67 @@ Misc.tests.cpp: Misc.tests.cpp:: PASSED: +------------------------------------------------------------------------------- +failed assertions before SKIP cause test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: FAILED: + CHECK( 3 == 4 ) + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +failing for some generator values causes entire test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: FAILED: + +------------------------------------------------------------------------------- +failing for some generator values causes entire test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +failing for some generator values causes entire test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: FAILED: + +------------------------------------------------------------------------------- +failing for some generator values causes entire test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +failing in some unskipped sections causes entire test case to fail + skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +failing in some unskipped sections causes entire test case to fail + not skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: FAILED: + ------------------------------------------------------------------------------- first tag ------------------------------------------------------------------------------- @@ -15749,6 +16887,40 @@ Misc.tests.cpp:: PASSED: with expansion: 1 != 2 +a------------------------------------------------------------------------------- +nested sections can be skipped dynamically at runtime + A +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + + +No assertions in section 'A' + +! +b1------------------------------------------------------------------------------- +nested sections can be skipped dynamically at runtime + B + B1 +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + + +No assertions in section 'B1' + +! +------------------------------------------------------------------------------- +nested sections can be skipped dynamically at runtime + B + B2 +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +! ------------------------------------------------------------------------------- non streamable - with conv. op ------------------------------------------------------------------------------- @@ -16350,6 +17522,33 @@ Misc.tests.cpp: No assertions in test case 'second tag' +------------------------------------------------------------------------------- +sections can be skipped dynamically at runtime + not skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: PASSED: + +------------------------------------------------------------------------------- +sections can be skipped dynamically at runtime + skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +sections can be skipped dynamically at runtime + also not skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: PASSED: + ------------------------------------------------------------------------------- send a single char to INFO ------------------------------------------------------------------------------- @@ -16384,6 +17583,16 @@ Tag.tests.cpp:: PASSED: with expansion: { {?}, {?} } ( Contains: {?} and Contains: {?} ) +------------------------------------------------------------------------------- +skipped tests can optionally provide a reason +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: +explicitly with message: + skipping because answer = 43 + ------------------------------------------------------------------------------- splitString ------------------------------------------------------------------------------- @@ -16811,6 +18020,14 @@ Tag.tests.cpp:: PASSED: with expansion: magic.tag == magic.tag +------------------------------------------------------------------------------- +tests can be skipped dynamically at runtime +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + ------------------------------------------------------------------------------- thrown std::strings are translated ------------------------------------------------------------------------------- @@ -17031,6 +18248,22 @@ InternalBenchmark.tests.cpp:: PASSED: with expansion: 0.95 == 0.95 +------------------------------------------------------------------------------- +uniform_integer_distribution can return the bounds +------------------------------------------------------------------------------- +RandomNumberGeneration.tests.cpp: +............................................................................... + +RandomNumberGeneration.tests.cpp:: PASSED: + REQUIRE( dist.a() == -10 ) +with expansion: + -10 == -10 + +RandomNumberGeneration.tests.cpp:: PASSED: + REQUIRE( dist.b() == 10 ) +with expansion: + 10 == 10 + ------------------------------------------------------------------------------- unique_ptr reimplementation: basic functionality Default constructed unique_ptr is empty @@ -17518,6 +18751,6 @@ Misc.tests.cpp: Misc.tests.cpp:: PASSED: =============================================================================== -test cases: 394 | 304 passed | 83 failed | 7 failed as expected -assertions: 2159 | 1989 passed | 143 failed | 27 failed as expected +test cases: 417 | 312 passed | 85 failed | 6 skipped | 14 failed as expected +assertions: 2260 | 2079 passed | 146 failed | 35 failed as expected diff --git a/tests/SelfTest/Baselines/console.sw.multi.approved.txt b/tests/SelfTest/Baselines/console.sw.multi.approved.txt index c281374f..5d204990 100644 --- a/tests/SelfTest/Baselines/console.sw.multi.approved.txt +++ b/tests/SelfTest/Baselines/console.sw.multi.approved.txt @@ -759,6 +759,16 @@ with expansion: 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0. 00000000e+00]) +------------------------------------------------------------------------------- +#2615 - Throwing in constructor generator fails test case but does not abort +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: FAILED: +due to unexpected exception with message: + failure to init + ------------------------------------------------------------------------------- #748 - captures with unexpected exceptions outside assertions @@ -2728,9 +2738,9 @@ Message.tests.cpp: Message.tests.cpp:: PASSED: with messages: - std::vector{1, 2, 3}[0, 1, 2] := 3 - std::vector{1, 2, 3}[(0, 1)] := 2 - std::vector{1, 2, 3}[0] := 1 + custom_index_op{1, 2, 3}[0, 1, 2] := 0 + custom_index_op{1, 2, 3}[(0, 1)] := 0 + custom_index_op{1, 2, 3}[0] := 0 (helper_1436{12, -12}) := { 12, -12 } (helper_1436(-12, 12)) := { -12, 12 } (1, 2) := 2 @@ -3944,6 +3954,16 @@ with expansion: == "{** unexpected enum value **}" +------------------------------------------------------------------------------- +Empty generators can SKIP in constructor +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: +explicitly with message: + This generator is empty + ------------------------------------------------------------------------------- Empty stream name opens cout stream ------------------------------------------------------------------------------- @@ -3955,15 +3975,6 @@ Stream.tests.cpp:: PASSED: with expansion: true -------------------------------------------------------------------------------- -Empty tag is not allowed -------------------------------------------------------------------------------- -Tag.tests.cpp: -............................................................................... - -Tag.tests.cpp:: PASSED: - REQUIRE_THROWS( Catch::TestCaseInfo( "", { "fake test name", "[]" }, dummySourceLineInfo ) ) - ------------------------------------------------------------------------------- EndsWith string matcher ------------------------------------------------------------------------------- @@ -4280,6 +4291,32 @@ Matchers.tests.cpp:: PASSED: with expansion: SpecialException::what special exception has value of 2 +------------------------------------------------------------------------------- +Exception message can be matched +------------------------------------------------------------------------------- +Matchers.tests.cpp: +............................................................................... + +Matchers.tests.cpp:: PASSED: + REQUIRE_THROWS_MATCHES( throwsDerivedException(), DerivedException, MessageMatches( StartsWith( "Derived" ) ) ) +with expansion: + DerivedException::what matches "starts with: "Derived"" + +Matchers.tests.cpp:: PASSED: + REQUIRE_THROWS_MATCHES( throwsDerivedException(), DerivedException, MessageMatches( EndsWith( "::what" ) ) ) +with expansion: + DerivedException::what matches "ends with: "::what"" + +Matchers.tests.cpp:: PASSED: + REQUIRE_THROWS_MATCHES( throwsDerivedException(), DerivedException, MessageMatches( !StartsWith( "::what" ) ) ) +with expansion: + DerivedException::what matches "not starts with: "::what"" + +Matchers.tests.cpp:: PASSED: + REQUIRE_THROWS_MATCHES( throwsSpecialException( 2 ), SpecialException, MessageMatches( StartsWith( "Special" ) ) ) +with expansion: + SpecialException::what matches "starts with: "Special"" + ------------------------------------------------------------------------------- Exception messages can be tested for exact match @@ -4439,6 +4476,15 @@ Misc.tests.cpp:: PASSED: with expansion: 3628800 (0x) == 3628800 (0x) +------------------------------------------------------------------------------- +Filter generator throws exception for empty generator +------------------------------------------------------------------------------- +GeneratorsImpl.tests.cpp: +............................................................................... + +GeneratorsImpl.tests.cpp:: PASSED: + REQUIRE_THROWS_AS( filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException ) + ------------------------------------------------------------------------------- Floating point matchers: double Relative @@ -4624,6 +4670,18 @@ Matchers.tests.cpp:: PASSED: Matchers.tests.cpp:: PASSED: REQUIRE_THROWS_AS( WithinRel( 1., 1. ), std::domain_error ) +------------------------------------------------------------------------------- +Floating point matchers: double + IsNaN +------------------------------------------------------------------------------- +Matchers.tests.cpp: +............................................................................... + +Matchers.tests.cpp:: PASSED: + REQUIRE_THAT( 1., !IsNaN() ) +with expansion: + 1.0 not is NaN + ------------------------------------------------------------------------------- Floating point matchers: float Relative @@ -4817,6 +4875,62 @@ Matchers.tests.cpp:: PASSED: Matchers.tests.cpp:: PASSED: REQUIRE_THROWS_AS( WithinRel( 1.f, 1.f ), std::domain_error ) +------------------------------------------------------------------------------- +Floating point matchers: float + IsNaN +------------------------------------------------------------------------------- +Matchers.tests.cpp: +............................................................................... + +Matchers.tests.cpp:: PASSED: + REQUIRE_THAT( 1., !IsNaN() ) +with expansion: + 1.0 not is NaN + +------------------------------------------------------------------------------- +GENERATE can combine literals and generators +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i % 2 == 0 ) +with expansion: + 0 == 0 + +------------------------------------------------------------------------------- +GENERATE can combine literals and generators +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i % 2 == 0 ) +with expansion: + 0 == 0 + +------------------------------------------------------------------------------- +GENERATE can combine literals and generators +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i % 2 == 0 ) +with expansion: + 0 == 0 + +------------------------------------------------------------------------------- +GENERATE can combine literals and generators +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i % 2 == 0 ) +with expansion: + 0 == 0 + ------------------------------------------------------------------------------- Generators -- adapters Filtering by predicate @@ -6910,6 +7024,18 @@ with expansion: == 3422778688 (0x) +------------------------------------------------------------------------------- +INFO and UNSCOPED_INFO can stream multiple arguments +------------------------------------------------------------------------------- +Message.tests.cpp: +............................................................................... + +Message.tests.cpp:: FAILED: +explicitly with messages: + This info has multiple parts. + This unscoped info has multiple parts. + Show infos! + ------------------------------------------------------------------------------- INFO and WARN do not abort tests ------------------------------------------------------------------------------- @@ -7071,6 +7197,17 @@ with messages: current counter 10 i := 10 +------------------------------------------------------------------------------- +Incomplete AssertionHandler +------------------------------------------------------------------------------- +AssertionHandler.tests.cpp: +............................................................................... + +AssertionHandler.tests.cpp:: FAILED: + REQUIRE( Dummy ) +due to unexpected exception with message: + Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE + ------------------------------------------------------------------------------- Inequality checks that should fail ------------------------------------------------------------------------------- @@ -7163,6 +7300,291 @@ Condition.tests.cpp:: PASSED: with expansion: 5 != 6 +------------------------------------------------------------------------------- +JsonWriter + Newly constructed JsonWriter does nothing +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "" ) +with expansion: + "" == "" + +------------------------------------------------------------------------------- +JsonWriter + Calling writeObject will create an empty pair of braces +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "{\n}" ) +with expansion: + "{ + }" + == + "{ + }" + +------------------------------------------------------------------------------- +JsonWriter + Calling writeObject with key will create an object to write the value +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE_THAT( stream.str(), ContainsSubstring( "\"int\": 1," ) && ContainsSubstring( "\"double\": 1.5," ) && ContainsSubstring( "\"true\": true," ) && ContainsSubstring( "\"false\": false," ) && ContainsSubstring( "\"string\": \"this is a string\"," ) && ContainsSubstring( "\"array\": [\n 1,\n 2\n ]\n}" ) ) +with expansion: + "{ + "int": 1, + "double": 1.5, + "true": true, + "false": false, + "string": "this is a string", + "array": [ + 1, + 2 + ] + }" ( contains: ""int": 1," and contains: ""double": 1.5," and contains: + ""true": true," and contains: ""false": false," and contains: ""string": + "this is a string"," and contains: ""array": [ + 1, + 2 + ] + }" ) + +------------------------------------------------------------------------------- +JsonWriter + nesting objects +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE_THAT( stream.str(), ContainsSubstring( "\"empty_object\": {\n }," ) && ContainsSubstring( "\"fully_object\": {\n \"key\": 1\n }" ) ) +with expansion: + "{ + "empty_object": { + }, + "fully_object": { + "key": 1 + } + }" ( contains: ""empty_object": { + }," and contains: ""fully_object": { + "key": 1 + }" ) + +------------------------------------------------------------------------------- +JsonWriter + Calling writeArray will create an empty pair of braces +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "[\n]" ) +with expansion: + "[ + ]" + == + "[ + ]" + +------------------------------------------------------------------------------- +JsonWriter + Calling writeArray creates array to write the values to +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "[\n 1,\n 1.5,\n true,\n false,\n \"this is a string\",\n {\n \"object\": 42\n },\n [\n \"array\",\n 42.5\n ]\n]" ) +with expansion: + "[ + 1, + 1.5, + true, + false, + "this is a string", + { + "object": 42 + }, + [ + "array", + 42.5 + ] + ]" + == + "[ + 1, + 1.5, + true, + false, + "this is a string", + { + "object": 42 + }, + [ + "array", + 42.5 + ] + ]" + +------------------------------------------------------------------------------- +JsonWriter + Moved from JsonObjectWriter shall not insert superfluous brace +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "{\n}" ) +with expansion: + "{ + }" + == + "{ + }" + +------------------------------------------------------------------------------- +JsonWriter + Moved from JsonArrayWriter shall not insert superfluous bracket +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "[\n]" ) +with expansion: + "[ + ]" + == + "[ + ]" + +------------------------------------------------------------------------------- +JsonWriter + Custom class shall be quoted +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( stream.str() == "\"custom\"" ) +with expansion: + ""custom"" == ""custom"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + Quote in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\\"\"" ) +with expansion: + ""\""" == ""\""" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + Backslash in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\\\\"" ) +with expansion: + ""\\"" == ""\\"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + Forward slash in a string is **not** escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"/\"" ) +with expansion: + ""/"" == ""/"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + Backspace in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\b\"" ) +with expansion: + ""\b"" == ""\b"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + Formfeed in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\f\"" ) +with expansion: + ""\f"" == ""\f"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + linefeed in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\n\"" ) +with expansion: + ""\n"" == ""\n"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + carriage return in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\r\"" ) +with expansion: + ""\r"" == ""\r"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + tab in a string is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\t\"" ) +with expansion: + ""\t"" == ""\t"" + +------------------------------------------------------------------------------- +JsonWriter escapes charaters in strings properly + combination of characters is escaped +------------------------------------------------------------------------------- +Json.tests.cpp: +............................................................................... + +Json.tests.cpp:: PASSED: + REQUIRE( sstream.str() == "\"\\\\/\\t\\r\\n\"" ) +with expansion: + ""\\/\t\r\n"" == ""\\/\t\r\n"" + ------------------------------------------------------------------------------- Lambdas in assertions ------------------------------------------------------------------------------- @@ -9661,6 +10083,129 @@ Reporter's write listings to provided stream Reporters.tests.cpp: ............................................................................... +Reporters.tests.cpp:: PASSED: + REQUIRE_FALSE( factories.empty() ) +with expansion: + !false + +------------------------------------------------------------------------------- +Reporter's write listings to provided stream + JSON reporter lists tags +------------------------------------------------------------------------------- +Reporters.tests.cpp: +............................................................................... + +Reporters.tests.cpp:: PASSED: + REQUIRE_THAT( listingString, ContainsSubstring("fakeTag"s) ) +with expansion: + "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "tags": [ + { + "aliases": [ + "fakeTag" + ], + "count": 1 + } + ]" contains: "fakeTag" +with message: + Tested reporter: JSON + +------------------------------------------------------------------------------- +Reporter's write listings to provided stream +------------------------------------------------------------------------------- +Reporters.tests.cpp: +............................................................................... + +Reporters.tests.cpp:: PASSED: + REQUIRE_FALSE( factories.empty() ) +with expansion: + !false + +------------------------------------------------------------------------------- +Reporter's write listings to provided stream + JSON reporter lists reporters +------------------------------------------------------------------------------- +Reporters.tests.cpp: +............................................................................... + +Reporters.tests.cpp:: PASSED: + REQUIRE_THAT( listingString, ContainsSubstring("fake reporter"s) ) +with expansion: + "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "reporters": [ + { + "name": "fake reporter", + "description": "fake description" + } + ]" contains: "fake reporter" +with message: + Tested reporter: JSON + +------------------------------------------------------------------------------- +Reporter's write listings to provided stream +------------------------------------------------------------------------------- +Reporters.tests.cpp: +............................................................................... + +Reporters.tests.cpp:: PASSED: + REQUIRE_FALSE( factories.empty() ) +with expansion: + !false + +------------------------------------------------------------------------------- +Reporter's write listings to provided stream + JSON reporter lists tests +------------------------------------------------------------------------------- +Reporters.tests.cpp: +............................................................................... + +Reporters.tests.cpp:: PASSED: + REQUIRE_THAT( listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) ) +with expansion: + "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "tests": [ + { + "name": "fake test name", + "class-name": "", + "tags": [ + "fakeTestTag" + ], + "source-location": { + "filename": "fake-file.cpp", + "line": 123456789 + } + } + ]" ( contains: "fake test name" and contains: "fakeTestTag" ) +with message: + Tested reporter: JSON + +------------------------------------------------------------------------------- +Reporter's write listings to provided stream +------------------------------------------------------------------------------- +Reporters.tests.cpp: +............................................................................... + Reporters.tests.cpp:: PASSED: REQUIRE_FALSE( factories.empty() ) with expansion: @@ -12445,6 +12990,34 @@ Misc.tests.cpp:: FAILED - but was ok: Misc.tests.cpp:: FAILED: +------------------------------------------------------------------------------- +Testing checked-if 4 +------------------------------------------------------------------------------- +Misc.tests.cpp: +............................................................................... + +Misc.tests.cpp:: PASSED: + CHECKED_ELSE( true ) + +Misc.tests.cpp:: FAILED: + {Unknown expression after the reported line} +due to unexpected exception with message: + Uncaught exception should fail! + +------------------------------------------------------------------------------- +Testing checked-if 5 +------------------------------------------------------------------------------- +Misc.tests.cpp: +............................................................................... + +Misc.tests.cpp:: FAILED - but was ok: + CHECKED_ELSE( false ) + +Misc.tests.cpp:: FAILED: + {Unknown expression after the reported line} +due to unexpected exception with message: + Uncaught exception should fail! + ------------------------------------------------------------------------------- The NO_FAIL macro reports a failure but does not fail the test ------------------------------------------------------------------------------- @@ -13065,6 +13638,154 @@ with expansion: == There is no extra whitespace here +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Container conversions + Two equal containers of different container types +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_a, RangeEquals( c_array ) ) +with expansion: + { 1, 2, 3 } elements are { 1, 2, 3 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_a, UnorderedRangeEquals( c_array ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Container conversions + Two equal containers of different container types (differ in array N) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_3, !RangeEquals( array_int_4 ) ) +with expansion: + { 1, 2, 3 } not elements are { 1, 2, 3, 4 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_3, !UnorderedRangeEquals( array_int_4 ) ) +with expansion: + { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Container conversions + Two equal containers of different container types and value types +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_a, RangeEquals( vector_char_a ) ) +with expansion: + { 1, 2, 3 } elements are { 1, 2, 3 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_a, UnorderedRangeEquals( vector_char_a ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Container conversions + Two equal containers, one random access, one not +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: +with message: + ContainerIsRandomAccess( array_int_a ) != ContainerIsRandomAccess( + list_char_a ) + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_a, RangeEquals( list_char_a ) ) +with expansion: + { 1, 2, 3 } elements are { 1, 2, 3 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_int_a, UnorderedRangeEquals( list_char_a ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Value type + Two equal containers of different value types +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_int_a, RangeEquals( vector_char_a ) ) +with expansion: + { 1, 2, 3 } elements are { 1, 2, 3 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_int_a, UnorderedRangeEquals( vector_char_a ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Value type + Two non-equal containers of different value types +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_int_a, !RangeEquals( vector_char_b ) ) +with expansion: + { 1, 2, 3 } not elements are { 1, 2, 2 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_int_a, !UnorderedRangeEquals( vector_char_b ) ) +with expansion: + { 1, 2, 3 } not unordered elements are { 1, 2, 2 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Ranges with begin that needs ADL +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( a, !RangeEquals( b ) ) +with expansion: + { 1, 2, 3 } not elements are { 3, 2, 1 } + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( a, UnorderedRangeEquals( b ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 3, 2, 1 } + +------------------------------------------------------------------------------- +Type conversions of RangeEquals and similar + Custom predicate + Two equal non-empty containers (close enough) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, RangeEquals( array_a_plus_1, close_enough ) ) +with expansion: + { 1, 2, 3 } elements are { 2, 3, 4 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, UnorderedRangeEquals( array_a_plus_1, close_enough ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 2, 3, 4 } + ------------------------------------------------------------------------------- Unexpected exceptions can be translated ------------------------------------------------------------------------------- @@ -13236,7 +13957,7 @@ with expansion: ------------------------------------------------------------------------------- Usage of AllTrue range matcher Basic usage - One false evalutes to false + One false evaluates to false ------------------------------------------------------------------------------- MatchersRanges.tests.cpp: ............................................................................... @@ -13275,7 +13996,7 @@ with expansion: ------------------------------------------------------------------------------- Usage of AllTrue range matcher Contained type is convertible to bool - One false evalutes to false + One false evaluates to false ------------------------------------------------------------------------------- MatchersRanges.tests.cpp: ............................................................................... @@ -13511,7 +14232,7 @@ with expansion: ------------------------------------------------------------------------------- Usage of AnyTrue range matcher Basic usage - One true evalutes to true + One true evaluates to true ------------------------------------------------------------------------------- MatchersRanges.tests.cpp: ............................................................................... @@ -13550,7 +14271,7 @@ with expansion: ------------------------------------------------------------------------------- Usage of AnyTrue range matcher Contained type is convertible to bool - One true evalutes to true + One true evaluates to true ------------------------------------------------------------------------------- MatchersRanges.tests.cpp: ............................................................................... @@ -13786,7 +14507,7 @@ with expansion: ------------------------------------------------------------------------------- Usage of NoneTrue range matcher Basic usage - One true evalutes to false + One true evaluates to false ------------------------------------------------------------------------------- MatchersRanges.tests.cpp: ............................................................................... @@ -13825,7 +14546,7 @@ with expansion: ------------------------------------------------------------------------------- Usage of NoneTrue range matcher Contained type is convertible to bool - One true evalutes to false + One true evaluates to false ------------------------------------------------------------------------------- MatchersRanges.tests.cpp: ............................................................................... @@ -13924,6 +14645,324 @@ MatchersRanges.tests.cpp:: PASSED: with expansion: !false +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Basic usage + Empty container matches empty container +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( empty_vector, RangeEquals( empty_vector ) ) +with expansion: + { } elements are { } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Basic usage + Empty container does not match non-empty container +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( empty_vector, !RangeEquals( non_empty_vector ) ) +with expansion: + { } not elements are { 1 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( non_empty_vector, !RangeEquals( empty_vector ) ) +with expansion: + { 1 } not elements are { } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Basic usage + Two equal 1-length non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( non_empty_array, RangeEquals( non_empty_array ) ) +with expansion: + { 1 } elements are { 1 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Basic usage + Two equal-sized, equal, non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_a, RangeEquals( array_a ) ) +with expansion: + { 1, 2, 3 } elements are { 1, 2, 3 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Basic usage + Two equal-sized, non-equal, non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_a, !RangeEquals( array_b ) ) +with expansion: + { 1, 2, 3 } not elements are { 2, 2, 3 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_a, !RangeEquals( array_c ) ) +with expansion: + { 1, 2, 3 } not elements are { 1, 2, 2 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Basic usage + Two non-equal-sized, non-empty containers (with same first elements) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, !RangeEquals( vector_b ) ) +with expansion: + { 1, 2, 3 } not elements are { 1, 2, 3, 4 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Custom predicate + Two equal non-empty containers (close enough) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, RangeEquals( vector_a_plus_1, close_enough ) ) +with expansion: + { 1, 2, 3 } elements are { 2, 3, 4 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Custom predicate + Two non-equal non-empty containers (close enough) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, !RangeEquals( vector_b, close_enough ) ) +with expansion: + { 1, 2, 3 } not elements are { 3, 3, 4 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Ranges that need ADL begin/end +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl2 ) ) +with expansion: + { 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 } + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) ) +with expansion: + { 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 } + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Check short-circuiting behaviour + Check short-circuits on failure +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( mocked1, !RangeEquals( arr ) ) +with expansion: + { 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 } + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[0] ) +with expansion: + true + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[1] ) +with expansion: + true + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[2] ) +with expansion: + true + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_FALSE( mocked1.m_derefed[3] ) +with expansion: + !false + +------------------------------------------------------------------------------- +Usage of RangeEquals range matcher + Check short-circuiting behaviour + All elements are checked on success +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( mocked1, RangeEquals( arr ) ) +with expansion: + { 1, 2, 3, 4 } elements are { 1, 2, 3, 4 } + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[0] ) +with expansion: + true + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[1] ) +with expansion: + true + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[2] ) +with expansion: + true + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE( mocked1.m_derefed[3] ) +with expansion: + true + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Basic usage + Empty container matches empty container +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( empty_vector, UnorderedRangeEquals( empty_vector ) ) +with expansion: + { } unordered elements are { } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Basic usage + Empty container does not match non-empty container +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( empty_vector, !UnorderedRangeEquals( non_empty_vector ) ) +with expansion: + { } not unordered elements are { 1 } + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( non_empty_vector, !UnorderedRangeEquals( empty_vector ) ) +with expansion: + { 1 } not unordered elements are { } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Basic usage + Two equal 1-length non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( non_empty_array, UnorderedRangeEquals( non_empty_array ) ) +with expansion: + { 1 } unordered elements are { 1 } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Basic usage + Two equal-sized, equal, non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_a, UnorderedRangeEquals( array_a ) ) +with expansion: + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Basic usage + Two equal-sized, non-equal, non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( array_a, !UnorderedRangeEquals( array_b ) ) +with expansion: + { 1, 2, 3 } not unordered elements are { 2, 2, 3 } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Basic usage + Two non-equal-sized, non-empty containers +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, !UnorderedRangeEquals( vector_b ) ) +with expansion: + { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Custom predicate + Two equal non-empty containers (close enough) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, UnorderedRangeEquals( vector_a_plus_1, close_enough ) ) +with expansion: + { 1, 10, 20 } unordered elements are { 11, 21, 2 } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Custom predicate + Two non-equal non-empty containers (close enough) +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + CHECK_THAT( vector_a, !UnorderedRangeEquals( vector_b, close_enough ) ) +with expansion: + { 1, 10, 21 } not unordered elements are { 11, 21, 3 } + +------------------------------------------------------------------------------- +Usage of UnorderedRangeEquals range matcher + Ranges that need ADL begin/end +------------------------------------------------------------------------------- +MatchersRanges.tests.cpp: +............................................................................... + +MatchersRanges.tests.cpp:: PASSED: + REQUIRE_THAT( needs_adl1, UnorderedRangeEquals( needs_adl2 ) ) +with expansion: + { 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 } + ------------------------------------------------------------------------------- Usage of the SizeIs range matcher Some with stdlib containers @@ -14626,6 +15665,16 @@ with expansion: " ( contains: "attr1="true"" and contains: "attr2="false"" ) +------------------------------------------------------------------------------- +a succeeding test can still be skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: PASSED: + +Skip.tests.cpp:: SKIPPED: + ------------------------------------------------------------------------------- analyse no analysis ------------------------------------------------------------------------------- @@ -15171,6 +16220,34 @@ FloatingPoint.tests.cpp:: PASSED: with expansion: 1 == 1 +------------------------------------------------------------------------------- +dynamic skipping works with generators +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: +explicitly with message: + skipping because answer = 41 + +------------------------------------------------------------------------------- +dynamic skipping works with generators +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: PASSED: + +------------------------------------------------------------------------------- +dynamic skipping works with generators +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: +explicitly with message: + skipping because answer = 43 + ------------------------------------------------------------------------------- empty tags are not allowed ------------------------------------------------------------------------------- @@ -15246,6 +16323,67 @@ Misc.tests.cpp: Misc.tests.cpp:: PASSED: +------------------------------------------------------------------------------- +failed assertions before SKIP cause test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: FAILED: + CHECK( 3 == 4 ) + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +failing for some generator values causes entire test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: FAILED: + +------------------------------------------------------------------------------- +failing for some generator values causes entire test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +failing for some generator values causes entire test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: FAILED: + +------------------------------------------------------------------------------- +failing for some generator values causes entire test case to fail +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +failing in some unskipped sections causes entire test case to fail + skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +failing in some unskipped sections causes entire test case to fail + not skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: FAILED: + ------------------------------------------------------------------------------- first tag ------------------------------------------------------------------------------- @@ -15741,6 +16879,37 @@ Misc.tests.cpp:: PASSED: with expansion: 1 != 2 +------------------------------------------------------------------------------- +nested sections can be skipped dynamically at runtime + A +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + + +No assertions in section 'A' + +------------------------------------------------------------------------------- +nested sections can be skipped dynamically at runtime + B + B1 +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + + +No assertions in section 'B1' + +------------------------------------------------------------------------------- +nested sections can be skipped dynamically at runtime + B + B2 +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + ------------------------------------------------------------------------------- non streamable - with conv. op ------------------------------------------------------------------------------- @@ -16342,6 +17511,33 @@ Misc.tests.cpp: No assertions in test case 'second tag' +------------------------------------------------------------------------------- +sections can be skipped dynamically at runtime + not skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: PASSED: + +------------------------------------------------------------------------------- +sections can be skipped dynamically at runtime + skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + +------------------------------------------------------------------------------- +sections can be skipped dynamically at runtime + also not skipped +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: PASSED: + ------------------------------------------------------------------------------- send a single char to INFO ------------------------------------------------------------------------------- @@ -16376,6 +17572,16 @@ Tag.tests.cpp:: PASSED: with expansion: { {?}, {?} } ( Contains: {?} and Contains: {?} ) +------------------------------------------------------------------------------- +skipped tests can optionally provide a reason +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: +explicitly with message: + skipping because answer = 43 + ------------------------------------------------------------------------------- splitString ------------------------------------------------------------------------------- @@ -16803,6 +18009,14 @@ Tag.tests.cpp:: PASSED: with expansion: magic.tag == magic.tag +------------------------------------------------------------------------------- +tests can be skipped dynamically at runtime +------------------------------------------------------------------------------- +Skip.tests.cpp: +............................................................................... + +Skip.tests.cpp:: SKIPPED: + ------------------------------------------------------------------------------- thrown std::strings are translated ------------------------------------------------------------------------------- @@ -17023,6 +18237,22 @@ InternalBenchmark.tests.cpp:: PASSED: with expansion: 0.95 == 0.95 +------------------------------------------------------------------------------- +uniform_integer_distribution can return the bounds +------------------------------------------------------------------------------- +RandomNumberGeneration.tests.cpp: +............................................................................... + +RandomNumberGeneration.tests.cpp:: PASSED: + REQUIRE( dist.a() == -10 ) +with expansion: + -10 == -10 + +RandomNumberGeneration.tests.cpp:: PASSED: + REQUIRE( dist.b() == 10 ) +with expansion: + 10 == 10 + ------------------------------------------------------------------------------- unique_ptr reimplementation: basic functionality Default constructed unique_ptr is empty @@ -17510,6 +18740,6 @@ Misc.tests.cpp: Misc.tests.cpp:: PASSED: =============================================================================== -test cases: 394 | 304 passed | 83 failed | 7 failed as expected -assertions: 2159 | 1989 passed | 143 failed | 27 failed as expected +test cases: 417 | 312 passed | 85 failed | 6 skipped | 14 failed as expected +assertions: 2260 | 2079 passed | 146 failed | 35 failed as expected diff --git a/tests/SelfTest/Baselines/console.swa4.approved.txt b/tests/SelfTest/Baselines/console.swa4.approved.txt index 60517504..41b7612a 100644 --- a/tests/SelfTest/Baselines/console.swa4.approved.txt +++ b/tests/SelfTest/Baselines/console.swa4.approved.txt @@ -761,6 +761,16 @@ with expansion: 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0. 00000000e+00]) +------------------------------------------------------------------------------- +#2615 - Throwing in constructor generator fails test case but does not abort +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: FAILED: +due to unexpected exception with message: + failure to init + ------------------------------------------------------------------------------- #748 - captures with unexpected exceptions outside assertions @@ -941,6 +951,6 @@ Condition.tests.cpp:: FAILED: CHECK( true != true ) =============================================================================== -test cases: 32 | 27 passed | 3 failed | 2 failed as expected -assertions: 101 | 94 passed | 4 failed | 3 failed as expected +test cases: 33 | 27 passed | 3 failed | 3 failed as expected +assertions: 102 | 94 passed | 4 failed | 4 failed as expected diff --git a/tests/SelfTest/Baselines/default.sw.multi.approved.txt b/tests/SelfTest/Baselines/default.sw.multi.approved.txt index 12717aa5..bb174844 100644 --- a/tests/SelfTest/Baselines/default.sw.multi.approved.txt +++ b/tests/SelfTest/Baselines/default.sw.multi.approved.txt @@ -6,3 +6,6 @@ A string sent to stderr via clog Message from section one Message from section two loose text artifact +a! +b1! +! diff --git a/tests/SelfTest/Baselines/junit.sw.approved.txt b/tests/SelfTest/Baselines/junit.sw.approved.txt index bd983051..48eccfc3 100644 --- a/tests/SelfTest/Baselines/junit.sw.approved.txt +++ b/tests/SelfTest/Baselines/junit.sw.approved.txt @@ -1,7 +1,7 @@ - + @@ -19,7 +19,7 @@ FAILED: 1514 -Tricky.tests.cpp: +at Tricky.tests.cpp: This would not be caught previously @@ -48,13 +48,21 @@ Nor would this + + + +FAILED: +failure to init +at Generators.tests.cpp: + + FAILED: expected exception answer := 42 -Exception.tests.cpp: +at Exception.tests.cpp: @@ -64,7 +72,7 @@ FAILED: REQUIRE_NOTHROW( thisThrows() ) expected exception answer := 42 -Exception.tests.cpp: +at Exception.tests.cpp: @@ -77,7 +85,7 @@ FAILED: CHECK( f() == 0 ) with expansion: 1 == 0 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -90,52 +98,52 @@ Misc.tests.cpp: FAILED: CHECK( false != false ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( true != true ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( !true ) with expansion: false -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK_FALSE( true ) with expansion: !true -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( !trueValue ) with expansion: false -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK_FALSE( trueValue ) with expansion: !true -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( !(1 == 1) ) with expansion: false -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK_FALSE( 1 == 1 ) -Condition.tests.cpp: +at Condition.tests.cpp: @@ -151,7 +159,7 @@ FAILED: REQUIRE( s == "world" ) with expansion: "hello" == "world" -Class.tests.cpp: +at Class.tests.cpp: @@ -161,7 +169,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -170,7 +178,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -179,7 +187,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -188,7 +196,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -201,7 +209,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 6 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -210,7 +218,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 2 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -219,7 +227,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 6 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -228,7 +236,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 2 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -241,7 +249,7 @@ FAILED: REQUIRE( Template_Fixture<TestType>::m_a == 2 ) with expansion: 1.0 == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -250,7 +258,7 @@ FAILED: REQUIRE( Template_Fixture<TestType>::m_a == 2 ) with expansion: 1.0f == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -259,7 +267,7 @@ FAILED: REQUIRE( Template_Fixture<TestType>::m_a == 2 ) with expansion: 1 == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -271,7 +279,7 @@ FAILED: REQUIRE( Nttp_Fixture<V>::value == 0 ) with expansion: 1 == 0 -Class.tests.cpp: +at Class.tests.cpp: @@ -280,7 +288,7 @@ FAILED: REQUIRE( Nttp_Fixture<V>::value == 0 ) with expansion: 3 == 0 -Class.tests.cpp: +at Class.tests.cpp: @@ -289,7 +297,7 @@ FAILED: REQUIRE( Nttp_Fixture<V>::value == 0 ) with expansion: 6 == 0 -Class.tests.cpp: +at Class.tests.cpp: @@ -301,7 +309,7 @@ FAILED: REQUIRE( m_a == 2 ) with expansion: 1 == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -318,7 +326,7 @@ Class.tests.cpp: FAILED: to infinity and beyond -Misc.tests.cpp: +at Misc.tests.cpp: @@ -328,14 +336,14 @@ FAILED: CHECK( &o1 == &o2 ) with expansion: 0x == 0x -Tricky.tests.cpp: +at Tricky.tests.cpp: FAILED: CHECK( o1 == o2 ) with expansion: {?} == {?} -Tricky.tests.cpp: +at Tricky.tests.cpp: @@ -345,7 +353,7 @@ Tricky.tests.cpp: FAILED: {Unknown expression after the reported line} unexpected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -415,14 +423,14 @@ FAILED: with expansion: "this string contains 'abc' as a substring" contains: "not there" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), ContainsSubstring( "STRING" ) ) with expansion: "this string contains 'abc' as a substring" contains: "STRING" -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -434,7 +442,7 @@ Matchers.tests.cpp: FAILED: REQUIRE_NOTHROW( throwCustom() ) custom exception - not std -Exception.tests.cpp: +at Exception.tests.cpp: @@ -442,27 +450,33 @@ Exception.tests.cpp: FAILED: REQUIRE_THROWS_AS( throwCustom(), std::exception ) custom exception - not std -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: custom std exception -Exception.tests.cpp: +at Exception.tests.cpp: + + +SKIPPED +This generator is empty +at Skip.tests.cpp: + + - FAILED: CHECK_THAT( testStringForMatching(), EndsWith( "Substring" ) ) with expansion: "this string contains 'abc' as a substring" ends with: "Substring" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: @@ -470,7 +484,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" ends with: "this" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -483,91 +497,91 @@ FAILED: CHECK( data.int_seven == 6 ) with expansion: 7 == 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven == 8 ) with expansion: 7 == 8 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven == 0 ) with expansion: 7 == 0 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 9.11f ) ) with expansion: 9.1f == Approx( 9.1099996567 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 9.0f ) ) with expansion: 9.1f == Approx( 9.0 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 1 ) ) with expansion: 9.1f == Approx( 1.0 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 0 ) ) with expansion: 9.1f == Approx( 0.0 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.double_pi == Approx( 3.1415 ) ) with expansion: 3.1415926535 == Approx( 3.1415 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello == "goodbye" ) with expansion: "hello" == "goodbye" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello == "hell" ) with expansion: "hello" == "hell" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello == "hello1" ) with expansion: "hello" == "hello1" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello.size() == 6 ) with expansion: 5 == 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( x == Approx( 1.301 ) ) with expansion: 1.3 == Approx( 1.301 ) -Condition.tests.cpp: +at Condition.tests.cpp: @@ -579,7 +593,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: @@ -587,7 +601,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" equals: "something else" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -595,12 +609,12 @@ Matchers.tests.cpp: FAILED: CHECK_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } ) -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: REQUIRE_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } ) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -608,13 +622,13 @@ Matchers.tests.cpp: FAILED: CHECK_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } ) Unknown exception -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: REQUIRE_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } ) Unknown exception -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -623,17 +637,18 @@ FAILED: CHECK_THROWS_MATCHES( throwsSpecialException( 3 ), SpecialException, ExceptionMatcher{ 1 } ) with expansion: SpecialException::what special exception has value of 1 -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: REQUIRE_THROWS_MATCHES( throwsSpecialException( 4 ), SpecialException, ExceptionMatcher{ 1 } ) with expansion: SpecialException::what special exception has value of 1 -Matchers.tests.cpp: +at Matchers.tests.cpp: + @@ -643,53 +658,57 @@ Matchers.tests.cpp: FAILED: CHECK_THROWS_AS( thisThrows(), std::string ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error ) -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: CHECK_NOTHROW( thisThrows() ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: This is a failure -Message.tests.cpp: +at Message.tests.cpp: FAILED: -Message.tests.cpp: +at Message.tests.cpp: FAILED: This is a failure -Message.tests.cpp: +at Message.tests.cpp: + + + + @@ -734,6 +753,15 @@ Message.tests.cpp: + + +FAILED: +Show infos! +This info has multiple parts. +This unscoped info has multiple parts. +at Message.tests.cpp: + + @@ -743,7 +771,7 @@ with expansion: 2 == 1 this message should be logged so should this -Message.tests.cpp: +at Message.tests.cpp: @@ -754,7 +782,7 @@ with expansion: 2 == 1 this message may be logged later this message should be logged -Message.tests.cpp: +at Message.tests.cpp: FAILED: @@ -764,7 +792,7 @@ with expansion: this message may be logged later this message should be logged and this, but later -Message.tests.cpp: +at Message.tests.cpp: @@ -775,9 +803,18 @@ with expansion: 10 < 10 current counter 10 i := 10 -Message.tests.cpp: +at Message.tests.cpp: + + + +FAILED: + REQUIRE( Dummy ) +Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE +at AssertionHandler.tests.cpp: + + @@ -785,38 +822,56 @@ FAILED: CHECK( data.int_seven != 7 ) with expansion: 7 != 7 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one != Approx( 9.1f ) ) with expansion: 9.1f != Approx( 9.1000003815 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.double_pi != Approx( 3.1415926535 ) ) with expansion: 3.1415926535 != Approx( 3.1415926535 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello != "hello" ) with expansion: "hello" != "hello" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello.size() != 5 ) with expansion: 5 != 5 -Condition.tests.cpp: +at Condition.tests.cpp: + + + + + + + + + + + + + + + + + + @@ -830,7 +885,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" ) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -840,35 +895,35 @@ FAILED: CHECK_THAT( testStringForMatching(), !ContainsSubstring( "substring" ) ) with expansion: "this string contains 'abc' as a substring" not contains: "substring" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: @@ -877,7 +932,7 @@ FAILED: REQUIRE_THROWS_WITH( thisThrows(), "should fail" ) with expansion: "expected exception" equals: "should fail" -Exception.tests.cpp: +at Exception.tests.cpp: @@ -890,7 +945,7 @@ Exception.tests.cpp: FAILED: custom exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -901,133 +956,133 @@ FAILED: CHECK( data.int_seven > 7 ) with expansion: 7 > 7 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < 7 ) with expansion: 7 < 7 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven > 8 ) with expansion: 7 > 8 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < 6 ) with expansion: 7 < 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < 0 ) with expansion: 7 < 0 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < -1 ) with expansion: 7 < -1 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven >= 8 ) with expansion: 7 >= 8 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven <= 6 ) with expansion: 7 <= 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one < 9 ) with expansion: 9.1f < 9 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one > 10 ) with expansion: 9.1f > 10 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one > 9.2 ) with expansion: 9.1f > 9.2 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello > "hello" ) with expansion: "hello" > "hello" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello < "hello" ) with expansion: "hello" < "hello" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello > "hellp" ) with expansion: "hello" > "hellp" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello > "z" ) with expansion: "hello" > "z" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello < "hellm" ) with expansion: "hello" < "hellm" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello < "a" ) with expansion: "hello" < "a" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello >= "z" ) with expansion: "hello" >= "z" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello <= "a" ) with expansion: "hello" <= "a" -Condition.tests.cpp: +at Condition.tests.cpp: @@ -1037,14 +1092,14 @@ Condition.tests.cpp: FAILED: Message from section one -Message.tests.cpp: +at Message.tests.cpp: FAILED: Message from section two -Message.tests.cpp: +at Message.tests.cpp: @@ -1113,7 +1168,7 @@ FAILED: CHECK( truthy(false) ) with expansion: Hey, its truthy! -Decomposition.tests.cpp: +at Decomposition.tests.cpp: @@ -1123,7 +1178,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: @@ -1131,7 +1186,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" matches "contains 'abc' as a substring" case sensitively -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: @@ -1139,7 +1194,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" matches "this string contains 'abc' as a" case sensitively -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1154,6 +1209,9 @@ Matchers.tests.cpp: + + + @@ -1203,7 +1261,7 @@ FAILED: CHECK_THAT( testStringForMatching(), StartsWith( "This String" ) ) with expansion: "this string contains 'abc' as a substring" starts with: "This String" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: @@ -1211,7 +1269,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" starts with: "string" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1259,7 +1317,7 @@ with expansion: $a = 20; } " -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1332,16 +1390,34 @@ Misc.tests.cpp: FAILED: -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: -Misc.tests.cpp: +at Misc.tests.cpp: + + + +FAILED: + {Unknown expression after the reported line} +Uncaught exception should fail! +at Misc.tests.cpp: + + + + + +FAILED: + {Unknown expression after the reported line} +Uncaught exception should fail! +at Misc.tests.cpp: + + @@ -1352,7 +1428,7 @@ Misc.tests.cpp: FAILED: For some reason someone is throwing a string literal! -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1366,11 +1442,19 @@ Exception.tests.cpp: + + + + + + + + FAILED: 3.14 -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1381,10 +1465,10 @@ Exception.tests.cpp: - + - + @@ -1394,10 +1478,10 @@ Exception.tests.cpp: - + - + @@ -1407,13 +1491,33 @@ Exception.tests.cpp: - + - + + + + + + + + + + + + + + + + + + + + + @@ -1429,7 +1533,7 @@ FAILED: CHECK_THAT( empty, Approx( t1 ) ) with expansion: { } is approx: { 1.0, 2.0 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1438,7 +1542,7 @@ FAILED: CHECK_THAT( v1, Approx( v2 ) ) with expansion: { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1452,14 +1556,14 @@ FAILED: CHECK_THAT( v, VectorContains( -1 ) ) with expansion: { 1, 2, 3 } Contains: -1 -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( empty, VectorContains( 1 ) ) with expansion: { } Contains: 1 -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1468,14 +1572,14 @@ FAILED: CHECK_THAT( empty, Contains( v ) ) with expansion: { } Contains: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( v, Contains( v2 ) ) with expansion: { 1, 2, 3 } Contains: { 1, 2, 4 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1484,28 +1588,28 @@ FAILED: CHECK_THAT( v, Equals( v2 ) ) with expansion: { 1, 2, 3 } Equals: { 1, 2 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( v2, Equals( v ) ) with expansion: { 1, 2 } Equals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( empty, Equals( v ) ) with expansion: { } Equals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( v, Equals( empty ) ) with expansion: { 1, 2, 3 } Equals: { } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1514,28 +1618,28 @@ FAILED: CHECK_THAT( v, UnorderedEquals( empty ) ) with expansion: { 1, 2, 3 } UnorderedEquals: { } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( empty, UnorderedEquals( v ) ) with expansion: { } UnorderedEquals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( permuted, UnorderedEquals( v ) ) with expansion: { 1, 3 } UnorderedEquals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( permuted, UnorderedEquals( v ) ) with expansion: { 3, 1 } UnorderedEquals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1543,7 +1647,7 @@ Matchers.tests.cpp: FAILED: unexpected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1551,7 +1655,7 @@ Exception.tests.cpp: FAILED: CHECK( thisThrows() == 0 ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1559,7 +1663,7 @@ Exception.tests.cpp: FAILED: REQUIRE( thisThrows() == 0 ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1567,14 +1671,14 @@ Exception.tests.cpp: FAILED: CHECK( thisThrows() == 0 ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: unexpected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1590,6 +1694,12 @@ Exception.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + @@ -1602,7 +1712,7 @@ FAILED: REQUIRE( testCheckedElse( false ) ) with expansion: false -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1612,7 +1722,7 @@ FAILED: REQUIRE( testCheckedIf( false ) ) with expansion: false -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1624,25 +1734,80 @@ Misc.tests.cpp: + + +SKIPPED +skipping because answer = 41 +at Skip.tests.cpp: + + +SKIPPED +skipping because answer = 43 +at Skip.tests.cpp: + + + + + +FAILED: + CHECK( 3 == 4 ) +at Skip.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + + + +FAILED: +at Skip.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + +FAILED: +at Skip.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + + + +SKIPPED +at Skip.tests.cpp: + + + + + +FAILED: +at Skip.tests.cpp: + + FAILED: Previous info should not be seen -Message.tests.cpp: +at Message.tests.cpp: FAILED: previous unscoped info SHOULD not be seen -Message.tests.cpp: +at Message.tests.cpp: @@ -1652,7 +1817,7 @@ FAILED: CHECK( b > a ) with expansion: 0 > 1 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1661,7 +1826,7 @@ FAILED: CHECK( b > a ) with expansion: 1 > 1 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1679,7 +1844,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[0] (1) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1687,7 +1852,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[1] (1) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1695,7 +1860,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[3] (3) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1703,7 +1868,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[4] (5) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1711,7 +1876,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[6] (13) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1719,7 +1884,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[7] (21) is even -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1735,13 +1900,26 @@ FAILED: REQUIRE( a == b ) with expansion: 1 == 2 -Misc.tests.cpp: +at Misc.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + + + +a! +b1! +! + + @@ -1752,7 +1930,7 @@ Misc.tests.cpp: FAILED: REQUIRE( false ) this SHOULD be seen -Message.tests.cpp: +at Message.tests.cpp: @@ -1769,7 +1947,7 @@ FAILED: REQUIRE( false ) this SHOULD be seen this SHOULD also be seen -Message.tests.cpp: +at Message.tests.cpp: @@ -1777,7 +1955,7 @@ Message.tests.cpp: FAILED: CHECK( false ) this SHOULD be seen only ONCE -Message.tests.cpp: +at Message.tests.cpp: @@ -1793,12 +1971,20 @@ Message.tests.cpp: + + + +SKIPPED +at Skip.tests.cpp: + + + FAILED: REQUIRE( false ) 3 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1807,10 +1993,17 @@ FAILED: REQUIRE( false ) hi i := 7 -Message.tests.cpp: +at Message.tests.cpp: + + +SKIPPED +skipping because answer = 43 +at Skip.tests.cpp: + + @@ -1820,7 +2013,7 @@ Count 1 to 3... 1 2 3 -Message.tests.cpp: +at Message.tests.cpp: FAILED: @@ -1829,7 +2022,7 @@ Count 4 to 6... 4 5 6 -Message.tests.cpp: +at Message.tests.cpp: @@ -1855,11 +2048,17 @@ Message.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + FAILED: Why would you throw a std::string? -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1876,6 +2075,7 @@ Exception.tests.cpp: + @@ -1904,6 +2104,9 @@ This would not be caught previously A string sent directly to stdout Message from section one Message from section two +a! +b1! +! Nor would this diff --git a/tests/SelfTest/Baselines/junit.sw.multi.approved.txt b/tests/SelfTest/Baselines/junit.sw.multi.approved.txt index 3231c3e8..d270c88f 100644 --- a/tests/SelfTest/Baselines/junit.sw.multi.approved.txt +++ b/tests/SelfTest/Baselines/junit.sw.multi.approved.txt @@ -1,6 +1,6 @@ - + @@ -18,7 +18,7 @@ FAILED: 1514 -Tricky.tests.cpp: +at Tricky.tests.cpp: This would not be caught previously @@ -47,13 +47,21 @@ Nor would this + + + +FAILED: +failure to init +at Generators.tests.cpp: + + FAILED: expected exception answer := 42 -Exception.tests.cpp: +at Exception.tests.cpp: @@ -63,7 +71,7 @@ FAILED: REQUIRE_NOTHROW( thisThrows() ) expected exception answer := 42 -Exception.tests.cpp: +at Exception.tests.cpp: @@ -76,7 +84,7 @@ FAILED: CHECK( f() == 0 ) with expansion: 1 == 0 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -89,52 +97,52 @@ Misc.tests.cpp: FAILED: CHECK( false != false ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( true != true ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( !true ) with expansion: false -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK_FALSE( true ) with expansion: !true -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( !trueValue ) with expansion: false -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK_FALSE( trueValue ) with expansion: !true -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( !(1 == 1) ) with expansion: false -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK_FALSE( 1 == 1 ) -Condition.tests.cpp: +at Condition.tests.cpp: @@ -150,7 +158,7 @@ FAILED: REQUIRE( s == "world" ) with expansion: "hello" == "world" -Class.tests.cpp: +at Class.tests.cpp: @@ -160,7 +168,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -169,7 +177,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -178,7 +186,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -187,7 +195,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -200,7 +208,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 6 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -209,7 +217,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 2 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -218,7 +226,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 6 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -227,7 +235,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 2 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -240,7 +248,7 @@ FAILED: REQUIRE( Template_Fixture<TestType>::m_a == 2 ) with expansion: 1.0 == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -249,7 +257,7 @@ FAILED: REQUIRE( Template_Fixture<TestType>::m_a == 2 ) with expansion: 1.0f == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -258,7 +266,7 @@ FAILED: REQUIRE( Template_Fixture<TestType>::m_a == 2 ) with expansion: 1 == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -270,7 +278,7 @@ FAILED: REQUIRE( Nttp_Fixture<V>::value == 0 ) with expansion: 1 == 0 -Class.tests.cpp: +at Class.tests.cpp: @@ -279,7 +287,7 @@ FAILED: REQUIRE( Nttp_Fixture<V>::value == 0 ) with expansion: 3 == 0 -Class.tests.cpp: +at Class.tests.cpp: @@ -288,7 +296,7 @@ FAILED: REQUIRE( Nttp_Fixture<V>::value == 0 ) with expansion: 6 == 0 -Class.tests.cpp: +at Class.tests.cpp: @@ -300,7 +308,7 @@ FAILED: REQUIRE( m_a == 2 ) with expansion: 1 == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -317,7 +325,7 @@ Class.tests.cpp: FAILED: to infinity and beyond -Misc.tests.cpp: +at Misc.tests.cpp: @@ -327,14 +335,14 @@ FAILED: CHECK( &o1 == &o2 ) with expansion: 0x == 0x -Tricky.tests.cpp: +at Tricky.tests.cpp: FAILED: CHECK( o1 == o2 ) with expansion: {?} == {?} -Tricky.tests.cpp: +at Tricky.tests.cpp: @@ -344,7 +352,7 @@ Tricky.tests.cpp: FAILED: {Unknown expression after the reported line} unexpected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -414,14 +422,14 @@ FAILED: with expansion: "this string contains 'abc' as a substring" contains: "not there" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), ContainsSubstring( "STRING" ) ) with expansion: "this string contains 'abc' as a substring" contains: "STRING" -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -433,7 +441,7 @@ Matchers.tests.cpp: FAILED: REQUIRE_NOTHROW( throwCustom() ) custom exception - not std -Exception.tests.cpp: +at Exception.tests.cpp: @@ -441,27 +449,33 @@ Exception.tests.cpp: FAILED: REQUIRE_THROWS_AS( throwCustom(), std::exception ) custom exception - not std -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: custom std exception -Exception.tests.cpp: +at Exception.tests.cpp: + + +SKIPPED +This generator is empty +at Skip.tests.cpp: + + - FAILED: CHECK_THAT( testStringForMatching(), EndsWith( "Substring" ) ) with expansion: "this string contains 'abc' as a substring" ends with: "Substring" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: @@ -469,7 +483,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" ends with: "this" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -482,91 +496,91 @@ FAILED: CHECK( data.int_seven == 6 ) with expansion: 7 == 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven == 8 ) with expansion: 7 == 8 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven == 0 ) with expansion: 7 == 0 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 9.11f ) ) with expansion: 9.1f == Approx( 9.1099996567 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 9.0f ) ) with expansion: 9.1f == Approx( 9.0 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 1 ) ) with expansion: 9.1f == Approx( 1.0 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 0 ) ) with expansion: 9.1f == Approx( 0.0 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.double_pi == Approx( 3.1415 ) ) with expansion: 3.1415926535 == Approx( 3.1415 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello == "goodbye" ) with expansion: "hello" == "goodbye" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello == "hell" ) with expansion: "hello" == "hell" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello == "hello1" ) with expansion: "hello" == "hello1" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello.size() == 6 ) with expansion: 5 == 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( x == Approx( 1.301 ) ) with expansion: 1.3 == Approx( 1.301 ) -Condition.tests.cpp: +at Condition.tests.cpp: @@ -578,7 +592,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: @@ -586,7 +600,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" equals: "something else" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -594,12 +608,12 @@ Matchers.tests.cpp: FAILED: CHECK_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } ) -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: REQUIRE_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } ) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -607,13 +621,13 @@ Matchers.tests.cpp: FAILED: CHECK_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } ) Unknown exception -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: REQUIRE_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } ) Unknown exception -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -622,17 +636,18 @@ FAILED: CHECK_THROWS_MATCHES( throwsSpecialException( 3 ), SpecialException, ExceptionMatcher{ 1 } ) with expansion: SpecialException::what special exception has value of 1 -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: REQUIRE_THROWS_MATCHES( throwsSpecialException( 4 ), SpecialException, ExceptionMatcher{ 1 } ) with expansion: SpecialException::what special exception has value of 1 -Matchers.tests.cpp: +at Matchers.tests.cpp: + @@ -642,53 +657,57 @@ Matchers.tests.cpp: FAILED: CHECK_THROWS_AS( thisThrows(), std::string ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error ) -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: CHECK_NOTHROW( thisThrows() ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: This is a failure -Message.tests.cpp: +at Message.tests.cpp: FAILED: -Message.tests.cpp: +at Message.tests.cpp: FAILED: This is a failure -Message.tests.cpp: +at Message.tests.cpp: + + + + @@ -733,6 +752,15 @@ Message.tests.cpp: + + +FAILED: +Show infos! +This info has multiple parts. +This unscoped info has multiple parts. +at Message.tests.cpp: + + @@ -742,7 +770,7 @@ with expansion: 2 == 1 this message should be logged so should this -Message.tests.cpp: +at Message.tests.cpp: @@ -753,7 +781,7 @@ with expansion: 2 == 1 this message may be logged later this message should be logged -Message.tests.cpp: +at Message.tests.cpp: FAILED: @@ -763,7 +791,7 @@ with expansion: this message may be logged later this message should be logged and this, but later -Message.tests.cpp: +at Message.tests.cpp: @@ -774,9 +802,18 @@ with expansion: 10 < 10 current counter 10 i := 10 -Message.tests.cpp: +at Message.tests.cpp: + + + +FAILED: + REQUIRE( Dummy ) +Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE +at AssertionHandler.tests.cpp: + + @@ -784,38 +821,56 @@ FAILED: CHECK( data.int_seven != 7 ) with expansion: 7 != 7 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one != Approx( 9.1f ) ) with expansion: 9.1f != Approx( 9.1000003815 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.double_pi != Approx( 3.1415926535 ) ) with expansion: 3.1415926535 != Approx( 3.1415926535 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello != "hello" ) with expansion: "hello" != "hello" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello.size() != 5 ) with expansion: 5 != 5 -Condition.tests.cpp: +at Condition.tests.cpp: + + + + + + + + + + + + + + + + + + @@ -829,7 +884,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" ) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -839,35 +894,35 @@ FAILED: CHECK_THAT( testStringForMatching(), !ContainsSubstring( "substring" ) ) with expansion: "this string contains 'abc' as a substring" not contains: "substring" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: @@ -876,7 +931,7 @@ FAILED: REQUIRE_THROWS_WITH( thisThrows(), "should fail" ) with expansion: "expected exception" equals: "should fail" -Exception.tests.cpp: +at Exception.tests.cpp: @@ -889,7 +944,7 @@ Exception.tests.cpp: FAILED: custom exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -900,133 +955,133 @@ FAILED: CHECK( data.int_seven > 7 ) with expansion: 7 > 7 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < 7 ) with expansion: 7 < 7 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven > 8 ) with expansion: 7 > 8 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < 6 ) with expansion: 7 < 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < 0 ) with expansion: 7 < 0 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < -1 ) with expansion: 7 < -1 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven >= 8 ) with expansion: 7 >= 8 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven <= 6 ) with expansion: 7 <= 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one < 9 ) with expansion: 9.1f < 9 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one > 10 ) with expansion: 9.1f > 10 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one > 9.2 ) with expansion: 9.1f > 9.2 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello > "hello" ) with expansion: "hello" > "hello" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello < "hello" ) with expansion: "hello" < "hello" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello > "hellp" ) with expansion: "hello" > "hellp" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello > "z" ) with expansion: "hello" > "z" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello < "hellm" ) with expansion: "hello" < "hellm" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello < "a" ) with expansion: "hello" < "a" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello >= "z" ) with expansion: "hello" >= "z" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello <= "a" ) with expansion: "hello" <= "a" -Condition.tests.cpp: +at Condition.tests.cpp: @@ -1036,14 +1091,14 @@ Condition.tests.cpp: FAILED: Message from section one -Message.tests.cpp: +at Message.tests.cpp: FAILED: Message from section two -Message.tests.cpp: +at Message.tests.cpp: @@ -1112,7 +1167,7 @@ FAILED: CHECK( truthy(false) ) with expansion: Hey, its truthy! -Decomposition.tests.cpp: +at Decomposition.tests.cpp: @@ -1122,7 +1177,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: @@ -1130,7 +1185,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" matches "contains 'abc' as a substring" case sensitively -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: @@ -1138,7 +1193,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" matches "this string contains 'abc' as a" case sensitively -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1153,6 +1208,9 @@ Matchers.tests.cpp: + + + @@ -1202,7 +1260,7 @@ FAILED: CHECK_THAT( testStringForMatching(), StartsWith( "This String" ) ) with expansion: "this string contains 'abc' as a substring" starts with: "This String" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: @@ -1210,7 +1268,7 @@ FAILED: with expansion: "this string contains 'abc' as a substring" starts with: "string" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1258,7 +1316,7 @@ with expansion: $a = 20; } " -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1331,16 +1389,34 @@ Misc.tests.cpp: FAILED: -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: -Misc.tests.cpp: +at Misc.tests.cpp: + + + +FAILED: + {Unknown expression after the reported line} +Uncaught exception should fail! +at Misc.tests.cpp: + + + + + +FAILED: + {Unknown expression after the reported line} +Uncaught exception should fail! +at Misc.tests.cpp: + + @@ -1351,7 +1427,7 @@ Misc.tests.cpp: FAILED: For some reason someone is throwing a string literal! -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1365,11 +1441,19 @@ Exception.tests.cpp: + + + + + + + + FAILED: 3.14 -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1380,10 +1464,10 @@ Exception.tests.cpp: - + - + @@ -1393,10 +1477,10 @@ Exception.tests.cpp: - + - + @@ -1406,13 +1490,33 @@ Exception.tests.cpp: - + - + + + + + + + + + + + + + + + + + + + + + @@ -1428,7 +1532,7 @@ FAILED: CHECK_THAT( empty, Approx( t1 ) ) with expansion: { } is approx: { 1.0, 2.0 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1437,7 +1541,7 @@ FAILED: CHECK_THAT( v1, Approx( v2 ) ) with expansion: { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1451,14 +1555,14 @@ FAILED: CHECK_THAT( v, VectorContains( -1 ) ) with expansion: { 1, 2, 3 } Contains: -1 -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( empty, VectorContains( 1 ) ) with expansion: { } Contains: 1 -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1467,14 +1571,14 @@ FAILED: CHECK_THAT( empty, Contains( v ) ) with expansion: { } Contains: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( v, Contains( v2 ) ) with expansion: { 1, 2, 3 } Contains: { 1, 2, 4 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1483,28 +1587,28 @@ FAILED: CHECK_THAT( v, Equals( v2 ) ) with expansion: { 1, 2, 3 } Equals: { 1, 2 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( v2, Equals( v ) ) with expansion: { 1, 2 } Equals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( empty, Equals( v ) ) with expansion: { } Equals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( v, Equals( empty ) ) with expansion: { 1, 2, 3 } Equals: { } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1513,28 +1617,28 @@ FAILED: CHECK_THAT( v, UnorderedEquals( empty ) ) with expansion: { 1, 2, 3 } UnorderedEquals: { } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( empty, UnorderedEquals( v ) ) with expansion: { } UnorderedEquals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( permuted, UnorderedEquals( v ) ) with expansion: { 1, 3 } UnorderedEquals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( permuted, UnorderedEquals( v ) ) with expansion: { 3, 1 } UnorderedEquals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1542,7 +1646,7 @@ Matchers.tests.cpp: FAILED: unexpected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1550,7 +1654,7 @@ Exception.tests.cpp: FAILED: CHECK( thisThrows() == 0 ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1558,7 +1662,7 @@ Exception.tests.cpp: FAILED: REQUIRE( thisThrows() == 0 ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1566,14 +1670,14 @@ Exception.tests.cpp: FAILED: CHECK( thisThrows() == 0 ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: unexpected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1589,6 +1693,12 @@ Exception.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + @@ -1601,7 +1711,7 @@ FAILED: REQUIRE( testCheckedElse( false ) ) with expansion: false -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1611,7 +1721,7 @@ FAILED: REQUIRE( testCheckedIf( false ) ) with expansion: false -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1623,25 +1733,80 @@ Misc.tests.cpp: + + +SKIPPED +skipping because answer = 41 +at Skip.tests.cpp: + + +SKIPPED +skipping because answer = 43 +at Skip.tests.cpp: + + + + + +FAILED: + CHECK( 3 == 4 ) +at Skip.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + + + +FAILED: +at Skip.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + +FAILED: +at Skip.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + + + +SKIPPED +at Skip.tests.cpp: + + + + + +FAILED: +at Skip.tests.cpp: + + FAILED: Previous info should not be seen -Message.tests.cpp: +at Message.tests.cpp: FAILED: previous unscoped info SHOULD not be seen -Message.tests.cpp: +at Message.tests.cpp: @@ -1651,7 +1816,7 @@ FAILED: CHECK( b > a ) with expansion: 0 > 1 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1660,7 +1825,7 @@ FAILED: CHECK( b > a ) with expansion: 1 > 1 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1678,7 +1843,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[0] (1) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1686,7 +1851,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[1] (1) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1694,7 +1859,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[3] (3) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1702,7 +1867,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[4] (5) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1710,7 +1875,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[6] (13) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1718,7 +1883,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[7] (21) is even -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1734,13 +1899,26 @@ FAILED: REQUIRE( a == b ) with expansion: 1 == 2 -Misc.tests.cpp: +at Misc.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + + + +a! +b1! +! + + @@ -1751,7 +1929,7 @@ Misc.tests.cpp: FAILED: REQUIRE( false ) this SHOULD be seen -Message.tests.cpp: +at Message.tests.cpp: @@ -1768,7 +1946,7 @@ FAILED: REQUIRE( false ) this SHOULD be seen this SHOULD also be seen -Message.tests.cpp: +at Message.tests.cpp: @@ -1776,7 +1954,7 @@ Message.tests.cpp: FAILED: CHECK( false ) this SHOULD be seen only ONCE -Message.tests.cpp: +at Message.tests.cpp: @@ -1792,12 +1970,20 @@ Message.tests.cpp: + + + +SKIPPED +at Skip.tests.cpp: + + + FAILED: REQUIRE( false ) 3 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1806,10 +1992,17 @@ FAILED: REQUIRE( false ) hi i := 7 -Message.tests.cpp: +at Message.tests.cpp: + + +SKIPPED +skipping because answer = 43 +at Skip.tests.cpp: + + @@ -1819,7 +2012,7 @@ Count 1 to 3... 1 2 3 -Message.tests.cpp: +at Message.tests.cpp: FAILED: @@ -1828,7 +2021,7 @@ Count 4 to 6... 4 5 6 -Message.tests.cpp: +at Message.tests.cpp: @@ -1854,11 +2047,17 @@ Message.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + FAILED: Why would you throw a std::string? -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1875,6 +2074,7 @@ Exception.tests.cpp: + @@ -1903,6 +2103,9 @@ This would not be caught previously A string sent directly to stdout Message from section one Message from section two +a! +b1! +! Nor would this diff --git a/tests/SelfTest/Baselines/sonarqube.sw.approved.txt b/tests/SelfTest/Baselines/sonarqube.sw.approved.txt index 122e3dda..36b05e54 100644 --- a/tests/SelfTest/Baselines/sonarqube.sw.approved.txt +++ b/tests/SelfTest/Baselines/sonarqube.sw.approved.txt @@ -2,6 +2,16 @@ + + + +FAILED: + REQUIRE( Dummy ) +Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE +at AssertionHandler.tests.cpp: + + + @@ -71,6 +81,7 @@ + @@ -119,6 +130,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -150,6 +181,7 @@ + @@ -167,6 +199,9 @@ + + + @@ -232,7 +267,6 @@ - @@ -330,7 +364,7 @@ FAILED: REQUIRE( s == "world" ) with expansion: "hello" == "world" -Class.tests.cpp: +at Class.tests.cpp: @@ -340,7 +374,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -349,7 +383,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -358,7 +392,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -367,7 +401,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -380,7 +414,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 6 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -389,7 +423,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 2 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -398,7 +432,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 6 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -407,7 +441,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 2 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -420,7 +454,7 @@ FAILED: REQUIRE( Template_Fixture<TestType>::m_a == 2 ) with expansion: 1.0 == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -429,7 +463,7 @@ FAILED: REQUIRE( Template_Fixture<TestType>::m_a == 2 ) with expansion: 1.0f == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -438,7 +472,7 @@ FAILED: REQUIRE( Template_Fixture<TestType>::m_a == 2 ) with expansion: 1 == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -450,7 +484,7 @@ FAILED: REQUIRE( Nttp_Fixture<V>::value == 0 ) with expansion: 1 == 0 -Class.tests.cpp: +at Class.tests.cpp: @@ -459,7 +493,7 @@ FAILED: REQUIRE( Nttp_Fixture<V>::value == 0 ) with expansion: 3 == 0 -Class.tests.cpp: +at Class.tests.cpp: @@ -468,7 +502,7 @@ FAILED: REQUIRE( Nttp_Fixture<V>::value == 0 ) with expansion: 6 == 0 -Class.tests.cpp: +at Class.tests.cpp: @@ -480,7 +514,7 @@ FAILED: REQUIRE( m_a == 2 ) with expansion: 1 == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -508,52 +542,52 @@ Class.tests.cpp: FAILED: CHECK( false != false ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( true != true ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( !true ) with expansion: false -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK_FALSE( true ) with expansion: !true -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( !trueValue ) with expansion: false -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK_FALSE( trueValue ) with expansion: !true -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( !(1 == 1) ) with expansion: false -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK_FALSE( 1 == 1 ) -Condition.tests.cpp: +at Condition.tests.cpp: @@ -566,91 +600,91 @@ FAILED: CHECK( data.int_seven == 6 ) with expansion: 7 == 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven == 8 ) with expansion: 7 == 8 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven == 0 ) with expansion: 7 == 0 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 9.11f ) ) with expansion: 9.1f == Approx( 9.1099996567 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 9.0f ) ) with expansion: 9.1f == Approx( 9.0 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 1 ) ) with expansion: 9.1f == Approx( 1.0 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 0 ) ) with expansion: 9.1f == Approx( 0.0 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.double_pi == Approx( 3.1415 ) ) with expansion: 3.1415926535 == Approx( 3.1415 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello == "goodbye" ) with expansion: "hello" == "goodbye" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello == "hell" ) with expansion: "hello" == "hell" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello == "hello1" ) with expansion: "hello" == "hello1" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello.size() == 6 ) with expansion: 5 == 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( x == Approx( 1.301 ) ) with expansion: 1.3 == Approx( 1.301 ) -Condition.tests.cpp: +at Condition.tests.cpp: @@ -660,60 +694,60 @@ FAILED: CHECK( data.int_seven != 7 ) with expansion: 7 != 7 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one != Approx( 9.1f ) ) with expansion: 9.1f != Approx( 9.1000003815 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.double_pi != Approx( 3.1415926535 ) ) with expansion: 3.1415926535 != Approx( 3.1415926535 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello != "hello" ) with expansion: "hello" != "hello" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello.size() != 5 ) with expansion: 5 != 5 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: @@ -722,133 +756,133 @@ FAILED: CHECK( data.int_seven > 7 ) with expansion: 7 > 7 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < 7 ) with expansion: 7 < 7 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven > 8 ) with expansion: 7 > 8 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < 6 ) with expansion: 7 < 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < 0 ) with expansion: 7 < 0 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < -1 ) with expansion: 7 < -1 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven >= 8 ) with expansion: 7 >= 8 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven <= 6 ) with expansion: 7 <= 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one < 9 ) with expansion: 9.1f < 9 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one > 10 ) with expansion: 9.1f > 10 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one > 9.2 ) with expansion: 9.1f > 9.2 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello > "hello" ) with expansion: "hello" > "hello" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello < "hello" ) with expansion: "hello" < "hello" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello > "hellp" ) with expansion: "hello" > "hellp" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello > "z" ) with expansion: "hello" > "z" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello < "hellm" ) with expansion: "hello" < "hellm" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello < "a" ) with expansion: "hello" < "a" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello >= "z" ) with expansion: "hello" >= "z" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello <= "a" ) with expansion: "hello" <= "a" -Condition.tests.cpp: +at Condition.tests.cpp: @@ -863,7 +897,7 @@ FAILED: CHECK( truthy(false) ) with expansion: Hey, its truthy! -Decomposition.tests.cpp: +at Decomposition.tests.cpp: @@ -881,7 +915,7 @@ Decomposition.tests.cpp: FAILED: expected exception answer := 42 -Exception.tests.cpp: +at Exception.tests.cpp: @@ -890,7 +924,7 @@ FAILED: REQUIRE_NOTHROW( thisThrows() ) expected exception answer := 42 -Exception.tests.cpp: +at Exception.tests.cpp: @@ -899,7 +933,7 @@ Exception.tests.cpp: FAILED: {Unknown expression after the reported line} unexpected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -907,7 +941,7 @@ Exception.tests.cpp: FAILED: REQUIRE_NOTHROW( throwCustom() ) custom exception - not std -Exception.tests.cpp: +at Exception.tests.cpp: @@ -915,14 +949,14 @@ Exception.tests.cpp: FAILED: REQUIRE_THROWS_AS( throwCustom(), std::exception ) custom exception - not std -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: custom std exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -933,18 +967,18 @@ Exception.tests.cpp: FAILED: CHECK_THROWS_AS( thisThrows(), std::string ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error ) -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: CHECK_NOTHROW( thisThrows() ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -953,28 +987,28 @@ FAILED: REQUIRE_THROWS_WITH( thisThrows(), "should fail" ) with expansion: "expected exception" equals: "should fail" -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: custom exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: For some reason someone is throwing a string literal! -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: 3.14 -Exception.tests.cpp: +at Exception.tests.cpp: @@ -982,7 +1016,7 @@ Exception.tests.cpp: FAILED: unexpected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -990,7 +1024,7 @@ Exception.tests.cpp: FAILED: CHECK( thisThrows() == 0 ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -998,7 +1032,7 @@ Exception.tests.cpp: FAILED: REQUIRE( thisThrows() == 0 ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1006,31 +1040,39 @@ Exception.tests.cpp: FAILED: CHECK( thisThrows() == 0 ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: unexpected exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: Why would you throw a std::string? -Exception.tests.cpp: +at Exception.tests.cpp: + + +FAILED: +failure to init +at Generators.tests.cpp: + + + @@ -1070,14 +1112,14 @@ FAILED: CHECK_THAT( testStringForMatching(), ContainsSubstring( "not there", Catch::CaseSensitive::No ) ) with expansion: "this string contains 'abc' as a substring" contains: "not there" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), ContainsSubstring( "STRING" ) ) with expansion: "this string contains 'abc' as a substring" contains: "STRING" -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1086,14 +1128,14 @@ FAILED: CHECK_THAT( testStringForMatching(), EndsWith( "Substring" ) ) with expansion: "this string contains 'abc' as a substring" ends with: "Substring" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) ) with expansion: "this string contains 'abc' as a substring" ends with: "this" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1103,26 +1145,26 @@ FAILED: CHECK_THAT( testStringForMatching(), Equals( "this string contains 'ABC' as a substring" ) ) with expansion: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), Equals( "something else", Catch::CaseSensitive::No ) ) with expansion: "this string contains 'abc' as a substring" equals: "something else" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } ) -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: REQUIRE_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } ) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1130,13 +1172,13 @@ Matchers.tests.cpp: FAILED: CHECK_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } ) Unknown exception -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: REQUIRE_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } ) Unknown exception -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1145,17 +1187,18 @@ FAILED: CHECK_THROWS_MATCHES( throwsSpecialException( 3 ), SpecialException, ExceptionMatcher{ 1 } ) with expansion: SpecialException::what special exception has value of 1 -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: REQUIRE_THROWS_MATCHES( throwsSpecialException( 4 ), SpecialException, ExceptionMatcher{ 1 } ) with expansion: SpecialException::what special exception has value of 1 -Matchers.tests.cpp: +at Matchers.tests.cpp: + @@ -1163,12 +1206,14 @@ Matchers.tests.cpp: + + @@ -1178,7 +1223,7 @@ FAILED: CHECK_THAT( testStringForMatching(), ( ContainsSubstring( "string" ) || ContainsSubstring( "different" ) ) && ContainsSubstring( "random" ) ) with expansion: "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" ) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1188,7 +1233,7 @@ FAILED: CHECK_THAT( testStringForMatching(), !ContainsSubstring( "substring" ) ) with expansion: "this string contains 'abc' as a substring" not contains: "substring" -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1199,21 +1244,21 @@ FAILED: CHECK_THAT( testStringForMatching(), Matches( "this STRING contains 'abc' as a substring" ) ) with expansion: "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), Matches( "contains 'abc' as a substring" ) ) with expansion: "this string contains 'abc' as a substring" matches "contains 'abc' as a substring" case sensitively -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), Matches( "this string contains 'abc' as a" ) ) with expansion: "this string contains 'abc' as a substring" matches "this string contains 'abc' as a" case sensitively -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1223,14 +1268,14 @@ FAILED: CHECK_THAT( testStringForMatching(), StartsWith( "This String" ) ) with expansion: "this string contains 'abc' as a substring" starts with: "This String" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), StartsWith( "string", Catch::CaseSensitive::No ) ) with expansion: "this string contains 'abc' as a substring" starts with: "string" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1244,7 +1289,7 @@ FAILED: CHECK_THAT( empty, Approx( t1 ) ) with expansion: { } is approx: { 1.0, 2.0 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1253,7 +1298,7 @@ FAILED: CHECK_THAT( v1, Approx( v2 ) ) with expansion: { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1267,14 +1312,14 @@ FAILED: CHECK_THAT( v, VectorContains( -1 ) ) with expansion: { 1, 2, 3 } Contains: -1 -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( empty, VectorContains( 1 ) ) with expansion: { } Contains: 1 -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1283,14 +1328,14 @@ FAILED: CHECK_THAT( empty, Contains( v ) ) with expansion: { } Contains: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( v, Contains( v2 ) ) with expansion: { 1, 2, 3 } Contains: { 1, 2, 4 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1299,28 +1344,28 @@ FAILED: CHECK_THAT( v, Equals( v2 ) ) with expansion: { 1, 2, 3 } Equals: { 1, 2 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( v2, Equals( v ) ) with expansion: { 1, 2 } Equals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( empty, Equals( v ) ) with expansion: { } Equals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( v, Equals( empty ) ) with expansion: { 1, 2, 3 } Equals: { } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1329,28 +1374,28 @@ FAILED: CHECK_THAT( v, UnorderedEquals( empty ) ) with expansion: { 1, 2, 3 } UnorderedEquals: { } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( empty, UnorderedEquals( v ) ) with expansion: { } UnorderedEquals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( permuted, UnorderedEquals( v ) ) with expansion: { 1, 3 } UnorderedEquals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( permuted, UnorderedEquals( v ) ) with expansion: { 3, 1 } UnorderedEquals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1364,16 +1409,24 @@ Matchers.tests.cpp: + + + + + + + + - + - + @@ -1383,10 +1436,10 @@ Matchers.tests.cpp: - + - + @@ -1396,13 +1449,33 @@ Matchers.tests.cpp: - + - + + + + + + + + + + + + + + + + + + + + + @@ -1416,20 +1489,29 @@ Matchers.tests.cpp: FAILED: This is a failure -Message.tests.cpp: +at Message.tests.cpp: FAILED: -Message.tests.cpp: +at Message.tests.cpp: FAILED: This is a failure -Message.tests.cpp: +at Message.tests.cpp: + + + + +FAILED: +Show infos! +This info has multiple parts. +This unscoped info has multiple parts. +at Message.tests.cpp: @@ -1441,7 +1523,7 @@ with expansion: 2 == 1 this message should be logged so should this -Message.tests.cpp: +at Message.tests.cpp: @@ -1452,7 +1534,7 @@ with expansion: 2 == 1 this message may be logged later this message should be logged -Message.tests.cpp: +at Message.tests.cpp: FAILED: @@ -1462,7 +1544,7 @@ with expansion: this message may be logged later this message should be logged and this, but later -Message.tests.cpp: +at Message.tests.cpp: @@ -1473,21 +1555,21 @@ with expansion: 10 < 10 current counter 10 i := 10 -Message.tests.cpp: +at Message.tests.cpp: FAILED: Message from section one -Message.tests.cpp: +at Message.tests.cpp: FAILED: Message from section two -Message.tests.cpp: +at Message.tests.cpp: @@ -1498,14 +1580,14 @@ Message.tests.cpp: FAILED: Previous info should not be seen -Message.tests.cpp: +at Message.tests.cpp: FAILED: previous unscoped info SHOULD not be seen -Message.tests.cpp: +at Message.tests.cpp: @@ -1514,7 +1596,7 @@ Message.tests.cpp: FAILED: REQUIRE( false ) this SHOULD be seen -Message.tests.cpp: +at Message.tests.cpp: @@ -1524,7 +1606,7 @@ FAILED: REQUIRE( false ) this SHOULD be seen this SHOULD also be seen -Message.tests.cpp: +at Message.tests.cpp: @@ -1532,7 +1614,7 @@ Message.tests.cpp: FAILED: CHECK( false ) this SHOULD be seen only ONCE -Message.tests.cpp: +at Message.tests.cpp: @@ -1541,7 +1623,7 @@ FAILED: REQUIRE( false ) hi i := 7 -Message.tests.cpp: +at Message.tests.cpp: @@ -1552,7 +1634,7 @@ Count 1 to 3... 1 2 3 -Message.tests.cpp: +at Message.tests.cpp: FAILED: @@ -1561,7 +1643,7 @@ Count 4 to 6... 4 5 6 -Message.tests.cpp: +at Message.tests.cpp: @@ -1577,7 +1659,7 @@ FAILED: CHECK( f() == 0 ) with expansion: 1 == 0 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1597,7 +1679,7 @@ Misc.tests.cpp: FAILED: to infinity and beyond -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1621,7 +1703,7 @@ with expansion: $a = 20; } " -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1683,13 +1765,29 @@ Misc.tests.cpp: FAILED: -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: -Misc.tests.cpp: +at Misc.tests.cpp: + + + + +FAILED: + {Unknown expression after the reported line} +Uncaught exception should fail! +at Misc.tests.cpp: + + + + +FAILED: + {Unknown expression after the reported line} +Uncaught exception should fail! +at Misc.tests.cpp: @@ -1700,7 +1798,7 @@ FAILED: REQUIRE( testCheckedElse( false ) ) with expansion: false -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1710,7 +1808,7 @@ FAILED: REQUIRE( testCheckedIf( false ) ) with expansion: false -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1723,7 +1821,7 @@ FAILED: CHECK( b > a ) with expansion: 0 > 1 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1732,7 +1830,7 @@ FAILED: CHECK( b > a ) with expansion: 1 > 1 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1750,7 +1848,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[0] (1) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1758,7 +1856,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[1] (1) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1766,7 +1864,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[3] (3) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1774,7 +1872,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[4] (5) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1782,7 +1880,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[6] (13) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1790,7 +1888,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[7] (21) is even -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1799,7 +1897,7 @@ FAILED: REQUIRE( a == b ) with expansion: 1 == 2 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1815,7 +1913,7 @@ Misc.tests.cpp: FAILED: REQUIRE( false ) 3 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1831,6 +1929,102 @@ Misc.tests.cpp: + + + +SKIPPED +This generator is empty +at Skip.tests.cpp: + + + + +SKIPPED +at Skip.tests.cpp: + + + + +SKIPPED +skipping because answer = 41 +at Skip.tests.cpp: + + +SKIPPED +skipping because answer = 43 +at Skip.tests.cpp: + + + + +FAILED: + CHECK( 3 == 4 ) +at Skip.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + + + +FAILED: +at Skip.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + +FAILED: +at Skip.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + + + +SKIPPED +at Skip.tests.cpp: + + + + +FAILED: +at Skip.tests.cpp: + + + + +SKIPPED +at Skip.tests.cpp: + + + + + + +SKIPPED +at Skip.tests.cpp: + + + + + +SKIPPED +skipping because answer = 43 +at Skip.tests.cpp: + + + + +SKIPPED +at Skip.tests.cpp: + + + @@ -1892,7 +2086,7 @@ Misc.tests.cpp: FAILED: 1514 -Tricky.tests.cpp: +at Tricky.tests.cpp: @@ -1906,14 +2100,14 @@ FAILED: CHECK( &o1 == &o2 ) with expansion: 0x == 0x -Tricky.tests.cpp: +at Tricky.tests.cpp: FAILED: CHECK( o1 == o2 ) with expansion: {?} == {?} -Tricky.tests.cpp: +at Tricky.tests.cpp: diff --git a/tests/SelfTest/Baselines/sonarqube.sw.multi.approved.txt b/tests/SelfTest/Baselines/sonarqube.sw.multi.approved.txt index 8025e455..c9d3d205 100644 --- a/tests/SelfTest/Baselines/sonarqube.sw.multi.approved.txt +++ b/tests/SelfTest/Baselines/sonarqube.sw.multi.approved.txt @@ -1,6 +1,16 @@ + + + +FAILED: + REQUIRE( Dummy ) +Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE +at AssertionHandler.tests.cpp: + + + @@ -70,6 +80,7 @@ + @@ -118,6 +129,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -149,6 +180,7 @@ + @@ -166,6 +198,9 @@ + + + @@ -231,7 +266,6 @@ - @@ -329,7 +363,7 @@ FAILED: REQUIRE( s == "world" ) with expansion: "hello" == "world" -Class.tests.cpp: +at Class.tests.cpp: @@ -339,7 +373,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -348,7 +382,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -357,7 +391,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -366,7 +400,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 ) with expansion: 0 == 1 -Class.tests.cpp: +at Class.tests.cpp: @@ -379,7 +413,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 6 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -388,7 +422,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 2 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -397,7 +431,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 6 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -406,7 +440,7 @@ FAILED: REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 ) with expansion: 2 < 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -419,7 +453,7 @@ FAILED: REQUIRE( Template_Fixture<TestType>::m_a == 2 ) with expansion: 1.0 == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -428,7 +462,7 @@ FAILED: REQUIRE( Template_Fixture<TestType>::m_a == 2 ) with expansion: 1.0f == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -437,7 +471,7 @@ FAILED: REQUIRE( Template_Fixture<TestType>::m_a == 2 ) with expansion: 1 == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -449,7 +483,7 @@ FAILED: REQUIRE( Nttp_Fixture<V>::value == 0 ) with expansion: 1 == 0 -Class.tests.cpp: +at Class.tests.cpp: @@ -458,7 +492,7 @@ FAILED: REQUIRE( Nttp_Fixture<V>::value == 0 ) with expansion: 3 == 0 -Class.tests.cpp: +at Class.tests.cpp: @@ -467,7 +501,7 @@ FAILED: REQUIRE( Nttp_Fixture<V>::value == 0 ) with expansion: 6 == 0 -Class.tests.cpp: +at Class.tests.cpp: @@ -479,7 +513,7 @@ FAILED: REQUIRE( m_a == 2 ) with expansion: 1 == 2 -Class.tests.cpp: +at Class.tests.cpp: @@ -507,52 +541,52 @@ Class.tests.cpp: FAILED: CHECK( false != false ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( true != true ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( !true ) with expansion: false -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK_FALSE( true ) with expansion: !true -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( !trueValue ) with expansion: false -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK_FALSE( trueValue ) with expansion: !true -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( !(1 == 1) ) with expansion: false -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK_FALSE( 1 == 1 ) -Condition.tests.cpp: +at Condition.tests.cpp: @@ -565,91 +599,91 @@ FAILED: CHECK( data.int_seven == 6 ) with expansion: 7 == 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven == 8 ) with expansion: 7 == 8 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven == 0 ) with expansion: 7 == 0 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 9.11f ) ) with expansion: 9.1f == Approx( 9.1099996567 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 9.0f ) ) with expansion: 9.1f == Approx( 9.0 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 1 ) ) with expansion: 9.1f == Approx( 1.0 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one == Approx( 0 ) ) with expansion: 9.1f == Approx( 0.0 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.double_pi == Approx( 3.1415 ) ) with expansion: 3.1415926535 == Approx( 3.1415 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello == "goodbye" ) with expansion: "hello" == "goodbye" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello == "hell" ) with expansion: "hello" == "hell" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello == "hello1" ) with expansion: "hello" == "hello1" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello.size() == 6 ) with expansion: 5 == 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( x == Approx( 1.301 ) ) with expansion: 1.3 == Approx( 1.301 ) -Condition.tests.cpp: +at Condition.tests.cpp: @@ -659,60 +693,60 @@ FAILED: CHECK( data.int_seven != 7 ) with expansion: 7 != 7 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one != Approx( 9.1f ) ) with expansion: 9.1f != Approx( 9.1000003815 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.double_pi != Approx( 3.1415926535 ) ) with expansion: 3.1415926535 != Approx( 3.1415926535 ) -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello != "hello" ) with expansion: "hello" != "hello" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello.size() != 5 ) with expansion: 5 != 5 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: -Condition.tests.cpp: +at Condition.tests.cpp: @@ -721,133 +755,133 @@ FAILED: CHECK( data.int_seven > 7 ) with expansion: 7 > 7 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < 7 ) with expansion: 7 < 7 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven > 8 ) with expansion: 7 > 8 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < 6 ) with expansion: 7 < 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < 0 ) with expansion: 7 < 0 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven < -1 ) with expansion: 7 < -1 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven >= 8 ) with expansion: 7 >= 8 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.int_seven <= 6 ) with expansion: 7 <= 6 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one < 9 ) with expansion: 9.1f < 9 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one > 10 ) with expansion: 9.1f > 10 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.float_nine_point_one > 9.2 ) with expansion: 9.1f > 9.2 -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello > "hello" ) with expansion: "hello" > "hello" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello < "hello" ) with expansion: "hello" < "hello" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello > "hellp" ) with expansion: "hello" > "hellp" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello > "z" ) with expansion: "hello" > "z" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello < "hellm" ) with expansion: "hello" < "hellm" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello < "a" ) with expansion: "hello" < "a" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello >= "z" ) with expansion: "hello" >= "z" -Condition.tests.cpp: +at Condition.tests.cpp: FAILED: CHECK( data.str_hello <= "a" ) with expansion: "hello" <= "a" -Condition.tests.cpp: +at Condition.tests.cpp: @@ -862,7 +896,7 @@ FAILED: CHECK( truthy(false) ) with expansion: Hey, its truthy! -Decomposition.tests.cpp: +at Decomposition.tests.cpp: @@ -880,7 +914,7 @@ Decomposition.tests.cpp: FAILED: expected exception answer := 42 -Exception.tests.cpp: +at Exception.tests.cpp: @@ -889,7 +923,7 @@ FAILED: REQUIRE_NOTHROW( thisThrows() ) expected exception answer := 42 -Exception.tests.cpp: +at Exception.tests.cpp: @@ -898,7 +932,7 @@ Exception.tests.cpp: FAILED: {Unknown expression after the reported line} unexpected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -906,7 +940,7 @@ Exception.tests.cpp: FAILED: REQUIRE_NOTHROW( throwCustom() ) custom exception - not std -Exception.tests.cpp: +at Exception.tests.cpp: @@ -914,14 +948,14 @@ Exception.tests.cpp: FAILED: REQUIRE_THROWS_AS( throwCustom(), std::exception ) custom exception - not std -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: custom std exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -932,18 +966,18 @@ Exception.tests.cpp: FAILED: CHECK_THROWS_AS( thisThrows(), std::string ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error ) -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: CHECK_NOTHROW( thisThrows() ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -952,28 +986,28 @@ FAILED: REQUIRE_THROWS_WITH( thisThrows(), "should fail" ) with expansion: "expected exception" equals: "should fail" -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: custom exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: For some reason someone is throwing a string literal! -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: 3.14 -Exception.tests.cpp: +at Exception.tests.cpp: @@ -981,7 +1015,7 @@ Exception.tests.cpp: FAILED: unexpected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -989,7 +1023,7 @@ Exception.tests.cpp: FAILED: CHECK( thisThrows() == 0 ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -997,7 +1031,7 @@ Exception.tests.cpp: FAILED: REQUIRE( thisThrows() == 0 ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: @@ -1005,31 +1039,39 @@ Exception.tests.cpp: FAILED: CHECK( thisThrows() == 0 ) expected exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: unexpected exception -Exception.tests.cpp: +at Exception.tests.cpp: FAILED: Why would you throw a std::string? -Exception.tests.cpp: +at Exception.tests.cpp: + + +FAILED: +failure to init +at Generators.tests.cpp: + + + @@ -1069,14 +1111,14 @@ FAILED: CHECK_THAT( testStringForMatching(), ContainsSubstring( "not there", Catch::CaseSensitive::No ) ) with expansion: "this string contains 'abc' as a substring" contains: "not there" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), ContainsSubstring( "STRING" ) ) with expansion: "this string contains 'abc' as a substring" contains: "STRING" -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1085,14 +1127,14 @@ FAILED: CHECK_THAT( testStringForMatching(), EndsWith( "Substring" ) ) with expansion: "this string contains 'abc' as a substring" ends with: "Substring" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) ) with expansion: "this string contains 'abc' as a substring" ends with: "this" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1102,26 +1144,26 @@ FAILED: CHECK_THAT( testStringForMatching(), Equals( "this string contains 'ABC' as a substring" ) ) with expansion: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), Equals( "something else", Catch::CaseSensitive::No ) ) with expansion: "this string contains 'abc' as a substring" equals: "something else" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } ) -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: REQUIRE_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } ) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1129,13 +1171,13 @@ Matchers.tests.cpp: FAILED: CHECK_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } ) Unknown exception -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: REQUIRE_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } ) Unknown exception -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1144,17 +1186,18 @@ FAILED: CHECK_THROWS_MATCHES( throwsSpecialException( 3 ), SpecialException, ExceptionMatcher{ 1 } ) with expansion: SpecialException::what special exception has value of 1 -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: REQUIRE_THROWS_MATCHES( throwsSpecialException( 4 ), SpecialException, ExceptionMatcher{ 1 } ) with expansion: SpecialException::what special exception has value of 1 -Matchers.tests.cpp: +at Matchers.tests.cpp: + @@ -1162,12 +1205,14 @@ Matchers.tests.cpp: + + @@ -1177,7 +1222,7 @@ FAILED: CHECK_THAT( testStringForMatching(), ( ContainsSubstring( "string" ) || ContainsSubstring( "different" ) ) && ContainsSubstring( "random" ) ) with expansion: "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" ) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1187,7 +1232,7 @@ FAILED: CHECK_THAT( testStringForMatching(), !ContainsSubstring( "substring" ) ) with expansion: "this string contains 'abc' as a substring" not contains: "substring" -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1198,21 +1243,21 @@ FAILED: CHECK_THAT( testStringForMatching(), Matches( "this STRING contains 'abc' as a substring" ) ) with expansion: "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), Matches( "contains 'abc' as a substring" ) ) with expansion: "this string contains 'abc' as a substring" matches "contains 'abc' as a substring" case sensitively -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), Matches( "this string contains 'abc' as a" ) ) with expansion: "this string contains 'abc' as a substring" matches "this string contains 'abc' as a" case sensitively -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1222,14 +1267,14 @@ FAILED: CHECK_THAT( testStringForMatching(), StartsWith( "This String" ) ) with expansion: "this string contains 'abc' as a substring" starts with: "This String" -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( testStringForMatching(), StartsWith( "string", Catch::CaseSensitive::No ) ) with expansion: "this string contains 'abc' as a substring" starts with: "string" (case insensitive) -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1243,7 +1288,7 @@ FAILED: CHECK_THAT( empty, Approx( t1 ) ) with expansion: { } is approx: { 1.0, 2.0 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1252,7 +1297,7 @@ FAILED: CHECK_THAT( v1, Approx( v2 ) ) with expansion: { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1266,14 +1311,14 @@ FAILED: CHECK_THAT( v, VectorContains( -1 ) ) with expansion: { 1, 2, 3 } Contains: -1 -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( empty, VectorContains( 1 ) ) with expansion: { } Contains: 1 -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1282,14 +1327,14 @@ FAILED: CHECK_THAT( empty, Contains( v ) ) with expansion: { } Contains: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( v, Contains( v2 ) ) with expansion: { 1, 2, 3 } Contains: { 1, 2, 4 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1298,28 +1343,28 @@ FAILED: CHECK_THAT( v, Equals( v2 ) ) with expansion: { 1, 2, 3 } Equals: { 1, 2 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( v2, Equals( v ) ) with expansion: { 1, 2 } Equals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( empty, Equals( v ) ) with expansion: { } Equals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( v, Equals( empty ) ) with expansion: { 1, 2, 3 } Equals: { } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1328,28 +1373,28 @@ FAILED: CHECK_THAT( v, UnorderedEquals( empty ) ) with expansion: { 1, 2, 3 } UnorderedEquals: { } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( empty, UnorderedEquals( v ) ) with expansion: { } UnorderedEquals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( permuted, UnorderedEquals( v ) ) with expansion: { 1, 3 } UnorderedEquals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: FAILED: CHECK_THAT( permuted, UnorderedEquals( v ) ) with expansion: { 3, 1 } UnorderedEquals: { 1, 2, 3 } -Matchers.tests.cpp: +at Matchers.tests.cpp: @@ -1363,16 +1408,24 @@ Matchers.tests.cpp: + + + + + + + + - + - + @@ -1382,10 +1435,10 @@ Matchers.tests.cpp: - + - + @@ -1395,13 +1448,33 @@ Matchers.tests.cpp: - + - + + + + + + + + + + + + + + + + + + + + + @@ -1415,20 +1488,29 @@ Matchers.tests.cpp: FAILED: This is a failure -Message.tests.cpp: +at Message.tests.cpp: FAILED: -Message.tests.cpp: +at Message.tests.cpp: FAILED: This is a failure -Message.tests.cpp: +at Message.tests.cpp: + + + + +FAILED: +Show infos! +This info has multiple parts. +This unscoped info has multiple parts. +at Message.tests.cpp: @@ -1440,7 +1522,7 @@ with expansion: 2 == 1 this message should be logged so should this -Message.tests.cpp: +at Message.tests.cpp: @@ -1451,7 +1533,7 @@ with expansion: 2 == 1 this message may be logged later this message should be logged -Message.tests.cpp: +at Message.tests.cpp: FAILED: @@ -1461,7 +1543,7 @@ with expansion: this message may be logged later this message should be logged and this, but later -Message.tests.cpp: +at Message.tests.cpp: @@ -1472,21 +1554,21 @@ with expansion: 10 < 10 current counter 10 i := 10 -Message.tests.cpp: +at Message.tests.cpp: FAILED: Message from section one -Message.tests.cpp: +at Message.tests.cpp: FAILED: Message from section two -Message.tests.cpp: +at Message.tests.cpp: @@ -1497,14 +1579,14 @@ Message.tests.cpp: FAILED: Previous info should not be seen -Message.tests.cpp: +at Message.tests.cpp: FAILED: previous unscoped info SHOULD not be seen -Message.tests.cpp: +at Message.tests.cpp: @@ -1513,7 +1595,7 @@ Message.tests.cpp: FAILED: REQUIRE( false ) this SHOULD be seen -Message.tests.cpp: +at Message.tests.cpp: @@ -1523,7 +1605,7 @@ FAILED: REQUIRE( false ) this SHOULD be seen this SHOULD also be seen -Message.tests.cpp: +at Message.tests.cpp: @@ -1531,7 +1613,7 @@ Message.tests.cpp: FAILED: CHECK( false ) this SHOULD be seen only ONCE -Message.tests.cpp: +at Message.tests.cpp: @@ -1540,7 +1622,7 @@ FAILED: REQUIRE( false ) hi i := 7 -Message.tests.cpp: +at Message.tests.cpp: @@ -1551,7 +1633,7 @@ Count 1 to 3... 1 2 3 -Message.tests.cpp: +at Message.tests.cpp: FAILED: @@ -1560,7 +1642,7 @@ Count 4 to 6... 4 5 6 -Message.tests.cpp: +at Message.tests.cpp: @@ -1576,7 +1658,7 @@ FAILED: CHECK( f() == 0 ) with expansion: 1 == 0 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1596,7 +1678,7 @@ Misc.tests.cpp: FAILED: to infinity and beyond -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1620,7 +1702,7 @@ with expansion: $a = 20; } " -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1682,13 +1764,29 @@ Misc.tests.cpp: FAILED: -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: -Misc.tests.cpp: +at Misc.tests.cpp: + + + + +FAILED: + {Unknown expression after the reported line} +Uncaught exception should fail! +at Misc.tests.cpp: + + + + +FAILED: + {Unknown expression after the reported line} +Uncaught exception should fail! +at Misc.tests.cpp: @@ -1699,7 +1797,7 @@ FAILED: REQUIRE( testCheckedElse( false ) ) with expansion: false -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1709,7 +1807,7 @@ FAILED: REQUIRE( testCheckedIf( false ) ) with expansion: false -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1722,7 +1820,7 @@ FAILED: CHECK( b > a ) with expansion: 0 > 1 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1731,7 +1829,7 @@ FAILED: CHECK( b > a ) with expansion: 1 > 1 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1749,7 +1847,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[0] (1) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1757,7 +1855,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[1] (1) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1765,7 +1863,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[3] (3) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1773,7 +1871,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[4] (5) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1781,7 +1879,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[6] (13) is even -Misc.tests.cpp: +at Misc.tests.cpp: FAILED: @@ -1789,7 +1887,7 @@ FAILED: with expansion: 1 == 0 Testing if fib[7] (21) is even -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1798,7 +1896,7 @@ FAILED: REQUIRE( a == b ) with expansion: 1 == 2 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1814,7 +1912,7 @@ Misc.tests.cpp: FAILED: REQUIRE( false ) 3 -Misc.tests.cpp: +at Misc.tests.cpp: @@ -1830,6 +1928,102 @@ Misc.tests.cpp: + + + +SKIPPED +This generator is empty +at Skip.tests.cpp: + + + + +SKIPPED +at Skip.tests.cpp: + + + + +SKIPPED +skipping because answer = 41 +at Skip.tests.cpp: + + +SKIPPED +skipping because answer = 43 +at Skip.tests.cpp: + + + + +FAILED: + CHECK( 3 == 4 ) +at Skip.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + + + +FAILED: +at Skip.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + +FAILED: +at Skip.tests.cpp: + + +SKIPPED +at Skip.tests.cpp: + + + + +SKIPPED +at Skip.tests.cpp: + + + + +FAILED: +at Skip.tests.cpp: + + + + +SKIPPED +at Skip.tests.cpp: + + + + + + +SKIPPED +at Skip.tests.cpp: + + + + + +SKIPPED +skipping because answer = 43 +at Skip.tests.cpp: + + + + +SKIPPED +at Skip.tests.cpp: + + + @@ -1891,7 +2085,7 @@ Misc.tests.cpp: FAILED: 1514 -Tricky.tests.cpp: +at Tricky.tests.cpp: @@ -1905,14 +2099,14 @@ FAILED: CHECK( &o1 == &o2 ) with expansion: 0x == 0x -Tricky.tests.cpp: +at Tricky.tests.cpp: FAILED: CHECK( o1 == o2 ) with expansion: {?} == {?} -Tricky.tests.cpp: +at Tricky.tests.cpp: diff --git a/tests/SelfTest/Baselines/tap.sw.approved.txt b/tests/SelfTest/Baselines/tap.sw.approved.txt index 1832282a..a02dbd95 100644 --- a/tests/SelfTest/Baselines/tap.sw.approved.txt +++ b/tests/SelfTest/Baselines/tap.sw.approved.txt @@ -164,6 +164,8 @@ ok {test-number} - smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) for: 0 ok {test-number} - smallest_non_zero, WithinULP( -smallest_non_zero, 2 ) for: 0.0f is within 2 ULPs of -1.40129846e-45f ([-4.20389539e-45, 1.40129846e-45]) # #2152 - ULP checks between differently signed values were wrong - float ok {test-number} - smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) for: 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0.00000000e+00]) +# #2615 - Throwing in constructor generator fails test case but does not abort +not ok {test-number} - unexpected exception with message: 'failure to init' # #748 - captures with unexpected exceptions not ok {test-number} - unexpected exception with message: 'answer := 42' with 1 message: 'expected exception' # #748 - captures with unexpected exceptions @@ -657,7 +659,7 @@ ok {test-number} - unrelated::ADL_empty{}, IsEmpty() for: {?} is empty # CAPTURE can deal with complex expressions ok {test-number} - with 7 messages: 'a := 1' and 'b := 2' and 'c := 3' and 'a + b := 3' and 'a+b := 3' and 'c > b := true' and 'a == 1 := true' # CAPTURE can deal with complex expressions involving commas -ok {test-number} - with 7 messages: 'std::vector{1, 2, 3}[0, 1, 2] := 3' and 'std::vector{1, 2, 3}[(0, 1)] := 2' and 'std::vector{1, 2, 3}[0] := 1' and '(helper_1436{12, -12}) := { 12, -12 }' and '(helper_1436(-12, 12)) := { -12, 12 }' and '(1, 2) := 2' and '(2, 3) := 3' +ok {test-number} - with 7 messages: 'custom_index_op{1, 2, 3}[0, 1, 2] := 0' and 'custom_index_op{1, 2, 3}[(0, 1)] := 0' and 'custom_index_op{1, 2, 3}[0] := 0' and '(helper_1436{12, -12}) := { 12, -12 }' and '(helper_1436(-12, 12)) := { -12, 12 }' and '(1, 2) := 2' and '(2, 3) := 3' # CAPTURE parses string and character constants ok {test-number} - with 11 messages: '("comma, in string", "escaped, \", ") := "escaped, ", "' and '"single quote in string,'," := "single quote in string,',"' and '"some escapes, \\,\\\\" := "some escapes, \,\\"' and '"some, ), unmatched, } prenheses {[<" := "some, ), unmatched, } prenheses {[<"' and ''"' := '"'' and ''\'' := '''' and '',' := ','' and ''}' := '}'' and '')' := ')'' and ''(' := '('' and ''{' := '{'' # Capture and info messages @@ -982,10 +984,10 @@ ok {test-number} - enumInfo->lookup(0) == "Value1" for: Value1 == "Value1" ok {test-number} - enumInfo->lookup(1) == "Value2" for: Value2 == "Value2" # Directly creating an EnumInfo ok {test-number} - enumInfo->lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **} == "{** unexpected enum value **}" +# Empty generators can SKIP in constructor +ok {test-number} - # SKIP 'This generator is empty' # Empty stream name opens cout stream ok {test-number} - Catch::makeStream( "" )->isConsole() for: true -# Empty tag is not allowed -ok {test-number} - Catch::TestCaseInfo( "", { "fake test name", "[]" }, dummySourceLineInfo ) # EndsWith string matcher not ok {test-number} - testStringForMatching(), EndsWith( "Substring" ) for: "this string contains 'abc' as a substring" ends with: "Substring" # EndsWith string matcher @@ -1076,6 +1078,14 @@ not ok {test-number} - throwsSpecialException( 4 ), SpecialException, ExceptionM ok {test-number} - throwsSpecialException( 1 ), SpecialException, ExceptionMatcher{ 1 } for: SpecialException::what special exception has value of 1 # Exception matchers that succeed ok {test-number} - throwsSpecialException( 2 ), SpecialException, ExceptionMatcher{ 2 } for: SpecialException::what special exception has value of 2 +# Exception message can be matched +ok {test-number} - throwsDerivedException(), DerivedException, MessageMatches( StartsWith( "Derived" ) ) for: DerivedException::what matches "starts with: "Derived"" +# Exception message can be matched +ok {test-number} - throwsDerivedException(), DerivedException, MessageMatches( EndsWith( "::what" ) ) for: DerivedException::what matches "ends with: "::what"" +# Exception message can be matched +ok {test-number} - throwsDerivedException(), DerivedException, MessageMatches( !StartsWith( "::what" ) ) for: DerivedException::what matches "not starts with: "::what"" +# Exception message can be matched +ok {test-number} - throwsSpecialException( 2 ), SpecialException, MessageMatches( StartsWith( "Special" ) ) for: SpecialException::what matches "starts with: "Special"" # Exception messages can be tested for ok {test-number} - thisThrows(), "expected exception" for: "expected exception" equals: "expected exception" # Exception messages can be tested for @@ -1120,6 +1130,8 @@ ok {test-number} - Factorial(2) == 2 for: 2 == 2 ok {test-number} - Factorial(3) == 6 for: 6 == 6 # Factorials are computed ok {test-number} - Factorial(10) == 3628800 for: 3628800 (0x) == 3628800 (0x) +# Filter generator throws exception for empty generator +ok {test-number} - filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException # Floating point matchers: double ok {test-number} - 10., WithinRel( 11.1, 0.1 ) for: 10.0 and 11.1 are within 10% of each other # Floating point matchers: double @@ -1178,6 +1190,8 @@ ok {test-number} - WithinRel( 1., 0. ) ok {test-number} - WithinRel( 1., -0.2 ), std::domain_error # Floating point matchers: double ok {test-number} - WithinRel( 1., 1. ), std::domain_error +# Floating point matchers: double +ok {test-number} - 1., !IsNaN() for: 1.0 not is NaN # Floating point matchers: float ok {test-number} - 10.f, WithinRel( 11.1f, 0.1f ) for: 10.0f and 11.1 are within 10% of each other # Floating point matchers: float @@ -1242,6 +1256,16 @@ ok {test-number} - WithinRel( 1.f, 0.f ) ok {test-number} - WithinRel( 1.f, -0.2f ), std::domain_error # Floating point matchers: float ok {test-number} - WithinRel( 1.f, 1.f ), std::domain_error +# Floating point matchers: float +ok {test-number} - 1., !IsNaN() for: 1.0 not is NaN +# GENERATE can combine literals and generators +ok {test-number} - i % 2 == 0 for: 0 == 0 +# GENERATE can combine literals and generators +ok {test-number} - i % 2 == 0 for: 0 == 0 +# GENERATE can combine literals and generators +ok {test-number} - i % 2 == 0 for: 0 == 0 +# GENERATE can combine literals and generators +ok {test-number} - i % 2 == 0 for: 0 == 0 # Generators -- adapters ok {test-number} - i % 2 == 0 for: 0 == 0 # Generators -- adapters @@ -1780,6 +1804,8 @@ ok {test-number} - h( dummy1 ) != h( dummy2 ) for: 2673152918 (0x) ! ok {test-number} - h( dummy1 ) != h( dummy2 ) for: 2074929312 (0x) != 3429949824 (0x) # Hashing test case produces same hash across multiple calls ok {test-number} - h( dummy ) == h( dummy ) for: 3422778688 (0x) == 3422778688 (0x) +# INFO and UNSCOPED_INFO can stream multiple arguments +not ok {test-number} - explicitly with 3 messages: 'This info has multiple parts.' and 'This unscoped info has multiple parts.' and 'Show infos!' # INFO and WARN do not abort tests warning {test-number} - 'this is a message' with 1 message: 'this is a warning' # INFO gets logged on failure @@ -1814,6 +1840,8 @@ ok {test-number} - i < 10 for: 8 < 10 with 2 messages: 'current counter 8' and ' ok {test-number} - i < 10 for: 9 < 10 with 2 messages: 'current counter 9' and 'i := 9' # INFO is reset for each loop not ok {test-number} - i < 10 for: 10 < 10 with 2 messages: 'current counter 10' and 'i := 10' +# Incomplete AssertionHandler +not ok {test-number} - unexpected exception with message: 'Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE'; expression was: Dummy # Inequality checks that should fail not ok {test-number} - data.int_seven != 7 for: 7 != 7 # Inequality checks that should fail @@ -1846,6 +1874,42 @@ ok {test-number} - data.str_hello != "hell" for: "hello" != "hell" ok {test-number} - data.str_hello != "hello1" for: "hello" != "hello1" # Inequality checks that should succeed ok {test-number} - data.str_hello.size() != 6 for: 5 != 6 +# JsonWriter +ok {test-number} - stream.str() == "" for: "" == "" +# JsonWriter +ok {test-number} - stream.str() == "{\n}" for: "{ }" == "{ }" +# JsonWriter +ok {test-number} - stream.str(), ContainsSubstring( "\"int\": 1," ) && ContainsSubstring( "\"double\": 1.5," ) && ContainsSubstring( "\"true\": true," ) && ContainsSubstring( "\"false\": false," ) && ContainsSubstring( "\"string\": \"this is a string\"," ) && ContainsSubstring( "\"array\": [\n 1,\n 2\n ]\n}" ) for: "{ "int": 1, "double": 1.5, "true": true, "false": false, "string": "this is a string", "array": [ 1, 2 ] }" ( contains: ""int": 1," and contains: ""double": 1.5," and contains: ""true": true," and contains: ""false": false," and contains: ""string": "this is a string"," and contains: ""array": [ 1, 2 ] }" ) +# JsonWriter +ok {test-number} - stream.str(), ContainsSubstring( "\"empty_object\": {\n }," ) && ContainsSubstring( "\"fully_object\": {\n \"key\": 1\n }" ) for: "{ "empty_object": { }, "fully_object": { "key": 1 } }" ( contains: ""empty_object": { }," and contains: ""fully_object": { "key": 1 }" ) +# JsonWriter +ok {test-number} - stream.str() == "[\n]" for: "[ ]" == "[ ]" +# JsonWriter +ok {test-number} - stream.str() == "[\n 1,\n 1.5,\n true,\n false,\n \"this is a string\",\n {\n \"object\": 42\n },\n [\n \"array\",\n 42.5\n ]\n]" for: "[ 1, 1.5, true, false, "this is a string", { "object": 42 }, [ "array", 42.5 ] ]" == "[ 1, 1.5, true, false, "this is a string", { "object": 42 }, [ "array", 42.5 ] ]" +# JsonWriter +ok {test-number} - stream.str() == "{\n}" for: "{ }" == "{ }" +# JsonWriter +ok {test-number} - stream.str() == "[\n]" for: "[ ]" == "[ ]" +# JsonWriter +ok {test-number} - stream.str() == "\"custom\"" for: ""custom"" == ""custom"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\\"\"" for: ""\""" == ""\""" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\\\\"" for: ""\\"" == ""\\"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"/\"" for: ""/"" == ""/"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\b\"" for: ""\b"" == ""\b"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\f\"" for: ""\f"" == ""\f"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\n\"" for: ""\n"" == ""\n"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\r\"" for: ""\r"" == ""\r"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\t\"" for: ""\t"" == ""\t"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\\\/\\t\\r\\n\"" for: ""\\/\t\r\n"" == ""\\/\t\r\n"" # Lambdas in assertions ok {test-number} - []() { return true; }() for: true # Less-than inequalities with different epsilons @@ -2439,6 +2503,18 @@ ok {test-number} - listingString, ContainsSubstring( "fake test name"s ) && Cont # Reporter's write listings to provided stream ok {test-number} - !(factories.empty()) for: !false # Reporter's write listings to provided stream +ok {test-number} - listingString, ContainsSubstring("fakeTag"s) for: "{ "version": 1, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "" }, "listings": { "tags": [ { "aliases": [ "fakeTag" ], "count": 1 } ]" contains: "fakeTag" with 1 message: 'Tested reporter: JSON' +# Reporter's write listings to provided stream +ok {test-number} - !(factories.empty()) for: !false +# Reporter's write listings to provided stream +ok {test-number} - listingString, ContainsSubstring("fake reporter"s) for: "{ "version": 1, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "" }, "listings": { "reporters": [ { "name": "fake reporter", "description": "fake description" } ]" contains: "fake reporter" with 1 message: 'Tested reporter: JSON' +# Reporter's write listings to provided stream +ok {test-number} - !(factories.empty()) for: !false +# Reporter's write listings to provided stream +ok {test-number} - listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) for: "{ "version": 1, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "" }, "listings": { "tests": [ { "name": "fake test name", "class-name": "", "tags": [ "fakeTestTag" ], "source-location": { "filename": "fake-file.cpp", "line": 123456789 } } ]" ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: JSON' +# Reporter's write listings to provided stream +ok {test-number} - !(factories.empty()) for: !false +# Reporter's write listings to provided stream ok {test-number} - listingString, ContainsSubstring("fakeTag"s) for: " All available tags: 1 [fakeTag] 1 tag " contains: "fakeTag" with 1 message: 'Tested reporter: JUnit' # Reporter's write listings to provided stream ok {test-number} - !(factories.empty()) for: !false @@ -3051,6 +3127,14 @@ not ok {test-number} - explicitly ok {test-number} - false # TODO # Testing checked-if 3 not ok {test-number} - explicitly +# Testing checked-if 4 +ok {test-number} - true +# Testing checked-if 4 +not ok {test-number} - unexpected exception with message: 'Uncaught exception should fail!'; expression was: {Unknown expression after the reported line} +# Testing checked-if 5 +ok {test-number} - false # TODO +# Testing checked-if 5 +not ok {test-number} - unexpected exception with message: 'Uncaught exception should fail!'; expression was: {Unknown expression after the reported line} # The NO_FAIL macro reports a failure but does not fail the test ok {test-number} - 1 == 2 # TODO # The default listing implementation write to provided stream @@ -3215,6 +3299,40 @@ ok {test-number} - trim(StringRef(leading_whitespace)) == StringRef(no_whitespac ok {test-number} - trim(StringRef(trailing_whitespace)) == StringRef(no_whitespace) for: There is no extra whitespace here == There is no extra whitespace here # Trim strings ok {test-number} - trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace) for: There is no extra whitespace here == There is no extra whitespace here +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_a, RangeEquals( c_array ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_a, UnorderedRangeEquals( c_array ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_3, !RangeEquals( array_int_4 ) for: { 1, 2, 3 } not elements are { 1, 2, 3, 4 } +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_3, !UnorderedRangeEquals( array_int_4 ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_a, RangeEquals( vector_char_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_a, UnorderedRangeEquals( vector_char_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - with 1 message: 'ContainerIsRandomAccess( array_int_a ) != ContainerIsRandomAccess( list_char_a )' +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_a, RangeEquals( list_char_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_a, UnorderedRangeEquals( list_char_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - vector_int_a, RangeEquals( vector_char_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - vector_int_a, UnorderedRangeEquals( vector_char_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - vector_int_a, !RangeEquals( vector_char_b ) for: { 1, 2, 3 } not elements are { 1, 2, 2 } +# Type conversions of RangeEquals and similar +ok {test-number} - vector_int_a, !UnorderedRangeEquals( vector_char_b ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 2 } +# Type conversions of RangeEquals and similar +ok {test-number} - a, !RangeEquals( b ) for: { 1, 2, 3 } not elements are { 3, 2, 1 } +# Type conversions of RangeEquals and similar +ok {test-number} - a, UnorderedRangeEquals( b ) for: { 1, 2, 3 } unordered elements are { 3, 2, 1 } +# Type conversions of RangeEquals and similar +ok {test-number} - vector_a, RangeEquals( array_a_plus_1, close_enough ) for: { 1, 2, 3 } elements are { 2, 3, 4 } +# Type conversions of RangeEquals and similar +ok {test-number} - vector_a, UnorderedRangeEquals( array_a_plus_1, close_enough ) for: { 1, 2, 3 } unordered elements are { 2, 3, 4 } # Unexpected exceptions can be translated not ok {test-number} - unexpected exception with message: '3.14' # Upcasting special member functions @@ -3425,6 +3543,70 @@ ok {test-number} - mocked.m_derefed[2] for: true ok {test-number} - !(mocked.m_derefed[3]) for: !false # Usage of NoneTrue range matcher ok {test-number} - !(mocked.m_derefed[4]) for: !false +# Usage of RangeEquals range matcher +ok {test-number} - empty_vector, RangeEquals( empty_vector ) for: { } elements are { } +# Usage of RangeEquals range matcher +ok {test-number} - empty_vector, !RangeEquals( non_empty_vector ) for: { } not elements are { 1 } +# Usage of RangeEquals range matcher +ok {test-number} - non_empty_vector, !RangeEquals( empty_vector ) for: { 1 } not elements are { } +# Usage of RangeEquals range matcher +ok {test-number} - non_empty_array, RangeEquals( non_empty_array ) for: { 1 } elements are { 1 } +# Usage of RangeEquals range matcher +ok {test-number} - array_a, RangeEquals( array_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +# Usage of RangeEquals range matcher +ok {test-number} - array_a, !RangeEquals( array_b ) for: { 1, 2, 3 } not elements are { 2, 2, 3 } +# Usage of RangeEquals range matcher +ok {test-number} - array_a, !RangeEquals( array_c ) for: { 1, 2, 3 } not elements are { 1, 2, 2 } +# Usage of RangeEquals range matcher +ok {test-number} - vector_a, !RangeEquals( vector_b ) for: { 1, 2, 3 } not elements are { 1, 2, 3, 4 } +# Usage of RangeEquals range matcher +ok {test-number} - vector_a, RangeEquals( vector_a_plus_1, close_enough ) for: { 1, 2, 3 } elements are { 2, 3, 4 } +# Usage of RangeEquals range matcher +ok {test-number} - vector_a, !RangeEquals( vector_b, close_enough ) for: { 1, 2, 3 } not elements are { 3, 3, 4 } +# Usage of RangeEquals range matcher +ok {test-number} - needs_adl1, RangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 } +# Usage of RangeEquals range matcher +ok {test-number} - needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) for: { 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 } +# Usage of RangeEquals range matcher +ok {test-number} - mocked1, !RangeEquals( arr ) for: { 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 } +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[0] for: true +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[1] for: true +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[2] for: true +# Usage of RangeEquals range matcher +ok {test-number} - !(mocked1.m_derefed[3]) for: !false +# Usage of RangeEquals range matcher +ok {test-number} - mocked1, RangeEquals( arr ) for: { 1, 2, 3, 4 } elements are { 1, 2, 3, 4 } +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[0] for: true +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[1] for: true +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[2] for: true +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[3] for: true +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - empty_vector, UnorderedRangeEquals( empty_vector ) for: { } unordered elements are { } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - empty_vector, !UnorderedRangeEquals( non_empty_vector ) for: { } not unordered elements are { 1 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - non_empty_vector, !UnorderedRangeEquals( empty_vector ) for: { 1 } not unordered elements are { } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - non_empty_array, UnorderedRangeEquals( non_empty_array ) for: { 1 } unordered elements are { 1 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - array_a, UnorderedRangeEquals( array_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - array_a, !UnorderedRangeEquals( array_b ) for: { 1, 2, 3 } not unordered elements are { 2, 2, 3 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - vector_a, !UnorderedRangeEquals( vector_b ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - vector_a, UnorderedRangeEquals( vector_a_plus_1, close_enough ) for: { 1, 10, 20 } unordered elements are { 11, 21, 2 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - vector_a, !UnorderedRangeEquals( vector_b, close_enough ) for: { 1, 10, 21 } not unordered elements are { 11, 21, 3 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - needs_adl1, UnorderedRangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 } # Usage of the SizeIs range matcher ok {test-number} - empty_vec, SizeIs(0) for: { } has size == 0 # Usage of the SizeIs range matcher @@ -3601,6 +3783,10 @@ ok {test-number} - encode( "[\x01]" ) == "[\\x01]" for: "[\x01]" == "[\x01]" ok {test-number} - encode( "[\x7F]" ) == "[\\x7F]" for: "[\x7F]" == "[\x7F]" # XmlWriter writes boolean attributes as true/false ok {test-number} - stream.str(), ContainsSubstring(R"(attr1="true")") && ContainsSubstring(R"(attr2="false")") for: " " ( contains: "attr1="true"" and contains: "attr2="false"" ) +# a succeeding test can still be skipped +ok {test-number} - +# a succeeding test can still be skipped +ok {test-number} - # SKIP # analyse no analysis ok {test-number} - analysis.mean.point.count() == 23 for: 23.0 == 23 # analyse no analysis @@ -3771,6 +3957,12 @@ ok {test-number} - convertToBits( -0. ) == ( 1ULL << 63 ) for: 92233720368547758 ok {test-number} - convertToBits( std::numeric_limits::denorm_min() ) == 1 for: 1 == 1 # convertToBits ok {test-number} - convertToBits( std::numeric_limits::denorm_min() ) == 1 for: 1 == 1 +# dynamic skipping works with generators +ok {test-number} - # SKIP 'skipping because answer = 41' +# dynamic skipping works with generators +ok {test-number} - +# dynamic skipping works with generators +ok {test-number} - # SKIP 'skipping because answer = 43' # empty tags are not allowed ok {test-number} - Catch::TestCaseInfo("", { "test with an empty tag", "[]" }, dummySourceLineInfo) # erfc_inv @@ -3789,6 +3981,22 @@ ok {test-number} - ok {test-number} - # even more nested SECTION tests ok {test-number} - +# failed assertions before SKIP cause test case to fail +not ok {test-number} - 3 == 4 +# failed assertions before SKIP cause test case to fail +ok {test-number} - # SKIP +# failing for some generator values causes entire test case to fail +not ok {test-number} - explicitly +# failing for some generator values causes entire test case to fail +ok {test-number} - # SKIP +# failing for some generator values causes entire test case to fail +not ok {test-number} - explicitly +# failing for some generator values causes entire test case to fail +ok {test-number} - # SKIP +# failing in some unskipped sections causes entire test case to fail +ok {test-number} - # SKIP +# failing in some unskipped sections causes entire test case to fail +not ok {test-number} - explicitly loose text artifact # is_unary_function ok {test-number} - with 1 message: 'Catch::Clara::Detail::is_unary_function::value' @@ -3898,6 +4106,11 @@ ok {test-number} - a != b for: 1 != 2 ok {test-number} - b != a for: 2 != 1 # nested SECTION tests ok {test-number} - a != b for: 1 != 2 +a! +b1! +# nested sections can be skipped dynamically at runtime +ok {test-number} - # SKIP +! # non streamable - with conv. op ok {test-number} - s == "7" for: "7" == "7" # non-copyable objects @@ -4062,12 +4275,20 @@ ok {test-number} - Timing.elapsed >= time for: 128 ns >= 100 ns ok {test-number} - Timing.result == Timing.iterations + 17 for: 145 == 145 # run_for_at_least, int ok {test-number} - Timing.iterations >= time.count() for: 128 >= 100 +# sections can be skipped dynamically at runtime +ok {test-number} - +# sections can be skipped dynamically at runtime +ok {test-number} - # SKIP +# sections can be skipped dynamically at runtime +ok {test-number} - # send a single char to INFO not ok {test-number} - false with 1 message: '3' # sends information to INFO not ok {test-number} - false with 2 messages: 'hi' and 'i := 7' # shortened hide tags are split apart ok {test-number} - testcase.tags, VectorContains( Tag( "magic-tag" ) ) && VectorContains( Tag( "."_catch_sr ) ) for: { {?}, {?} } ( Contains: {?} and Contains: {?} ) +# skipped tests can optionally provide a reason +ok {test-number} - # SKIP 'skipping because answer = 43' # splitString ok {test-number} - splitStringRef("", ','), Equals(std::vector()) for: { } Equals: { } # splitString @@ -4150,6 +4371,8 @@ ok {test-number} - strlen(std::get<0>(data)) == static_cast(std::get<1>( ok {test-number} - testcase.tags.size() == 1 for: 1 == 1 # tags with dots in later positions are not parsed as hidden ok {test-number} - testcase.tags[0].original == "magic.tag"_catch_sr for: magic.tag == magic.tag +# tests can be skipped dynamically at runtime +ok {test-number} - # SKIP # thrown std::strings are translated not ok {test-number} - unexpected exception with message: 'Why would you throw a std::string?' # toString on const wchar_t const pointer returns the string contents @@ -4200,6 +4423,10 @@ ok {test-number} - e.upper_bound == 23 for: 23.0 == 23 ok {test-number} - e.lower_bound == 23 for: 23.0 == 23 # uniform samples ok {test-number} - e.confidence_interval == 0.95 for: 0.95 == 0.95 +# uniform_integer_distribution can return the bounds +ok {test-number} - dist.a() == -10 for: -10 == -10 +# uniform_integer_distribution can return the bounds +ok {test-number} - dist.b() == 10 for: 10 == 10 # unique_ptr reimplementation: basic functionality ok {test-number} - !(ptr) for: !{?} # unique_ptr reimplementation: basic functionality @@ -4322,5 +4549,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0 ok {test-number} - # xmlentitycheck ok {test-number} - -1..2159 +1..2272 diff --git a/tests/SelfTest/Baselines/tap.sw.multi.approved.txt b/tests/SelfTest/Baselines/tap.sw.multi.approved.txt index 4446141d..13449bd4 100644 --- a/tests/SelfTest/Baselines/tap.sw.multi.approved.txt +++ b/tests/SelfTest/Baselines/tap.sw.multi.approved.txt @@ -162,6 +162,8 @@ ok {test-number} - smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) for: 0 ok {test-number} - smallest_non_zero, WithinULP( -smallest_non_zero, 2 ) for: 0.0f is within 2 ULPs of -1.40129846e-45f ([-4.20389539e-45, 1.40129846e-45]) # #2152 - ULP checks between differently signed values were wrong - float ok {test-number} - smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) for: 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0.00000000e+00]) +# #2615 - Throwing in constructor generator fails test case but does not abort +not ok {test-number} - unexpected exception with message: 'failure to init' # #748 - captures with unexpected exceptions not ok {test-number} - unexpected exception with message: 'answer := 42' with 1 message: 'expected exception' # #748 - captures with unexpected exceptions @@ -655,7 +657,7 @@ ok {test-number} - unrelated::ADL_empty{}, IsEmpty() for: {?} is empty # CAPTURE can deal with complex expressions ok {test-number} - with 7 messages: 'a := 1' and 'b := 2' and 'c := 3' and 'a + b := 3' and 'a+b := 3' and 'c > b := true' and 'a == 1 := true' # CAPTURE can deal with complex expressions involving commas -ok {test-number} - with 7 messages: 'std::vector{1, 2, 3}[0, 1, 2] := 3' and 'std::vector{1, 2, 3}[(0, 1)] := 2' and 'std::vector{1, 2, 3}[0] := 1' and '(helper_1436{12, -12}) := { 12, -12 }' and '(helper_1436(-12, 12)) := { -12, 12 }' and '(1, 2) := 2' and '(2, 3) := 3' +ok {test-number} - with 7 messages: 'custom_index_op{1, 2, 3}[0, 1, 2] := 0' and 'custom_index_op{1, 2, 3}[(0, 1)] := 0' and 'custom_index_op{1, 2, 3}[0] := 0' and '(helper_1436{12, -12}) := { 12, -12 }' and '(helper_1436(-12, 12)) := { -12, 12 }' and '(1, 2) := 2' and '(2, 3) := 3' # CAPTURE parses string and character constants ok {test-number} - with 11 messages: '("comma, in string", "escaped, \", ") := "escaped, ", "' and '"single quote in string,'," := "single quote in string,',"' and '"some escapes, \\,\\\\" := "some escapes, \,\\"' and '"some, ), unmatched, } prenheses {[<" := "some, ), unmatched, } prenheses {[<"' and ''"' := '"'' and ''\'' := '''' and '',' := ','' and ''}' := '}'' and '')' := ')'' and ''(' := '('' and ''{' := '{'' # Capture and info messages @@ -980,10 +982,10 @@ ok {test-number} - enumInfo->lookup(0) == "Value1" for: Value1 == "Value1" ok {test-number} - enumInfo->lookup(1) == "Value2" for: Value2 == "Value2" # Directly creating an EnumInfo ok {test-number} - enumInfo->lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **} == "{** unexpected enum value **}" +# Empty generators can SKIP in constructor +ok {test-number} - # SKIP 'This generator is empty' # Empty stream name opens cout stream ok {test-number} - Catch::makeStream( "" )->isConsole() for: true -# Empty tag is not allowed -ok {test-number} - Catch::TestCaseInfo( "", { "fake test name", "[]" }, dummySourceLineInfo ) # EndsWith string matcher not ok {test-number} - testStringForMatching(), EndsWith( "Substring" ) for: "this string contains 'abc' as a substring" ends with: "Substring" # EndsWith string matcher @@ -1074,6 +1076,14 @@ not ok {test-number} - throwsSpecialException( 4 ), SpecialException, ExceptionM ok {test-number} - throwsSpecialException( 1 ), SpecialException, ExceptionMatcher{ 1 } for: SpecialException::what special exception has value of 1 # Exception matchers that succeed ok {test-number} - throwsSpecialException( 2 ), SpecialException, ExceptionMatcher{ 2 } for: SpecialException::what special exception has value of 2 +# Exception message can be matched +ok {test-number} - throwsDerivedException(), DerivedException, MessageMatches( StartsWith( "Derived" ) ) for: DerivedException::what matches "starts with: "Derived"" +# Exception message can be matched +ok {test-number} - throwsDerivedException(), DerivedException, MessageMatches( EndsWith( "::what" ) ) for: DerivedException::what matches "ends with: "::what"" +# Exception message can be matched +ok {test-number} - throwsDerivedException(), DerivedException, MessageMatches( !StartsWith( "::what" ) ) for: DerivedException::what matches "not starts with: "::what"" +# Exception message can be matched +ok {test-number} - throwsSpecialException( 2 ), SpecialException, MessageMatches( StartsWith( "Special" ) ) for: SpecialException::what matches "starts with: "Special"" # Exception messages can be tested for ok {test-number} - thisThrows(), "expected exception" for: "expected exception" equals: "expected exception" # Exception messages can be tested for @@ -1118,6 +1128,8 @@ ok {test-number} - Factorial(2) == 2 for: 2 == 2 ok {test-number} - Factorial(3) == 6 for: 6 == 6 # Factorials are computed ok {test-number} - Factorial(10) == 3628800 for: 3628800 (0x) == 3628800 (0x) +# Filter generator throws exception for empty generator +ok {test-number} - filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException # Floating point matchers: double ok {test-number} - 10., WithinRel( 11.1, 0.1 ) for: 10.0 and 11.1 are within 10% of each other # Floating point matchers: double @@ -1176,6 +1188,8 @@ ok {test-number} - WithinRel( 1., 0. ) ok {test-number} - WithinRel( 1., -0.2 ), std::domain_error # Floating point matchers: double ok {test-number} - WithinRel( 1., 1. ), std::domain_error +# Floating point matchers: double +ok {test-number} - 1., !IsNaN() for: 1.0 not is NaN # Floating point matchers: float ok {test-number} - 10.f, WithinRel( 11.1f, 0.1f ) for: 10.0f and 11.1 are within 10% of each other # Floating point matchers: float @@ -1240,6 +1254,16 @@ ok {test-number} - WithinRel( 1.f, 0.f ) ok {test-number} - WithinRel( 1.f, -0.2f ), std::domain_error # Floating point matchers: float ok {test-number} - WithinRel( 1.f, 1.f ), std::domain_error +# Floating point matchers: float +ok {test-number} - 1., !IsNaN() for: 1.0 not is NaN +# GENERATE can combine literals and generators +ok {test-number} - i % 2 == 0 for: 0 == 0 +# GENERATE can combine literals and generators +ok {test-number} - i % 2 == 0 for: 0 == 0 +# GENERATE can combine literals and generators +ok {test-number} - i % 2 == 0 for: 0 == 0 +# GENERATE can combine literals and generators +ok {test-number} - i % 2 == 0 for: 0 == 0 # Generators -- adapters ok {test-number} - i % 2 == 0 for: 0 == 0 # Generators -- adapters @@ -1778,6 +1802,8 @@ ok {test-number} - h( dummy1 ) != h( dummy2 ) for: 2673152918 (0x) ! ok {test-number} - h( dummy1 ) != h( dummy2 ) for: 2074929312 (0x) != 3429949824 (0x) # Hashing test case produces same hash across multiple calls ok {test-number} - h( dummy ) == h( dummy ) for: 3422778688 (0x) == 3422778688 (0x) +# INFO and UNSCOPED_INFO can stream multiple arguments +not ok {test-number} - explicitly with 3 messages: 'This info has multiple parts.' and 'This unscoped info has multiple parts.' and 'Show infos!' # INFO and WARN do not abort tests warning {test-number} - 'this is a message' with 1 message: 'this is a warning' # INFO gets logged on failure @@ -1812,6 +1838,8 @@ ok {test-number} - i < 10 for: 8 < 10 with 2 messages: 'current counter 8' and ' ok {test-number} - i < 10 for: 9 < 10 with 2 messages: 'current counter 9' and 'i := 9' # INFO is reset for each loop not ok {test-number} - i < 10 for: 10 < 10 with 2 messages: 'current counter 10' and 'i := 10' +# Incomplete AssertionHandler +not ok {test-number} - unexpected exception with message: 'Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE'; expression was: Dummy # Inequality checks that should fail not ok {test-number} - data.int_seven != 7 for: 7 != 7 # Inequality checks that should fail @@ -1844,6 +1872,42 @@ ok {test-number} - data.str_hello != "hell" for: "hello" != "hell" ok {test-number} - data.str_hello != "hello1" for: "hello" != "hello1" # Inequality checks that should succeed ok {test-number} - data.str_hello.size() != 6 for: 5 != 6 +# JsonWriter +ok {test-number} - stream.str() == "" for: "" == "" +# JsonWriter +ok {test-number} - stream.str() == "{\n}" for: "{ }" == "{ }" +# JsonWriter +ok {test-number} - stream.str(), ContainsSubstring( "\"int\": 1," ) && ContainsSubstring( "\"double\": 1.5," ) && ContainsSubstring( "\"true\": true," ) && ContainsSubstring( "\"false\": false," ) && ContainsSubstring( "\"string\": \"this is a string\"," ) && ContainsSubstring( "\"array\": [\n 1,\n 2\n ]\n}" ) for: "{ "int": 1, "double": 1.5, "true": true, "false": false, "string": "this is a string", "array": [ 1, 2 ] }" ( contains: ""int": 1," and contains: ""double": 1.5," and contains: ""true": true," and contains: ""false": false," and contains: ""string": "this is a string"," and contains: ""array": [ 1, 2 ] }" ) +# JsonWriter +ok {test-number} - stream.str(), ContainsSubstring( "\"empty_object\": {\n }," ) && ContainsSubstring( "\"fully_object\": {\n \"key\": 1\n }" ) for: "{ "empty_object": { }, "fully_object": { "key": 1 } }" ( contains: ""empty_object": { }," and contains: ""fully_object": { "key": 1 }" ) +# JsonWriter +ok {test-number} - stream.str() == "[\n]" for: "[ ]" == "[ ]" +# JsonWriter +ok {test-number} - stream.str() == "[\n 1,\n 1.5,\n true,\n false,\n \"this is a string\",\n {\n \"object\": 42\n },\n [\n \"array\",\n 42.5\n ]\n]" for: "[ 1, 1.5, true, false, "this is a string", { "object": 42 }, [ "array", 42.5 ] ]" == "[ 1, 1.5, true, false, "this is a string", { "object": 42 }, [ "array", 42.5 ] ]" +# JsonWriter +ok {test-number} - stream.str() == "{\n}" for: "{ }" == "{ }" +# JsonWriter +ok {test-number} - stream.str() == "[\n]" for: "[ ]" == "[ ]" +# JsonWriter +ok {test-number} - stream.str() == "\"custom\"" for: ""custom"" == ""custom"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\\"\"" for: ""\""" == ""\""" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\\\\"" for: ""\\"" == ""\\"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"/\"" for: ""/"" == ""/"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\b\"" for: ""\b"" == ""\b"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\f\"" for: ""\f"" == ""\f"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\n\"" for: ""\n"" == ""\n"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\r\"" for: ""\r"" == ""\r"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\t\"" for: ""\t"" == ""\t"" +# JsonWriter escapes charaters in strings properly +ok {test-number} - sstream.str() == "\"\\\\/\\t\\r\\n\"" for: ""\\/\t\r\n"" == ""\\/\t\r\n"" # Lambdas in assertions ok {test-number} - []() { return true; }() for: true # Less-than inequalities with different epsilons @@ -2437,6 +2501,18 @@ ok {test-number} - listingString, ContainsSubstring( "fake test name"s ) && Cont # Reporter's write listings to provided stream ok {test-number} - !(factories.empty()) for: !false # Reporter's write listings to provided stream +ok {test-number} - listingString, ContainsSubstring("fakeTag"s) for: "{ "version": 1, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "" }, "listings": { "tags": [ { "aliases": [ "fakeTag" ], "count": 1 } ]" contains: "fakeTag" with 1 message: 'Tested reporter: JSON' +# Reporter's write listings to provided stream +ok {test-number} - !(factories.empty()) for: !false +# Reporter's write listings to provided stream +ok {test-number} - listingString, ContainsSubstring("fake reporter"s) for: "{ "version": 1, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "" }, "listings": { "reporters": [ { "name": "fake reporter", "description": "fake description" } ]" contains: "fake reporter" with 1 message: 'Tested reporter: JSON' +# Reporter's write listings to provided stream +ok {test-number} - !(factories.empty()) for: !false +# Reporter's write listings to provided stream +ok {test-number} - listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) for: "{ "version": 1, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "" }, "listings": { "tests": [ { "name": "fake test name", "class-name": "", "tags": [ "fakeTestTag" ], "source-location": { "filename": "fake-file.cpp", "line": 123456789 } } ]" ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: JSON' +# Reporter's write listings to provided stream +ok {test-number} - !(factories.empty()) for: !false +# Reporter's write listings to provided stream ok {test-number} - listingString, ContainsSubstring("fakeTag"s) for: " All available tags: 1 [fakeTag] 1 tag " contains: "fakeTag" with 1 message: 'Tested reporter: JUnit' # Reporter's write listings to provided stream ok {test-number} - !(factories.empty()) for: !false @@ -3044,6 +3120,14 @@ not ok {test-number} - explicitly ok {test-number} - false # TODO # Testing checked-if 3 not ok {test-number} - explicitly +# Testing checked-if 4 +ok {test-number} - true +# Testing checked-if 4 +not ok {test-number} - unexpected exception with message: 'Uncaught exception should fail!'; expression was: {Unknown expression after the reported line} +# Testing checked-if 5 +ok {test-number} - false # TODO +# Testing checked-if 5 +not ok {test-number} - unexpected exception with message: 'Uncaught exception should fail!'; expression was: {Unknown expression after the reported line} # The NO_FAIL macro reports a failure but does not fail the test ok {test-number} - 1 == 2 # TODO # The default listing implementation write to provided stream @@ -3208,6 +3292,40 @@ ok {test-number} - trim(StringRef(leading_whitespace)) == StringRef(no_whitespac ok {test-number} - trim(StringRef(trailing_whitespace)) == StringRef(no_whitespace) for: There is no extra whitespace here == There is no extra whitespace here # Trim strings ok {test-number} - trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace) for: There is no extra whitespace here == There is no extra whitespace here +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_a, RangeEquals( c_array ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_a, UnorderedRangeEquals( c_array ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_3, !RangeEquals( array_int_4 ) for: { 1, 2, 3 } not elements are { 1, 2, 3, 4 } +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_3, !UnorderedRangeEquals( array_int_4 ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_a, RangeEquals( vector_char_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_a, UnorderedRangeEquals( vector_char_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - with 1 message: 'ContainerIsRandomAccess( array_int_a ) != ContainerIsRandomAccess( list_char_a )' +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_a, RangeEquals( list_char_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - array_int_a, UnorderedRangeEquals( list_char_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - vector_int_a, RangeEquals( vector_char_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - vector_int_a, UnorderedRangeEquals( vector_char_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +# Type conversions of RangeEquals and similar +ok {test-number} - vector_int_a, !RangeEquals( vector_char_b ) for: { 1, 2, 3 } not elements are { 1, 2, 2 } +# Type conversions of RangeEquals and similar +ok {test-number} - vector_int_a, !UnorderedRangeEquals( vector_char_b ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 2 } +# Type conversions of RangeEquals and similar +ok {test-number} - a, !RangeEquals( b ) for: { 1, 2, 3 } not elements are { 3, 2, 1 } +# Type conversions of RangeEquals and similar +ok {test-number} - a, UnorderedRangeEquals( b ) for: { 1, 2, 3 } unordered elements are { 3, 2, 1 } +# Type conversions of RangeEquals and similar +ok {test-number} - vector_a, RangeEquals( array_a_plus_1, close_enough ) for: { 1, 2, 3 } elements are { 2, 3, 4 } +# Type conversions of RangeEquals and similar +ok {test-number} - vector_a, UnorderedRangeEquals( array_a_plus_1, close_enough ) for: { 1, 2, 3 } unordered elements are { 2, 3, 4 } # Unexpected exceptions can be translated not ok {test-number} - unexpected exception with message: '3.14' # Upcasting special member functions @@ -3418,6 +3536,70 @@ ok {test-number} - mocked.m_derefed[2] for: true ok {test-number} - !(mocked.m_derefed[3]) for: !false # Usage of NoneTrue range matcher ok {test-number} - !(mocked.m_derefed[4]) for: !false +# Usage of RangeEquals range matcher +ok {test-number} - empty_vector, RangeEquals( empty_vector ) for: { } elements are { } +# Usage of RangeEquals range matcher +ok {test-number} - empty_vector, !RangeEquals( non_empty_vector ) for: { } not elements are { 1 } +# Usage of RangeEquals range matcher +ok {test-number} - non_empty_vector, !RangeEquals( empty_vector ) for: { 1 } not elements are { } +# Usage of RangeEquals range matcher +ok {test-number} - non_empty_array, RangeEquals( non_empty_array ) for: { 1 } elements are { 1 } +# Usage of RangeEquals range matcher +ok {test-number} - array_a, RangeEquals( array_a ) for: { 1, 2, 3 } elements are { 1, 2, 3 } +# Usage of RangeEquals range matcher +ok {test-number} - array_a, !RangeEquals( array_b ) for: { 1, 2, 3 } not elements are { 2, 2, 3 } +# Usage of RangeEquals range matcher +ok {test-number} - array_a, !RangeEquals( array_c ) for: { 1, 2, 3 } not elements are { 1, 2, 2 } +# Usage of RangeEquals range matcher +ok {test-number} - vector_a, !RangeEquals( vector_b ) for: { 1, 2, 3 } not elements are { 1, 2, 3, 4 } +# Usage of RangeEquals range matcher +ok {test-number} - vector_a, RangeEquals( vector_a_plus_1, close_enough ) for: { 1, 2, 3 } elements are { 2, 3, 4 } +# Usage of RangeEquals range matcher +ok {test-number} - vector_a, !RangeEquals( vector_b, close_enough ) for: { 1, 2, 3 } not elements are { 3, 3, 4 } +# Usage of RangeEquals range matcher +ok {test-number} - needs_adl1, RangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 } +# Usage of RangeEquals range matcher +ok {test-number} - needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) for: { 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 } +# Usage of RangeEquals range matcher +ok {test-number} - mocked1, !RangeEquals( arr ) for: { 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 } +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[0] for: true +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[1] for: true +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[2] for: true +# Usage of RangeEquals range matcher +ok {test-number} - !(mocked1.m_derefed[3]) for: !false +# Usage of RangeEquals range matcher +ok {test-number} - mocked1, RangeEquals( arr ) for: { 1, 2, 3, 4 } elements are { 1, 2, 3, 4 } +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[0] for: true +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[1] for: true +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[2] for: true +# Usage of RangeEquals range matcher +ok {test-number} - mocked1.m_derefed[3] for: true +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - empty_vector, UnorderedRangeEquals( empty_vector ) for: { } unordered elements are { } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - empty_vector, !UnorderedRangeEquals( non_empty_vector ) for: { } not unordered elements are { 1 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - non_empty_vector, !UnorderedRangeEquals( empty_vector ) for: { 1 } not unordered elements are { } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - non_empty_array, UnorderedRangeEquals( non_empty_array ) for: { 1 } unordered elements are { 1 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - array_a, UnorderedRangeEquals( array_a ) for: { 1, 2, 3 } unordered elements are { 1, 2, 3 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - array_a, !UnorderedRangeEquals( array_b ) for: { 1, 2, 3 } not unordered elements are { 2, 2, 3 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - vector_a, !UnorderedRangeEquals( vector_b ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - vector_a, UnorderedRangeEquals( vector_a_plus_1, close_enough ) for: { 1, 10, 20 } unordered elements are { 11, 21, 2 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - vector_a, !UnorderedRangeEquals( vector_b, close_enough ) for: { 1, 10, 21 } not unordered elements are { 11, 21, 3 } +# Usage of UnorderedRangeEquals range matcher +ok {test-number} - needs_adl1, UnorderedRangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 } # Usage of the SizeIs range matcher ok {test-number} - empty_vec, SizeIs(0) for: { } has size == 0 # Usage of the SizeIs range matcher @@ -3594,6 +3776,10 @@ ok {test-number} - encode( "[\x01]" ) == "[\\x01]" for: "[\x01]" == "[\x01]" ok {test-number} - encode( "[\x7F]" ) == "[\\x7F]" for: "[\x7F]" == "[\x7F]" # XmlWriter writes boolean attributes as true/false ok {test-number} - stream.str(), ContainsSubstring(R"(attr1="true")") && ContainsSubstring(R"(attr2="false")") for: " " ( contains: "attr1="true"" and contains: "attr2="false"" ) +# a succeeding test can still be skipped +ok {test-number} - +# a succeeding test can still be skipped +ok {test-number} - # SKIP # analyse no analysis ok {test-number} - analysis.mean.point.count() == 23 for: 23.0 == 23 # analyse no analysis @@ -3764,6 +3950,12 @@ ok {test-number} - convertToBits( -0. ) == ( 1ULL << 63 ) for: 92233720368547758 ok {test-number} - convertToBits( std::numeric_limits::denorm_min() ) == 1 for: 1 == 1 # convertToBits ok {test-number} - convertToBits( std::numeric_limits::denorm_min() ) == 1 for: 1 == 1 +# dynamic skipping works with generators +ok {test-number} - # SKIP 'skipping because answer = 41' +# dynamic skipping works with generators +ok {test-number} - +# dynamic skipping works with generators +ok {test-number} - # SKIP 'skipping because answer = 43' # empty tags are not allowed ok {test-number} - Catch::TestCaseInfo("", { "test with an empty tag", "[]" }, dummySourceLineInfo) # erfc_inv @@ -3782,6 +3974,22 @@ ok {test-number} - ok {test-number} - # even more nested SECTION tests ok {test-number} - +# failed assertions before SKIP cause test case to fail +not ok {test-number} - 3 == 4 +# failed assertions before SKIP cause test case to fail +ok {test-number} - # SKIP +# failing for some generator values causes entire test case to fail +not ok {test-number} - explicitly +# failing for some generator values causes entire test case to fail +ok {test-number} - # SKIP +# failing for some generator values causes entire test case to fail +not ok {test-number} - explicitly +# failing for some generator values causes entire test case to fail +ok {test-number} - # SKIP +# failing in some unskipped sections causes entire test case to fail +ok {test-number} - # SKIP +# failing in some unskipped sections causes entire test case to fail +not ok {test-number} - explicitly # is_unary_function ok {test-number} - with 1 message: 'Catch::Clara::Detail::is_unary_function::value' # is_unary_function @@ -3890,6 +4098,8 @@ ok {test-number} - a != b for: 1 != 2 ok {test-number} - b != a for: 2 != 1 # nested SECTION tests ok {test-number} - a != b for: 1 != 2 +# nested sections can be skipped dynamically at runtime +ok {test-number} - # SKIP # non streamable - with conv. op ok {test-number} - s == "7" for: "7" == "7" # non-copyable objects @@ -4054,12 +4264,20 @@ ok {test-number} - Timing.elapsed >= time for: 128 ns >= 100 ns ok {test-number} - Timing.result == Timing.iterations + 17 for: 145 == 145 # run_for_at_least, int ok {test-number} - Timing.iterations >= time.count() for: 128 >= 100 +# sections can be skipped dynamically at runtime +ok {test-number} - +# sections can be skipped dynamically at runtime +ok {test-number} - # SKIP +# sections can be skipped dynamically at runtime +ok {test-number} - # send a single char to INFO not ok {test-number} - false with 1 message: '3' # sends information to INFO not ok {test-number} - false with 2 messages: 'hi' and 'i := 7' # shortened hide tags are split apart ok {test-number} - testcase.tags, VectorContains( Tag( "magic-tag" ) ) && VectorContains( Tag( "."_catch_sr ) ) for: { {?}, {?} } ( Contains: {?} and Contains: {?} ) +# skipped tests can optionally provide a reason +ok {test-number} - # SKIP 'skipping because answer = 43' # splitString ok {test-number} - splitStringRef("", ','), Equals(std::vector()) for: { } Equals: { } # splitString @@ -4142,6 +4360,8 @@ ok {test-number} - strlen(std::get<0>(data)) == static_cast(std::get<1>( ok {test-number} - testcase.tags.size() == 1 for: 1 == 1 # tags with dots in later positions are not parsed as hidden ok {test-number} - testcase.tags[0].original == "magic.tag"_catch_sr for: magic.tag == magic.tag +# tests can be skipped dynamically at runtime +ok {test-number} - # SKIP # thrown std::strings are translated not ok {test-number} - unexpected exception with message: 'Why would you throw a std::string?' # toString on const wchar_t const pointer returns the string contents @@ -4192,6 +4412,10 @@ ok {test-number} - e.upper_bound == 23 for: 23.0 == 23 ok {test-number} - e.lower_bound == 23 for: 23.0 == 23 # uniform samples ok {test-number} - e.confidence_interval == 0.95 for: 0.95 == 0.95 +# uniform_integer_distribution can return the bounds +ok {test-number} - dist.a() == -10 for: -10 == -10 +# uniform_integer_distribution can return the bounds +ok {test-number} - dist.b() == 10 for: 10 == 10 # unique_ptr reimplementation: basic functionality ok {test-number} - !(ptr) for: !{?} # unique_ptr reimplementation: basic functionality @@ -4314,5 +4538,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0 ok {test-number} - # xmlentitycheck ok {test-number} - -1..2159 +1..2272 diff --git a/tests/SelfTest/Baselines/teamcity.sw.approved.txt b/tests/SelfTest/Baselines/teamcity.sw.approved.txt index 7049f2b6..2a2c40cf 100644 --- a/tests/SelfTest/Baselines/teamcity.sw.approved.txt +++ b/tests/SelfTest/Baselines/teamcity.sw.approved.txt @@ -18,7 +18,7 @@ ##teamcity[testStarted name='#1455 - INFO and WARN can start with a linebreak'] ##teamcity[testFinished name='#1455 - INFO and WARN can start with a linebreak' duration="{duration}"] ##teamcity[testStarted name='#1514: stderr/stdout is not captured in tests aborted by an exception'] -Tricky.tests.cpp:|nexplicit failure with message:|n "1514"'] +##teamcity[testFailed name='#1514: stderr/stdout is not captured in tests aborted by an exception' message='Tricky.tests.cpp:|n...............................................................................|n|nTricky.tests.cpp:|nexplicit failure with message:|n "1514"'] ##teamcity[testStdOut name='#1514: stderr/stdout is not captured in tests aborted by an exception' out='This would not be caught previously|n'] ##teamcity[testStdErr name='#1514: stderr/stdout is not captured in tests aborted by an exception' out='Nor would this|n'] ##teamcity[testFinished name='#1514: stderr/stdout is not captured in tests aborted by an exception' duration="{duration}"] @@ -52,30 +52,33 @@ Tricky.tests.cpp:|nexplicit failure with message:|n "1514"'] ##teamcity[testFinished name='#2152 - ULP checks between differently signed values were wrong - double' duration="{duration}"] ##teamcity[testStarted name='#2152 - ULP checks between differently signed values were wrong - float'] ##teamcity[testFinished name='#2152 - ULP checks between differently signed values were wrong - float' duration="{duration}"] +##teamcity[testStarted name='#2615 - Throwing in constructor generator fails test case but does not abort'] +##teamcity[testIgnored name='#2615 - Throwing in constructor generator fails test case but does not abort' message='Generators.tests.cpp:|n...............................................................................|n|nGenerators.tests.cpp:|nunexpected exception with message:|n "failure to init"- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testFinished name='#2615 - Throwing in constructor generator fails test case but does not abort' duration="{duration}"] ##teamcity[testStarted name='#748 - captures with unexpected exceptions'] -Exception.tests.cpp:|nunexpected exception with messages:|n "answer := 42"|n "expected exception"- failure ignore as test marked as |'ok to fail|'|n'] -Exception.tests.cpp:|nunexpected exception with messages:|n "answer := 42"|n "expected exception"|n REQUIRE_NOTHROW( thisThrows() )|nwith expansion:|n thisThrows()|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='#748 - captures with unexpected exceptions' message='-------------------------------------------------------------------------------|noutside assertions|n-------------------------------------------------------------------------------|nException.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with messages:|n "answer := 42"|n "expected exception"- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='#748 - captures with unexpected exceptions' message='-------------------------------------------------------------------------------|ninside REQUIRE_NOTHROW|n-------------------------------------------------------------------------------|nException.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with messages:|n "answer := 42"|n "expected exception"|n REQUIRE_NOTHROW( thisThrows() )|nwith expansion:|n thisThrows()|n- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='#748 - captures with unexpected exceptions' duration="{duration}"] ##teamcity[testStarted name='#809'] ##teamcity[testFinished name='#809' duration="{duration}"] ##teamcity[testStarted name='#833'] ##teamcity[testFinished name='#833' duration="{duration}"] ##teamcity[testStarted name='#835 -- errno should not be touched by Catch2'] -Misc.tests.cpp:|nexpression failed|n CHECK( f() == 0 )|nwith expansion:|n 1 == 0|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='#835 -- errno should not be touched by Catch2' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n CHECK( f() == 0 )|nwith expansion:|n 1 == 0|n- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='#835 -- errno should not be touched by Catch2' duration="{duration}"] ##teamcity[testStarted name='#872'] ##teamcity[testFinished name='#872' duration="{duration}"] ##teamcity[testStarted name='#961 -- Dynamically created sections should all be reported'] ##teamcity[testFinished name='#961 -- Dynamically created sections should all be reported' duration="{duration}"] ##teamcity[testStarted name='|'Not|' checks that should fail'] -Condition.tests.cpp:|nexpression failed|n CHECK( false != false )|nwith expansion:|n false != false|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( true != true )|nwith expansion:|n true != true|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( !true )|nwith expansion:|n false|n'] -Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( true )|nwith expansion:|n !true|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( !trueValue )|nwith expansion:|n false|n'] -Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( trueValue )|nwith expansion:|n !true|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( !(1 == 1) )|nwith expansion:|n false|n'] -Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( 1 == 1 )|nwith expansion:|n !(1 == 1)|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexpression failed|n CHECK( false != false )|nwith expansion:|n false != false|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( true != true )|nwith expansion:|n true != true|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( !true )|nwith expansion:|n false|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( true )|nwith expansion:|n !true|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( !trueValue )|nwith expansion:|n false|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( trueValue )|nwith expansion:|n !true|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( !(1 == 1) )|nwith expansion:|n false|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( 1 == 1 )|nwith expansion:|n !(1 == 1)|n'] ##teamcity[testFinished name='|'Not|' checks that should fail' duration="{duration}"] ##teamcity[testStarted name='|'Not|' checks that should succeed'] ##teamcity[testFinished name='|'Not|' checks that should succeed' duration="{duration}"] @@ -84,21 +87,21 @@ Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( 1 == 1 )|nw ##teamcity[testStarted name='3x3x3 ints'] ##teamcity[testFinished name='3x3x3 ints' duration="{duration}"] ##teamcity[testStarted name='A METHOD_AS_TEST_CASE based test run that fails'] -Class.tests.cpp:|nexpression failed|n REQUIRE( s == "world" )|nwith expansion:|n "hello" == "world"|n'] +##teamcity[testFailed name='A METHOD_AS_TEST_CASE based test run that fails' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( s == "world" )|nwith expansion:|n "hello" == "world"|n'] ##teamcity[testFinished name='A METHOD_AS_TEST_CASE based test run that fails' duration="{duration}"] ##teamcity[testStarted name='A METHOD_AS_TEST_CASE based test run that succeeds'] ##teamcity[testFinished name='A METHOD_AS_TEST_CASE based test run that succeeds' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo' duration="{duration}"] @@ -109,16 +112,16 @@ Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2< ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 6 < 2|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 6 < 2|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 2 < 2|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 2 < 2|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 6 < 2|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 6 < 2|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 2 < 2|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 2 < 2|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2' duration="{duration}"] @@ -129,13 +132,13 @@ Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2< ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - double'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture::m_a == 2 )|nwith expansion:|n 1.0 == 2|n'] +##teamcity[testFailed name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - double' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture::m_a == 2 )|nwith expansion:|n 1.0 == 2|n'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - double' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - float'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture::m_a == 2 )|nwith expansion:|n 1.0f == 2|n'] +##teamcity[testFailed name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - float' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture::m_a == 2 )|nwith expansion:|n 1.0f == 2|n'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - float' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - int'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture::m_a == 2 )|nwith expansion:|n 1 == 2|n'] +##teamcity[testFailed name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - int' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture::m_a == 2 )|nwith expansion:|n 1 == 2|n'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - int' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - double'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - double' duration="{duration}"] @@ -144,13 +147,13 @@ Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture|nexpression failed|n REQUIRE( Nttp_Fixture::value == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Nttp_Fixture::value == 0 )|nwith expansion:|n 1 == 0|n'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Nttp_Fixture::value == 0 )|nwith expansion:|n 3 == 0|n'] +##teamcity[testFailed name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Nttp_Fixture::value == 0 )|nwith expansion:|n 3 == 0|n'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Nttp_Fixture::value == 0 )|nwith expansion:|n 6 == 0|n'] +##teamcity[testFailed name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Nttp_Fixture::value == 0 )|nwith expansion:|n 6 == 0|n'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1' duration="{duration}"] @@ -159,7 +162,7 @@ Class.tests.cpp:|nexpression failed|n REQUIRE( Nttp_Fixture::va ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6' duration="{duration}"] ##teamcity[testStarted name='A TEST_CASE_METHOD based test run that fails'] -Class.tests.cpp:|nexpression failed|n REQUIRE( m_a == 2 )|nwith expansion:|n 1 == 2|n'] +##teamcity[testFailed name='A TEST_CASE_METHOD based test run that fails' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( m_a == 2 )|nwith expansion:|n 1 == 2|n'] ##teamcity[testFinished name='A TEST_CASE_METHOD based test run that fails' duration="{duration}"] ##teamcity[testStarted name='A TEST_CASE_METHOD based test run that succeeds'] ##teamcity[testFinished name='A TEST_CASE_METHOD based test run that succeeds' duration="{duration}"] @@ -182,11 +185,11 @@ Class.tests.cpp:|nexpression failed|n REQUIRE( m_a == 2 )|nwith ex ##teamcity[testStarted name='A comparison that uses literals instead of the normal constructor'] ##teamcity[testFinished name='A comparison that uses literals instead of the normal constructor' duration="{duration}"] ##teamcity[testStarted name='A couple of nested sections followed by a failure'] -Misc.tests.cpp:|nexplicit failure with message:|n "to infinity and beyond"'] +##teamcity[testFailed name='A couple of nested sections followed by a failure' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexplicit failure with message:|n "to infinity and beyond"'] ##teamcity[testFinished name='A couple of nested sections followed by a failure' duration="{duration}"] ##teamcity[testStarted name='A failing expression with a non streamable type is still captured'] -Tricky.tests.cpp:|nexpression failed|n CHECK( &o1 == &o2 )|nwith expansion:|n 0x == 0x|n'] -Tricky.tests.cpp:|nexpression failed|n CHECK( o1 == o2 )|nwith expansion:|n {?} == {?}|n'] +##teamcity[testFailed name='A failing expression with a non streamable type is still captured' message='Tricky.tests.cpp:|n...............................................................................|n|nTricky.tests.cpp:|nexpression failed|n CHECK( &o1 == &o2 )|nwith expansion:|n 0x == 0x|n'] +##teamcity[testFailed name='A failing expression with a non streamable type is still captured' message='Tricky.tests.cpp:|nexpression failed|n CHECK( o1 == o2 )|nwith expansion:|n {?} == {?}|n'] ##teamcity[testFinished name='A failing expression with a non streamable type is still captured' duration="{duration}"] ##teamcity[testStarted name='Absolute margin'] ##teamcity[testFinished name='Absolute margin' duration="{duration}"] @@ -195,7 +198,7 @@ Tricky.tests.cpp:|nexpression failed|n CHECK( o1 == o2 )|nwith exp ##teamcity[testStarted name='An expression with side-effects should only be evaluated once'] ##teamcity[testFinished name='An expression with side-effects should only be evaluated once' duration="{duration}"] ##teamcity[testStarted name='An unchecked exception reports the line of the last assertion'] -Exception.tests.cpp:|nunexpected exception with message:|n "unexpected exception"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n'] +##teamcity[testFailed name='An unchecked exception reports the line of the last assertion' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "unexpected exception"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n'] ##teamcity[testFinished name='An unchecked exception reports the line of the last assertion' duration="{duration}"] ##teamcity[testStarted name='Anonymous test case 1'] ##teamcity[testFinished name='Anonymous test case 1' duration="{duration}"] @@ -276,33 +279,34 @@ Exception.tests.cpp:|nunexpected exception with message:|n "unexpe ##teamcity[testStarted name='Composed matchers shortcircuit'] ##teamcity[testFinished name='Composed matchers shortcircuit' duration="{duration}"] ##teamcity[testStarted name='Contains string matcher'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), ContainsSubstring( "not there", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" contains: "not there" (case insensitive)|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), ContainsSubstring( "STRING" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" contains: "STRING"|n'] +##teamcity[testFailed name='Contains string matcher' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), ContainsSubstring( "not there", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" contains: "not there" (case insensitive)|n'] +##teamcity[testFailed name='Contains string matcher' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), ContainsSubstring( "STRING" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" contains: "STRING"|n'] ##teamcity[testFinished name='Contains string matcher' duration="{duration}"] ##teamcity[testStarted name='Copy and then generate a range'] ##teamcity[testFinished name='Copy and then generate a range' duration="{duration}"] ##teamcity[testStarted name='Cout stream properly declares it writes to stdout'] ##teamcity[testFinished name='Cout stream properly declares it writes to stdout' duration="{duration}"] ##teamcity[testStarted name='Custom exceptions can be translated when testing for nothrow'] -Exception.tests.cpp:|nunexpected exception with message:|n "custom exception - not std"|n REQUIRE_NOTHROW( throwCustom() )|nwith expansion:|n throwCustom()|n'] +##teamcity[testFailed name='Custom exceptions can be translated when testing for nothrow' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "custom exception - not std"|n REQUIRE_NOTHROW( throwCustom() )|nwith expansion:|n throwCustom()|n'] ##teamcity[testFinished name='Custom exceptions can be translated when testing for nothrow' duration="{duration}"] ##teamcity[testStarted name='Custom exceptions can be translated when testing for throwing as something else'] -Exception.tests.cpp:|nunexpected exception with message:|n "custom exception - not std"|n REQUIRE_THROWS_AS( throwCustom(), std::exception )|nwith expansion:|n throwCustom(), std::exception|n'] +##teamcity[testFailed name='Custom exceptions can be translated when testing for throwing as something else' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "custom exception - not std"|n REQUIRE_THROWS_AS( throwCustom(), std::exception )|nwith expansion:|n throwCustom(), std::exception|n'] ##teamcity[testFinished name='Custom exceptions can be translated when testing for throwing as something else' duration="{duration}"] ##teamcity[testStarted name='Custom std-exceptions can be custom translated'] -Exception.tests.cpp:|nunexpected exception with message:|n "custom std exception"'] +##teamcity[testFailed name='Custom std-exceptions can be custom translated' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "custom std exception"'] ##teamcity[testFinished name='Custom std-exceptions can be custom translated' duration="{duration}"] ##teamcity[testStarted name='Default scale is invisible to comparison'] ##teamcity[testFinished name='Default scale is invisible to comparison' duration="{duration}"] ##teamcity[testStarted name='Directly creating an EnumInfo'] ##teamcity[testFinished name='Directly creating an EnumInfo' duration="{duration}"] +##teamcity[testStarted name='Empty generators can SKIP in constructor'] +##teamcity[testIgnored name='Empty generators can SKIP in constructor' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip with message:|n "This generator is empty"'] +##teamcity[testFinished name='Empty generators can SKIP in constructor' duration="{duration}"] ##teamcity[testStarted name='Empty stream name opens cout stream'] ##teamcity[testFinished name='Empty stream name opens cout stream' duration="{duration}"] -##teamcity[testStarted name='Empty tag is not allowed'] -##teamcity[testFinished name='Empty tag is not allowed' duration="{duration}"] ##teamcity[testStarted name='EndsWith string matcher'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), EndsWith( "Substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ends with: "Substring"|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ends with: "this" (case insensitive)|n'] +##teamcity[testFailed name='EndsWith string matcher' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), EndsWith( "Substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ends with: "Substring"|n'] +##teamcity[testFailed name='EndsWith string matcher' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ends with: "this" (case insensitive)|n'] ##teamcity[testFinished name='EndsWith string matcher' duration="{duration}"] ##teamcity[testStarted name='Enums can quickly have stringification enabled using REGISTER_ENUM'] ##teamcity[testFinished name='Enums can quickly have stringification enabled using REGISTER_ENUM' duration="{duration}"] @@ -311,64 +315,70 @@ Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringFor ##teamcity[testStarted name='Epsilon only applies to Approx|'s value'] ##teamcity[testFinished name='Epsilon only applies to Approx|'s value' duration="{duration}"] ##teamcity[testStarted name='Equality checks that should fail'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven == 6 )|nwith expansion:|n 7 == 6|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven == 8 )|nwith expansion:|n 7 == 8|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven == 0 )|nwith expansion:|n 7 == 0|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 9.11f ) )|nwith expansion:|n 9.1f == Approx( 9.1099996567 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 9.0f ) )|nwith expansion:|n 9.1f == Approx( 9.0 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 1 ) )|nwith expansion:|n 9.1f == Approx( 1.0 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 0 ) )|nwith expansion:|n 9.1f == Approx( 0.0 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.double_pi == Approx( 3.1415 ) )|nwith expansion:|n 3.1415926535 == Approx( 3.1415 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello == "goodbye" )|nwith expansion:|n "hello" == "goodbye"|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello == "hell" )|nwith expansion:|n "hello" == "hell"|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello == "hello1" )|nwith expansion:|n "hello" == "hello1"|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello.size() == 6 )|nwith expansion:|n 5 == 6|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( x == Approx( 1.301 ) )|nwith expansion:|n 1.3 == Approx( 1.301 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexpression failed|n CHECK( data.int_seven == 6 )|nwith expansion:|n 7 == 6|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven == 8 )|nwith expansion:|n 7 == 8|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven == 0 )|nwith expansion:|n 7 == 0|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 9.11f ) )|nwith expansion:|n 9.1f == Approx( 9.1099996567 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 9.0f ) )|nwith expansion:|n 9.1f == Approx( 9.0 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 1 ) )|nwith expansion:|n 9.1f == Approx( 1.0 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 0 ) )|nwith expansion:|n 9.1f == Approx( 0.0 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.double_pi == Approx( 3.1415 ) )|nwith expansion:|n 3.1415926535 == Approx( 3.1415 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello == "goodbye" )|nwith expansion:|n "hello" == "goodbye"|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello == "hell" )|nwith expansion:|n "hello" == "hell"|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello == "hello1" )|nwith expansion:|n "hello" == "hello1"|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello.size() == 6 )|nwith expansion:|n 5 == 6|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( x == Approx( 1.301 ) )|nwith expansion:|n 1.3 == Approx( 1.301 )|n- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='Equality checks that should fail' duration="{duration}"] ##teamcity[testStarted name='Equality checks that should succeed'] ##teamcity[testFinished name='Equality checks that should succeed' duration="{duration}"] ##teamcity[testStarted name='Equals'] ##teamcity[testFinished name='Equals' duration="{duration}"] ##teamcity[testStarted name='Equals string matcher'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Equals( "this string contains |'ABC|' as a substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" equals: "this string contains |'ABC|' as a substring"|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Equals( "something else", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" equals: "something else" (case insensitive)|n'] +##teamcity[testFailed name='Equals string matcher' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Equals( "this string contains |'ABC|' as a substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" equals: "this string contains |'ABC|' as a substring"|n'] +##teamcity[testFailed name='Equals string matcher' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Equals( "something else", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" equals: "something else" (case insensitive)|n'] ##teamcity[testFinished name='Equals string matcher' duration="{duration}"] ##teamcity[testStarted name='Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified'] ##teamcity[testFinished name='Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified' duration="{duration}"] ##teamcity[testStarted name='Exception matchers that fail'] -Matchers.tests.cpp:|nno exception was thrown where one was expected|n CHECK_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n doesNotThrow(), SpecialException, ExceptionMatcher{ 1 }|n'] -Matchers.tests.cpp:|nno exception was thrown where one was expected|n REQUIRE_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n doesNotThrow(), SpecialException, ExceptionMatcher{ 1 }|n'] -Matchers.tests.cpp:|nunexpected exception with message:|n "Unknown exception"|n CHECK_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 }|n'] -Matchers.tests.cpp:|nunexpected exception with message:|n "Unknown exception"|n REQUIRE_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THROWS_MATCHES( throwsSpecialException( 3 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n SpecialException::what special exception has value of 1|n'] -Matchers.tests.cpp:|nexpression failed|n REQUIRE_THROWS_MATCHES( throwsSpecialException( 4 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n SpecialException::what special exception has value of 1|n'] +##teamcity[testFailed name='Exception matchers that fail' message='-------------------------------------------------------------------------------|nNo exception|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nno exception was thrown where one was expected|n CHECK_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n doesNotThrow(), SpecialException, ExceptionMatcher{ 1 }|n'] +##teamcity[testFailed name='Exception matchers that fail' message='Matchers.tests.cpp:|nno exception was thrown where one was expected|n REQUIRE_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n doesNotThrow(), SpecialException, ExceptionMatcher{ 1 }|n'] +##teamcity[testFailed name='Exception matchers that fail' message='-------------------------------------------------------------------------------|nType mismatch|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nunexpected exception with message:|n "Unknown exception"|n CHECK_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 }|n'] +##teamcity[testFailed name='Exception matchers that fail' message='Matchers.tests.cpp:|nunexpected exception with message:|n "Unknown exception"|n REQUIRE_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 }|n'] +##teamcity[testFailed name='Exception matchers that fail' message='-------------------------------------------------------------------------------|nContents are wrong|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THROWS_MATCHES( throwsSpecialException( 3 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n SpecialException::what special exception has value of 1|n'] +##teamcity[testFailed name='Exception matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n REQUIRE_THROWS_MATCHES( throwsSpecialException( 4 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n SpecialException::what special exception has value of 1|n'] ##teamcity[testFinished name='Exception matchers that fail' duration="{duration}"] ##teamcity[testStarted name='Exception matchers that succeed'] ##teamcity[testFinished name='Exception matchers that succeed' duration="{duration}"] +##teamcity[testStarted name='Exception message can be matched'] +##teamcity[testFinished name='Exception message can be matched' duration="{duration}"] ##teamcity[testStarted name='Exception messages can be tested for'] ##teamcity[testFinished name='Exception messages can be tested for' duration="{duration}"] ##teamcity[testStarted name='Exceptions matchers'] ##teamcity[testFinished name='Exceptions matchers' duration="{duration}"] ##teamcity[testStarted name='Expected exceptions that don|'t throw or unexpected exceptions fail the test'] -Exception.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK_THROWS_AS( thisThrows(), std::string )|nwith expansion:|n thisThrows(), std::string|n'] -Exception.tests.cpp:|nno exception was thrown where one was expected|n CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error )|nwith expansion:|n thisDoesntThrow(), std::domain_error|n'] -Exception.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK_NOTHROW( thisThrows() )|nwith expansion:|n thisThrows()|n'] +##teamcity[testFailed name='Expected exceptions that don|'t throw or unexpected exceptions fail the test' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK_THROWS_AS( thisThrows(), std::string )|nwith expansion:|n thisThrows(), std::string|n'] +##teamcity[testFailed name='Expected exceptions that don|'t throw or unexpected exceptions fail the test' message='Exception.tests.cpp:|nno exception was thrown where one was expected|n CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error )|nwith expansion:|n thisDoesntThrow(), std::domain_error|n'] +##teamcity[testFailed name='Expected exceptions that don|'t throw or unexpected exceptions fail the test' message='Exception.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK_NOTHROW( thisThrows() )|nwith expansion:|n thisThrows()|n'] ##teamcity[testFinished name='Expected exceptions that don|'t throw or unexpected exceptions fail the test' duration="{duration}"] ##teamcity[testStarted name='FAIL aborts the test'] -Message.tests.cpp:|nexplicit failure with message:|n "This is a failure"'] +##teamcity[testFailed name='FAIL aborts the test' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with message:|n "This is a failure"'] ##teamcity[testFinished name='FAIL aborts the test' duration="{duration}"] ##teamcity[testStarted name='FAIL does not require an argument'] -Message.tests.cpp:|nexplicit failure'] +##teamcity[testFailed name='FAIL does not require an argument' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure'] ##teamcity[testFinished name='FAIL does not require an argument' duration="{duration}"] ##teamcity[testStarted name='FAIL_CHECK does not abort the test'] -Message.tests.cpp:|nexplicit failure with message:|n "This is a failure"'] +##teamcity[testFailed name='FAIL_CHECK does not abort the test' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with message:|n "This is a failure"'] ##teamcity[testFinished name='FAIL_CHECK does not abort the test' duration="{duration}"] ##teamcity[testStarted name='Factorials are computed'] ##teamcity[testFinished name='Factorials are computed' duration="{duration}"] +##teamcity[testStarted name='Filter generator throws exception for empty generator'] +##teamcity[testFinished name='Filter generator throws exception for empty generator' duration="{duration}"] ##teamcity[testStarted name='Floating point matchers: double'] ##teamcity[testFinished name='Floating point matchers: double' duration="{duration}"] ##teamcity[testStarted name='Floating point matchers: float'] ##teamcity[testFinished name='Floating point matchers: float' duration="{duration}"] +##teamcity[testStarted name='GENERATE can combine literals and generators'] +##teamcity[testFinished name='GENERATE can combine literals and generators' duration="{duration}"] ##teamcity[testStarted name='Generators -- adapters'] ##teamcity[testFinished name='Generators -- adapters' duration="{duration}"] ##teamcity[testStarted name='Generators -- simple'] @@ -385,27 +395,37 @@ Message.tests.cpp:|nexplicit failure with message:|n "This is a fa ##teamcity[testFinished name='Hashing different test cases produces different result' duration="{duration}"] ##teamcity[testStarted name='Hashing test case produces same hash across multiple calls'] ##teamcity[testFinished name='Hashing test case produces same hash across multiple calls' duration="{duration}"] +##teamcity[testStarted name='INFO and UNSCOPED_INFO can stream multiple arguments'] +##teamcity[testFailed name='INFO and UNSCOPED_INFO can stream multiple arguments' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with messages:|n "This info has multiple parts."|n "This unscoped info has multiple parts."|n "Show infos!"'] +##teamcity[testFinished name='INFO and UNSCOPED_INFO can stream multiple arguments' duration="{duration}"] ##teamcity[testStarted name='INFO and WARN do not abort tests'] ##teamcity[testFinished name='INFO and WARN do not abort tests' duration="{duration}"] ##teamcity[testStarted name='INFO gets logged on failure'] -Message.tests.cpp:|nexpression failed with messages:|n "this message should be logged"|n "so should this"|n REQUIRE( a == 1 )|nwith expansion:|n 2 == 1|n'] +##teamcity[testFailed name='INFO gets logged on failure' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with messages:|n "this message should be logged"|n "so should this"|n REQUIRE( a == 1 )|nwith expansion:|n 2 == 1|n'] ##teamcity[testFinished name='INFO gets logged on failure' duration="{duration}"] ##teamcity[testStarted name='INFO gets logged on failure, even if captured before successful assertions'] -Message.tests.cpp:|nexpression failed with messages:|n "this message may be logged later"|n "this message should be logged"|n CHECK( a == 1 )|nwith expansion:|n 2 == 1|n'] -Message.tests.cpp:|nexpression failed with messages:|n "this message may be logged later"|n "this message should be logged"|n "and this, but later"|n CHECK( a == 0 )|nwith expansion:|n 2 == 0|n'] +##teamcity[testFailed name='INFO gets logged on failure, even if captured before successful assertions' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with messages:|n "this message may be logged later"|n "this message should be logged"|n CHECK( a == 1 )|nwith expansion:|n 2 == 1|n'] +##teamcity[testFailed name='INFO gets logged on failure, even if captured before successful assertions' message='Message.tests.cpp:|nexpression failed with messages:|n "this message may be logged later"|n "this message should be logged"|n "and this, but later"|n CHECK( a == 0 )|nwith expansion:|n 2 == 0|n'] ##teamcity[testFinished name='INFO gets logged on failure, even if captured before successful assertions' duration="{duration}"] ##teamcity[testStarted name='INFO is reset for each loop'] -Message.tests.cpp:|nexpression failed with messages:|n "current counter 10"|n "i := 10"|n REQUIRE( i < 10 )|nwith expansion:|n 10 < 10|n'] +##teamcity[testFailed name='INFO is reset for each loop' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with messages:|n "current counter 10"|n "i := 10"|n REQUIRE( i < 10 )|nwith expansion:|n 10 < 10|n'] ##teamcity[testFinished name='INFO is reset for each loop' duration="{duration}"] +##teamcity[testStarted name='Incomplete AssertionHandler'] +##teamcity[testIgnored name='Incomplete AssertionHandler' message='AssertionHandler.tests.cpp:|n...............................................................................|n|nAssertionHandler.tests.cpp:|nunexpected exception with message:|n "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"|n REQUIRE( Dummy )|nwith expansion:|n Dummy|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testFinished name='Incomplete AssertionHandler' duration="{duration}"] ##teamcity[testStarted name='Inequality checks that should fail'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven != 7 )|nwith expansion:|n 7 != 7|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one != Approx( 9.1f ) )|nwith expansion:|n 9.1f != Approx( 9.1000003815 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.double_pi != Approx( 3.1415926535 ) )|nwith expansion:|n 3.1415926535 != Approx( 3.1415926535 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello != "hello" )|nwith expansion:|n "hello" != "hello"|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello.size() != 5 )|nwith expansion:|n 5 != 5|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Inequality checks that should fail' message='Condition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexpression failed|n CHECK( data.int_seven != 7 )|nwith expansion:|n 7 != 7|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Inequality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one != Approx( 9.1f ) )|nwith expansion:|n 9.1f != Approx( 9.1000003815 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Inequality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.double_pi != Approx( 3.1415926535 ) )|nwith expansion:|n 3.1415926535 != Approx( 3.1415926535 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Inequality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello != "hello" )|nwith expansion:|n "hello" != "hello"|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Inequality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello.size() != 5 )|nwith expansion:|n 5 != 5|n- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='Inequality checks that should fail' duration="{duration}"] ##teamcity[testStarted name='Inequality checks that should succeed'] ##teamcity[testFinished name='Inequality checks that should succeed' duration="{duration}"] +##teamcity[testStarted name='JsonWriter'] +##teamcity[testFinished name='JsonWriter' duration="{duration}"] +##teamcity[testStarted name='JsonWriter escapes charaters in strings properly'] +##teamcity[testFinished name='JsonWriter escapes charaters in strings properly' duration="{duration}"] ##teamcity[testStarted name='Lambdas in assertions'] ##teamcity[testFinished name='Lambdas in assertions' duration="{duration}"] ##teamcity[testStarted name='Less-than inequalities with different epsilons'] @@ -419,21 +439,21 @@ Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello.si ##teamcity[testStarted name='Matchers can be composed with both && and ||||'] ##teamcity[testFinished name='Matchers can be composed with both && and ||||' duration="{duration}"] ##teamcity[testStarted name='Matchers can be composed with both && and |||| - failing'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), ( ContainsSubstring( "string" ) |||| ContainsSubstring( "different" ) ) && ContainsSubstring( "random" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" )|n'] +##teamcity[testFailed name='Matchers can be composed with both && and |||| - failing' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), ( ContainsSubstring( "string" ) |||| ContainsSubstring( "different" ) ) && ContainsSubstring( "random" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" )|n'] ##teamcity[testFinished name='Matchers can be composed with both && and |||| - failing' duration="{duration}"] ##teamcity[testStarted name='Matchers can be negated (Not) with the ! operator'] ##teamcity[testFinished name='Matchers can be negated (Not) with the ! operator' duration="{duration}"] ##teamcity[testStarted name='Matchers can be negated (Not) with the ! operator - failing'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), !ContainsSubstring( "substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" not contains: "substring"|n'] +##teamcity[testFailed name='Matchers can be negated (Not) with the ! operator - failing' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), !ContainsSubstring( "substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" not contains: "substring"|n'] ##teamcity[testFinished name='Matchers can be negated (Not) with the ! operator - failing' duration="{duration}"] ##teamcity[testStarted name='Mayfail test case with nested sections'] -Condition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Mayfail test case with nested sections' message='-------------------------------------------------------------------------------|nA|n1|n-------------------------------------------------------------------------------|nCondition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Mayfail test case with nested sections' message='-------------------------------------------------------------------------------|nA|n2|n-------------------------------------------------------------------------------|nCondition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Mayfail test case with nested sections' message='-------------------------------------------------------------------------------|nB|n1|n-------------------------------------------------------------------------------|nCondition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Mayfail test case with nested sections' message='-------------------------------------------------------------------------------|nB|n2|n-------------------------------------------------------------------------------|nCondition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='Mayfail test case with nested sections' duration="{duration}"] ##teamcity[testStarted name='Mismatching exception messages failing the test'] -Exception.tests.cpp:|nexpression failed|n REQUIRE_THROWS_WITH( thisThrows(), "should fail" )|nwith expansion:|n "expected exception" equals: "should fail"|n'] +##teamcity[testFailed name='Mismatching exception messages failing the test' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nexpression failed|n REQUIRE_THROWS_WITH( thisThrows(), "should fail" )|nwith expansion:|n "expected exception" equals: "should fail"|n'] ##teamcity[testFinished name='Mismatching exception messages failing the test' duration="{duration}"] ##teamcity[testStarted name='Multireporter calls reporters and listeners in correct order'] ##teamcity[testFinished name='Multireporter calls reporters and listeners in correct order' duration="{duration}"] @@ -444,40 +464,40 @@ Exception.tests.cpp:|nexpression failed|n REQUIRE_THROWS_WITH( thi ##teamcity[testStarted name='Nice descriptive name'] ##teamcity[testFinished name='Nice descriptive name' duration="{duration}"] ##teamcity[testStarted name='Non-std exceptions can be translated'] -Exception.tests.cpp:|nunexpected exception with message:|n "custom exception"'] +##teamcity[testFailed name='Non-std exceptions can be translated' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "custom exception"'] ##teamcity[testFinished name='Non-std exceptions can be translated' duration="{duration}"] ##teamcity[testStarted name='Objects that evaluated in boolean contexts can be checked'] ##teamcity[testFinished name='Objects that evaluated in boolean contexts can be checked' duration="{duration}"] ##teamcity[testStarted name='Optionally static assertions'] ##teamcity[testFinished name='Optionally static assertions' duration="{duration}"] ##teamcity[testStarted name='Ordering comparison checks that should fail'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven > 7 )|nwith expansion:|n 7 > 7|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < 7 )|nwith expansion:|n 7 < 7|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven > 8 )|nwith expansion:|n 7 > 8|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < 6 )|nwith expansion:|n 7 < 6|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < 0 )|nwith expansion:|n 7 < 0|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < -1 )|nwith expansion:|n 7 < -1|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven >= 8 )|nwith expansion:|n 7 >= 8|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven <= 6 )|nwith expansion:|n 7 <= 6|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one < 9 )|nwith expansion:|n 9.1f < 9|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one > 10 )|nwith expansion:|n 9.1f > 10|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one > 9.2 )|nwith expansion:|n 9.1f > 9.2|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello > "hello" )|nwith expansion:|n "hello" > "hello"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello < "hello" )|nwith expansion:|n "hello" < "hello"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello > "hellp" )|nwith expansion:|n "hello" > "hellp"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello > "z" )|nwith expansion:|n "hello" > "z"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello < "hellm" )|nwith expansion:|n "hello" < "hellm"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello < "a" )|nwith expansion:|n "hello" < "a"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello >= "z" )|nwith expansion:|n "hello" >= "z"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello <= "a" )|nwith expansion:|n "hello" <= "a"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexpression failed|n CHECK( data.int_seven > 7 )|nwith expansion:|n 7 > 7|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < 7 )|nwith expansion:|n 7 < 7|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven > 8 )|nwith expansion:|n 7 > 8|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < 6 )|nwith expansion:|n 7 < 6|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < 0 )|nwith expansion:|n 7 < 0|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < -1 )|nwith expansion:|n 7 < -1|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven >= 8 )|nwith expansion:|n 7 >= 8|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven <= 6 )|nwith expansion:|n 7 <= 6|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one < 9 )|nwith expansion:|n 9.1f < 9|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one > 10 )|nwith expansion:|n 9.1f > 10|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one > 9.2 )|nwith expansion:|n 9.1f > 9.2|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello > "hello" )|nwith expansion:|n "hello" > "hello"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello < "hello" )|nwith expansion:|n "hello" < "hello"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello > "hellp" )|nwith expansion:|n "hello" > "hellp"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello > "z" )|nwith expansion:|n "hello" > "z"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello < "hellm" )|nwith expansion:|n "hello" < "hellm"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello < "a" )|nwith expansion:|n "hello" < "a"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello >= "z" )|nwith expansion:|n "hello" >= "z"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello <= "a" )|nwith expansion:|n "hello" <= "a"|n'] ##teamcity[testFinished name='Ordering comparison checks that should fail' duration="{duration}"] ##teamcity[testStarted name='Ordering comparison checks that should succeed'] ##teamcity[testFinished name='Ordering comparison checks that should succeed' duration="{duration}"] ##teamcity[testStarted name='Our PCG implementation provides expected results for known seeds'] ##teamcity[testFinished name='Our PCG implementation provides expected results for known seeds' duration="{duration}"] ##teamcity[testStarted name='Output from all sections is reported'] -Message.tests.cpp:|nexplicit failure with message:|n "Message from section one"'] -Message.tests.cpp:|nexplicit failure with message:|n "Message from section two"'] +##teamcity[testFailed name='Output from all sections is reported' message='-------------------------------------------------------------------------------|none|n-------------------------------------------------------------------------------|nMessage.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with message:|n "Message from section one"'] +##teamcity[testFailed name='Output from all sections is reported' message='-------------------------------------------------------------------------------|ntwo|n-------------------------------------------------------------------------------|nMessage.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with message:|n "Message from section two"'] ##teamcity[testFinished name='Output from all sections is reported' duration="{duration}"] ##teamcity[testStarted name='Overloaded comma or address-of operators are not used'] ##teamcity[testFinished name='Overloaded comma or address-of operators are not used' duration="{duration}"] @@ -512,12 +532,12 @@ Message.tests.cpp:|nexplicit failure with message:|n "Message from ##teamcity[testStarted name='Range type with sentinel'] ##teamcity[testFinished name='Range type with sentinel' duration="{duration}"] ##teamcity[testStarted name='Reconstruction should be based on stringification: #914'] -Decomposition.tests.cpp:|nexpression failed|n CHECK( truthy(false) )|nwith expansion:|n Hey, its truthy!|n'] +##teamcity[testFailed name='Reconstruction should be based on stringification: #914' message='Decomposition.tests.cpp:|n...............................................................................|n|nDecomposition.tests.cpp:|nexpression failed|n CHECK( truthy(false) )|nwith expansion:|n Hey, its truthy!|n'] ##teamcity[testFinished name='Reconstruction should be based on stringification: #914' duration="{duration}"] ##teamcity[testStarted name='Regex string matcher'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Matches( "this STRING contains |'abc|' as a substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" matches "this STRING contains |'abc|' as a substring" case sensitively|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Matches( "contains |'abc|' as a substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" matches "contains |'abc|' as a substring" case sensitively|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Matches( "this string contains |'abc|' as a" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" matches "this string contains |'abc|' as a" case sensitively|n'] +##teamcity[testFailed name='Regex string matcher' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Matches( "this STRING contains |'abc|' as a substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" matches "this STRING contains |'abc|' as a substring" case sensitively|n'] +##teamcity[testFailed name='Regex string matcher' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Matches( "contains |'abc|' as a substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" matches "contains |'abc|' as a substring" case sensitively|n'] +##teamcity[testFailed name='Regex string matcher' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Matches( "this string contains |'abc|' as a" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" matches "this string contains |'abc|' as a" case sensitively|n'] ##teamcity[testFinished name='Regex string matcher' duration="{duration}"] ##teamcity[testStarted name='Registering reporter with |'::|' in name fails'] ##teamcity[testFinished name='Registering reporter with |'::|' in name fails' duration="{duration}"] @@ -549,8 +569,8 @@ Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringFor ##teamcity[testStdOut name='Standard output from all sections is reported' out='Message from section one|nMessage from section two|n'] ##teamcity[testFinished name='Standard output from all sections is reported' duration="{duration}"] ##teamcity[testStarted name='StartsWith string matcher'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), StartsWith( "This String" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" starts with: "This String"|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), StartsWith( "string", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" starts with: "string" (case insensitive)|n'] +##teamcity[testFailed name='StartsWith string matcher' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), StartsWith( "This String" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" starts with: "This String"|n'] +##teamcity[testFailed name='StartsWith string matcher' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), StartsWith( "string", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" starts with: "string" (case insensitive)|n'] ##teamcity[testFinished name='StartsWith string matcher' duration="{duration}"] ##teamcity[testStarted name='Static arrays are convertible to string'] ##teamcity[testFinished name='Static arrays are convertible to string' duration="{duration}"] @@ -573,7 +593,7 @@ Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringFor ##teamcity[testStarted name='Stringifying std::chrono::time_point'] ##teamcity[testFinished name='Stringifying std::chrono::time_point' duration="{duration}"] ##teamcity[testStarted name='Tabs and newlines show in output'] -Misc.tests.cpp:|nexpression failed|n CHECK( s1 == s2 )|nwith expansion:|n "if ($b == 10) {|n $a = 20;|n}"|n==|n"if ($b == 10) {|n $a = 20;|n}|n"|n'] +##teamcity[testFailed name='Tabs and newlines show in output' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n CHECK( s1 == s2 )|nwith expansion:|n "if ($b == 10) {|n $a = 20;|n}"|n==|n"if ($b == 10) {|n $a = 20;|n}|n"|n'] ##teamcity[testFinished name='Tabs and newlines show in output' duration="{duration}"] ##teamcity[testStarted name='Tag alias can be registered against tag patterns'] ##teamcity[testFinished name='Tag alias can be registered against tag patterns' duration="{duration}"] @@ -626,11 +646,17 @@ Misc.tests.cpp:|nexpression failed|n CHECK( s1 == s2 )|nwith expan ##teamcity[testStarted name='Testing checked-if'] ##teamcity[testFinished name='Testing checked-if' duration="{duration}"] ##teamcity[testStarted name='Testing checked-if 2'] -Misc.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Testing checked-if 2' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='Testing checked-if 2' duration="{duration}"] ##teamcity[testStarted name='Testing checked-if 3'] -Misc.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Testing checked-if 3' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='Testing checked-if 3' duration="{duration}"] +##teamcity[testStarted name='Testing checked-if 4'] +##teamcity[testIgnored name='Testing checked-if 4' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nunexpected exception with message:|n "Uncaught exception should fail!"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testFinished name='Testing checked-if 4' duration="{duration}"] +##teamcity[testStarted name='Testing checked-if 5'] +##teamcity[testIgnored name='Testing checked-if 5' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nunexpected exception with message:|n "Uncaught exception should fail!"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testFinished name='Testing checked-if 5' duration="{duration}"] ##teamcity[testStarted name='The NO_FAIL macro reports a failure but does not fail the test'] ##teamcity[testFinished name='The NO_FAIL macro reports a failure but does not fail the test' duration="{duration}"] ##teamcity[testStarted name='The default listing implementation write to provided stream'] @@ -638,14 +664,16 @@ Misc.tests.cpp:|nexplicit failure- failure ignore as test marked as ##teamcity[testStarted name='This test |'should|' fail but doesn|'t'] ##teamcity[testFinished name='This test |'should|' fail but doesn|'t' duration="{duration}"] ##teamcity[testStarted name='Thrown string literals are translated'] -Exception.tests.cpp:|nunexpected exception with message:|n "For some reason someone is throwing a string literal!"'] +##teamcity[testFailed name='Thrown string literals are translated' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "For some reason someone is throwing a string literal!"'] ##teamcity[testFinished name='Thrown string literals are translated' duration="{duration}"] ##teamcity[testStarted name='Tracker'] ##teamcity[testFinished name='Tracker' duration="{duration}"] ##teamcity[testStarted name='Trim strings'] ##teamcity[testFinished name='Trim strings' duration="{duration}"] +##teamcity[testStarted name='Type conversions of RangeEquals and similar'] +##teamcity[testFinished name='Type conversions of RangeEquals and similar' duration="{duration}"] ##teamcity[testStarted name='Unexpected exceptions can be translated'] -Exception.tests.cpp:|nunexpected exception with message:|n "3.14"'] +##teamcity[testFailed name='Unexpected exceptions can be translated' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "3.14"'] ##teamcity[testFinished name='Unexpected exceptions can be translated' duration="{duration}"] ##teamcity[testStarted name='Upcasting special member functions'] ##teamcity[testFinished name='Upcasting special member functions' duration="{duration}"] @@ -661,6 +689,10 @@ Exception.tests.cpp:|nunexpected exception with message:|n "3.14"' ##teamcity[testFinished name='Usage of NoneMatch range matcher' duration="{duration}"] ##teamcity[testStarted name='Usage of NoneTrue range matcher'] ##teamcity[testFinished name='Usage of NoneTrue range matcher' duration="{duration}"] +##teamcity[testStarted name='Usage of RangeEquals range matcher'] +##teamcity[testFinished name='Usage of RangeEquals range matcher' duration="{duration}"] +##teamcity[testStarted name='Usage of UnorderedRangeEquals range matcher'] +##teamcity[testFinished name='Usage of UnorderedRangeEquals range matcher' duration="{duration}"] ##teamcity[testStarted name='Usage of the SizeIs range matcher'] ##teamcity[testFinished name='Usage of the SizeIs range matcher' duration="{duration}"] ##teamcity[testStarted name='Use a custom approx'] @@ -670,41 +702,41 @@ Exception.tests.cpp:|nunexpected exception with message:|n "3.14"' ##teamcity[testStarted name='Vector Approx matcher'] ##teamcity[testFinished name='Vector Approx matcher' duration="{duration}"] ##teamcity[testStarted name='Vector Approx matcher -- failing'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, Approx( t1 ) )|nwith expansion:|n { } is approx: { 1.0, 2.0 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v1, Approx( v2 ) )|nwith expansion:|n { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 }|n'] +##teamcity[testFailed name='Vector Approx matcher -- failing' message='-------------------------------------------------------------------------------|nEmpty and non empty vectors are not approx equal|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, Approx( t1 ) )|nwith expansion:|n { } is approx: { 1.0, 2.0 }|n'] +##teamcity[testFailed name='Vector Approx matcher -- failing' message='-------------------------------------------------------------------------------|nJust different vectors|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( v1, Approx( v2 ) )|nwith expansion:|n { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 }|n'] ##teamcity[testFinished name='Vector Approx matcher -- failing' duration="{duration}"] ##teamcity[testStarted name='Vector matchers'] ##teamcity[testFinished name='Vector matchers' duration="{duration}"] ##teamcity[testStarted name='Vector matchers that fail'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, VectorContains( -1 ) )|nwith expansion:|n { 1, 2, 3 } Contains: -1|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, VectorContains( 1 ) )|nwith expansion:|n { } Contains: 1|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, Contains( v ) )|nwith expansion:|n { } Contains: { 1, 2, 3 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, Contains( v2 ) )|nwith expansion:|n { 1, 2, 3 } Contains: { 1, 2, 4 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, Equals( v2 ) )|nwith expansion:|n { 1, 2, 3 } Equals: { 1, 2 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v2, Equals( v ) )|nwith expansion:|n { 1, 2 } Equals: { 1, 2, 3 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, Equals( v ) )|nwith expansion:|n { } Equals: { 1, 2, 3 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, Equals( empty ) )|nwith expansion:|n { 1, 2, 3 } Equals: { }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, UnorderedEquals( empty ) )|nwith expansion:|n { 1, 2, 3 } UnorderedEquals: { }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, UnorderedEquals( v ) )|nwith expansion:|n { } UnorderedEquals: { 1, 2, 3 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( permuted, UnorderedEquals( v ) )|nwith expansion:|n { 1, 3 } UnorderedEquals: { 1, 2, 3 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( permuted, UnorderedEquals( v ) )|nwith expansion:|n { 3, 1 } UnorderedEquals: { 1, 2, 3 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='-------------------------------------------------------------------------------|nContains (element)|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, VectorContains( -1 ) )|nwith expansion:|n { 1, 2, 3 } Contains: -1|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, VectorContains( 1 ) )|nwith expansion:|n { } Contains: 1|n'] +##teamcity[testFailed name='Vector matchers that fail' message='-------------------------------------------------------------------------------|nContains (vector)|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, Contains( v ) )|nwith expansion:|n { } Contains: { 1, 2, 3 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, Contains( v2 ) )|nwith expansion:|n { 1, 2, 3 } Contains: { 1, 2, 4 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='-------------------------------------------------------------------------------|nEquals|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, Equals( v2 ) )|nwith expansion:|n { 1, 2, 3 } Equals: { 1, 2 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v2, Equals( v ) )|nwith expansion:|n { 1, 2 } Equals: { 1, 2, 3 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, Equals( v ) )|nwith expansion:|n { } Equals: { 1, 2, 3 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, Equals( empty ) )|nwith expansion:|n { 1, 2, 3 } Equals: { }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='-------------------------------------------------------------------------------|nUnorderedEquals|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, UnorderedEquals( empty ) )|nwith expansion:|n { 1, 2, 3 } UnorderedEquals: { }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, UnorderedEquals( v ) )|nwith expansion:|n { } UnorderedEquals: { 1, 2, 3 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( permuted, UnorderedEquals( v ) )|nwith expansion:|n { 1, 3 } UnorderedEquals: { 1, 2, 3 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( permuted, UnorderedEquals( v ) )|nwith expansion:|n { 3, 1 } UnorderedEquals: { 1, 2, 3 }|n'] ##teamcity[testFinished name='Vector matchers that fail' duration="{duration}"] ##teamcity[testStarted name='When checked exceptions are thrown they can be expected or unexpected'] ##teamcity[testFinished name='When checked exceptions are thrown they can be expected or unexpected' duration="{duration}"] ##teamcity[testStarted name='When unchecked exceptions are thrown directly they are always failures'] -Exception.tests.cpp:|nunexpected exception with message:|n "unexpected exception"'] +##teamcity[testFailed name='When unchecked exceptions are thrown directly they are always failures' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "unexpected exception"'] ##teamcity[testFinished name='When unchecked exceptions are thrown directly they are always failures' duration="{duration}"] ##teamcity[testStarted name='When unchecked exceptions are thrown during a CHECK the test should continue'] -Exception.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK( thisThrows() == 0 )|nwith expansion:|n thisThrows() == 0|n'] +##teamcity[testFailed name='When unchecked exceptions are thrown during a CHECK the test should continue' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK( thisThrows() == 0 )|nwith expansion:|n thisThrows() == 0|n'] ##teamcity[testFinished name='When unchecked exceptions are thrown during a CHECK the test should continue' duration="{duration}"] ##teamcity[testStarted name='When unchecked exceptions are thrown during a REQUIRE the test should abort fail'] -Exception.tests.cpp:|nunexpected exception with message:|n "expected exception"|n REQUIRE( thisThrows() == 0 )|nwith expansion:|n thisThrows() == 0|n'] +##teamcity[testFailed name='When unchecked exceptions are thrown during a REQUIRE the test should abort fail' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "expected exception"|n REQUIRE( thisThrows() == 0 )|nwith expansion:|n thisThrows() == 0|n'] ##teamcity[testFinished name='When unchecked exceptions are thrown during a REQUIRE the test should abort fail' duration="{duration}"] ##teamcity[testStarted name='When unchecked exceptions are thrown from functions they are always failures'] -Exception.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK( thisThrows() == 0 )|nwith expansion:|n thisThrows() == 0|n'] +##teamcity[testFailed name='When unchecked exceptions are thrown from functions they are always failures' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK( thisThrows() == 0 )|nwith expansion:|n thisThrows() == 0|n'] ##teamcity[testFinished name='When unchecked exceptions are thrown from functions they are always failures' duration="{duration}"] ##teamcity[testStarted name='When unchecked exceptions are thrown from sections they are always failures'] -Exception.tests.cpp:|nunexpected exception with message:|n "unexpected exception"'] +##teamcity[testFailed name='When unchecked exceptions are thrown from sections they are always failures' message='-------------------------------------------------------------------------------|nsection name|n-------------------------------------------------------------------------------|nException.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "unexpected exception"'] ##teamcity[testFinished name='When unchecked exceptions are thrown from sections they are always failures' duration="{duration}"] ##teamcity[testStarted name='When unchecked exceptions are thrown, but caught, they do not affect the test'] ##teamcity[testFinished name='When unchecked exceptions are thrown, but caught, they do not affect the test' duration="{duration}"] @@ -720,6 +752,9 @@ Exception.tests.cpp:|nunexpected exception with message:|n "unexpe ##teamcity[testFinished name='XmlEncode' duration="{duration}"] ##teamcity[testStarted name='XmlWriter writes boolean attributes as true/false'] ##teamcity[testFinished name='XmlWriter writes boolean attributes as true/false' duration="{duration}"] +##teamcity[testStarted name='a succeeding test can still be skipped'] +##teamcity[testIgnored name='a succeeding test can still be skipped' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testFinished name='a succeeding test can still be skipped' duration="{duration}"] ##teamcity[testStarted name='analyse no analysis'] ##teamcity[testFinished name='analyse no analysis' duration="{duration}"] ##teamcity[testStarted name='array -> toString'] @@ -731,12 +766,12 @@ Exception.tests.cpp:|nunexpected exception with message:|n "unexpe ##teamcity[testStarted name='checkedElse'] ##teamcity[testFinished name='checkedElse' duration="{duration}"] ##teamcity[testStarted name='checkedElse, failing'] -Misc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedElse( false ) )|nwith expansion:|n false|n'] +##teamcity[testFailed name='checkedElse, failing' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedElse( false ) )|nwith expansion:|n false|n'] ##teamcity[testFinished name='checkedElse, failing' duration="{duration}"] ##teamcity[testStarted name='checkedIf'] ##teamcity[testFinished name='checkedIf' duration="{duration}"] ##teamcity[testStarted name='checkedIf, failing'] -Misc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedIf( false ) )|nwith expansion:|n false|n'] +##teamcity[testFailed name='checkedIf, failing' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedIf( false ) )|nwith expansion:|n false|n'] ##teamcity[testFinished name='checkedIf, failing' duration="{duration}"] ##teamcity[testStarted name='classify_outliers'] ##teamcity[testFinished name='classify_outliers' duration="{duration}"] @@ -746,6 +781,10 @@ Misc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedIf( false ##teamcity[testFinished name='comparisons between int variables' duration="{duration}"] ##teamcity[testStarted name='convertToBits'] ##teamcity[testFinished name='convertToBits' duration="{duration}"] +##teamcity[testStarted name='dynamic skipping works with generators'] +##teamcity[testIgnored name='dynamic skipping works with generators' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip with message:|n "skipping because answer = 41"'] +##teamcity[testIgnored name='dynamic skipping works with generators' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip with message:|n "skipping because answer = 43"'] +##teamcity[testFinished name='dynamic skipping works with generators' duration="{duration}"] ##teamcity[testStarted name='empty tags are not allowed'] ##teamcity[testFinished name='empty tags are not allowed' duration="{duration}"] ##teamcity[testStarted name='erfc_inv'] @@ -754,6 +793,20 @@ Misc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedIf( false ##teamcity[testFinished name='estimate_clock_resolution' duration="{duration}"] ##teamcity[testStarted name='even more nested SECTION tests'] ##teamcity[testFinished name='even more nested SECTION tests' duration="{duration}"] +##teamcity[testStarted name='failed assertions before SKIP cause test case to fail'] +##teamcity[testIgnored name='failed assertions before SKIP cause test case to fail' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexpression failed|n CHECK( 3 == 4 )|nwith expansion:|n 3 == 4|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='failed assertions before SKIP cause test case to fail' message='Skip.tests.cpp:|nexplicit skip'] +##teamcity[testFinished name='failed assertions before SKIP cause test case to fail' duration="{duration}"] +##teamcity[testStarted name='failing for some generator values causes entire test case to fail'] +##teamcity[testIgnored name='failing for some generator values causes entire test case to fail' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='failing for some generator values causes entire test case to fail' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testIgnored name='failing for some generator values causes entire test case to fail' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='failing for some generator values causes entire test case to fail' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testFinished name='failing for some generator values causes entire test case to fail' duration="{duration}"] +##teamcity[testStarted name='failing in some unskipped sections causes entire test case to fail'] +##teamcity[testIgnored name='failing in some unskipped sections causes entire test case to fail' message='-------------------------------------------------------------------------------|nskipped|n-------------------------------------------------------------------------------|nSkip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testIgnored name='failing in some unskipped sections causes entire test case to fail' message='-------------------------------------------------------------------------------|nnot skipped|n-------------------------------------------------------------------------------|nSkip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testFinished name='failing in some unskipped sections causes entire test case to fail' duration="{duration}"] ##teamcity[testStarted name='first tag'] ##teamcity[testFinished name='first tag' duration="{duration}"] ##teamcity[testStarted name='has printf'] @@ -762,10 +815,10 @@ loose text artifact ##teamcity[testStarted name='is_unary_function'] ##teamcity[testFinished name='is_unary_function' duration="{duration}"] ##teamcity[testStarted name='just failure'] -Message.tests.cpp:|nexplicit failure with message:|n "Previous info should not be seen"'] +##teamcity[testFailed name='just failure' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with message:|n "Previous info should not be seen"'] ##teamcity[testFinished name='just failure' duration="{duration}"] ##teamcity[testStarted name='just failure after unscoped info'] -Message.tests.cpp:|nexplicit failure with message:|n "previous unscoped info SHOULD not be seen"'] +##teamcity[testFailed name='just failure after unscoped info' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with message:|n "previous unscoped info SHOULD not be seen"'] ##teamcity[testFinished name='just failure after unscoped info' duration="{duration}"] ##teamcity[testStarted name='just info'] ##teamcity[testFinished name='just info' duration="{duration}"] @@ -774,16 +827,16 @@ Message.tests.cpp:|nexplicit failure with message:|n "previous uns ##teamcity[testStarted name='long long'] ##teamcity[testFinished name='long long' duration="{duration}"] ##teamcity[testStarted name='looped SECTION tests'] -Misc.tests.cpp:|nexpression failed|n CHECK( b > a )|nwith expansion:|n 0 > 1|n'] -Misc.tests.cpp:|nexpression failed|n CHECK( b > a )|nwith expansion:|n 1 > 1|n'] +##teamcity[testFailed name='looped SECTION tests' message='-------------------------------------------------------------------------------|nb is currently: 0|n-------------------------------------------------------------------------------|nMisc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n CHECK( b > a )|nwith expansion:|n 0 > 1|n'] +##teamcity[testFailed name='looped SECTION tests' message='-------------------------------------------------------------------------------|nb is currently: 1|n-------------------------------------------------------------------------------|nMisc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n CHECK( b > a )|nwith expansion:|n 1 > 1|n'] ##teamcity[testFinished name='looped SECTION tests' duration="{duration}"] ##teamcity[testStarted name='looped tests'] -Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[0|] (1) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] -Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[1|] (1) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] -Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[3|] (3) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] -Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[4|] (5) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] -Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[6|] (13) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] -Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[7|] (21) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='looped tests' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[0|] (1) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='looped tests' message='Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[1|] (1) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='looped tests' message='Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[3|] (3) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='looped tests' message='Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[4|] (5) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='looped tests' message='Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[6|] (13) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='looped tests' message='Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[7|] (21) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] ##teamcity[testFinished name='looped tests' duration="{duration}"] ##teamcity[testStarted name='makeStream recognizes %debug stream name'] ##teamcity[testFinished name='makeStream recognizes %debug stream name' duration="{duration}"] @@ -796,10 +849,14 @@ Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib ##teamcity[testStarted name='mix info, unscoped info and warning'] ##teamcity[testFinished name='mix info, unscoped info and warning' duration="{duration}"] ##teamcity[testStarted name='more nested SECTION tests'] -Misc.tests.cpp:|nexpression failed|n REQUIRE( a == b )|nwith expansion:|n 1 == 2|n'] +##teamcity[testFailed name='more nested SECTION tests' message='-------------------------------------------------------------------------------|ndoesn|'t equal|nequal|n-------------------------------------------------------------------------------|nMisc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n REQUIRE( a == b )|nwith expansion:|n 1 == 2|n'] ##teamcity[testFinished name='more nested SECTION tests' duration="{duration}"] ##teamcity[testStarted name='nested SECTION tests'] ##teamcity[testFinished name='nested SECTION tests' duration="{duration}"] +##teamcity[testStarted name='nested sections can be skipped dynamically at runtime'] +##teamcity[testIgnored name='nested sections can be skipped dynamically at runtime' message='-------------------------------------------------------------------------------|nB|nB2|n-------------------------------------------------------------------------------|nSkip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testStdOut name='nested sections can be skipped dynamically at runtime' out='a!|nb1!|n!|n'] +##teamcity[testFinished name='nested sections can be skipped dynamically at runtime' duration="{duration}"] ##teamcity[testStarted name='non streamable - with conv. op'] ##teamcity[testFinished name='non streamable - with conv. op' duration="{duration}"] ##teamcity[testStarted name='non-copyable objects'] @@ -811,7 +868,7 @@ Misc.tests.cpp:|nexpression failed|n REQUIRE( a == b )|nwith expan ##teamcity[testStarted name='not allowed'] ##teamcity[testFinished name='not allowed' duration="{duration}"] ##teamcity[testStarted name='not prints unscoped info from previous failures'] -Message.tests.cpp:|nexpression failed with message:|n "this SHOULD be seen"|n REQUIRE( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='not prints unscoped info from previous failures' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with message:|n "this SHOULD be seen"|n REQUIRE( false )|nwith expansion:|n false|n'] ##teamcity[testFinished name='not prints unscoped info from previous failures' duration="{duration}"] ##teamcity[testStarted name='null strings'] ##teamcity[testFinished name='null strings' duration="{duration}"] @@ -826,10 +883,10 @@ Message.tests.cpp:|nexpression failed with message:|n "this SHOULD ##teamcity[testStarted name='print unscoped info if passing unscoped info is printed'] ##teamcity[testFinished name='print unscoped info if passing unscoped info is printed' duration="{duration}"] ##teamcity[testStarted name='prints unscoped info on failure'] -Message.tests.cpp:|nexpression failed with messages:|n "this SHOULD be seen"|n "this SHOULD also be seen"|n REQUIRE( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='prints unscoped info on failure' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with messages:|n "this SHOULD be seen"|n "this SHOULD also be seen"|n REQUIRE( false )|nwith expansion:|n false|n'] ##teamcity[testFinished name='prints unscoped info on failure' duration="{duration}"] ##teamcity[testStarted name='prints unscoped info only for the first assertion'] -Message.tests.cpp:|nexpression failed with message:|n "this SHOULD be seen only ONCE"|n CHECK( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='prints unscoped info only for the first assertion' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with message:|n "this SHOULD be seen only ONCE"|n CHECK( false )|nwith expansion:|n false|n'] ##teamcity[testFinished name='prints unscoped info only for the first assertion' duration="{duration}"] ##teamcity[testStarted name='random SECTION tests'] ##teamcity[testFinished name='random SECTION tests' duration="{duration}"] @@ -845,19 +902,25 @@ Message.tests.cpp:|nexpression failed with message:|n "this SHOULD ##teamcity[testFinished name='run_for_at_least, int' duration="{duration}"] ##teamcity[testStarted name='second tag'] ##teamcity[testFinished name='second tag' duration="{duration}"] +##teamcity[testStarted name='sections can be skipped dynamically at runtime'] +##teamcity[testIgnored name='sections can be skipped dynamically at runtime' message='-------------------------------------------------------------------------------|nskipped|n-------------------------------------------------------------------------------|nSkip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testFinished name='sections can be skipped dynamically at runtime' duration="{duration}"] ##teamcity[testStarted name='send a single char to INFO'] -Misc.tests.cpp:|nexpression failed with message:|n "3"|n REQUIRE( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='send a single char to INFO' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed with message:|n "3"|n REQUIRE( false )|nwith expansion:|n false|n'] ##teamcity[testFinished name='send a single char to INFO' duration="{duration}"] ##teamcity[testStarted name='sends information to INFO'] -Message.tests.cpp:|nexpression failed with messages:|n "hi"|n "i := 7"|n REQUIRE( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='sends information to INFO' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with messages:|n "hi"|n "i := 7"|n REQUIRE( false )|nwith expansion:|n false|n'] ##teamcity[testFinished name='sends information to INFO' duration="{duration}"] ##teamcity[testStarted name='shortened hide tags are split apart'] ##teamcity[testFinished name='shortened hide tags are split apart' duration="{duration}"] +##teamcity[testStarted name='skipped tests can optionally provide a reason'] +##teamcity[testIgnored name='skipped tests can optionally provide a reason' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip with message:|n "skipping because answer = 43"'] +##teamcity[testFinished name='skipped tests can optionally provide a reason' duration="{duration}"] ##teamcity[testStarted name='splitString'] ##teamcity[testFinished name='splitString' duration="{duration}"] ##teamcity[testStarted name='stacks unscoped info in loops'] -Message.tests.cpp:|nexpression failed with messages:|n "Count 1 to 3..."|n "1"|n "2"|n "3"|n CHECK( false )|nwith expansion:|n false|n'] -Message.tests.cpp:|nexpression failed with messages:|n "Count 4 to 6..."|n "4"|n "5"|n "6"|n CHECK( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='stacks unscoped info in loops' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with messages:|n "Count 1 to 3..."|n "1"|n "2"|n "3"|n CHECK( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='stacks unscoped info in loops' message='Message.tests.cpp:|nexpression failed with messages:|n "Count 4 to 6..."|n "4"|n "5"|n "6"|n CHECK( false )|nwith expansion:|n false|n'] ##teamcity[testFinished name='stacks unscoped info in loops' duration="{duration}"] ##teamcity[testStarted name='startsWith'] ##teamcity[testFinished name='startsWith' duration="{duration}"] @@ -897,8 +960,11 @@ Message.tests.cpp:|nexpression failed with messages:|n "Count 4 to ##teamcity[testFinished name='tables' duration="{duration}"] ##teamcity[testStarted name='tags with dots in later positions are not parsed as hidden'] ##teamcity[testFinished name='tags with dots in later positions are not parsed as hidden' duration="{duration}"] +##teamcity[testStarted name='tests can be skipped dynamically at runtime'] +##teamcity[testIgnored name='tests can be skipped dynamically at runtime' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testFinished name='tests can be skipped dynamically at runtime' duration="{duration}"] ##teamcity[testStarted name='thrown std::strings are translated'] -Exception.tests.cpp:|nunexpected exception with message:|n "Why would you throw a std::string?"'] +##teamcity[testFailed name='thrown std::strings are translated' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "Why would you throw a std::string?"'] ##teamcity[testFinished name='thrown std::strings are translated' duration="{duration}"] ##teamcity[testStarted name='toString on const wchar_t const pointer returns the string contents'] ##teamcity[testFinished name='toString on const wchar_t const pointer returns the string contents' duration="{duration}"] @@ -928,6 +994,8 @@ Exception.tests.cpp:|nunexpected exception with message:|n "Why wo ##teamcity[testFinished name='tuple,tuple<>,float>' duration="{duration}"] ##teamcity[testStarted name='uniform samples'] ##teamcity[testFinished name='uniform samples' duration="{duration}"] +##teamcity[testStarted name='uniform_integer_distribution can return the bounds'] +##teamcity[testFinished name='uniform_integer_distribution can return the bounds' duration="{duration}"] ##teamcity[testStarted name='unique_ptr reimplementation: basic functionality'] ##teamcity[testFinished name='unique_ptr reimplementation: basic functionality' duration="{duration}"] ##teamcity[testStarted name='vec> -> toString'] diff --git a/tests/SelfTest/Baselines/teamcity.sw.multi.approved.txt b/tests/SelfTest/Baselines/teamcity.sw.multi.approved.txt index 96de7dd8..24ed5d98 100644 --- a/tests/SelfTest/Baselines/teamcity.sw.multi.approved.txt +++ b/tests/SelfTest/Baselines/teamcity.sw.multi.approved.txt @@ -18,7 +18,7 @@ ##teamcity[testStarted name='#1455 - INFO and WARN can start with a linebreak'] ##teamcity[testFinished name='#1455 - INFO and WARN can start with a linebreak' duration="{duration}"] ##teamcity[testStarted name='#1514: stderr/stdout is not captured in tests aborted by an exception'] -Tricky.tests.cpp:|nexplicit failure with message:|n "1514"'] +##teamcity[testFailed name='#1514: stderr/stdout is not captured in tests aborted by an exception' message='Tricky.tests.cpp:|n...............................................................................|n|nTricky.tests.cpp:|nexplicit failure with message:|n "1514"'] ##teamcity[testStdOut name='#1514: stderr/stdout is not captured in tests aborted by an exception' out='This would not be caught previously|n'] ##teamcity[testStdErr name='#1514: stderr/stdout is not captured in tests aborted by an exception' out='Nor would this|n'] ##teamcity[testFinished name='#1514: stderr/stdout is not captured in tests aborted by an exception' duration="{duration}"] @@ -52,30 +52,33 @@ Tricky.tests.cpp:|nexplicit failure with message:|n "1514"'] ##teamcity[testFinished name='#2152 - ULP checks between differently signed values were wrong - double' duration="{duration}"] ##teamcity[testStarted name='#2152 - ULP checks between differently signed values were wrong - float'] ##teamcity[testFinished name='#2152 - ULP checks between differently signed values were wrong - float' duration="{duration}"] +##teamcity[testStarted name='#2615 - Throwing in constructor generator fails test case but does not abort'] +##teamcity[testIgnored name='#2615 - Throwing in constructor generator fails test case but does not abort' message='Generators.tests.cpp:|n...............................................................................|n|nGenerators.tests.cpp:|nunexpected exception with message:|n "failure to init"- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testFinished name='#2615 - Throwing in constructor generator fails test case but does not abort' duration="{duration}"] ##teamcity[testStarted name='#748 - captures with unexpected exceptions'] -Exception.tests.cpp:|nunexpected exception with messages:|n "answer := 42"|n "expected exception"- failure ignore as test marked as |'ok to fail|'|n'] -Exception.tests.cpp:|nunexpected exception with messages:|n "answer := 42"|n "expected exception"|n REQUIRE_NOTHROW( thisThrows() )|nwith expansion:|n thisThrows()|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='#748 - captures with unexpected exceptions' message='-------------------------------------------------------------------------------|noutside assertions|n-------------------------------------------------------------------------------|nException.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with messages:|n "answer := 42"|n "expected exception"- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='#748 - captures with unexpected exceptions' message='-------------------------------------------------------------------------------|ninside REQUIRE_NOTHROW|n-------------------------------------------------------------------------------|nException.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with messages:|n "answer := 42"|n "expected exception"|n REQUIRE_NOTHROW( thisThrows() )|nwith expansion:|n thisThrows()|n- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='#748 - captures with unexpected exceptions' duration="{duration}"] ##teamcity[testStarted name='#809'] ##teamcity[testFinished name='#809' duration="{duration}"] ##teamcity[testStarted name='#833'] ##teamcity[testFinished name='#833' duration="{duration}"] ##teamcity[testStarted name='#835 -- errno should not be touched by Catch2'] -Misc.tests.cpp:|nexpression failed|n CHECK( f() == 0 )|nwith expansion:|n 1 == 0|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='#835 -- errno should not be touched by Catch2' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n CHECK( f() == 0 )|nwith expansion:|n 1 == 0|n- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='#835 -- errno should not be touched by Catch2' duration="{duration}"] ##teamcity[testStarted name='#872'] ##teamcity[testFinished name='#872' duration="{duration}"] ##teamcity[testStarted name='#961 -- Dynamically created sections should all be reported'] ##teamcity[testFinished name='#961 -- Dynamically created sections should all be reported' duration="{duration}"] ##teamcity[testStarted name='|'Not|' checks that should fail'] -Condition.tests.cpp:|nexpression failed|n CHECK( false != false )|nwith expansion:|n false != false|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( true != true )|nwith expansion:|n true != true|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( !true )|nwith expansion:|n false|n'] -Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( true )|nwith expansion:|n !true|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( !trueValue )|nwith expansion:|n false|n'] -Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( trueValue )|nwith expansion:|n !true|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( !(1 == 1) )|nwith expansion:|n false|n'] -Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( 1 == 1 )|nwith expansion:|n !(1 == 1)|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexpression failed|n CHECK( false != false )|nwith expansion:|n false != false|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( true != true )|nwith expansion:|n true != true|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( !true )|nwith expansion:|n false|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( true )|nwith expansion:|n !true|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( !trueValue )|nwith expansion:|n false|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( trueValue )|nwith expansion:|n !true|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( !(1 == 1) )|nwith expansion:|n false|n'] +##teamcity[testFailed name='|'Not|' checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( 1 == 1 )|nwith expansion:|n !(1 == 1)|n'] ##teamcity[testFinished name='|'Not|' checks that should fail' duration="{duration}"] ##teamcity[testStarted name='|'Not|' checks that should succeed'] ##teamcity[testFinished name='|'Not|' checks that should succeed' duration="{duration}"] @@ -84,21 +87,21 @@ Condition.tests.cpp:|nexpression failed|n CHECK_FALSE( 1 == 1 )|nw ##teamcity[testStarted name='3x3x3 ints'] ##teamcity[testFinished name='3x3x3 ints' duration="{duration}"] ##teamcity[testStarted name='A METHOD_AS_TEST_CASE based test run that fails'] -Class.tests.cpp:|nexpression failed|n REQUIRE( s == "world" )|nwith expansion:|n "hello" == "world"|n'] +##teamcity[testFailed name='A METHOD_AS_TEST_CASE based test run that fails' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( s == "world" )|nwith expansion:|n "hello" == "world"|n'] ##teamcity[testFinished name='A METHOD_AS_TEST_CASE based test run that fails' duration="{duration}"] ##teamcity[testStarted name='A METHOD_AS_TEST_CASE based test run that succeeds'] ##teamcity[testFinished name='A METHOD_AS_TEST_CASE based test run that succeeds' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2::m_a.size() == 1 )|nwith expansion:|n 0 == 1|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo' duration="{duration}"] @@ -109,16 +112,16 @@ Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2< ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 6 < 2|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 6 < 2|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 2 < 2|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 2 < 2|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 6 < 2|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 6 < 2|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 2 < 2|n'] +##teamcity[testFailed name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2{}.m_a.size() < 2 )|nwith expansion:|n 2 < 2|n'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2' duration="{duration}"] @@ -129,13 +132,13 @@ Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture_2< ##teamcity[testStarted name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array'] ##teamcity[testFinished name='A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - double'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture::m_a == 2 )|nwith expansion:|n 1.0 == 2|n'] +##teamcity[testFailed name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - double' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture::m_a == 2 )|nwith expansion:|n 1.0 == 2|n'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - double' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - float'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture::m_a == 2 )|nwith expansion:|n 1.0f == 2|n'] +##teamcity[testFailed name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - float' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture::m_a == 2 )|nwith expansion:|n 1.0f == 2|n'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - float' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - int'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture::m_a == 2 )|nwith expansion:|n 1 == 2|n'] +##teamcity[testFailed name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - int' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture::m_a == 2 )|nwith expansion:|n 1 == 2|n'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD based test run that fails - int' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - double'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - double' duration="{duration}"] @@ -144,13 +147,13 @@ Class.tests.cpp:|nexpression failed|n REQUIRE( Template_Fixture|nexpression failed|n REQUIRE( Nttp_Fixture::value == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Nttp_Fixture::value == 0 )|nwith expansion:|n 1 == 0|n'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Nttp_Fixture::value == 0 )|nwith expansion:|n 3 == 0|n'] +##teamcity[testFailed name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Nttp_Fixture::value == 0 )|nwith expansion:|n 3 == 0|n'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6'] -Class.tests.cpp:|nexpression failed|n REQUIRE( Nttp_Fixture::value == 0 )|nwith expansion:|n 6 == 0|n'] +##teamcity[testFailed name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( Nttp_Fixture::value == 0 )|nwith expansion:|n 6 == 0|n'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6' duration="{duration}"] ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1' duration="{duration}"] @@ -159,7 +162,7 @@ Class.tests.cpp:|nexpression failed|n REQUIRE( Nttp_Fixture::va ##teamcity[testStarted name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6'] ##teamcity[testFinished name='A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6' duration="{duration}"] ##teamcity[testStarted name='A TEST_CASE_METHOD based test run that fails'] -Class.tests.cpp:|nexpression failed|n REQUIRE( m_a == 2 )|nwith expansion:|n 1 == 2|n'] +##teamcity[testFailed name='A TEST_CASE_METHOD based test run that fails' message='Class.tests.cpp:|n...............................................................................|n|nClass.tests.cpp:|nexpression failed|n REQUIRE( m_a == 2 )|nwith expansion:|n 1 == 2|n'] ##teamcity[testFinished name='A TEST_CASE_METHOD based test run that fails' duration="{duration}"] ##teamcity[testStarted name='A TEST_CASE_METHOD based test run that succeeds'] ##teamcity[testFinished name='A TEST_CASE_METHOD based test run that succeeds' duration="{duration}"] @@ -182,11 +185,11 @@ Class.tests.cpp:|nexpression failed|n REQUIRE( m_a == 2 )|nwith ex ##teamcity[testStarted name='A comparison that uses literals instead of the normal constructor'] ##teamcity[testFinished name='A comparison that uses literals instead of the normal constructor' duration="{duration}"] ##teamcity[testStarted name='A couple of nested sections followed by a failure'] -Misc.tests.cpp:|nexplicit failure with message:|n "to infinity and beyond"'] +##teamcity[testFailed name='A couple of nested sections followed by a failure' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexplicit failure with message:|n "to infinity and beyond"'] ##teamcity[testFinished name='A couple of nested sections followed by a failure' duration="{duration}"] ##teamcity[testStarted name='A failing expression with a non streamable type is still captured'] -Tricky.tests.cpp:|nexpression failed|n CHECK( &o1 == &o2 )|nwith expansion:|n 0x == 0x|n'] -Tricky.tests.cpp:|nexpression failed|n CHECK( o1 == o2 )|nwith expansion:|n {?} == {?}|n'] +##teamcity[testFailed name='A failing expression with a non streamable type is still captured' message='Tricky.tests.cpp:|n...............................................................................|n|nTricky.tests.cpp:|nexpression failed|n CHECK( &o1 == &o2 )|nwith expansion:|n 0x == 0x|n'] +##teamcity[testFailed name='A failing expression with a non streamable type is still captured' message='Tricky.tests.cpp:|nexpression failed|n CHECK( o1 == o2 )|nwith expansion:|n {?} == {?}|n'] ##teamcity[testFinished name='A failing expression with a non streamable type is still captured' duration="{duration}"] ##teamcity[testStarted name='Absolute margin'] ##teamcity[testFinished name='Absolute margin' duration="{duration}"] @@ -195,7 +198,7 @@ Tricky.tests.cpp:|nexpression failed|n CHECK( o1 == o2 )|nwith exp ##teamcity[testStarted name='An expression with side-effects should only be evaluated once'] ##teamcity[testFinished name='An expression with side-effects should only be evaluated once' duration="{duration}"] ##teamcity[testStarted name='An unchecked exception reports the line of the last assertion'] -Exception.tests.cpp:|nunexpected exception with message:|n "unexpected exception"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n'] +##teamcity[testFailed name='An unchecked exception reports the line of the last assertion' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "unexpected exception"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n'] ##teamcity[testFinished name='An unchecked exception reports the line of the last assertion' duration="{duration}"] ##teamcity[testStarted name='Anonymous test case 1'] ##teamcity[testFinished name='Anonymous test case 1' duration="{duration}"] @@ -276,33 +279,34 @@ Exception.tests.cpp:|nunexpected exception with message:|n "unexpe ##teamcity[testStarted name='Composed matchers shortcircuit'] ##teamcity[testFinished name='Composed matchers shortcircuit' duration="{duration}"] ##teamcity[testStarted name='Contains string matcher'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), ContainsSubstring( "not there", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" contains: "not there" (case insensitive)|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), ContainsSubstring( "STRING" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" contains: "STRING"|n'] +##teamcity[testFailed name='Contains string matcher' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), ContainsSubstring( "not there", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" contains: "not there" (case insensitive)|n'] +##teamcity[testFailed name='Contains string matcher' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), ContainsSubstring( "STRING" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" contains: "STRING"|n'] ##teamcity[testFinished name='Contains string matcher' duration="{duration}"] ##teamcity[testStarted name='Copy and then generate a range'] ##teamcity[testFinished name='Copy and then generate a range' duration="{duration}"] ##teamcity[testStarted name='Cout stream properly declares it writes to stdout'] ##teamcity[testFinished name='Cout stream properly declares it writes to stdout' duration="{duration}"] ##teamcity[testStarted name='Custom exceptions can be translated when testing for nothrow'] -Exception.tests.cpp:|nunexpected exception with message:|n "custom exception - not std"|n REQUIRE_NOTHROW( throwCustom() )|nwith expansion:|n throwCustom()|n'] +##teamcity[testFailed name='Custom exceptions can be translated when testing for nothrow' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "custom exception - not std"|n REQUIRE_NOTHROW( throwCustom() )|nwith expansion:|n throwCustom()|n'] ##teamcity[testFinished name='Custom exceptions can be translated when testing for nothrow' duration="{duration}"] ##teamcity[testStarted name='Custom exceptions can be translated when testing for throwing as something else'] -Exception.tests.cpp:|nunexpected exception with message:|n "custom exception - not std"|n REQUIRE_THROWS_AS( throwCustom(), std::exception )|nwith expansion:|n throwCustom(), std::exception|n'] +##teamcity[testFailed name='Custom exceptions can be translated when testing for throwing as something else' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "custom exception - not std"|n REQUIRE_THROWS_AS( throwCustom(), std::exception )|nwith expansion:|n throwCustom(), std::exception|n'] ##teamcity[testFinished name='Custom exceptions can be translated when testing for throwing as something else' duration="{duration}"] ##teamcity[testStarted name='Custom std-exceptions can be custom translated'] -Exception.tests.cpp:|nunexpected exception with message:|n "custom std exception"'] +##teamcity[testFailed name='Custom std-exceptions can be custom translated' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "custom std exception"'] ##teamcity[testFinished name='Custom std-exceptions can be custom translated' duration="{duration}"] ##teamcity[testStarted name='Default scale is invisible to comparison'] ##teamcity[testFinished name='Default scale is invisible to comparison' duration="{duration}"] ##teamcity[testStarted name='Directly creating an EnumInfo'] ##teamcity[testFinished name='Directly creating an EnumInfo' duration="{duration}"] +##teamcity[testStarted name='Empty generators can SKIP in constructor'] +##teamcity[testIgnored name='Empty generators can SKIP in constructor' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip with message:|n "This generator is empty"'] +##teamcity[testFinished name='Empty generators can SKIP in constructor' duration="{duration}"] ##teamcity[testStarted name='Empty stream name opens cout stream'] ##teamcity[testFinished name='Empty stream name opens cout stream' duration="{duration}"] -##teamcity[testStarted name='Empty tag is not allowed'] -##teamcity[testFinished name='Empty tag is not allowed' duration="{duration}"] ##teamcity[testStarted name='EndsWith string matcher'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), EndsWith( "Substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ends with: "Substring"|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ends with: "this" (case insensitive)|n'] +##teamcity[testFailed name='EndsWith string matcher' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), EndsWith( "Substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ends with: "Substring"|n'] +##teamcity[testFailed name='EndsWith string matcher' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ends with: "this" (case insensitive)|n'] ##teamcity[testFinished name='EndsWith string matcher' duration="{duration}"] ##teamcity[testStarted name='Enums can quickly have stringification enabled using REGISTER_ENUM'] ##teamcity[testFinished name='Enums can quickly have stringification enabled using REGISTER_ENUM' duration="{duration}"] @@ -311,64 +315,70 @@ Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringFor ##teamcity[testStarted name='Epsilon only applies to Approx|'s value'] ##teamcity[testFinished name='Epsilon only applies to Approx|'s value' duration="{duration}"] ##teamcity[testStarted name='Equality checks that should fail'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven == 6 )|nwith expansion:|n 7 == 6|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven == 8 )|nwith expansion:|n 7 == 8|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven == 0 )|nwith expansion:|n 7 == 0|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 9.11f ) )|nwith expansion:|n 9.1f == Approx( 9.1099996567 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 9.0f ) )|nwith expansion:|n 9.1f == Approx( 9.0 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 1 ) )|nwith expansion:|n 9.1f == Approx( 1.0 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 0 ) )|nwith expansion:|n 9.1f == Approx( 0.0 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.double_pi == Approx( 3.1415 ) )|nwith expansion:|n 3.1415926535 == Approx( 3.1415 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello == "goodbye" )|nwith expansion:|n "hello" == "goodbye"|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello == "hell" )|nwith expansion:|n "hello" == "hell"|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello == "hello1" )|nwith expansion:|n "hello" == "hello1"|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello.size() == 6 )|nwith expansion:|n 5 == 6|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( x == Approx( 1.301 ) )|nwith expansion:|n 1.3 == Approx( 1.301 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexpression failed|n CHECK( data.int_seven == 6 )|nwith expansion:|n 7 == 6|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven == 8 )|nwith expansion:|n 7 == 8|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven == 0 )|nwith expansion:|n 7 == 0|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 9.11f ) )|nwith expansion:|n 9.1f == Approx( 9.1099996567 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 9.0f ) )|nwith expansion:|n 9.1f == Approx( 9.0 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 1 ) )|nwith expansion:|n 9.1f == Approx( 1.0 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one == Approx( 0 ) )|nwith expansion:|n 9.1f == Approx( 0.0 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.double_pi == Approx( 3.1415 ) )|nwith expansion:|n 3.1415926535 == Approx( 3.1415 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello == "goodbye" )|nwith expansion:|n "hello" == "goodbye"|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello == "hell" )|nwith expansion:|n "hello" == "hell"|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello == "hello1" )|nwith expansion:|n "hello" == "hello1"|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello.size() == 6 )|nwith expansion:|n 5 == 6|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Equality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( x == Approx( 1.301 ) )|nwith expansion:|n 1.3 == Approx( 1.301 )|n- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='Equality checks that should fail' duration="{duration}"] ##teamcity[testStarted name='Equality checks that should succeed'] ##teamcity[testFinished name='Equality checks that should succeed' duration="{duration}"] ##teamcity[testStarted name='Equals'] ##teamcity[testFinished name='Equals' duration="{duration}"] ##teamcity[testStarted name='Equals string matcher'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Equals( "this string contains |'ABC|' as a substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" equals: "this string contains |'ABC|' as a substring"|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Equals( "something else", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" equals: "something else" (case insensitive)|n'] +##teamcity[testFailed name='Equals string matcher' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Equals( "this string contains |'ABC|' as a substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" equals: "this string contains |'ABC|' as a substring"|n'] +##teamcity[testFailed name='Equals string matcher' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Equals( "something else", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" equals: "something else" (case insensitive)|n'] ##teamcity[testFinished name='Equals string matcher' duration="{duration}"] ##teamcity[testStarted name='Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified'] ##teamcity[testFinished name='Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified' duration="{duration}"] ##teamcity[testStarted name='Exception matchers that fail'] -Matchers.tests.cpp:|nno exception was thrown where one was expected|n CHECK_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n doesNotThrow(), SpecialException, ExceptionMatcher{ 1 }|n'] -Matchers.tests.cpp:|nno exception was thrown where one was expected|n REQUIRE_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n doesNotThrow(), SpecialException, ExceptionMatcher{ 1 }|n'] -Matchers.tests.cpp:|nunexpected exception with message:|n "Unknown exception"|n CHECK_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 }|n'] -Matchers.tests.cpp:|nunexpected exception with message:|n "Unknown exception"|n REQUIRE_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THROWS_MATCHES( throwsSpecialException( 3 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n SpecialException::what special exception has value of 1|n'] -Matchers.tests.cpp:|nexpression failed|n REQUIRE_THROWS_MATCHES( throwsSpecialException( 4 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n SpecialException::what special exception has value of 1|n'] +##teamcity[testFailed name='Exception matchers that fail' message='-------------------------------------------------------------------------------|nNo exception|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nno exception was thrown where one was expected|n CHECK_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n doesNotThrow(), SpecialException, ExceptionMatcher{ 1 }|n'] +##teamcity[testFailed name='Exception matchers that fail' message='Matchers.tests.cpp:|nno exception was thrown where one was expected|n REQUIRE_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n doesNotThrow(), SpecialException, ExceptionMatcher{ 1 }|n'] +##teamcity[testFailed name='Exception matchers that fail' message='-------------------------------------------------------------------------------|nType mismatch|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nunexpected exception with message:|n "Unknown exception"|n CHECK_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 }|n'] +##teamcity[testFailed name='Exception matchers that fail' message='Matchers.tests.cpp:|nunexpected exception with message:|n "Unknown exception"|n REQUIRE_THROWS_MATCHES( throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n throwsAsInt( 1 ), SpecialException, ExceptionMatcher{ 1 }|n'] +##teamcity[testFailed name='Exception matchers that fail' message='-------------------------------------------------------------------------------|nContents are wrong|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THROWS_MATCHES( throwsSpecialException( 3 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n SpecialException::what special exception has value of 1|n'] +##teamcity[testFailed name='Exception matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n REQUIRE_THROWS_MATCHES( throwsSpecialException( 4 ), SpecialException, ExceptionMatcher{ 1 } )|nwith expansion:|n SpecialException::what special exception has value of 1|n'] ##teamcity[testFinished name='Exception matchers that fail' duration="{duration}"] ##teamcity[testStarted name='Exception matchers that succeed'] ##teamcity[testFinished name='Exception matchers that succeed' duration="{duration}"] +##teamcity[testStarted name='Exception message can be matched'] +##teamcity[testFinished name='Exception message can be matched' duration="{duration}"] ##teamcity[testStarted name='Exception messages can be tested for'] ##teamcity[testFinished name='Exception messages can be tested for' duration="{duration}"] ##teamcity[testStarted name='Exceptions matchers'] ##teamcity[testFinished name='Exceptions matchers' duration="{duration}"] ##teamcity[testStarted name='Expected exceptions that don|'t throw or unexpected exceptions fail the test'] -Exception.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK_THROWS_AS( thisThrows(), std::string )|nwith expansion:|n thisThrows(), std::string|n'] -Exception.tests.cpp:|nno exception was thrown where one was expected|n CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error )|nwith expansion:|n thisDoesntThrow(), std::domain_error|n'] -Exception.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK_NOTHROW( thisThrows() )|nwith expansion:|n thisThrows()|n'] +##teamcity[testFailed name='Expected exceptions that don|'t throw or unexpected exceptions fail the test' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK_THROWS_AS( thisThrows(), std::string )|nwith expansion:|n thisThrows(), std::string|n'] +##teamcity[testFailed name='Expected exceptions that don|'t throw or unexpected exceptions fail the test' message='Exception.tests.cpp:|nno exception was thrown where one was expected|n CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error )|nwith expansion:|n thisDoesntThrow(), std::domain_error|n'] +##teamcity[testFailed name='Expected exceptions that don|'t throw or unexpected exceptions fail the test' message='Exception.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK_NOTHROW( thisThrows() )|nwith expansion:|n thisThrows()|n'] ##teamcity[testFinished name='Expected exceptions that don|'t throw or unexpected exceptions fail the test' duration="{duration}"] ##teamcity[testStarted name='FAIL aborts the test'] -Message.tests.cpp:|nexplicit failure with message:|n "This is a failure"'] +##teamcity[testFailed name='FAIL aborts the test' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with message:|n "This is a failure"'] ##teamcity[testFinished name='FAIL aborts the test' duration="{duration}"] ##teamcity[testStarted name='FAIL does not require an argument'] -Message.tests.cpp:|nexplicit failure'] +##teamcity[testFailed name='FAIL does not require an argument' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure'] ##teamcity[testFinished name='FAIL does not require an argument' duration="{duration}"] ##teamcity[testStarted name='FAIL_CHECK does not abort the test'] -Message.tests.cpp:|nexplicit failure with message:|n "This is a failure"'] +##teamcity[testFailed name='FAIL_CHECK does not abort the test' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with message:|n "This is a failure"'] ##teamcity[testFinished name='FAIL_CHECK does not abort the test' duration="{duration}"] ##teamcity[testStarted name='Factorials are computed'] ##teamcity[testFinished name='Factorials are computed' duration="{duration}"] +##teamcity[testStarted name='Filter generator throws exception for empty generator'] +##teamcity[testFinished name='Filter generator throws exception for empty generator' duration="{duration}"] ##teamcity[testStarted name='Floating point matchers: double'] ##teamcity[testFinished name='Floating point matchers: double' duration="{duration}"] ##teamcity[testStarted name='Floating point matchers: float'] ##teamcity[testFinished name='Floating point matchers: float' duration="{duration}"] +##teamcity[testStarted name='GENERATE can combine literals and generators'] +##teamcity[testFinished name='GENERATE can combine literals and generators' duration="{duration}"] ##teamcity[testStarted name='Generators -- adapters'] ##teamcity[testFinished name='Generators -- adapters' duration="{duration}"] ##teamcity[testStarted name='Generators -- simple'] @@ -385,27 +395,37 @@ Message.tests.cpp:|nexplicit failure with message:|n "This is a fa ##teamcity[testFinished name='Hashing different test cases produces different result' duration="{duration}"] ##teamcity[testStarted name='Hashing test case produces same hash across multiple calls'] ##teamcity[testFinished name='Hashing test case produces same hash across multiple calls' duration="{duration}"] +##teamcity[testStarted name='INFO and UNSCOPED_INFO can stream multiple arguments'] +##teamcity[testFailed name='INFO and UNSCOPED_INFO can stream multiple arguments' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with messages:|n "This info has multiple parts."|n "This unscoped info has multiple parts."|n "Show infos!"'] +##teamcity[testFinished name='INFO and UNSCOPED_INFO can stream multiple arguments' duration="{duration}"] ##teamcity[testStarted name='INFO and WARN do not abort tests'] ##teamcity[testFinished name='INFO and WARN do not abort tests' duration="{duration}"] ##teamcity[testStarted name='INFO gets logged on failure'] -Message.tests.cpp:|nexpression failed with messages:|n "this message should be logged"|n "so should this"|n REQUIRE( a == 1 )|nwith expansion:|n 2 == 1|n'] +##teamcity[testFailed name='INFO gets logged on failure' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with messages:|n "this message should be logged"|n "so should this"|n REQUIRE( a == 1 )|nwith expansion:|n 2 == 1|n'] ##teamcity[testFinished name='INFO gets logged on failure' duration="{duration}"] ##teamcity[testStarted name='INFO gets logged on failure, even if captured before successful assertions'] -Message.tests.cpp:|nexpression failed with messages:|n "this message may be logged later"|n "this message should be logged"|n CHECK( a == 1 )|nwith expansion:|n 2 == 1|n'] -Message.tests.cpp:|nexpression failed with messages:|n "this message may be logged later"|n "this message should be logged"|n "and this, but later"|n CHECK( a == 0 )|nwith expansion:|n 2 == 0|n'] +##teamcity[testFailed name='INFO gets logged on failure, even if captured before successful assertions' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with messages:|n "this message may be logged later"|n "this message should be logged"|n CHECK( a == 1 )|nwith expansion:|n 2 == 1|n'] +##teamcity[testFailed name='INFO gets logged on failure, even if captured before successful assertions' message='Message.tests.cpp:|nexpression failed with messages:|n "this message may be logged later"|n "this message should be logged"|n "and this, but later"|n CHECK( a == 0 )|nwith expansion:|n 2 == 0|n'] ##teamcity[testFinished name='INFO gets logged on failure, even if captured before successful assertions' duration="{duration}"] ##teamcity[testStarted name='INFO is reset for each loop'] -Message.tests.cpp:|nexpression failed with messages:|n "current counter 10"|n "i := 10"|n REQUIRE( i < 10 )|nwith expansion:|n 10 < 10|n'] +##teamcity[testFailed name='INFO is reset for each loop' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with messages:|n "current counter 10"|n "i := 10"|n REQUIRE( i < 10 )|nwith expansion:|n 10 < 10|n'] ##teamcity[testFinished name='INFO is reset for each loop' duration="{duration}"] +##teamcity[testStarted name='Incomplete AssertionHandler'] +##teamcity[testIgnored name='Incomplete AssertionHandler' message='AssertionHandler.tests.cpp:|n...............................................................................|n|nAssertionHandler.tests.cpp:|nunexpected exception with message:|n "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"|n REQUIRE( Dummy )|nwith expansion:|n Dummy|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testFinished name='Incomplete AssertionHandler' duration="{duration}"] ##teamcity[testStarted name='Inequality checks that should fail'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven != 7 )|nwith expansion:|n 7 != 7|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one != Approx( 9.1f ) )|nwith expansion:|n 9.1f != Approx( 9.1000003815 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.double_pi != Approx( 3.1415926535 ) )|nwith expansion:|n 3.1415926535 != Approx( 3.1415926535 )|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello != "hello" )|nwith expansion:|n "hello" != "hello"|n- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello.size() != 5 )|nwith expansion:|n 5 != 5|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Inequality checks that should fail' message='Condition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexpression failed|n CHECK( data.int_seven != 7 )|nwith expansion:|n 7 != 7|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Inequality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one != Approx( 9.1f ) )|nwith expansion:|n 9.1f != Approx( 9.1000003815 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Inequality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.double_pi != Approx( 3.1415926535 ) )|nwith expansion:|n 3.1415926535 != Approx( 3.1415926535 )|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Inequality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello != "hello" )|nwith expansion:|n "hello" != "hello"|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Inequality checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello.size() != 5 )|nwith expansion:|n 5 != 5|n- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='Inequality checks that should fail' duration="{duration}"] ##teamcity[testStarted name='Inequality checks that should succeed'] ##teamcity[testFinished name='Inequality checks that should succeed' duration="{duration}"] +##teamcity[testStarted name='JsonWriter'] +##teamcity[testFinished name='JsonWriter' duration="{duration}"] +##teamcity[testStarted name='JsonWriter escapes charaters in strings properly'] +##teamcity[testFinished name='JsonWriter escapes charaters in strings properly' duration="{duration}"] ##teamcity[testStarted name='Lambdas in assertions'] ##teamcity[testFinished name='Lambdas in assertions' duration="{duration}"] ##teamcity[testStarted name='Less-than inequalities with different epsilons'] @@ -419,21 +439,21 @@ Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello.si ##teamcity[testStarted name='Matchers can be composed with both && and ||||'] ##teamcity[testFinished name='Matchers can be composed with both && and ||||' duration="{duration}"] ##teamcity[testStarted name='Matchers can be composed with both && and |||| - failing'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), ( ContainsSubstring( "string" ) |||| ContainsSubstring( "different" ) ) && ContainsSubstring( "random" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" )|n'] +##teamcity[testFailed name='Matchers can be composed with both && and |||| - failing' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), ( ContainsSubstring( "string" ) |||| ContainsSubstring( "different" ) ) && ContainsSubstring( "random" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" )|n'] ##teamcity[testFinished name='Matchers can be composed with both && and |||| - failing' duration="{duration}"] ##teamcity[testStarted name='Matchers can be negated (Not) with the ! operator'] ##teamcity[testFinished name='Matchers can be negated (Not) with the ! operator' duration="{duration}"] ##teamcity[testStarted name='Matchers can be negated (Not) with the ! operator - failing'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), !ContainsSubstring( "substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" not contains: "substring"|n'] +##teamcity[testFailed name='Matchers can be negated (Not) with the ! operator - failing' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), !ContainsSubstring( "substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" not contains: "substring"|n'] ##teamcity[testFinished name='Matchers can be negated (Not) with the ! operator - failing' duration="{duration}"] ##teamcity[testStarted name='Mayfail test case with nested sections'] -Condition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] -Condition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Mayfail test case with nested sections' message='-------------------------------------------------------------------------------|nA|n1|n-------------------------------------------------------------------------------|nCondition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Mayfail test case with nested sections' message='-------------------------------------------------------------------------------|nA|n2|n-------------------------------------------------------------------------------|nCondition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Mayfail test case with nested sections' message='-------------------------------------------------------------------------------|nB|n1|n-------------------------------------------------------------------------------|nCondition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Mayfail test case with nested sections' message='-------------------------------------------------------------------------------|nB|n2|n-------------------------------------------------------------------------------|nCondition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='Mayfail test case with nested sections' duration="{duration}"] ##teamcity[testStarted name='Mismatching exception messages failing the test'] -Exception.tests.cpp:|nexpression failed|n REQUIRE_THROWS_WITH( thisThrows(), "should fail" )|nwith expansion:|n "expected exception" equals: "should fail"|n'] +##teamcity[testFailed name='Mismatching exception messages failing the test' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nexpression failed|n REQUIRE_THROWS_WITH( thisThrows(), "should fail" )|nwith expansion:|n "expected exception" equals: "should fail"|n'] ##teamcity[testFinished name='Mismatching exception messages failing the test' duration="{duration}"] ##teamcity[testStarted name='Multireporter calls reporters and listeners in correct order'] ##teamcity[testFinished name='Multireporter calls reporters and listeners in correct order' duration="{duration}"] @@ -444,40 +464,40 @@ Exception.tests.cpp:|nexpression failed|n REQUIRE_THROWS_WITH( thi ##teamcity[testStarted name='Nice descriptive name'] ##teamcity[testFinished name='Nice descriptive name' duration="{duration}"] ##teamcity[testStarted name='Non-std exceptions can be translated'] -Exception.tests.cpp:|nunexpected exception with message:|n "custom exception"'] +##teamcity[testFailed name='Non-std exceptions can be translated' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "custom exception"'] ##teamcity[testFinished name='Non-std exceptions can be translated' duration="{duration}"] ##teamcity[testStarted name='Objects that evaluated in boolean contexts can be checked'] ##teamcity[testFinished name='Objects that evaluated in boolean contexts can be checked' duration="{duration}"] ##teamcity[testStarted name='Optionally static assertions'] ##teamcity[testFinished name='Optionally static assertions' duration="{duration}"] ##teamcity[testStarted name='Ordering comparison checks that should fail'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven > 7 )|nwith expansion:|n 7 > 7|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < 7 )|nwith expansion:|n 7 < 7|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven > 8 )|nwith expansion:|n 7 > 8|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < 6 )|nwith expansion:|n 7 < 6|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < 0 )|nwith expansion:|n 7 < 0|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < -1 )|nwith expansion:|n 7 < -1|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven >= 8 )|nwith expansion:|n 7 >= 8|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven <= 6 )|nwith expansion:|n 7 <= 6|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one < 9 )|nwith expansion:|n 9.1f < 9|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one > 10 )|nwith expansion:|n 9.1f > 10|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one > 9.2 )|nwith expansion:|n 9.1f > 9.2|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello > "hello" )|nwith expansion:|n "hello" > "hello"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello < "hello" )|nwith expansion:|n "hello" < "hello"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello > "hellp" )|nwith expansion:|n "hello" > "hellp"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello > "z" )|nwith expansion:|n "hello" > "z"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello < "hellm" )|nwith expansion:|n "hello" < "hellm"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello < "a" )|nwith expansion:|n "hello" < "a"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello >= "z" )|nwith expansion:|n "hello" >= "z"|n'] -Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello <= "a" )|nwith expansion:|n "hello" <= "a"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|n...............................................................................|n|nCondition.tests.cpp:|nexpression failed|n CHECK( data.int_seven > 7 )|nwith expansion:|n 7 > 7|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < 7 )|nwith expansion:|n 7 < 7|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven > 8 )|nwith expansion:|n 7 > 8|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < 6 )|nwith expansion:|n 7 < 6|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < 0 )|nwith expansion:|n 7 < 0|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven < -1 )|nwith expansion:|n 7 < -1|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven >= 8 )|nwith expansion:|n 7 >= 8|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.int_seven <= 6 )|nwith expansion:|n 7 <= 6|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one < 9 )|nwith expansion:|n 9.1f < 9|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one > 10 )|nwith expansion:|n 9.1f > 10|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.float_nine_point_one > 9.2 )|nwith expansion:|n 9.1f > 9.2|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello > "hello" )|nwith expansion:|n "hello" > "hello"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello < "hello" )|nwith expansion:|n "hello" < "hello"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello > "hellp" )|nwith expansion:|n "hello" > "hellp"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello > "z" )|nwith expansion:|n "hello" > "z"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello < "hellm" )|nwith expansion:|n "hello" < "hellm"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello < "a" )|nwith expansion:|n "hello" < "a"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello >= "z" )|nwith expansion:|n "hello" >= "z"|n'] +##teamcity[testFailed name='Ordering comparison checks that should fail' message='Condition.tests.cpp:|nexpression failed|n CHECK( data.str_hello <= "a" )|nwith expansion:|n "hello" <= "a"|n'] ##teamcity[testFinished name='Ordering comparison checks that should fail' duration="{duration}"] ##teamcity[testStarted name='Ordering comparison checks that should succeed'] ##teamcity[testFinished name='Ordering comparison checks that should succeed' duration="{duration}"] ##teamcity[testStarted name='Our PCG implementation provides expected results for known seeds'] ##teamcity[testFinished name='Our PCG implementation provides expected results for known seeds' duration="{duration}"] ##teamcity[testStarted name='Output from all sections is reported'] -Message.tests.cpp:|nexplicit failure with message:|n "Message from section one"'] -Message.tests.cpp:|nexplicit failure with message:|n "Message from section two"'] +##teamcity[testFailed name='Output from all sections is reported' message='-------------------------------------------------------------------------------|none|n-------------------------------------------------------------------------------|nMessage.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with message:|n "Message from section one"'] +##teamcity[testFailed name='Output from all sections is reported' message='-------------------------------------------------------------------------------|ntwo|n-------------------------------------------------------------------------------|nMessage.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with message:|n "Message from section two"'] ##teamcity[testFinished name='Output from all sections is reported' duration="{duration}"] ##teamcity[testStarted name='Overloaded comma or address-of operators are not used'] ##teamcity[testFinished name='Overloaded comma or address-of operators are not used' duration="{duration}"] @@ -512,12 +532,12 @@ Message.tests.cpp:|nexplicit failure with message:|n "Message from ##teamcity[testStarted name='Range type with sentinel'] ##teamcity[testFinished name='Range type with sentinel' duration="{duration}"] ##teamcity[testStarted name='Reconstruction should be based on stringification: #914'] -Decomposition.tests.cpp:|nexpression failed|n CHECK( truthy(false) )|nwith expansion:|n Hey, its truthy!|n'] +##teamcity[testFailed name='Reconstruction should be based on stringification: #914' message='Decomposition.tests.cpp:|n...............................................................................|n|nDecomposition.tests.cpp:|nexpression failed|n CHECK( truthy(false) )|nwith expansion:|n Hey, its truthy!|n'] ##teamcity[testFinished name='Reconstruction should be based on stringification: #914' duration="{duration}"] ##teamcity[testStarted name='Regex string matcher'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Matches( "this STRING contains |'abc|' as a substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" matches "this STRING contains |'abc|' as a substring" case sensitively|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Matches( "contains |'abc|' as a substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" matches "contains |'abc|' as a substring" case sensitively|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Matches( "this string contains |'abc|' as a" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" matches "this string contains |'abc|' as a" case sensitively|n'] +##teamcity[testFailed name='Regex string matcher' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Matches( "this STRING contains |'abc|' as a substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" matches "this STRING contains |'abc|' as a substring" case sensitively|n'] +##teamcity[testFailed name='Regex string matcher' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Matches( "contains |'abc|' as a substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" matches "contains |'abc|' as a substring" case sensitively|n'] +##teamcity[testFailed name='Regex string matcher' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), Matches( "this string contains |'abc|' as a" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" matches "this string contains |'abc|' as a" case sensitively|n'] ##teamcity[testFinished name='Regex string matcher' duration="{duration}"] ##teamcity[testStarted name='Registering reporter with |'::|' in name fails'] ##teamcity[testFinished name='Registering reporter with |'::|' in name fails' duration="{duration}"] @@ -549,8 +569,8 @@ Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringFor ##teamcity[testStdOut name='Standard output from all sections is reported' out='Message from section one|nMessage from section two|n'] ##teamcity[testFinished name='Standard output from all sections is reported' duration="{duration}"] ##teamcity[testStarted name='StartsWith string matcher'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), StartsWith( "This String" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" starts with: "This String"|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), StartsWith( "string", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" starts with: "string" (case insensitive)|n'] +##teamcity[testFailed name='StartsWith string matcher' message='Matchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), StartsWith( "This String" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" starts with: "This String"|n'] +##teamcity[testFailed name='StartsWith string matcher' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringForMatching(), StartsWith( "string", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" starts with: "string" (case insensitive)|n'] ##teamcity[testFinished name='StartsWith string matcher' duration="{duration}"] ##teamcity[testStarted name='Static arrays are convertible to string'] ##teamcity[testFinished name='Static arrays are convertible to string' duration="{duration}"] @@ -573,7 +593,7 @@ Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( testStringFor ##teamcity[testStarted name='Stringifying std::chrono::time_point'] ##teamcity[testFinished name='Stringifying std::chrono::time_point' duration="{duration}"] ##teamcity[testStarted name='Tabs and newlines show in output'] -Misc.tests.cpp:|nexpression failed|n CHECK( s1 == s2 )|nwith expansion:|n "if ($b == 10) {|n $a = 20;|n}"|n==|n"if ($b == 10) {|n $a = 20;|n}|n"|n'] +##teamcity[testFailed name='Tabs and newlines show in output' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n CHECK( s1 == s2 )|nwith expansion:|n "if ($b == 10) {|n $a = 20;|n}"|n==|n"if ($b == 10) {|n $a = 20;|n}|n"|n'] ##teamcity[testFinished name='Tabs and newlines show in output' duration="{duration}"] ##teamcity[testStarted name='Tag alias can be registered against tag patterns'] ##teamcity[testFinished name='Tag alias can be registered against tag patterns' duration="{duration}"] @@ -626,11 +646,17 @@ Misc.tests.cpp:|nexpression failed|n CHECK( s1 == s2 )|nwith expan ##teamcity[testStarted name='Testing checked-if'] ##teamcity[testFinished name='Testing checked-if' duration="{duration}"] ##teamcity[testStarted name='Testing checked-if 2'] -Misc.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Testing checked-if 2' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='Testing checked-if 2' duration="{duration}"] ##teamcity[testStarted name='Testing checked-if 3'] -Misc.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='Testing checked-if 3' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] ##teamcity[testFinished name='Testing checked-if 3' duration="{duration}"] +##teamcity[testStarted name='Testing checked-if 4'] +##teamcity[testIgnored name='Testing checked-if 4' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nunexpected exception with message:|n "Uncaught exception should fail!"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testFinished name='Testing checked-if 4' duration="{duration}"] +##teamcity[testStarted name='Testing checked-if 5'] +##teamcity[testIgnored name='Testing checked-if 5' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nunexpected exception with message:|n "Uncaught exception should fail!"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testFinished name='Testing checked-if 5' duration="{duration}"] ##teamcity[testStarted name='The NO_FAIL macro reports a failure but does not fail the test'] ##teamcity[testFinished name='The NO_FAIL macro reports a failure but does not fail the test' duration="{duration}"] ##teamcity[testStarted name='The default listing implementation write to provided stream'] @@ -638,14 +664,16 @@ Misc.tests.cpp:|nexplicit failure- failure ignore as test marked as ##teamcity[testStarted name='This test |'should|' fail but doesn|'t'] ##teamcity[testFinished name='This test |'should|' fail but doesn|'t' duration="{duration}"] ##teamcity[testStarted name='Thrown string literals are translated'] -Exception.tests.cpp:|nunexpected exception with message:|n "For some reason someone is throwing a string literal!"'] +##teamcity[testFailed name='Thrown string literals are translated' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "For some reason someone is throwing a string literal!"'] ##teamcity[testFinished name='Thrown string literals are translated' duration="{duration}"] ##teamcity[testStarted name='Tracker'] ##teamcity[testFinished name='Tracker' duration="{duration}"] ##teamcity[testStarted name='Trim strings'] ##teamcity[testFinished name='Trim strings' duration="{duration}"] +##teamcity[testStarted name='Type conversions of RangeEquals and similar'] +##teamcity[testFinished name='Type conversions of RangeEquals and similar' duration="{duration}"] ##teamcity[testStarted name='Unexpected exceptions can be translated'] -Exception.tests.cpp:|nunexpected exception with message:|n "3.14"'] +##teamcity[testFailed name='Unexpected exceptions can be translated' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "3.14"'] ##teamcity[testFinished name='Unexpected exceptions can be translated' duration="{duration}"] ##teamcity[testStarted name='Upcasting special member functions'] ##teamcity[testFinished name='Upcasting special member functions' duration="{duration}"] @@ -661,6 +689,10 @@ Exception.tests.cpp:|nunexpected exception with message:|n "3.14"' ##teamcity[testFinished name='Usage of NoneMatch range matcher' duration="{duration}"] ##teamcity[testStarted name='Usage of NoneTrue range matcher'] ##teamcity[testFinished name='Usage of NoneTrue range matcher' duration="{duration}"] +##teamcity[testStarted name='Usage of RangeEquals range matcher'] +##teamcity[testFinished name='Usage of RangeEquals range matcher' duration="{duration}"] +##teamcity[testStarted name='Usage of UnorderedRangeEquals range matcher'] +##teamcity[testFinished name='Usage of UnorderedRangeEquals range matcher' duration="{duration}"] ##teamcity[testStarted name='Usage of the SizeIs range matcher'] ##teamcity[testFinished name='Usage of the SizeIs range matcher' duration="{duration}"] ##teamcity[testStarted name='Use a custom approx'] @@ -670,41 +702,41 @@ Exception.tests.cpp:|nunexpected exception with message:|n "3.14"' ##teamcity[testStarted name='Vector Approx matcher'] ##teamcity[testFinished name='Vector Approx matcher' duration="{duration}"] ##teamcity[testStarted name='Vector Approx matcher -- failing'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, Approx( t1 ) )|nwith expansion:|n { } is approx: { 1.0, 2.0 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v1, Approx( v2 ) )|nwith expansion:|n { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 }|n'] +##teamcity[testFailed name='Vector Approx matcher -- failing' message='-------------------------------------------------------------------------------|nEmpty and non empty vectors are not approx equal|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, Approx( t1 ) )|nwith expansion:|n { } is approx: { 1.0, 2.0 }|n'] +##teamcity[testFailed name='Vector Approx matcher -- failing' message='-------------------------------------------------------------------------------|nJust different vectors|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( v1, Approx( v2 ) )|nwith expansion:|n { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 }|n'] ##teamcity[testFinished name='Vector Approx matcher -- failing' duration="{duration}"] ##teamcity[testStarted name='Vector matchers'] ##teamcity[testFinished name='Vector matchers' duration="{duration}"] ##teamcity[testStarted name='Vector matchers that fail'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, VectorContains( -1 ) )|nwith expansion:|n { 1, 2, 3 } Contains: -1|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, VectorContains( 1 ) )|nwith expansion:|n { } Contains: 1|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, Contains( v ) )|nwith expansion:|n { } Contains: { 1, 2, 3 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, Contains( v2 ) )|nwith expansion:|n { 1, 2, 3 } Contains: { 1, 2, 4 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, Equals( v2 ) )|nwith expansion:|n { 1, 2, 3 } Equals: { 1, 2 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v2, Equals( v ) )|nwith expansion:|n { 1, 2 } Equals: { 1, 2, 3 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, Equals( v ) )|nwith expansion:|n { } Equals: { 1, 2, 3 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, Equals( empty ) )|nwith expansion:|n { 1, 2, 3 } Equals: { }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, UnorderedEquals( empty ) )|nwith expansion:|n { 1, 2, 3 } UnorderedEquals: { }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, UnorderedEquals( v ) )|nwith expansion:|n { } UnorderedEquals: { 1, 2, 3 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( permuted, UnorderedEquals( v ) )|nwith expansion:|n { 1, 3 } UnorderedEquals: { 1, 2, 3 }|n'] -Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( permuted, UnorderedEquals( v ) )|nwith expansion:|n { 3, 1 } UnorderedEquals: { 1, 2, 3 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='-------------------------------------------------------------------------------|nContains (element)|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, VectorContains( -1 ) )|nwith expansion:|n { 1, 2, 3 } Contains: -1|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, VectorContains( 1 ) )|nwith expansion:|n { } Contains: 1|n'] +##teamcity[testFailed name='Vector matchers that fail' message='-------------------------------------------------------------------------------|nContains (vector)|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, Contains( v ) )|nwith expansion:|n { } Contains: { 1, 2, 3 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, Contains( v2 ) )|nwith expansion:|n { 1, 2, 3 } Contains: { 1, 2, 4 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='-------------------------------------------------------------------------------|nEquals|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, Equals( v2 ) )|nwith expansion:|n { 1, 2, 3 } Equals: { 1, 2 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v2, Equals( v ) )|nwith expansion:|n { 1, 2 } Equals: { 1, 2, 3 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, Equals( v ) )|nwith expansion:|n { } Equals: { 1, 2, 3 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, Equals( empty ) )|nwith expansion:|n { 1, 2, 3 } Equals: { }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='-------------------------------------------------------------------------------|nUnorderedEquals|n-------------------------------------------------------------------------------|nMatchers.tests.cpp:|n...............................................................................|n|nMatchers.tests.cpp:|nexpression failed|n CHECK_THAT( v, UnorderedEquals( empty ) )|nwith expansion:|n { 1, 2, 3 } UnorderedEquals: { }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( empty, UnorderedEquals( v ) )|nwith expansion:|n { } UnorderedEquals: { 1, 2, 3 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( permuted, UnorderedEquals( v ) )|nwith expansion:|n { 1, 3 } UnorderedEquals: { 1, 2, 3 }|n'] +##teamcity[testFailed name='Vector matchers that fail' message='Matchers.tests.cpp:|nexpression failed|n CHECK_THAT( permuted, UnorderedEquals( v ) )|nwith expansion:|n { 3, 1 } UnorderedEquals: { 1, 2, 3 }|n'] ##teamcity[testFinished name='Vector matchers that fail' duration="{duration}"] ##teamcity[testStarted name='When checked exceptions are thrown they can be expected or unexpected'] ##teamcity[testFinished name='When checked exceptions are thrown they can be expected or unexpected' duration="{duration}"] ##teamcity[testStarted name='When unchecked exceptions are thrown directly they are always failures'] -Exception.tests.cpp:|nunexpected exception with message:|n "unexpected exception"'] +##teamcity[testFailed name='When unchecked exceptions are thrown directly they are always failures' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "unexpected exception"'] ##teamcity[testFinished name='When unchecked exceptions are thrown directly they are always failures' duration="{duration}"] ##teamcity[testStarted name='When unchecked exceptions are thrown during a CHECK the test should continue'] -Exception.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK( thisThrows() == 0 )|nwith expansion:|n thisThrows() == 0|n'] +##teamcity[testFailed name='When unchecked exceptions are thrown during a CHECK the test should continue' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK( thisThrows() == 0 )|nwith expansion:|n thisThrows() == 0|n'] ##teamcity[testFinished name='When unchecked exceptions are thrown during a CHECK the test should continue' duration="{duration}"] ##teamcity[testStarted name='When unchecked exceptions are thrown during a REQUIRE the test should abort fail'] -Exception.tests.cpp:|nunexpected exception with message:|n "expected exception"|n REQUIRE( thisThrows() == 0 )|nwith expansion:|n thisThrows() == 0|n'] +##teamcity[testFailed name='When unchecked exceptions are thrown during a REQUIRE the test should abort fail' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "expected exception"|n REQUIRE( thisThrows() == 0 )|nwith expansion:|n thisThrows() == 0|n'] ##teamcity[testFinished name='When unchecked exceptions are thrown during a REQUIRE the test should abort fail' duration="{duration}"] ##teamcity[testStarted name='When unchecked exceptions are thrown from functions they are always failures'] -Exception.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK( thisThrows() == 0 )|nwith expansion:|n thisThrows() == 0|n'] +##teamcity[testFailed name='When unchecked exceptions are thrown from functions they are always failures' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "expected exception"|n CHECK( thisThrows() == 0 )|nwith expansion:|n thisThrows() == 0|n'] ##teamcity[testFinished name='When unchecked exceptions are thrown from functions they are always failures' duration="{duration}"] ##teamcity[testStarted name='When unchecked exceptions are thrown from sections they are always failures'] -Exception.tests.cpp:|nunexpected exception with message:|n "unexpected exception"'] +##teamcity[testFailed name='When unchecked exceptions are thrown from sections they are always failures' message='-------------------------------------------------------------------------------|nsection name|n-------------------------------------------------------------------------------|nException.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "unexpected exception"'] ##teamcity[testFinished name='When unchecked exceptions are thrown from sections they are always failures' duration="{duration}"] ##teamcity[testStarted name='When unchecked exceptions are thrown, but caught, they do not affect the test'] ##teamcity[testFinished name='When unchecked exceptions are thrown, but caught, they do not affect the test' duration="{duration}"] @@ -720,6 +752,9 @@ Exception.tests.cpp:|nunexpected exception with message:|n "unexpe ##teamcity[testFinished name='XmlEncode' duration="{duration}"] ##teamcity[testStarted name='XmlWriter writes boolean attributes as true/false'] ##teamcity[testFinished name='XmlWriter writes boolean attributes as true/false' duration="{duration}"] +##teamcity[testStarted name='a succeeding test can still be skipped'] +##teamcity[testIgnored name='a succeeding test can still be skipped' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testFinished name='a succeeding test can still be skipped' duration="{duration}"] ##teamcity[testStarted name='analyse no analysis'] ##teamcity[testFinished name='analyse no analysis' duration="{duration}"] ##teamcity[testStarted name='array -> toString'] @@ -731,12 +766,12 @@ Exception.tests.cpp:|nunexpected exception with message:|n "unexpe ##teamcity[testStarted name='checkedElse'] ##teamcity[testFinished name='checkedElse' duration="{duration}"] ##teamcity[testStarted name='checkedElse, failing'] -Misc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedElse( false ) )|nwith expansion:|n false|n'] +##teamcity[testFailed name='checkedElse, failing' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedElse( false ) )|nwith expansion:|n false|n'] ##teamcity[testFinished name='checkedElse, failing' duration="{duration}"] ##teamcity[testStarted name='checkedIf'] ##teamcity[testFinished name='checkedIf' duration="{duration}"] ##teamcity[testStarted name='checkedIf, failing'] -Misc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedIf( false ) )|nwith expansion:|n false|n'] +##teamcity[testFailed name='checkedIf, failing' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedIf( false ) )|nwith expansion:|n false|n'] ##teamcity[testFinished name='checkedIf, failing' duration="{duration}"] ##teamcity[testStarted name='classify_outliers'] ##teamcity[testFinished name='classify_outliers' duration="{duration}"] @@ -746,6 +781,10 @@ Misc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedIf( false ##teamcity[testFinished name='comparisons between int variables' duration="{duration}"] ##teamcity[testStarted name='convertToBits'] ##teamcity[testFinished name='convertToBits' duration="{duration}"] +##teamcity[testStarted name='dynamic skipping works with generators'] +##teamcity[testIgnored name='dynamic skipping works with generators' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip with message:|n "skipping because answer = 41"'] +##teamcity[testIgnored name='dynamic skipping works with generators' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip with message:|n "skipping because answer = 43"'] +##teamcity[testFinished name='dynamic skipping works with generators' duration="{duration}"] ##teamcity[testStarted name='empty tags are not allowed'] ##teamcity[testFinished name='empty tags are not allowed' duration="{duration}"] ##teamcity[testStarted name='erfc_inv'] @@ -754,6 +793,20 @@ Misc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedIf( false ##teamcity[testFinished name='estimate_clock_resolution' duration="{duration}"] ##teamcity[testStarted name='even more nested SECTION tests'] ##teamcity[testFinished name='even more nested SECTION tests' duration="{duration}"] +##teamcity[testStarted name='failed assertions before SKIP cause test case to fail'] +##teamcity[testIgnored name='failed assertions before SKIP cause test case to fail' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexpression failed|n CHECK( 3 == 4 )|nwith expansion:|n 3 == 4|n- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='failed assertions before SKIP cause test case to fail' message='Skip.tests.cpp:|nexplicit skip'] +##teamcity[testFinished name='failed assertions before SKIP cause test case to fail' duration="{duration}"] +##teamcity[testStarted name='failing for some generator values causes entire test case to fail'] +##teamcity[testIgnored name='failing for some generator values causes entire test case to fail' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='failing for some generator values causes entire test case to fail' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testIgnored name='failing for some generator values causes entire test case to fail' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testIgnored name='failing for some generator values causes entire test case to fail' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testFinished name='failing for some generator values causes entire test case to fail' duration="{duration}"] +##teamcity[testStarted name='failing in some unskipped sections causes entire test case to fail'] +##teamcity[testIgnored name='failing in some unskipped sections causes entire test case to fail' message='-------------------------------------------------------------------------------|nskipped|n-------------------------------------------------------------------------------|nSkip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testIgnored name='failing in some unskipped sections causes entire test case to fail' message='-------------------------------------------------------------------------------|nnot skipped|n-------------------------------------------------------------------------------|nSkip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit failure- failure ignore as test marked as |'ok to fail|'|n'] +##teamcity[testFinished name='failing in some unskipped sections causes entire test case to fail' duration="{duration}"] ##teamcity[testStarted name='first tag'] ##teamcity[testFinished name='first tag' duration="{duration}"] ##teamcity[testStarted name='has printf'] @@ -761,10 +814,10 @@ Misc.tests.cpp:|nexpression failed|n REQUIRE( testCheckedIf( false ##teamcity[testStarted name='is_unary_function'] ##teamcity[testFinished name='is_unary_function' duration="{duration}"] ##teamcity[testStarted name='just failure'] -Message.tests.cpp:|nexplicit failure with message:|n "Previous info should not be seen"'] +##teamcity[testFailed name='just failure' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with message:|n "Previous info should not be seen"'] ##teamcity[testFinished name='just failure' duration="{duration}"] ##teamcity[testStarted name='just failure after unscoped info'] -Message.tests.cpp:|nexplicit failure with message:|n "previous unscoped info SHOULD not be seen"'] +##teamcity[testFailed name='just failure after unscoped info' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexplicit failure with message:|n "previous unscoped info SHOULD not be seen"'] ##teamcity[testFinished name='just failure after unscoped info' duration="{duration}"] ##teamcity[testStarted name='just info'] ##teamcity[testFinished name='just info' duration="{duration}"] @@ -773,16 +826,16 @@ Message.tests.cpp:|nexplicit failure with message:|n "previous uns ##teamcity[testStarted name='long long'] ##teamcity[testFinished name='long long' duration="{duration}"] ##teamcity[testStarted name='looped SECTION tests'] -Misc.tests.cpp:|nexpression failed|n CHECK( b > a )|nwith expansion:|n 0 > 1|n'] -Misc.tests.cpp:|nexpression failed|n CHECK( b > a )|nwith expansion:|n 1 > 1|n'] +##teamcity[testFailed name='looped SECTION tests' message='-------------------------------------------------------------------------------|nb is currently: 0|n-------------------------------------------------------------------------------|nMisc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n CHECK( b > a )|nwith expansion:|n 0 > 1|n'] +##teamcity[testFailed name='looped SECTION tests' message='-------------------------------------------------------------------------------|nb is currently: 1|n-------------------------------------------------------------------------------|nMisc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n CHECK( b > a )|nwith expansion:|n 1 > 1|n'] ##teamcity[testFinished name='looped SECTION tests' duration="{duration}"] ##teamcity[testStarted name='looped tests'] -Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[0|] (1) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] -Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[1|] (1) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] -Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[3|] (3) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] -Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[4|] (5) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] -Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[6|] (13) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] -Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[7|] (21) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='looped tests' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[0|] (1) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='looped tests' message='Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[1|] (1) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='looped tests' message='Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[3|] (3) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='looped tests' message='Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[4|] (5) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='looped tests' message='Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[6|] (13) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] +##teamcity[testFailed name='looped tests' message='Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[7|] (21) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] ##teamcity[testFinished name='looped tests' duration="{duration}"] ##teamcity[testStarted name='makeStream recognizes %debug stream name'] ##teamcity[testFinished name='makeStream recognizes %debug stream name' duration="{duration}"] @@ -795,10 +848,14 @@ Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib ##teamcity[testStarted name='mix info, unscoped info and warning'] ##teamcity[testFinished name='mix info, unscoped info and warning' duration="{duration}"] ##teamcity[testStarted name='more nested SECTION tests'] -Misc.tests.cpp:|nexpression failed|n REQUIRE( a == b )|nwith expansion:|n 1 == 2|n'] +##teamcity[testFailed name='more nested SECTION tests' message='-------------------------------------------------------------------------------|ndoesn|'t equal|nequal|n-------------------------------------------------------------------------------|nMisc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed|n REQUIRE( a == b )|nwith expansion:|n 1 == 2|n'] ##teamcity[testFinished name='more nested SECTION tests' duration="{duration}"] ##teamcity[testStarted name='nested SECTION tests'] ##teamcity[testFinished name='nested SECTION tests' duration="{duration}"] +##teamcity[testStarted name='nested sections can be skipped dynamically at runtime'] +##teamcity[testIgnored name='nested sections can be skipped dynamically at runtime' message='-------------------------------------------------------------------------------|nB|nB2|n-------------------------------------------------------------------------------|nSkip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testStdOut name='nested sections can be skipped dynamically at runtime' out='a!|nb1!|n!|n'] +##teamcity[testFinished name='nested sections can be skipped dynamically at runtime' duration="{duration}"] ##teamcity[testStarted name='non streamable - with conv. op'] ##teamcity[testFinished name='non streamable - with conv. op' duration="{duration}"] ##teamcity[testStarted name='non-copyable objects'] @@ -810,7 +867,7 @@ Misc.tests.cpp:|nexpression failed|n REQUIRE( a == b )|nwith expan ##teamcity[testStarted name='not allowed'] ##teamcity[testFinished name='not allowed' duration="{duration}"] ##teamcity[testStarted name='not prints unscoped info from previous failures'] -Message.tests.cpp:|nexpression failed with message:|n "this SHOULD be seen"|n REQUIRE( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='not prints unscoped info from previous failures' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with message:|n "this SHOULD be seen"|n REQUIRE( false )|nwith expansion:|n false|n'] ##teamcity[testFinished name='not prints unscoped info from previous failures' duration="{duration}"] ##teamcity[testStarted name='null strings'] ##teamcity[testFinished name='null strings' duration="{duration}"] @@ -825,10 +882,10 @@ Message.tests.cpp:|nexpression failed with message:|n "this SHOULD ##teamcity[testStarted name='print unscoped info if passing unscoped info is printed'] ##teamcity[testFinished name='print unscoped info if passing unscoped info is printed' duration="{duration}"] ##teamcity[testStarted name='prints unscoped info on failure'] -Message.tests.cpp:|nexpression failed with messages:|n "this SHOULD be seen"|n "this SHOULD also be seen"|n REQUIRE( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='prints unscoped info on failure' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with messages:|n "this SHOULD be seen"|n "this SHOULD also be seen"|n REQUIRE( false )|nwith expansion:|n false|n'] ##teamcity[testFinished name='prints unscoped info on failure' duration="{duration}"] ##teamcity[testStarted name='prints unscoped info only for the first assertion'] -Message.tests.cpp:|nexpression failed with message:|n "this SHOULD be seen only ONCE"|n CHECK( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='prints unscoped info only for the first assertion' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with message:|n "this SHOULD be seen only ONCE"|n CHECK( false )|nwith expansion:|n false|n'] ##teamcity[testFinished name='prints unscoped info only for the first assertion' duration="{duration}"] ##teamcity[testStarted name='random SECTION tests'] ##teamcity[testFinished name='random SECTION tests' duration="{duration}"] @@ -844,19 +901,25 @@ Message.tests.cpp:|nexpression failed with message:|n "this SHOULD ##teamcity[testFinished name='run_for_at_least, int' duration="{duration}"] ##teamcity[testStarted name='second tag'] ##teamcity[testFinished name='second tag' duration="{duration}"] +##teamcity[testStarted name='sections can be skipped dynamically at runtime'] +##teamcity[testIgnored name='sections can be skipped dynamically at runtime' message='-------------------------------------------------------------------------------|nskipped|n-------------------------------------------------------------------------------|nSkip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testFinished name='sections can be skipped dynamically at runtime' duration="{duration}"] ##teamcity[testStarted name='send a single char to INFO'] -Misc.tests.cpp:|nexpression failed with message:|n "3"|n REQUIRE( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='send a single char to INFO' message='Misc.tests.cpp:|n...............................................................................|n|nMisc.tests.cpp:|nexpression failed with message:|n "3"|n REQUIRE( false )|nwith expansion:|n false|n'] ##teamcity[testFinished name='send a single char to INFO' duration="{duration}"] ##teamcity[testStarted name='sends information to INFO'] -Message.tests.cpp:|nexpression failed with messages:|n "hi"|n "i := 7"|n REQUIRE( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='sends information to INFO' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with messages:|n "hi"|n "i := 7"|n REQUIRE( false )|nwith expansion:|n false|n'] ##teamcity[testFinished name='sends information to INFO' duration="{duration}"] ##teamcity[testStarted name='shortened hide tags are split apart'] ##teamcity[testFinished name='shortened hide tags are split apart' duration="{duration}"] +##teamcity[testStarted name='skipped tests can optionally provide a reason'] +##teamcity[testIgnored name='skipped tests can optionally provide a reason' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip with message:|n "skipping because answer = 43"'] +##teamcity[testFinished name='skipped tests can optionally provide a reason' duration="{duration}"] ##teamcity[testStarted name='splitString'] ##teamcity[testFinished name='splitString' duration="{duration}"] ##teamcity[testStarted name='stacks unscoped info in loops'] -Message.tests.cpp:|nexpression failed with messages:|n "Count 1 to 3..."|n "1"|n "2"|n "3"|n CHECK( false )|nwith expansion:|n false|n'] -Message.tests.cpp:|nexpression failed with messages:|n "Count 4 to 6..."|n "4"|n "5"|n "6"|n CHECK( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='stacks unscoped info in loops' message='Message.tests.cpp:|n...............................................................................|n|nMessage.tests.cpp:|nexpression failed with messages:|n "Count 1 to 3..."|n "1"|n "2"|n "3"|n CHECK( false )|nwith expansion:|n false|n'] +##teamcity[testFailed name='stacks unscoped info in loops' message='Message.tests.cpp:|nexpression failed with messages:|n "Count 4 to 6..."|n "4"|n "5"|n "6"|n CHECK( false )|nwith expansion:|n false|n'] ##teamcity[testFinished name='stacks unscoped info in loops' duration="{duration}"] ##teamcity[testStarted name='startsWith'] ##teamcity[testFinished name='startsWith' duration="{duration}"] @@ -896,8 +959,11 @@ Message.tests.cpp:|nexpression failed with messages:|n "Count 4 to ##teamcity[testFinished name='tables' duration="{duration}"] ##teamcity[testStarted name='tags with dots in later positions are not parsed as hidden'] ##teamcity[testFinished name='tags with dots in later positions are not parsed as hidden' duration="{duration}"] +##teamcity[testStarted name='tests can be skipped dynamically at runtime'] +##teamcity[testIgnored name='tests can be skipped dynamically at runtime' message='Skip.tests.cpp:|n...............................................................................|n|nSkip.tests.cpp:|nexplicit skip'] +##teamcity[testFinished name='tests can be skipped dynamically at runtime' duration="{duration}"] ##teamcity[testStarted name='thrown std::strings are translated'] -Exception.tests.cpp:|nunexpected exception with message:|n "Why would you throw a std::string?"'] +##teamcity[testFailed name='thrown std::strings are translated' message='Exception.tests.cpp:|n...............................................................................|n|nException.tests.cpp:|nunexpected exception with message:|n "Why would you throw a std::string?"'] ##teamcity[testFinished name='thrown std::strings are translated' duration="{duration}"] ##teamcity[testStarted name='toString on const wchar_t const pointer returns the string contents'] ##teamcity[testFinished name='toString on const wchar_t const pointer returns the string contents' duration="{duration}"] @@ -927,6 +993,8 @@ Exception.tests.cpp:|nunexpected exception with message:|n "Why wo ##teamcity[testFinished name='tuple,tuple<>,float>' duration="{duration}"] ##teamcity[testStarted name='uniform samples'] ##teamcity[testFinished name='uniform samples' duration="{duration}"] +##teamcity[testStarted name='uniform_integer_distribution can return the bounds'] +##teamcity[testFinished name='uniform_integer_distribution can return the bounds' duration="{duration}"] ##teamcity[testStarted name='unique_ptr reimplementation: basic functionality'] ##teamcity[testFinished name='unique_ptr reimplementation: basic functionality' duration="{duration}"] ##teamcity[testStarted name='vec> -> toString'] diff --git a/tests/SelfTest/Baselines/xml.sw.approved.txt b/tests/SelfTest/Baselines/xml.sw.approved.txt index 4ff2e4f2..be57798b 100644 --- a/tests/SelfTest/Baselines/xml.sw.approved.txt +++ b/tests/SelfTest/Baselines/xml.sw.approved.txt @@ -1,7 +1,7 @@ - + - + @@ -20,7 +20,7 @@ 0 == 0 - + @@ -71,16 +71,16 @@ {?} >= {?} - + - + - + uarr := "123" - + sarr := "456" @@ -91,10 +91,10 @@ 0 == 0 - + uarr := "123" - + sarr := "456" @@ -105,16 +105,16 @@ 0 == 0 - + - +
- +
- +
@@ -125,24 +125,24 @@ [1403 helper] == [1403 helper] - + - + This info message starts with a linebreak - + This warning message starts with a linebreak - + 1514 - + This would not be caught previously @@ -160,7 +160,7 @@ Nor would this true - + @@ -187,7 +187,7 @@ Nor would this !false - +
@@ -215,7 +215,7 @@ Nor would this !false - +
@@ -226,9 +226,9 @@ Nor would this true - +
- +
@@ -247,7 +247,7 @@ Nor would this 6 < 7 - + @@ -282,11 +282,11 @@ Nor would this 2 != 4 - +
- +
@@ -297,7 +297,7 @@ Nor would this 1 - +
@@ -308,7 +308,7 @@ Nor would this 2 - +
@@ -319,9 +319,9 @@ Nor would this 3 - +
- +
@@ -333,7 +333,7 @@ Nor would this 1 - +
@@ -351,7 +351,7 @@ Nor would this 3 - +
@@ -378,100 +378,100 @@ Nor would this 3 - +
- +
- + i := 1 - + j := 3 - + k := 5
- +
- + i := 1 - + j := 3 - + k := 6
- +
- + i := 1 - + j := 4 - + k := 5 - + i := 1 - + j := 4 - + k := 6
- +
- + i := 2 - + j := 3 - + k := 5
- +
- + i := 2 - + j := 3 - + k := 6
- +
- + i := 2 - + j := 4 - + k := 5 - + i := 2 - + j := 4 - + k := 6 - +
@@ -618,16 +618,16 @@ Nor would this 3 - + - + - + - + @@ -646,7 +646,7 @@ Nor would this 0.0 not is within 1 ULPs of -4.9406564584124654e-324 ([-9.8813129168249309e-324, -0.0000000000000000e+00]) - + @@ -665,20 +665,26 @@ Nor would this 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0.00000000e+00]) - + + + + + failure to init + +
- + answer := 42 expected exception - +
- + answer := 42 @@ -692,10 +698,10 @@ Nor would this expected exception - +
- + answer := 42 @@ -706,9 +712,9 @@ Nor would this thisThrows() - +
- +
@@ -719,7 +725,7 @@ Nor would this 42 == {?} - + @@ -778,7 +784,7 @@ Nor would this true - + @@ -797,10 +803,10 @@ Nor would this 1 == 1 - + - + dummy := 0 @@ -811,25 +817,25 @@ Nor would this {?} == 4 - +
- +
- +
- +
- +
- +
- +
@@ -896,7 +902,7 @@ Nor would this !(1 == 1) - + @@ -963,7 +969,7 @@ Nor would this !(1 == 2) - +
@@ -983,7 +989,7 @@ Nor would this true == true - +
@@ -1002,7 +1008,7 @@ Nor would this false == false - +
@@ -1013,7 +1019,7 @@ Nor would this true - +
@@ -1024,7 +1030,7 @@ Nor would this true - +
@@ -1043,9 +1049,9 @@ Nor would this !false - +
- +
@@ -1696,7 +1702,7 @@ Nor would this 3 < 9 - + @@ -1707,7 +1713,7 @@ Nor would this "hello" == "world" - + @@ -1718,7 +1724,7 @@ Nor would this "hello" == "hello" - + @@ -1729,7 +1735,7 @@ Nor would this 0 == 1 - + @@ -1740,7 +1746,7 @@ Nor would this 0 == 1 - + @@ -1751,7 +1757,7 @@ Nor would this 0 == 1 - + @@ -1762,7 +1768,7 @@ Nor would this 0 == 1 - + @@ -1773,7 +1779,7 @@ Nor would this 0 == 0 - + @@ -1784,7 +1790,7 @@ Nor would this 0 == 0 - + @@ -1795,7 +1801,7 @@ Nor would this 0 == 0 - + @@ -1806,7 +1812,7 @@ Nor would this 0 == 0 - + @@ -1817,7 +1823,7 @@ Nor would this 6 < 2 - + @@ -1828,7 +1834,7 @@ Nor would this 2 < 2 - + @@ -1839,7 +1845,7 @@ Nor would this 6 < 2 - + @@ -1850,7 +1856,7 @@ Nor would this 2 < 2 - + @@ -1861,7 +1867,7 @@ Nor would this 6 >= 2 - + @@ -1872,7 +1878,7 @@ Nor would this 2 >= 2 - + @@ -1883,7 +1889,7 @@ Nor would this 6 >= 2 - + @@ -1894,7 +1900,7 @@ Nor would this 2 >= 2 - + @@ -1905,7 +1911,7 @@ Nor would this 1.0 == 2 - + @@ -1916,7 +1922,7 @@ Nor would this 1.0f == 2 - + @@ -1927,7 +1933,7 @@ Nor would this 1 == 2 - + @@ -1938,7 +1944,7 @@ Nor would this 1.0 == 1 - + @@ -1949,7 +1955,7 @@ Nor would this 1.0f == 1 - + @@ -1960,7 +1966,7 @@ Nor would this 1 == 1 - + @@ -1971,7 +1977,7 @@ Nor would this 1 == 0 - + @@ -1982,7 +1988,7 @@ Nor would this 3 == 0 - + @@ -1993,7 +1999,7 @@ Nor would this 6 == 0 - + @@ -2004,7 +2010,7 @@ Nor would this 1 > 0 - + @@ -2015,7 +2021,7 @@ Nor would this 3 > 0 - + @@ -2026,7 +2032,7 @@ Nor would this 6 > 0 - + @@ -2037,7 +2043,7 @@ Nor would this 1 == 2 - + @@ -2048,7 +2054,7 @@ Nor would this 1 == 1 - + @@ -2059,7 +2065,7 @@ Nor would this 0 == 0 - + @@ -2070,7 +2076,7 @@ Nor would this 0 == 0 - + @@ -2081,7 +2087,7 @@ Nor would this 0 == 0 - + @@ -2092,7 +2098,7 @@ Nor would this 0 == 0 - + @@ -2103,7 +2109,7 @@ Nor would this 42 > 0 - + @@ -2114,7 +2120,7 @@ Nor would this 9 > 0 - + @@ -2125,7 +2131,7 @@ Nor would this 42 > 0 - + @@ -2136,7 +2142,7 @@ Nor would this 9 > 0 - + @@ -2187,19 +2193,19 @@ Nor would this 1.23 == Approx( 1.0 ) - +
- +
- +
to infinity and beyond - +
@@ -2218,7 +2224,7 @@ Nor would this {?} == {?} - + @@ -2269,10 +2275,10 @@ Nor would this 100.3 == Approx( 100.0 ) - + - + @@ -2291,7 +2297,7 @@ Nor would this 8 == 8 - + @@ -2313,10 +2319,10 @@ Nor would this unexpected exception
- + - + @@ -2375,7 +2381,7 @@ Nor would this Approx(0).epsilon(1.0001), std::domain_error - + @@ -2418,7 +2424,7 @@ Nor would this 245.5f == Approx( 245.25 ) - + @@ -2437,7 +2443,7 @@ Nor would this 3.1428571429 != Approx( 3.141 ) - + @@ -2456,7 +2462,7 @@ Nor would this 1.23 == Approx( 1.231 ) - + @@ -2475,7 +2481,7 @@ Nor would this 0.0f == Approx( 0.0 ) - + @@ -2494,7 +2500,7 @@ Nor would this 0 == Approx( 0.0 ) - + @@ -2537,7 +2543,7 @@ Nor would this 1.234 == Approx( 1.2339999676 ) - +
@@ -2557,7 +2563,7 @@ Nor would this 1 not matches predicate: "always false" - +
@@ -2576,9 +2582,9 @@ Nor would this "This wouldn't pass" not matches undescribed predicate - +
- +
@@ -2621,7 +2627,7 @@ Nor would this !(Val: 1 ^ Val: 1) - + @@ -2650,9 +2656,9 @@ Nor would this true - + - + @@ -2680,11 +2686,11 @@ Nor would this true - + - + - +
@@ -2712,7 +2718,7 @@ Nor would this { 4, 5, 6 } not contains element 1 - +
@@ -2739,7 +2745,7 @@ Nor would this { 4, 5, 6 } not contains element 0 - +
@@ -2750,7 +2756,7 @@ Nor would this { "abc", "abcd", "abcde" } contains element 4 - +
@@ -2769,7 +2775,7 @@ Nor would this { 1, 2, 3, 4, 5 } not contains element 8 - +
@@ -2788,7 +2794,7 @@ Nor would this { 1, 2, 3 } not contains element 9 - +
@@ -2799,9 +2805,9 @@ Nor would this { 1.0, 2.0, 3.0, 0.0 } contains element matching is within 0.5 of 0.5 - +
- +
@@ -2853,7 +2859,7 @@ Nor would this { } is empty - +
@@ -2864,7 +2870,7 @@ Nor would this {?} not is empty - +
@@ -2875,97 +2881,97 @@ Nor would this {?} is empty - +
- +
- + a := 1 - + b := 2 - + c := 3 - + a + b := 3 - + a+b := 3 - + c > b := true - + a == 1 := true - + - - std::vector<int>{1, 2, 3}[0, 1, 2] := 3 + + custom_index_op<int>{1, 2, 3}[0, 1, 2] := 0 - - std::vector<int>{1, 2, 3}[(0, 1)] := 2 + + custom_index_op<int>{1, 2, 3}[(0, 1)] := 0 - - std::vector<int>{1, 2, 3}[0] := 1 + + custom_index_op<int>{1, 2, 3}[0] := 0 - + (helper_1436<int, int>{12, -12}) := { 12, -12 } - + (helper_1436<int, int>(-12, 12)) := { -12, 12 } - + (1, 2) := 2 - + (2, 3) := 3 - + - + ("comma, in string", "escaped, \", ") := "escaped, ", " - + "single quote in string,'," := "single quote in string,'," - + "some escapes, \\,\\\\" := "some escapes, \,\\" - + "some, ), unmatched, } prenheses {[<" := "some, ), unmatched, } prenheses {[<" - + '"' := '"' - + '\'' := ''' - + ',' := ',' - + '}' := '}' - + ')' := ')' - + '(' := '(' - + '{' := '{' - +
- + i := 2 @@ -2976,10 +2982,10 @@ Nor would this true - +
- + 3 @@ -2990,9 +2996,9 @@ Nor would this true - +
- +
@@ -3012,7 +3018,7 @@ Nor would this !false - +
@@ -3063,9 +3069,9 @@ Nor would this !false - +
- +
@@ -3093,7 +3099,7 @@ Nor would this !false - +
@@ -3128,9 +3134,9 @@ Nor would this true - +
- +
@@ -3166,7 +3172,7 @@ Nor would this '\f' == '\f' - +
@@ -3209,7 +3215,7 @@ Nor would this 'Z' == 'Z' - +
@@ -3252,9 +3258,9 @@ Nor would this 5 == 5 - +
- +
@@ -3273,7 +3279,7 @@ Nor would this "foo" == "foo" - +
@@ -3285,7 +3291,7 @@ Nor would this !{?} - +
@@ -3304,9 +3310,9 @@ Nor would this { "aaa", "bbb" } == { "aaa", "bbb" } - +
- +
@@ -3318,7 +3324,7 @@ Nor would this true - +
@@ -3341,7 +3347,7 @@ Using code: 0 " - +
@@ -3364,9 +3370,9 @@ C " - +
- +
@@ -3393,7 +3399,7 @@ C 1 ( equals: (int) 1 or (string) "1" and equals: (long long) 1 and equals: (T) 1 and equals: true ) - + @@ -3420,7 +3426,7 @@ C 1 ( equals: (int) 1 or (string) "1" or equals: (long long) 1 or equals: (T) 1 or equals: true ) - + @@ -3455,10 +3461,10 @@ C 1 equals: (int) 1 or (string) "1" - + - + @@ -3485,7 +3491,7 @@ C 1 ( equals: (int) 1 or (string) "1" or not equals: (long long) 1 ) - + @@ -3544,7 +3550,7 @@ C "foobar" ( ( starts with: "foo" and ends with: "bar" ) or Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } ) - + @@ -3555,7 +3561,7 @@ C { 1, 2, 3 } ( Equals: { 1, 2, 3 } or Equals: { 0, 1, 2 } or Equals: { 4, 5, 6 } ) - + @@ -3654,7 +3660,7 @@ C { 1, 2 } == { 1, 2 } - + @@ -3673,7 +3679,7 @@ C 0x == 0x - + @@ -3708,7 +3714,7 @@ C !({?} != {?}) - + @@ -3807,7 +3813,7 @@ C Approx( 11.0 ) >= StrongDoubleTypedef(10) - + @@ -3818,7 +3824,7 @@ C 54 == 54 - + @@ -3869,7 +3875,7 @@ C -2147483648 > 2 - + @@ -3976,7 +3982,7 @@ C 4294967295 (0x) > 4 - +
@@ -4004,7 +4010,7 @@ C true - +
@@ -4031,9 +4037,9 @@ C true - +
- +
@@ -4061,7 +4067,7 @@ C true - +
@@ -4088,9 +4094,9 @@ C true - +
- +
@@ -4109,7 +4115,7 @@ C "this string contains 'abc' as a substring" contains: "STRING" - +
@@ -4121,7 +4127,7 @@ C 1 == 1 - +
@@ -4132,7 +4138,7 @@ C 1 == 1 - +
@@ -4143,7 +4149,7 @@ C 1 == 1 - +
@@ -4154,7 +4160,7 @@ C 1 == 1 - +
@@ -4165,7 +4171,7 @@ C 1 == 1 - +
@@ -4176,7 +4182,7 @@ C 1 == 1 - +
@@ -4187,7 +4193,7 @@ C 1 == 1 - +
@@ -4198,7 +4204,7 @@ C 1 == 1 - +
@@ -4209,7 +4215,7 @@ C 1 == 1 - +
@@ -4220,7 +4226,7 @@ C 1 == 1 - +
@@ -4231,7 +4237,7 @@ C 1 == 1 - +
@@ -4242,7 +4248,7 @@ C 1 == 1 - +
@@ -4261,9 +4267,9 @@ C 6 == 6 - +
- +
@@ -4274,7 +4280,7 @@ C true - + @@ -4288,7 +4294,7 @@ C custom exception - not std
- + @@ -4302,13 +4308,13 @@ C custom exception - not std
- + custom std exception - + @@ -4327,7 +4333,7 @@ C 0.00001 != Approx( 0.0000001 ) - + @@ -4356,7 +4362,13 @@ C "{** unexpected enum value **}" - + + + + + This generator is empty + + @@ -4367,18 +4379,7 @@ C true - - - - - - Catch::TestCaseInfo( "", { "fake test name", "[]" }, dummySourceLineInfo ) - - - Catch::TestCaseInfo( "", { "fake test name", "[]" }, dummySourceLineInfo ) - - - + @@ -4397,7 +4398,7 @@ C "this string contains 'abc' as a substring" ends with: "this" (case insensitive) - + @@ -4442,7 +4443,7 @@ C "Value2" == "Value2" - + @@ -4461,7 +4462,7 @@ C "Blue" == "Blue" - + @@ -4472,7 +4473,7 @@ C 101.01 != Approx( 100.0 ) - + @@ -4579,7 +4580,7 @@ C 1.3 == Approx( 1.301 ) - + @@ -4638,7 +4639,7 @@ C 1.3 == Approx( 1.3 ) - + @@ -4657,7 +4658,7 @@ C "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" (case insensitive) - + @@ -4676,7 +4677,7 @@ C "this string contains 'abc' as a substring" equals: "something else" (case insensitive) - + @@ -4707,7 +4708,7 @@ C "StringMakerException" - +
@@ -4727,7 +4728,7 @@ C doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } - +
@@ -4752,7 +4753,7 @@ C Unknown exception - +
@@ -4771,9 +4772,9 @@ C SpecialException::what special exception has value of 1 - +
- +
@@ -4792,7 +4793,42 @@ C SpecialException::what special exception has value of 2 - + + + + + + throwsDerivedException(), DerivedException, MessageMatches( StartsWith( "Derived" ) ) + + + DerivedException::what matches "starts with: "Derived"" + + + + + throwsDerivedException(), DerivedException, MessageMatches( EndsWith( "::what" ) ) + + + DerivedException::what matches "ends with: "::what"" + + + + + throwsDerivedException(), DerivedException, MessageMatches( !StartsWith( "::what" ) ) + + + DerivedException::what matches "not starts with: "::what"" + + + + + throwsSpecialException( 2 ), SpecialException, MessageMatches( StartsWith( "Special" ) ) + + + SpecialException::what matches "starts with: "Special"" + + +
@@ -4804,7 +4840,7 @@ C "expected exception" equals: "expected exception" - +
@@ -4815,7 +4851,7 @@ C "expected exception" equals: "expected exception" (case insensitive) - +
@@ -4850,9 +4886,9 @@ C "expected exception" contains: "except" (case insensitive) - +
- +
@@ -4887,7 +4923,7 @@ C SpecialException::what exception message matches "SpecialException::what" - + @@ -4920,26 +4956,26 @@ C expected exception
- + This is a failure - + - + This is a failure - + This message appears in the output - + @@ -4982,7 +5018,18 @@ C 3628800 (0x) == 3628800 (0x) - + + + + + + filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException + + + filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException + + +
@@ -5027,9 +5074,9 @@ C 0.0 and 2.22507e-308 are within 2.22045e-12% of each other - +
- +
@@ -5096,7 +5143,7 @@ C -10.0 is within 0.5 of -9.6 - +
@@ -5155,7 +5202,7 @@ C -0.0 is within 0 ULPs of 0.0000000000000000e+00 ([0.0000000000000000e+00, 0.0000000000000000e+00]) - +
@@ -5182,7 +5229,7 @@ C 0.0001 ( is within 0.001 of 0.0 or and 0 are within 10% of each other ) - +
@@ -5233,9 +5280,20 @@ C WithinRel( 1., 1. ), std::domain_error - +
- +
+ + + 1., !IsNaN() + + + 1.0 not is NaN + + + +
+
@@ -5280,9 +5338,9 @@ C 0.0f and 1.17549e-38 are within 0.00119209% of each other - +
- +
@@ -5357,7 +5415,7 @@ C -10.0f is within 0.5 of -9.6000003815 - +
@@ -5424,7 +5482,7 @@ C -0.0f is within 0 ULPs of 0.00000000e+00f ([0.00000000e+00, 0.00000000e+00]) - +
@@ -5451,7 +5509,7 @@ C 0.0001f ( is within 0.001 of 0.0 or and 0 are within 10% of each other ) - +
@@ -5510,9 +5568,55 @@ C WithinRel( 1.f, 1.f ), std::domain_error - +
- +
+ + + 1., !IsNaN() + + + 1.0 not is NaN + + + +
+ +
+ + + + i % 2 == 0 + + + 0 == 0 + + + + + i % 2 == 0 + + + 0 == 0 + + + + + i % 2 == 0 + + + 0 == 0 + + + + + i % 2 == 0 + + + 0 == 0 + + +
@@ -5525,9 +5629,9 @@ C 0 == 0 - +
- +
@@ -5539,9 +5643,9 @@ C 0 == 0 - +
- +
@@ -5553,9 +5657,9 @@ C 0 == 0 - +
- +
@@ -5567,9 +5671,9 @@ C filter([] (int) {return false; }, value(1)), Catch::GeneratorException - +
- +
@@ -5580,7 +5684,7 @@ C 1 < 4 - +
@@ -5591,7 +5695,7 @@ C 2 < 4 - +
@@ -5602,7 +5706,7 @@ C 3 < 4 - +
@@ -5614,9 +5718,9 @@ C 0 == 0 - +
- +
@@ -5628,9 +5732,9 @@ C 0 == 0 - +
- +
@@ -5642,9 +5746,9 @@ C 0 == 0 - +
- +
@@ -5656,9 +5760,9 @@ C 1 == 1 - +
- +
@@ -5670,9 +5774,9 @@ C 1 == 1 - +
- +
@@ -5684,9 +5788,9 @@ C 1 == 1 - +
- +
@@ -5698,9 +5802,9 @@ C 1 == 1 - +
- +
@@ -5712,9 +5816,9 @@ C 1 == 1 - +
- +
@@ -5726,9 +5830,9 @@ C 1 == 1 - +
- +
@@ -5739,7 +5843,7 @@ C 1 > 0 - +
@@ -5750,7 +5854,7 @@ C 2 > 0 - +
@@ -5761,7 +5865,7 @@ C 3 > 0 - +
@@ -5772,7 +5876,7 @@ C 1 > 0 - +
@@ -5783,7 +5887,7 @@ C 2 > 0 - +
@@ -5794,7 +5898,7 @@ C 3 > 0 - +
@@ -5814,9 +5918,9 @@ C 1 == 1 - +
- +
@@ -5836,9 +5940,9 @@ C 2 == 2 - +
- +
@@ -5858,9 +5962,9 @@ C 3 == 3 - +
- +
@@ -5888,9 +5992,9 @@ C 1 < 3 - +
- +
@@ -5918,9 +6022,9 @@ C 2 < 3 - +
- +
@@ -5932,9 +6036,9 @@ C 0 == 0 - +
- +
@@ -5946,9 +6050,9 @@ C 0 == 0 - +
- +
@@ -5960,9 +6064,9 @@ C 0 == 0 - +
- +
@@ -5974,11 +6078,11 @@ C chunk(2, value(1)), Catch::GeneratorException - +
- +
- +
@@ -5990,7 +6094,7 @@ C -3 < 1 - +
@@ -6001,7 +6105,7 @@ C -2 < 1 - +
@@ -6012,7 +6116,7 @@ C -1 < 1 - +
@@ -6023,7 +6127,7 @@ C 4 > 1 - +
@@ -6034,7 +6138,7 @@ C 4 > 2 - +
@@ -6045,7 +6149,7 @@ C 4 > 3 - +
@@ -6056,7 +6160,7 @@ C -3 < 2 - +
@@ -6067,7 +6171,7 @@ C -2 < 2 - +
@@ -6078,7 +6182,7 @@ C -1 < 2 - +
@@ -6089,7 +6193,7 @@ C 8 > 1 - +
@@ -6100,7 +6204,7 @@ C 8 > 2 - +
@@ -6111,7 +6215,7 @@ C 8 > 3 - +
@@ -6122,7 +6226,7 @@ C -3 < 3 - +
@@ -6133,7 +6237,7 @@ C -2 < 3 - +
@@ -6144,7 +6248,7 @@ C -1 < 3 - +
@@ -6155,7 +6259,7 @@ C 12 > 1 - +
@@ -6166,7 +6270,7 @@ C 12 > 2 - +
@@ -6177,9 +6281,9 @@ C 12 > 3 - +
- +
@@ -6199,7 +6303,7 @@ C !false - +
@@ -6250,7 +6354,7 @@ C !false - +
@@ -6333,7 +6437,7 @@ C !false - +
@@ -6392,7 +6496,7 @@ C !false - +
@@ -6428,9 +6532,9 @@ C !false - +
- +
@@ -6466,9 +6570,9 @@ C !false - +
- +
@@ -6488,9 +6592,9 @@ C filter([](int) { return false; }, values({ 1, 2, 3 })), Catch::GeneratorException - +
- +
@@ -6526,9 +6630,9 @@ C !false - +
- +
@@ -6548,9 +6652,9 @@ C !false - +
- +
@@ -6601,7 +6705,7 @@ C !false - +
@@ -6652,7 +6756,7 @@ C !false - +
@@ -6672,9 +6776,9 @@ C !false - +
- +
@@ -6774,9 +6878,9 @@ C !false - +
- +
@@ -6845,11 +6949,11 @@ C !false - +
- +
- +
@@ -6918,11 +7022,11 @@ C !false - +
- +
- +
@@ -6992,13 +7096,13 @@ C !false - +
- +
- + - +
@@ -7068,13 +7172,13 @@ C !false - +
- +
- + - +
@@ -7160,19 +7264,19 @@ C !false - +
- +
- + - +
- + Current expected value is -1 @@ -7183,7 +7287,7 @@ C -1.0 == Approx( -1.0 ) - + Current expected value is -1 @@ -7194,7 +7298,7 @@ C true - + Current expected value is -0.9 @@ -7205,7 +7309,7 @@ C -0.9 == Approx( -0.9 ) - + Current expected value is -0.9 @@ -7216,7 +7320,7 @@ C true - + Current expected value is -0.8 @@ -7227,7 +7331,7 @@ C -0.8 == Approx( -0.8 ) - + Current expected value is -0.8 @@ -7238,7 +7342,7 @@ C true - + Current expected value is -0.7 @@ -7249,7 +7353,7 @@ C -0.7 == Approx( -0.7 ) - + Current expected value is -0.7 @@ -7260,7 +7364,7 @@ C true - + Current expected value is -0.6 @@ -7271,7 +7375,7 @@ C -0.6 == Approx( -0.6 ) - + Current expected value is -0.6 @@ -7282,7 +7386,7 @@ C true - + Current expected value is -0.5 @@ -7293,7 +7397,7 @@ C -0.5 == Approx( -0.5 ) - + Current expected value is -0.5 @@ -7304,7 +7408,7 @@ C true - + Current expected value is -0.4 @@ -7315,7 +7419,7 @@ C -0.4 == Approx( -0.4 ) - + Current expected value is -0.4 @@ -7326,7 +7430,7 @@ C true - + Current expected value is -0.3 @@ -7337,7 +7441,7 @@ C -0.3 == Approx( -0.3 ) - + Current expected value is -0.3 @@ -7348,7 +7452,7 @@ C true - + Current expected value is -0.2 @@ -7359,7 +7463,7 @@ C -0.2 == Approx( -0.2 ) - + Current expected value is -0.2 @@ -7370,7 +7474,7 @@ C true - + Current expected value is -0.1 @@ -7381,7 +7485,7 @@ C -0.1 == Approx( -0.1 ) - + Current expected value is -0.1 @@ -7392,7 +7496,7 @@ C true - + Current expected value is -1.38778e-16 @@ -7403,7 +7507,7 @@ C -0.0 == Approx( -0.0 ) - + Current expected value is -1.38778e-16 @@ -7414,7 +7518,7 @@ C true - + Current expected value is 0.1 @@ -7425,7 +7529,7 @@ C 0.1 == Approx( 0.1 ) - + Current expected value is 0.1 @@ -7436,7 +7540,7 @@ C true - + Current expected value is 0.2 @@ -7447,7 +7551,7 @@ C 0.2 == Approx( 0.2 ) - + Current expected value is 0.2 @@ -7458,7 +7562,7 @@ C true - + Current expected value is 0.3 @@ -7469,7 +7573,7 @@ C 0.3 == Approx( 0.3 ) - + Current expected value is 0.3 @@ -7480,7 +7584,7 @@ C true - + Current expected value is 0.4 @@ -7491,7 +7595,7 @@ C 0.4 == Approx( 0.4 ) - + Current expected value is 0.4 @@ -7502,7 +7606,7 @@ C true - + Current expected value is 0.5 @@ -7513,7 +7617,7 @@ C 0.5 == Approx( 0.5 ) - + Current expected value is 0.5 @@ -7524,7 +7628,7 @@ C true - + Current expected value is 0.6 @@ -7535,7 +7639,7 @@ C 0.6 == Approx( 0.6 ) - + Current expected value is 0.6 @@ -7546,7 +7650,7 @@ C true - + Current expected value is 0.7 @@ -7557,7 +7661,7 @@ C 0.7 == Approx( 0.7 ) - + Current expected value is 0.7 @@ -7568,7 +7672,7 @@ C true - + Current expected value is 0.8 @@ -7579,7 +7683,7 @@ C 0.8 == Approx( 0.8 ) - + Current expected value is 0.8 @@ -7590,7 +7694,7 @@ C true - + Current expected value is 0.9 @@ -7601,7 +7705,7 @@ C 0.9 == Approx( 0.9 ) - + Current expected value is 0.9 @@ -7628,19 +7732,19 @@ C !false - +
- +
- +
- +
- + Current expected value is -1 @@ -7651,7 +7755,7 @@ C -1.0 == Approx( -1.0 ) - + Current expected value is -1 @@ -7662,7 +7766,7 @@ C true - + Current expected value is -0.7 @@ -7673,7 +7777,7 @@ C -0.7 == Approx( -0.7 ) - + Current expected value is -0.7 @@ -7684,7 +7788,7 @@ C true - + Current expected value is -0.4 @@ -7695,7 +7799,7 @@ C -0.4 == Approx( -0.4 ) - + Current expected value is -0.4 @@ -7706,7 +7810,7 @@ C true - + Current expected value is -0.1 @@ -7717,7 +7821,7 @@ C -0.1 == Approx( -0.1 ) - + Current expected value is -0.1 @@ -7728,7 +7832,7 @@ C true - + Current expected value is 0.2 @@ -7739,7 +7843,7 @@ C 0.2 == Approx( 0.2 ) - + Current expected value is 0.2 @@ -7750,7 +7854,7 @@ C true - + Current expected value is 0.5 @@ -7761,7 +7865,7 @@ C 0.5 == Approx( 0.5 ) - + Current expected value is 0.5 @@ -7780,19 +7884,19 @@ C !false - +
- +
- +
- +
- + Current expected value is -1 @@ -7803,7 +7907,7 @@ C -1.0 == Approx( -1.0 ) - + Current expected value is -1 @@ -7814,7 +7918,7 @@ C true - + Current expected value is -0.7 @@ -7825,7 +7929,7 @@ C -0.7 == Approx( -0.7 ) - + Current expected value is -0.7 @@ -7836,7 +7940,7 @@ C true - + Current expected value is -0.4 @@ -7847,7 +7951,7 @@ C -0.4 == Approx( -0.4 ) - + Current expected value is -0.4 @@ -7858,7 +7962,7 @@ C true - + Current expected value is -0.1 @@ -7869,7 +7973,7 @@ C -0.1 == Approx( -0.1 ) - + Current expected value is -0.1 @@ -7880,7 +7984,7 @@ C true - + Current expected value is 0.2 @@ -7891,7 +7995,7 @@ C 0.2 == Approx( 0.2 ) - + Current expected value is 0.2 @@ -7902,7 +8006,7 @@ C true - + Current expected value is 0.5 @@ -7913,7 +8017,7 @@ C 0.5 == Approx( 0.5 ) - + Current expected value is 0.5 @@ -7932,13 +8036,13 @@ C !false - +
- +
- +
- +
@@ -8008,13 +8112,13 @@ C !false - +
- +
- + - +
@@ -8084,13 +8188,13 @@ C !false - +
- +
- + - +
@@ -8176,15 +8280,15 @@ C !false - +
- +
- + - + - +
@@ -8219,7 +8323,7 @@ C 1.23 >= Approx( 1.24 ) - + @@ -8232,7 +8336,7 @@ C 130711275 (0x) - + @@ -8245,7 +8349,7 @@ C 3422778688 (0x) - +
@@ -8259,7 +8363,7 @@ C 2668622104 (0x) - +
@@ -8272,7 +8376,7 @@ C 3916075712 (0x) - +
@@ -8285,9 +8389,9 @@ C 3429949824 (0x) - +
- +
@@ -8300,22 +8404,34 @@ C 3422778688 (0x) - + + + + + This info has multiple parts. + + + This unscoped info has multiple parts. + + + Show infos! + + - + this is a message - + this is a warning - + - + this message should be logged - + so should this @@ -8326,10 +8442,10 @@ C 2 == 1 - + - + this message may be logged later @@ -8340,10 +8456,10 @@ C 2 == 2 - + this message may be logged later - + this message should be logged @@ -8354,13 +8470,13 @@ C 2 == 1 - + this message may be logged later - + this message should be logged - + and this, but later @@ -8371,16 +8487,16 @@ C 2 == 0 - + this message may be logged later - + this message should be logged - + and this, but later - + but not this @@ -8391,13 +8507,13 @@ C 2 == 2 - + - + current counter 0 - + i := 0 @@ -8408,10 +8524,10 @@ C 0 < 10 - + current counter 1 - + i := 1 @@ -8422,10 +8538,10 @@ C 1 < 10 - + current counter 2 - + i := 2 @@ -8436,10 +8552,10 @@ C 2 < 10 - + current counter 3 - + i := 3 @@ -8450,10 +8566,10 @@ C 3 < 10 - + current counter 4 - + i := 4 @@ -8464,10 +8580,10 @@ C 4 < 10 - + current counter 5 - + i := 5 @@ -8478,10 +8594,10 @@ C 5 < 10 - + current counter 6 - + i := 6 @@ -8492,10 +8608,10 @@ C 6 < 10 - + current counter 7 - + i := 7 @@ -8506,10 +8622,10 @@ C 7 < 10 - + current counter 8 - + i := 8 @@ -8520,10 +8636,10 @@ C 8 < 10 - + current counter 9 - + i := 9 @@ -8534,10 +8650,10 @@ C 9 < 10 - + current counter 10 - + i := 10 @@ -8548,7 +8664,21 @@ C 10 < 10 - + + + + + + Dummy + + + Dummy + + + Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE + + + @@ -8591,7 +8721,7 @@ C 5 != 5 - + @@ -8682,7 +8812,278 @@ C 5 != 6 - + + + +
+ + + stream.str() == "" + + + "" == "" + + + +
+
+ + + stream.str() == "{\n}" + + + "{ +}" +== +"{ +}" + + + +
+
+ + + stream.str(), ContainsSubstring( "\"int\": 1," ) && ContainsSubstring( "\"double\": 1.5," ) && ContainsSubstring( "\"true\": true," ) && ContainsSubstring( "\"false\": false," ) && ContainsSubstring( "\"string\": \"this is a string\"," ) && ContainsSubstring( "\"array\": [\n 1,\n 2\n ]\n}" ) + + + "{ + "int": 1, + "double": 1.5, + "true": true, + "false": false, + "string": "this is a string", + "array": [ + 1, + 2 + ] +}" ( contains: ""int": 1," and contains: ""double": 1.5," and contains: ""true": true," and contains: ""false": false," and contains: ""string": "this is a string"," and contains: ""array": [ + 1, + 2 + ] +}" ) + + + +
+
+ + + stream.str(), ContainsSubstring( "\"empty_object\": {\n }," ) && ContainsSubstring( "\"fully_object\": {\n \"key\": 1\n }" ) + + + "{ + "empty_object": { + }, + "fully_object": { + "key": 1 + } +}" ( contains: ""empty_object": { + }," and contains: ""fully_object": { + "key": 1 + }" ) + + + +
+
+ + + stream.str() == "[\n]" + + + "[ +]" +== +"[ +]" + + + +
+
+ + + stream.str() == "[\n 1,\n 1.5,\n true,\n false,\n \"this is a string\",\n {\n \"object\": 42\n },\n [\n \"array\",\n 42.5\n ]\n]" + + + "[ + 1, + 1.5, + true, + false, + "this is a string", + { + "object": 42 + }, + [ + "array", + 42.5 + ] +]" +== +"[ + 1, + 1.5, + true, + false, + "this is a string", + { + "object": 42 + }, + [ + "array", + 42.5 + ] +]" + + + +
+
+ + + stream.str() == "{\n}" + + + "{ +}" +== +"{ +}" + + + +
+
+ + + stream.str() == "[\n]" + + + "[ +]" +== +"[ +]" + + + +
+
+ + + stream.str() == "\"custom\"" + + + ""custom"" == ""custom"" + + + +
+ +
+ +
+ + + sstream.str() == "\"\\\"\"" + + + ""\""" == ""\""" + + + +
+
+ + + sstream.str() == "\"\\\\\"" + + + ""\\"" == ""\\"" + + + +
+
+ + + sstream.str() == "\"/\"" + + + ""/"" == ""/"" + + + +
+
+ + + sstream.str() == "\"\\b\"" + + + ""\b"" == ""\b"" + + + +
+
+ + + sstream.str() == "\"\\f\"" + + + ""\f"" == ""\f"" + + + +
+
+ + + sstream.str() == "\"\\n\"" + + + ""\n"" == ""\n"" + + + +
+
+ + + sstream.str() == "\"\\r\"" + + + ""\r"" == ""\r"" + + + +
+
+ + + sstream.str() == "\"\\t\"" + + + ""\t"" == ""\t"" + + + +
+
+ + + sstream.str() == "\"\\\\/\\t\\r\\n\"" + + + ""\\/\t\r\n"" == ""\\/\t\r\n"" + + + +
+
@@ -8693,7 +9094,7 @@ C true - + @@ -8728,10 +9129,10 @@ C 1.23 <= Approx( 1.22 ) - + - + @@ -8742,7 +9143,7 @@ C "this string contains 'abc' as a substring" ( contains: "string" and contains: "abc" and contains: "substring" and contains: "contains" ) - + @@ -8761,7 +9162,7 @@ C "some completely different text that contains one common word" ( contains: "string" or contains: "different" or contains: "random" ) - + @@ -8772,7 +9173,7 @@ C "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "substring" ) - + @@ -8783,7 +9184,7 @@ C "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" ) - + @@ -8794,7 +9195,7 @@ C "this string contains 'abc' as a substring" not contains: "different" - + @@ -8805,44 +9206,44 @@ C "this string contains 'abc' as a substring" not contains: "substring" - +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
@@ -8861,7 +9262,7 @@ C "expected exception" equals: "should fail" - + @@ -8874,7 +9275,7 @@ C { "Hello", "world", "Goodbye", "world" } - + @@ -8942,7 +9343,7 @@ C true == true - + @@ -9009,9 +9410,9 @@ C true == true - + - + @@ -9142,19 +9543,19 @@ C 99 > -6 - + - + This one ran - + custom exception - + @@ -9181,10 +9582,10 @@ C !{?} - + - + @@ -9339,7 +9740,7 @@ C "hello" <= "a" - + @@ -9478,7 +9879,7 @@ C "hello" > "a" - +
@@ -9532,7 +9933,7 @@ C 1827115164 (0x) - +
@@ -9635,24 +10036,24 @@ C 4261393167 (0x) - +
- +
Message from section one - +
Message from section two - +
- +
@@ -9687,7 +10088,7 @@ C ( EvilMatcher() && EvilMatcher() ) || !EvilMatcher() - +
@@ -9723,7 +10124,7 @@ C {?} == {?} - +
@@ -9782,9 +10183,9 @@ C !{?} - +
- +
@@ -9811,7 +10212,7 @@ C true - +
@@ -9831,7 +10232,7 @@ C 8 == 8 - +
@@ -9850,7 +10251,7 @@ C "Could not parse '-1' as shard count" contains: "Could not parse '-1' as shard count" - +
@@ -9869,7 +10270,7 @@ C "Shard count must be positive" contains: "Shard count must be positive" - +
@@ -9888,7 +10289,7 @@ C 2 == 2 - +
@@ -9907,7 +10308,7 @@ C "Could not parse '-12' as shard index" contains: "Could not parse '-12' as shard index" - +
@@ -9926,12 +10327,12 @@ C 0 == 0 - +
- +
- + tagString := "[tag with spaces]" @@ -9942,7 +10343,7 @@ C true - + tagString := "[tag with spaces]" @@ -9953,7 +10354,7 @@ C true - + tagString := "[tag with spaces]" @@ -9964,7 +10365,7 @@ C true - + tagString := "[I said "good day" sir!]" @@ -9975,7 +10376,7 @@ C true - + tagString := "[I said "good day" sir!]" @@ -9986,7 +10387,7 @@ C true - + tagString := "[I said "good day" sir!]" @@ -9997,7 +10398,7 @@ C true - +
@@ -10017,7 +10418,7 @@ C 1 == 1 - +
@@ -10028,7 +10429,7 @@ C !{?} - +
@@ -10047,9 +10448,9 @@ C 3 == 3 - +
- +
@@ -10116,7 +10517,7 @@ C 0 != 0x - +
@@ -10136,7 +10537,7 @@ C 13 == 13 - +
@@ -10155,9 +10556,9 @@ C 17 == 17 - +
- +
@@ -10168,7 +10569,7 @@ C "foo" matches undescribed predicate - +
@@ -10188,7 +10589,7 @@ C "" == "" - +
@@ -10279,7 +10680,7 @@ C {?} == {?} - +
@@ -10315,9 +10716,9 @@ C true - +
- +
@@ -10353,9 +10754,9 @@ C true - +
- +
@@ -10391,13 +10792,13 @@ C true - +
- +
- + result.errorMessage() := "" @@ -10408,7 +10809,7 @@ C {?} - + result.errorMessage() := "" @@ -10419,13 +10820,13 @@ C { {?} } == { {?} } - +
- +
- + result.errorMessage() := "" @@ -10436,7 +10837,7 @@ C {?} - + result.errorMessage() := "" @@ -10447,13 +10848,13 @@ C { {?} } == { {?} } - +
- +
- + result.errorMessage() := "" @@ -10464,7 +10865,7 @@ C {?} - + result.errorMessage() := "" @@ -10475,9 +10876,9 @@ C { {?} } == { {?} } - +
- +
@@ -10497,13 +10898,13 @@ C "Unrecognized reporter, 'unsupported'. Check available with --list-reporters" contains: "Unrecognized reporter" - +
- +
- + result.errorMessage() := "" @@ -10514,7 +10915,7 @@ C {?} - + result.errorMessage() := "" @@ -10525,13 +10926,13 @@ C { {?} } == { {?} } - +
- +
- + result.errorMessage() := "" @@ -10542,7 +10943,7 @@ C {?} - + result.errorMessage() := "" @@ -10553,9 +10954,9 @@ C { {?} } == { {?} } - +
- +
@@ -10576,11 +10977,11 @@ C { {?}, {?} } == { {?}, {?} } - +
- +
- +
@@ -10601,11 +11002,11 @@ C { {?}, {?} } == { {?}, {?} } - +
- +
- +
@@ -10626,11 +11027,11 @@ C "Only one reporter may have unspecified output file." contains: "Only one reporter may have unspecified output file." - +
- +
- +
@@ -10650,9 +11051,9 @@ C true == true - +
- +
@@ -10672,9 +11073,9 @@ C true - +
- +
@@ -10694,9 +11095,9 @@ C 1 == 1 - +
- +
@@ -10716,9 +11117,9 @@ C 2 == 2 - +
- +
@@ -10738,9 +11139,9 @@ C "Unable to convert 'oops' to destination type" ( contains: "convert" and contains: "oops" ) - +
- +
@@ -10761,11 +11162,11 @@ C 0 == 0 - +
- +
- +
@@ -10786,11 +11187,11 @@ C 1 == 1 - +
- +
- +
@@ -10811,11 +11212,11 @@ C 2 == 2 - +
- +
- +
@@ -10836,11 +11237,11 @@ C 3 == 3 - +
- +
- +
@@ -10861,11 +11262,11 @@ C "keypress argument must be one of: never, start, exit or both. 'sometimes' not recognised" ( contains: "never" and contains: "both" ) - +
- +
- +
@@ -10885,9 +11286,9 @@ C true - +
- +
@@ -10907,9 +11308,9 @@ C true - +
- +
@@ -10929,9 +11330,9 @@ C "filename.ext" == "filename.ext" - +
- +
@@ -10951,9 +11352,9 @@ C "filename.ext" == "filename.ext" - +
- +
@@ -10989,9 +11390,9 @@ C true == true - +
- +
@@ -11011,9 +11412,9 @@ C 0 == 0 - +
- +
@@ -11033,9 +11434,9 @@ C 0 == 0 - +
- +
@@ -11055,9 +11456,9 @@ C 1 == 1 - +
- +
@@ -11077,9 +11478,9 @@ C 3 == 3 - +
- +
@@ -11099,9 +11500,9 @@ C "colour mode must be one of: default, ansi, win32, or none. 'wrong' is not recognised" contains: "colour mode must be one of" - +
- +
@@ -11121,9 +11522,9 @@ C 200 == 200 - +
- +
@@ -11143,9 +11544,9 @@ C 20000 (0x) == 20000 (0x) - +
- +
@@ -11165,9 +11566,9 @@ C 0.99 == Approx( 0.99 ) - +
- +
@@ -11187,9 +11588,9 @@ C true - +
- +
@@ -11209,11 +11610,11 @@ C 10 == 10 - +
- +
- +
@@ -11224,7 +11625,7 @@ C 3 >= 1 - + @@ -11235,7 +11636,7 @@ C 2 >= 1 - + @@ -11246,7 +11647,7 @@ C 1 >= 1 - + @@ -11273,7 +11674,7 @@ C Catch::generateRandomSeed(method) - + @@ -11284,7 +11685,7 @@ C Catch::generateRandomSeed(static_cast<Catch::GenerateFrom>(77)) - + @@ -11295,7 +11696,7 @@ C "{ }" == "{ }" - + @@ -11306,7 +11707,7 @@ C Hey, its truthy! - + @@ -11333,7 +11734,7 @@ C "this string contains 'abc' as a substring" matches "this string contains 'abc' as a" case sensitively - + @@ -11344,7 +11745,7 @@ C "'::' is not allowed in reporter name: 'with::doublecolons'" equals: "'::' is not allowed in reporter name: 'with::doublecolons'" - + @@ -11355,7 +11756,7 @@ C { 'a', 'b' } not UnorderedEquals: { 'c', 'b' } - + @@ -11367,7 +11768,7 @@ C
- + Tested reporter: Automake @@ -11382,7 +11783,7 @@ C " contains: "fakeTag" - +
@@ -11393,7 +11794,7 @@ C
- + Tested reporter: Automake @@ -11407,7 +11808,7 @@ C " contains: "fake reporter" - +
@@ -11418,7 +11819,7 @@ C
- + Tested reporter: Automake @@ -11434,7 +11835,7 @@ C " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -11445,7 +11846,7 @@ C
- + Tested reporter: compact @@ -11460,7 +11861,7 @@ C " contains: "fakeTag" - +
@@ -11471,7 +11872,7 @@ C
- + Tested reporter: compact @@ -11485,7 +11886,7 @@ C " contains: "fake reporter" - +
@@ -11496,7 +11897,7 @@ C
- + Tested reporter: compact @@ -11512,7 +11913,7 @@ C " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -11523,7 +11924,7 @@ C
- + Tested reporter: console @@ -11538,7 +11939,7 @@ C " contains: "fakeTag" - +
@@ -11549,7 +11950,7 @@ C
- + Tested reporter: console @@ -11563,7 +11964,7 @@ C " contains: "fake reporter" - +
@@ -11574,7 +11975,7 @@ C
- + Tested reporter: console @@ -11590,7 +11991,121 @@ C " ( contains: "fake test name" and contains: "fakeTestTag" ) - + +
+ + + !(factories.empty()) + + + !false + + +
+ + Tested reporter: JSON + + + + listingString, ContainsSubstring("fakeTag"s) + + + "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "tags": [ + { + "aliases": [ + "fakeTag" + ], + "count": 1 + } + ]" contains: "fakeTag" + + + +
+ + + !(factories.empty()) + + + !false + + +
+ + Tested reporter: JSON + + + + listingString, ContainsSubstring("fake reporter"s) + + + "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "reporters": [ + { + "name": "fake reporter", + "description": "fake description" + } + ]" contains: "fake reporter" + + + +
+ + + !(factories.empty()) + + + !false + + +
+ + Tested reporter: JSON + + + + listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) + + + "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "tests": [ + { + "name": "fake test name", + "class-name": "", + "tags": [ + "fakeTestTag" + ], + "source-location": { + "filename": "fake-file.cpp", + "line": 123456789 + } + } + ]" ( contains: "fake test name" and contains: "fakeTestTag" ) + + +
@@ -11601,7 +12116,7 @@ C
- + Tested reporter: JUnit @@ -11617,7 +12132,7 @@ All available tags: " contains: "fakeTag" - +
@@ -11628,7 +12143,7 @@ All available tags:
- + Tested reporter: JUnit @@ -11643,7 +12158,7 @@ Available reporters: " contains: "fake reporter" - +
@@ -11654,7 +12169,7 @@ Available reporters:
- + Tested reporter: JUnit @@ -11671,7 +12186,7 @@ All available test cases: " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -11682,7 +12197,7 @@ All available test cases:
- + Tested reporter: SonarQube @@ -11698,7 +12213,7 @@ All available tags: " contains: "fakeTag" - +
@@ -11709,7 +12224,7 @@ All available tags:
- + Tested reporter: SonarQube @@ -11724,7 +12239,7 @@ Available reporters: " contains: "fake reporter" - +
@@ -11735,7 +12250,7 @@ Available reporters:
- + Tested reporter: SonarQube @@ -11752,7 +12267,7 @@ All available test cases: " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -11763,7 +12278,7 @@ All available test cases:
- + Tested reporter: TAP @@ -11778,7 +12293,7 @@ All available test cases: " contains: "fakeTag" - +
@@ -11789,7 +12304,7 @@ All available test cases:
- + Tested reporter: TAP @@ -11803,7 +12318,7 @@ All available test cases: " contains: "fake reporter" - +
@@ -11814,7 +12329,7 @@ All available test cases:
- + Tested reporter: TAP @@ -11830,7 +12345,7 @@ All available test cases: " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -11841,7 +12356,7 @@ All available test cases:
- + Tested reporter: TeamCity @@ -11856,7 +12371,7 @@ All available test cases: " contains: "fakeTag" - +
@@ -11867,7 +12382,7 @@ All available test cases:
- + Tested reporter: TeamCity @@ -11881,7 +12396,7 @@ All available test cases: " contains: "fake reporter" - +
@@ -11892,7 +12407,7 @@ All available test cases:
- + Tested reporter: TeamCity @@ -11908,7 +12423,7 @@ All available test cases: " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -11919,7 +12434,7 @@ All available test cases:
- + Tested reporter: XML @@ -11938,7 +12453,7 @@ All available test cases: </TagsFromMatchingTests>" contains: "fakeTag" - +
@@ -11949,7 +12464,7 @@ All available test cases:
- + Tested reporter: XML @@ -11966,7 +12481,7 @@ All available test cases: </AvailableReporters>" contains: "fake reporter" - +
@@ -11977,7 +12492,7 @@ All available test cases:
- + Tested reporter: XML @@ -11999,18 +12514,18 @@ All available test cases: </MatchingTests>" ( contains: "fake test name" and contains: "fakeTestTag" ) - +
- +
- + - + - +
@@ -12032,13 +12547,13 @@ All available test cases: 1 > 0 - +
- + - + - +
@@ -12062,29 +12577,29 @@ All available test cases: true - +
- + - + - + - + - +
- +
- +
- +
- +
@@ -12132,15 +12647,15 @@ All available test cases: 10 >= 10 - +
- + - + - + - +
@@ -12169,16 +12684,16 @@ All available test cases: 0 == 0 - +
- + - + - +
- + A string sent directly to stdout @@ -12253,16 +12768,16 @@ A string sent to stderr via clog Approx( 1.23 ) != 1.24 - +
- +
- +
- + Message from section one Message from section two @@ -12286,7 +12801,7 @@ Message from section two "this string contains 'abc' as a substring" starts with: "string" (case insensitive) - +
@@ -12298,7 +12813,7 @@ Message from section two "{ 1 }" == "{ 1 }" - +
@@ -12309,7 +12824,7 @@ Message from section two "{ 3, 2, 1 }" == "{ 3, 2, 1 }" - +
@@ -12322,9 +12837,9 @@ Message from section two "{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }" - +
- +
@@ -12391,7 +12906,7 @@ Message from section two "this string contains 'abc' as a substring" ends with: " substring" (case insensitive) - +
@@ -12419,7 +12934,7 @@ Message from section two 0 == 0 - +
@@ -12454,7 +12969,7 @@ Message from section two "hello" == "hello" - +
@@ -12473,7 +12988,7 @@ Message from section two original.data() - +
@@ -12484,7 +12999,7 @@ Message from section two "original string" == "original string" - +
@@ -12495,7 +13010,7 @@ Message from section two "original string" == "original string" - +
@@ -12531,9 +13046,9 @@ Message from section two hello == "hello" - +
- +
@@ -12553,9 +13068,9 @@ Message from section two 0 == 0 - +
- +
@@ -12567,9 +13082,9 @@ Message from section two "hello world!" == "hello world!" - +
- +
@@ -12581,9 +13096,9 @@ Message from section two "hello world!" == "hello world!" - +
- +
@@ -12595,9 +13110,9 @@ Message from section two true - +
- +
@@ -12609,9 +13124,9 @@ Message from section two 0 == 0 - +
- +
@@ -12623,9 +13138,9 @@ Message from section two true - +
- +
@@ -12652,7 +13167,7 @@ Message from section two Hello != Hel - +
@@ -12672,9 +13187,9 @@ Message from section two 17 == 17 - +
- +
@@ -12694,9 +13209,9 @@ Message from section two 17 == 17 - +
- +
@@ -12716,9 +13231,9 @@ Message from section two 17 == 17 - +
- +
@@ -12738,9 +13253,9 @@ Message from section two 11 == 11 - +
- +
@@ -12760,9 +13275,9 @@ Message from section two 11 == 11 - +
- +
@@ -12775,7 +13290,7 @@ Message from section two "some string += the stringref contents" - +
@@ -12786,18 +13301,18 @@ Message from section two "abrakadabra" == "abrakadabra" - +
- +
- +
- +
- +
@@ -12816,7 +13331,7 @@ Message from section two ""abc"" == ""abc"" - + @@ -12835,7 +13350,7 @@ Message from section two ""abc"" == ""abc"" - + @@ -12854,7 +13369,7 @@ Message from section two ""abc"" == ""abc"" - + @@ -12889,7 +13404,7 @@ Message from section two 1 ns != 1 us - + @@ -12908,7 +13423,7 @@ Message from section two 1 ps != 1 as - + @@ -12921,7 +13436,7 @@ Message from section two {iso8601-timestamp} - + @@ -12939,7 +13454,7 @@ Message from section two " - +
@@ -12983,7 +13498,7 @@ Message from section two Redefined at: file:10" contains: "10" - +
@@ -13018,9 +13533,9 @@ Message from section two registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) - +
- +
@@ -13039,7 +13554,7 @@ Message from section two { {?}, {?} } ( Contains: {?} and Contains: {?} ) - + @@ -13050,7 +13565,7 @@ Message from section two 1 == 1 - + @@ -13061,7 +13576,7 @@ Message from section two 1 == 1 - + @@ -13072,7 +13587,7 @@ Message from section two 1.0 == 1 - + @@ -13083,7 +13598,7 @@ Message from section two 1 > 0 - + @@ -13094,7 +13609,7 @@ Message from section two 4 > 0 - + @@ -13105,7 +13620,7 @@ Message from section two 1 > 0 - + @@ -13116,7 +13631,7 @@ Message from section two 4 > 0 - + @@ -13127,7 +13642,7 @@ Message from section two 4 > 0 - + @@ -13138,7 +13653,7 @@ Message from section two 1 > 0 - + @@ -13149,7 +13664,7 @@ Message from section two 4 > 0 - + @@ -13185,7 +13700,7 @@ Message from section two 10 >= 10 - + @@ -13229,9 +13744,9 @@ Message from section two 0 == 0 - + - + @@ -13266,7 +13781,7 @@ Message from section two 10 >= 10 - + @@ -13301,9 +13816,9 @@ Message from section two 5 >= 5 - + - + @@ -13339,7 +13854,7 @@ Message from section two 10 >= 10 - + @@ -13383,9 +13898,9 @@ Message from section two 0 == 0 - + - + @@ -13420,7 +13935,7 @@ Message from section two 10 >= 10 - + @@ -13455,9 +13970,9 @@ Message from section two 5 >= 5 - + - + @@ -13493,7 +14008,7 @@ Message from section two 10 >= 10 - + @@ -13537,9 +14052,9 @@ Message from section two 0 == 0 - + - + @@ -13574,7 +14089,7 @@ Message from section two 10 >= 10 - + @@ -13609,9 +14124,9 @@ Message from section two 5 >= 5 - + - + @@ -13647,7 +14162,7 @@ Message from section two 10 >= 10 - + @@ -13691,9 +14206,9 @@ Message from section two 0 == 0 - + - + @@ -13728,7 +14243,7 @@ Message from section two 10 >= 10 - + @@ -13763,9 +14278,9 @@ Message from section two 5 >= 5 - + - + @@ -13801,7 +14316,7 @@ Message from section two 12 >= 12 - + @@ -13845,9 +14360,9 @@ Message from section two 0 == 0 - + - + @@ -13882,7 +14397,7 @@ Message from section two 12 >= 12 - + @@ -13917,9 +14432,9 @@ Message from section two 6 >= 6 - + - + @@ -13955,7 +14470,7 @@ Message from section two 8 >= 8 - + @@ -13999,9 +14514,9 @@ Message from section two 0 == 0 - + - + @@ -14036,7 +14551,7 @@ Message from section two 8 >= 8 - + @@ -14071,9 +14586,9 @@ Message from section two 4 >= 4 - + - + @@ -14109,7 +14624,7 @@ Message from section two 10 >= 10 - + @@ -14153,9 +14668,9 @@ Message from section two 0 == 0 - + - + @@ -14190,7 +14705,7 @@ Message from section two 10 >= 10 - + @@ -14225,9 +14740,9 @@ Message from section two 5 >= 5 - + - + @@ -14263,7 +14778,7 @@ Message from section two 30 >= 30 - + @@ -14307,9 +14822,9 @@ Message from section two 0 == 0 - + - + @@ -14344,7 +14859,7 @@ Message from section two 30 >= 30 - + @@ -14379,9 +14894,9 @@ Message from section two 15 >= 15 - + - + @@ -14400,10 +14915,10 @@ Message from section two {?} == {?} - + - + @@ -14414,10 +14929,10 @@ Message from section two 3221225472 (0x) == 3221225472 - + - + @@ -14452,7 +14967,7 @@ Message from section two false - + @@ -14464,7 +14979,7 @@ Message from section two - + @@ -14476,7 +14991,51 @@ Message from section two - + + + + + + true + + + true + + + + + {Unknown expression after the reported line} + + + {Unknown expression after the reported line} + + + Uncaught exception should fail! + + + + + + + + false + + + false + + + + + {Unknown expression after the reported line} + + + {Unknown expression after the reported line} + + + Uncaught exception should fail! + + + @@ -14487,7 +15046,7 @@ Message from section two 1 == 2 - +
@@ -14503,7 +15062,7 @@ Message from section two " contains: "[fakeTag]" - +
@@ -14517,7 +15076,7 @@ Message from section two " ( contains: "fake reporter" and contains: "fake description" ) - +
@@ -14533,7 +15092,7 @@ Message from section two " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -14547,18 +15106,18 @@ Message from section two " ( contains: "fakeListener" and contains: "fake description" ) - +
- +
- + For some reason someone is throwing a string literal! - + @@ -14610,7 +15169,7 @@ Message from section two true - + @@ -14710,9 +15269,9 @@ Message from section two true - + - + @@ -14820,9 +15379,9 @@ Message from section two true - + - + @@ -14923,11 +15482,11 @@ Message from section two true - + - + - + @@ -15060,11 +15619,11 @@ Message from section two true - + - + - + @@ -15131,9 +15690,9 @@ Message from section two true - + - + @@ -15216,13 +15775,189 @@ There is no extra whitespace here There is no extra whitespace here - + + + +
+
+ + + array_int_a, RangeEquals( c_array ) + + + { 1, 2, 3 } elements are { 1, 2, 3 } + + + + + array_int_a, UnorderedRangeEquals( c_array ) + + + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + + + +
+ +
+
+
+ + + array_int_3, !RangeEquals( array_int_4 ) + + + { 1, 2, 3 } not elements are { 1, 2, 3, 4 } + + + + + array_int_3, !UnorderedRangeEquals( array_int_4 ) + + + { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } + + + +
+ +
+
+
+ + + array_int_a, RangeEquals( vector_char_a ) + + + { 1, 2, 3 } elements are { 1, 2, 3 } + + + + + array_int_a, UnorderedRangeEquals( vector_char_a ) + + + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + + + +
+ +
+
+
+ + + array_int_a, RangeEquals( list_char_a ) + + + { 1, 2, 3 } elements are { 1, 2, 3 } + + + + + array_int_a, UnorderedRangeEquals( list_char_a ) + + + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + + + +
+ +
+
+
+ + + vector_int_a, RangeEquals( vector_char_a ) + + + { 1, 2, 3 } elements are { 1, 2, 3 } + + + + + vector_int_a, UnorderedRangeEquals( vector_char_a ) + + + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + + + +
+ +
+
+
+ + + vector_int_a, !RangeEquals( vector_char_b ) + + + { 1, 2, 3 } not elements are { 1, 2, 2 } + + + + + vector_int_a, !UnorderedRangeEquals( vector_char_b ) + + + { 1, 2, 3 } not unordered elements are { 1, 2, 2 } + + + +
+ +
+
+ + + a, !RangeEquals( b ) + + + { 1, 2, 3 } not elements are { 3, 2, 1 } + + + + + a, UnorderedRangeEquals( b ) + + + { 1, 2, 3 } unordered elements are { 3, 2, 1 } + + + +
+
+
+ + + vector_a, RangeEquals( array_a_plus_1, close_enough ) + + + { 1, 2, 3 } elements are { 2, 3, 4 } + + + + + vector_a, UnorderedRangeEquals( array_a_plus_1, close_enough ) + + + { 1, 2, 3 } unordered elements are { 2, 3, 4 } + + + +
+ +
+
3.14 - +
@@ -15234,7 +15969,7 @@ There is no extra whitespace here 3 == 3 - +
@@ -15245,9 +15980,9 @@ There is no extra whitespace here 3 == 3 - +
- +
@@ -15267,7 +16002,7 @@ There is no extra whitespace here { { 0, 1, 2, 3, 5 }, { 4, -3, -2, 5, 0 }, { 0, 0, 0, 5, 0 }, { 0, -5, 0, 5, 0 }, { 1, 0, 0, -1, 5 } } not all match ( contains element 0 and contains element 1 ) - +
@@ -15278,7 +16013,7 @@ There is no extra whitespace here { 1, 2, 3, 4, 5 } all match matches undescribed predicate - +
@@ -15330,9 +16065,9 @@ There is no extra whitespace here true - +
- +
@@ -15384,11 +16119,11 @@ There is no extra whitespace here !false - +
- +
- +
@@ -15401,9 +16136,9 @@ There is no extra whitespace here { true, true, true, true, true } contains only true - +
- +
@@ -15415,12 +16150,12 @@ There is no extra whitespace here { } contains only true - +
- +
-
+
data, !AllTrue() @@ -15429,9 +16164,9 @@ There is no extra whitespace here { true, true, false, true, true } not contains only true - +
- +
@@ -15443,9 +16178,9 @@ There is no extra whitespace here { false, false, false, false, false } not contains only true - +
- +
@@ -15457,12 +16192,12 @@ There is no extra whitespace here { true, true, true, true, true } contains only true - +
- +
-
+
data, !AllTrue() @@ -15471,9 +16206,9 @@ There is no extra whitespace here { true, true, false, true, true } not contains only true - +
- +
@@ -15485,9 +16220,9 @@ There is no extra whitespace here { false, false, false, false, false } not contains only true - +
- +
@@ -15539,9 +16274,9 @@ There is no extra whitespace here true - +
- +
@@ -15593,11 +16328,11 @@ There is no extra whitespace here !false - +
- +
- +
@@ -15617,7 +16352,7 @@ There is no extra whitespace here { { 0, 1, 2, 3, 5 }, { 4, -3, -2, 5, 0 }, { 0, 0, 0, 5, 0 }, { 0, -5, 0, 5, 0 }, { 1, 0, 0, -1, 5 } } not any match ( contains element 0 and contains element 10 ) - +
@@ -15628,7 +16363,7 @@ There is no extra whitespace here { 1, 2, 3, 4, 5 } any match matches undescribed predicate - +
@@ -15680,9 +16415,9 @@ There is no extra whitespace here true - +
- +
@@ -15734,11 +16469,11 @@ There is no extra whitespace here !false - +
- +
- +
@@ -15751,9 +16486,9 @@ There is no extra whitespace here { true, true, true, true, true } contains at least one true - +
- +
@@ -15765,12 +16500,12 @@ There is no extra whitespace here { } not contains at least one true - +
- +
-
+
data, AnyTrue() @@ -15779,9 +16514,9 @@ There is no extra whitespace here { false, false, true, false, false } contains at least one true - +
- +
@@ -15793,9 +16528,9 @@ There is no extra whitespace here { false, false, false, false, false } not contains at least one true - +
- +
@@ -15807,12 +16542,12 @@ There is no extra whitespace here { true, true, true, true, true } contains at least one true - +
- +
-
+
data, AnyTrue() @@ -15821,9 +16556,9 @@ There is no extra whitespace here { false, false, true, false, false } contains at least one true - +
- +
@@ -15835,9 +16570,9 @@ There is no extra whitespace here { false, false, false, false, false } not contains at least one true - +
- +
@@ -15889,9 +16624,9 @@ There is no extra whitespace here true - +
- +
@@ -15943,11 +16678,11 @@ There is no extra whitespace here !false - +
- +
- +
@@ -15967,7 +16702,7 @@ There is no extra whitespace here { { 0, 1, 2, 3, 5 }, { 4, -3, -2, 5, 0 }, { 0, 0, 0, 5, 0 }, { 0, -5, 0, 5, 0 }, { 1, 0, 0, -1, 5 } } not none match ( contains element 0 and contains element 1 ) - +
@@ -15978,7 +16713,7 @@ There is no extra whitespace here { 1, 2, 3, 4, 5 } none match matches undescribed predicate - +
@@ -16030,9 +16765,9 @@ There is no extra whitespace here true - +
- +
@@ -16084,11 +16819,11 @@ There is no extra whitespace here !false - +
- +
- +
@@ -16101,9 +16836,9 @@ There is no extra whitespace here { true, true, true, true, true } not contains no true - +
- +
@@ -16115,12 +16850,12 @@ There is no extra whitespace here { } contains no true - +
- +
-
+
data, !NoneTrue() @@ -16129,9 +16864,9 @@ There is no extra whitespace here { false, false, true, false, false } not contains no true - +
- +
@@ -16143,9 +16878,9 @@ There is no extra whitespace here { false, false, false, false, false } contains no true - +
- +
@@ -16157,12 +16892,12 @@ There is no extra whitespace here { true, true, true, true, true } not contains no true - +
- +
-
+
data, !NoneTrue() @@ -16171,9 +16906,9 @@ There is no extra whitespace here { false, false, true, false, false } not contains no true - +
- +
@@ -16185,9 +16920,9 @@ There is no extra whitespace here { false, false, false, false, false } contains no true - +
- +
@@ -16239,9 +16974,9 @@ There is no extra whitespace here true - +
- +
@@ -16293,11 +17028,387 @@ There is no extra whitespace here !false - +
- +
- + + + +
+
+ + + empty_vector, RangeEquals( empty_vector ) + + + { } elements are { } + + + +
+ +
+
+
+ + + empty_vector, !RangeEquals( non_empty_vector ) + + + { } not elements are { 1 } + + + + + non_empty_vector, !RangeEquals( empty_vector ) + + + { 1 } not elements are { } + + + +
+ +
+
+
+ + + non_empty_array, RangeEquals( non_empty_array ) + + + { 1 } elements are { 1 } + + + +
+ +
+
+
+ + + array_a, RangeEquals( array_a ) + + + { 1, 2, 3 } elements are { 1, 2, 3 } + + + +
+ +
+
+
+ + + array_a, !RangeEquals( array_b ) + + + { 1, 2, 3 } not elements are { 2, 2, 3 } + + + + + array_a, !RangeEquals( array_c ) + + + { 1, 2, 3 } not elements are { 1, 2, 2 } + + + +
+ +
+
+
+ + + vector_a, !RangeEquals( vector_b ) + + + { 1, 2, 3 } not elements are { 1, 2, 3, 4 } + + + +
+ +
+
+
+ + + vector_a, RangeEquals( vector_a_plus_1, close_enough ) + + + { 1, 2, 3 } elements are { 2, 3, 4 } + + + +
+ +
+
+
+ + + vector_a, !RangeEquals( vector_b, close_enough ) + + + { 1, 2, 3 } not elements are { 3, 3, 4 } + + + +
+ +
+
+ + + needs_adl1, RangeEquals( needs_adl2 ) + + + { 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 } + + + + + needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) + + + { 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 } + + + +
+
+
+ + + mocked1, !RangeEquals( arr ) + + + { 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 } + + + + + mocked1.m_derefed[0] + + + true + + + + + mocked1.m_derefed[1] + + + true + + + + + mocked1.m_derefed[2] + + + true + + + + + !(mocked1.m_derefed[3]) + + + !false + + + +
+ +
+
+
+ + + mocked1, RangeEquals( arr ) + + + { 1, 2, 3, 4 } elements are { 1, 2, 3, 4 } + + + + + mocked1.m_derefed[0] + + + true + + + + + mocked1.m_derefed[1] + + + true + + + + + mocked1.m_derefed[2] + + + true + + + + + mocked1.m_derefed[3] + + + true + + + +
+ +
+ +
+ +
+
+ + + empty_vector, UnorderedRangeEquals( empty_vector ) + + + { } unordered elements are { } + + + +
+ +
+
+
+ + + empty_vector, !UnorderedRangeEquals( non_empty_vector ) + + + { } not unordered elements are { 1 } + + + + + non_empty_vector, !UnorderedRangeEquals( empty_vector ) + + + { 1 } not unordered elements are { } + + + +
+ +
+
+
+ + + non_empty_array, UnorderedRangeEquals( non_empty_array ) + + + { 1 } unordered elements are { 1 } + + + +
+ +
+
+
+ + + array_a, UnorderedRangeEquals( array_a ) + + + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + + + +
+ +
+
+
+ + + array_a, !UnorderedRangeEquals( array_b ) + + + { 1, 2, 3 } not unordered elements are { 2, 2, 3 } + + + +
+ +
+
+
+ + + vector_a, !UnorderedRangeEquals( vector_b ) + + + { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } + + + +
+ +
+
+
+ + + vector_a, UnorderedRangeEquals( vector_a_plus_1, close_enough ) + + + { 1, 10, 20 } unordered elements are { 11, 21, 2 } + + + +
+ +
+
+
+ + + vector_a, !UnorderedRangeEquals( vector_b, close_enough ) + + + { 1, 10, 21 } not unordered elements are { 11, 21, 3 } + + + +
+ +
+
+ + + needs_adl1, UnorderedRangeEquals( needs_adl2 ) + + + { 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 } + + + +
+
@@ -16357,7 +17468,7 @@ There is no extra whitespace here { {?}, {?}, {?} } has size == 3 - +
@@ -16368,7 +17479,7 @@ There is no extra whitespace here {?} has size == 12 - +
@@ -16379,9 +17490,9 @@ There is no extra whitespace here {?} has size == 13 - +
- +
@@ -16448,13 +17559,13 @@ There is no extra whitespace here Approx( 1.23 ) != 1.25 - +
- +
- +
@@ -16466,7 +17577,7 @@ There is no extra whitespace here { } is approx: { } - +
@@ -16486,9 +17597,9 @@ There is no extra whitespace here { 1.0, 2.0, 3.0 } is approx: { 1.0, 2.0, 3.0 } - +
- +
@@ -16500,9 +17611,9 @@ There is no extra whitespace here { 1.0, 2.0, 3.0 } not is approx: { 1.0, 2.0, 3.0, 4.0 } - +
- +
@@ -16538,11 +17649,11 @@ There is no extra whitespace here { 1.0, 2.0, 3.0 } is approx: { 1.5, 2.5, 3.5 } - +
- +
- +
@@ -16554,7 +17665,7 @@ There is no extra whitespace here { } is approx: { 1.0, 2.0 } - +
@@ -16565,9 +17676,9 @@ There is no extra whitespace here { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 } - +
- +
@@ -16595,7 +17706,7 @@ There is no extra whitespace here { 1, 2, 3 } Contains: 2 - +
@@ -16662,7 +17773,7 @@ There is no extra whitespace here { 1, 2, 3 } Contains: { 1, 2 } - +
@@ -16673,7 +17784,7 @@ There is no extra whitespace here { 1, 2, 3 } ( Contains: 1 and Contains: 2 ) - +
@@ -16724,7 +17835,7 @@ There is no extra whitespace here { 1, 2, 3 } Equals: { 1, 2, 3 } - +
@@ -16783,9 +17894,9 @@ There is no extra whitespace here { 1, 3, 2 } UnorderedEquals: { 1, 2, 3 } - +
- +
@@ -16805,7 +17916,7 @@ There is no extra whitespace here { } Contains: 1 - +
@@ -16824,7 +17935,7 @@ There is no extra whitespace here { 1, 2, 3 } Contains: { 1, 2, 4 } - +
@@ -16859,7 +17970,7 @@ There is no extra whitespace here { 1, 2, 3 } Equals: { } - +
@@ -16894,9 +18005,9 @@ There is no extra whitespace here { 3, 1 } UnorderedEquals: { 1, 2, 3 } - +
- +
@@ -16923,13 +18034,13 @@ There is no extra whitespace here thisThrows() - + unexpected exception - + @@ -16943,7 +18054,7 @@ There is no extra whitespace here expected exception - + @@ -16957,7 +18068,7 @@ There is no extra whitespace here expected exception - + @@ -16971,31 +18082,31 @@ There is no extra whitespace here expected exception - +
unexpected exception - +
- +
- + - + - + - + - +
@@ -17007,7 +18118,7 @@ There is no extra whitespace here "normal string" == "normal string" - +
@@ -17018,7 +18129,7 @@ There is no extra whitespace here "" == "" - +
@@ -17029,7 +18140,7 @@ There is no extra whitespace here "smith &amp; jones" == "smith &amp; jones" - +
@@ -17040,7 +18151,7 @@ There is no extra whitespace here "smith &lt; jones" == "smith &lt; jones" - +
@@ -17061,7 +18172,7 @@ There is no extra whitespace here "smith ]]&gt; jones" - +
@@ -17084,7 +18195,7 @@ There is no extra whitespace here "don't &quot;quote&quot; me on that" - +
@@ -17095,7 +18206,7 @@ There is no extra whitespace here "[\x01]" == "[\x01]" - +
@@ -17106,9 +18217,9 @@ There is no extra whitespace here "[\x7F]" == "[\x7F]" - +
- +
@@ -17121,7 +18232,11 @@ There is no extra whitespace here " ( contains: "attr1="true"" and contains: "attr2="false"" ) - + + + + + @@ -17228,7 +18343,7 @@ There is no extra whitespace here 0.0 == 0 - + @@ -17255,7 +18370,7 @@ There is no extra whitespace here "{ 42, 250 }" == "{ 42, 250 }" - +
@@ -17299,7 +18414,7 @@ There is no extra whitespace here 1 == 1 - +
@@ -17342,9 +18457,9 @@ There is no extra whitespace here 1 == 1 - +
- +
@@ -17355,7 +18470,7 @@ There is no extra whitespace here 0x != 0 - + @@ -17374,7 +18489,7 @@ There is no extra whitespace here true - + @@ -17393,7 +18508,7 @@ There is no extra whitespace here false - + @@ -17412,7 +18527,7 @@ There is no extra whitespace here true - + @@ -17431,7 +18546,7 @@ There is no extra whitespace here false - +
@@ -17483,7 +18598,7 @@ There is no extra whitespace here 0 == 0 - +
@@ -17534,7 +18649,7 @@ There is no extra whitespace here 1 == 1 - +
@@ -17585,7 +18700,7 @@ There is no extra whitespace here 1 == 1 - +
@@ -17636,7 +18751,7 @@ There is no extra whitespace here 1 == 1 - +
@@ -17687,7 +18802,7 @@ There is no extra whitespace here 1 == 1 - +
@@ -17738,9 +18853,9 @@ There is no extra whitespace here 2 == 2 - +
- +
@@ -17775,7 +18890,7 @@ There is no extra whitespace here 1 == 1 - + @@ -17810,7 +18925,7 @@ There is no extra whitespace here 1 == 1 - + @@ -17865,7 +18980,16 @@ There is no extra whitespace here 1 == 1 - + + + + + skipping because answer = 41 + + + skipping because answer = 43 + + @@ -17876,7 +19000,7 @@ There is no extra whitespace here Catch::TestCaseInfo("", { "test with an empty tag", "[]" }, dummySourceLineInfo) - + @@ -17903,7 +19027,7 @@ There is no extra whitespace here 1.3859038243 == Approx( 1.3859038243 ) - + @@ -17922,53 +19046,83 @@ There is no extra whitespace here 0 == 0 - +
- +
- +
- +
- +
- +
- + +
+ + + + 3 == 4 + + + 3 == 4 + + + + + + + + + + + + + +
+ + +
+
+ + +
+
- + loose text artifact - + - + Previous info should not be seen - + previous unscoped info SHOULD not be seen - + - + - + @@ -17981,7 +19135,7 @@ loose text artifact 9223372036854775807 (0x) - +
@@ -17993,7 +19147,7 @@ loose text artifact 0 > 1 - +
@@ -18004,7 +19158,7 @@ loose text artifact 1 > 1 - +
@@ -18015,7 +19169,7 @@ loose text artifact 2 > 1 - +
@@ -18026,7 +19180,7 @@ loose text artifact 3 > 1 - +
@@ -18037,7 +19191,7 @@ loose text artifact 4 > 1 - +
@@ -18048,7 +19202,7 @@ loose text artifact 5 > 1 - +
@@ -18059,7 +19213,7 @@ loose text artifact 6 > 1 - +
@@ -18070,7 +19224,7 @@ loose text artifact 7 > 1 - +
@@ -18081,7 +19235,7 @@ loose text artifact 8 > 1 - +
@@ -18092,12 +19246,12 @@ loose text artifact 9 > 1 - +
- +
- + Testing if fib[0] (1) is even @@ -18108,7 +19262,7 @@ loose text artifact 1 == 0 - + Testing if fib[1] (1) is even @@ -18119,7 +19273,7 @@ loose text artifact 1 == 0 - + Testing if fib[2] (2) is even @@ -18130,7 +19284,7 @@ loose text artifact 0 == 0 - + Testing if fib[3] (3) is even @@ -18141,7 +19295,7 @@ loose text artifact 1 == 0 - + Testing if fib[4] (5) is even @@ -18152,7 +19306,7 @@ loose text artifact 1 == 0 - + Testing if fib[5] (8) is even @@ -18163,7 +19317,7 @@ loose text artifact 0 == 0 - + Testing if fib[6] (13) is even @@ -18174,7 +19328,7 @@ loose text artifact 1 == 0 - + Testing if fib[7] (21) is even @@ -18185,7 +19339,7 @@ loose text artifact 1 == 0 - + @@ -18196,7 +19350,7 @@ loose text artifact Catch::makeStream( "%debug" ) - +
@@ -18208,7 +19362,7 @@ loose text artifact !false - +
@@ -18219,7 +19373,7 @@ loose text artifact true - +
@@ -18230,9 +19384,9 @@ loose text artifact {?} == {?} - +
- +
@@ -18243,7 +19397,7 @@ loose text artifact 19.0 == 19.0 - + @@ -18310,28 +19464,28 @@ loose text artifact 1 == 1 - + - + info - + unscoped info - + and warn may mix - + info - + unscoped info - + they are not cleared after warnings - +
@@ -18344,9 +19498,9 @@ loose text artifact 1 == 2 - +
- +
@@ -18358,9 +19512,9 @@ loose text artifact 1 != 2 - +
- +
@@ -18372,11 +19526,11 @@ loose text artifact 1 < 2 - +
- +
- +
@@ -18405,11 +19559,39 @@ loose text artifact 1 != 2 - +
- +
- + + + +
+ +
+
+
+ +
+ +
+
+
+ + +
+ +
+
+ +
+ + +a! +b1! +! + +
@@ -18420,7 +19602,7 @@ loose text artifact "7" == "7" - + @@ -18431,7 +19613,7 @@ loose text artifact {?} == {?} - + @@ -18474,7 +19656,7 @@ loose text artifact 0.088096521 == Approx( 0.088096521 ) - + @@ -18501,13 +19683,13 @@ loose text artifact -1.9599639845 == Approx( -1.9599639845 ) - + - + - + this MAY be seen only for the FIRST assertion IF info is printed for passing assertions @@ -18518,7 +19700,7 @@ loose text artifact true - + this MAY be seen only for the SECOND assertion IF info is printed for passing assertions @@ -18529,7 +19711,7 @@ loose text artifact true - + this SHOULD be seen @@ -18540,7 +19722,7 @@ loose text artifact false - + @@ -18559,7 +19741,7 @@ loose text artifact {null string} == {null string} - + @@ -18570,7 +19752,7 @@ loose text artifact 0 == 0 - + @@ -18583,7 +19765,7 @@ loose text artifact "{ { 42, "Arthur" }, { "Ford", 24 } }" - +
@@ -18595,7 +19777,7 @@ loose text artifact { } Equals: { } - +
@@ -18622,7 +19804,7 @@ loose text artifact { Value1 } Equals: { Value1 } - +
@@ -18649,9 +19831,9 @@ loose text artifact { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 } - +
- +
@@ -18662,10 +19844,10 @@ loose text artifact 0 == 0 - + - + this MAY be seen IF info is printed for passing assertions @@ -18676,13 +19858,13 @@ loose text artifact true - + - + this SHOULD be seen - + this SHOULD also be seen @@ -18693,10 +19875,10 @@ loose text artifact false - + - + this SHOULD be seen only ONCE @@ -18715,7 +19897,7 @@ loose text artifact true - + this MAY also be seen only ONCE IF info is printed for passing assertions @@ -18734,7 +19916,7 @@ loose text artifact true - +
@@ -18754,7 +19936,7 @@ loose text artifact 2 != 1 - +
@@ -18765,9 +19947,9 @@ loose text artifact 1 != 2 - +
- +
@@ -18787,7 +19969,7 @@ loose text artifact "azcdefcg" == "azcdefcg" - +
@@ -18806,7 +19988,7 @@ loose text artifact "abzdefzg" == "abzdefzg" - +
@@ -18825,7 +20007,7 @@ loose text artifact "zbcdefcg" == "zbcdefcg" - +
@@ -18844,7 +20026,7 @@ loose text artifact "abcdefcz" == "abcdefcz" - +
@@ -18863,7 +20045,7 @@ loose text artifact "replaced" == "replaced" - +
@@ -18882,7 +20064,7 @@ loose text artifact "abcdefcg" == "abcdefcg" - +
@@ -18901,9 +20083,9 @@ loose text artifact "didn|'t" == "didn|'t" - +
- +
@@ -18914,7 +20096,7 @@ loose text artifact Catch::makeStream( "%somestream" ) - + @@ -18997,7 +20179,7 @@ loose text artifact 1000.0 == 1000 (0x) - + @@ -19088,7 +20270,7 @@ loose text artifact 128 >= 100 - + @@ -19179,13 +20361,26 @@ loose text artifact 128 >= 100 - + - + + + +
+ +
+
+ + +
+
+ +
+
- + 3 @@ -19196,13 +20391,13 @@ loose text artifact false - + - + hi - + i := 7 @@ -19213,7 +20408,7 @@ loose text artifact false - + @@ -19224,7 +20419,13 @@ loose text artifact { {?}, {?} } ( Contains: {?} and Contains: {?} ) - + + + + + skipping because answer = 43 + + @@ -19251,19 +20452,19 @@ loose text artifact { abc, def } Equals: { abc, def } - + - + Count 1 to 3... - + 1 - + 2 - + 3 @@ -19274,16 +20475,16 @@ loose text artifact false - + Count 4 to 6... - + 4 - + 5 - + 6 @@ -19294,7 +20495,7 @@ loose text artifact false - + @@ -19321,7 +20522,7 @@ loose text artifact true - +
@@ -19333,7 +20534,7 @@ loose text artifact "{ }" == "{ }" - +
@@ -19344,7 +20545,7 @@ loose text artifact "{ { "one", 1 } }" == "{ { "one", 1 } }" - +
@@ -19357,9 +20558,9 @@ loose text artifact "{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }" - +
- +
@@ -19370,7 +20571,7 @@ loose text artifact "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" - + @@ -19381,7 +20582,7 @@ loose text artifact "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" - +
@@ -19393,7 +20594,7 @@ loose text artifact "{ }" == "{ }" - +
@@ -19404,7 +20605,7 @@ loose text artifact "{ "one" }" == "{ "one" }" - +
@@ -19417,9 +20618,9 @@ loose text artifact "{ "abc", "def", "ghi" }" - +
- +
@@ -19432,7 +20633,7 @@ loose text artifact "{ { "green", 55 } }" - + @@ -19451,7 +20652,7 @@ loose text artifact true - + @@ -19490,7 +20691,7 @@ loose text artifact "{?}" == "{?}" - + @@ -19503,7 +20704,7 @@ loose text artifact "StringMaker<has_maker>" - + @@ -19516,7 +20717,7 @@ loose text artifact "StringMaker<has_maker_and_operator>" - + @@ -19527,7 +20728,7 @@ loose text artifact "{?}" == "{?}" - + @@ -19540,7 +20741,7 @@ loose text artifact "operator<<( has_operator )" - + @@ -19553,7 +20754,7 @@ loose text artifact "operator<<( has_template_operator )" - + @@ -19566,7 +20767,7 @@ loose text artifact "{ StringMaker<has_maker> }" - + @@ -19579,7 +20780,7 @@ loose text artifact "{ StringMaker<has_maker_and_operator> }" - + @@ -19592,7 +20793,7 @@ loose text artifact "{ operator<<( has_operator ) }" - + @@ -19627,7 +20828,7 @@ loose text artifact 4 == 4 - + @@ -19662,7 +20863,7 @@ loose text artifact 6 == 6 - + @@ -19681,13 +20882,17 @@ loose text artifact magic.tag == magic.tag - + + + + + Why would you throw a std::string? - + @@ -19698,7 +20903,7 @@ loose text artifact ""wide load"" == ""wide load"" - + @@ -19709,7 +20914,7 @@ loose text artifact ""wide load"" == ""wide load"" - + @@ -19720,7 +20925,7 @@ loose text artifact ""wide load"" == ""wide load"" - + @@ -19731,7 +20936,7 @@ loose text artifact ""wide load"" == ""wide load"" - + @@ -19760,7 +20965,7 @@ loose text artifact "Unknown enum value 10" - + @@ -19779,7 +20984,7 @@ loose text artifact "1" == "1" - + @@ -19798,7 +21003,7 @@ loose text artifact "E2{1}" == "E2{1}" - + @@ -19817,7 +21022,7 @@ loose text artifact "1" == "1" - + @@ -19836,7 +21041,7 @@ loose text artifact "{ }" == "{ }" - + @@ -19855,7 +21060,7 @@ loose text artifact "{ 1.2f, 0 }" == "{ 1.2f, 0 }" - + @@ -19866,7 +21071,7 @@ loose text artifact "{ 0 }" == "{ 0 }" - + @@ -19879,7 +21084,7 @@ loose text artifact "{ "hello", "world" }" - + @@ -19892,7 +21097,7 @@ loose text artifact "{ { 42 }, { }, 1.2f }" - + @@ -19927,7 +21132,26 @@ loose text artifact 0.95 == 0.95 - + + + + + + dist.a() == -10 + + + -10 == -10 + + + + + dist.b() == 10 + + + 10 == 10 + + +
@@ -19947,7 +21171,7 @@ loose text artifact 0 == 0 - +
@@ -19991,9 +21215,9 @@ loose text artifact 0 == 0 - +
- +
@@ -20045,9 +21269,9 @@ loose text artifact 2 == 2 - +
- +
@@ -20066,7 +21290,7 @@ loose text artifact 0 == 0 - +
@@ -20093,7 +21317,7 @@ loose text artifact 1 == 1 - +
@@ -20120,7 +21344,7 @@ loose text artifact 2 == 2 - +
@@ -20139,9 +21363,9 @@ loose text artifact 1 == 1 - +
- +
@@ -20162,7 +21386,7 @@ loose text artifact "{ { "hello" }, { "world" } }" - + @@ -20189,7 +21413,7 @@ loose text artifact "{ true, false }" == "{ true, false }" - + @@ -20216,7 +21440,7 @@ loose text artifact "{ 42, 250 }" == "{ 42, 250 }" - + @@ -20243,7 +21467,7 @@ loose text artifact "{ 42, 250 }" == "{ 42, 250 }" - + @@ -20272,7 +21496,7 @@ loose text artifact "{ "hello", "world" }" - + @@ -20308,7 +21532,7 @@ loose text artifact 10 >= 10 - + @@ -20352,9 +21576,9 @@ loose text artifact 0 == 0 - + - + @@ -20389,7 +21613,7 @@ loose text artifact 10 >= 10 - + @@ -20424,9 +21648,9 @@ loose text artifact 5 >= 5 - + - + @@ -20445,7 +21669,7 @@ loose text artifact 310016000 ns > 100 ms - + @@ -20472,17 +21696,17 @@ loose text artifact 23.0 == 23.0 - +
- +
- +
- +
- - + + diff --git a/tests/SelfTest/Baselines/xml.sw.multi.approved.txt b/tests/SelfTest/Baselines/xml.sw.multi.approved.txt index a0096170..08ff6c43 100644 --- a/tests/SelfTest/Baselines/xml.sw.multi.approved.txt +++ b/tests/SelfTest/Baselines/xml.sw.multi.approved.txt @@ -1,7 +1,7 @@ - + - + @@ -20,7 +20,7 @@ 0 == 0 - + @@ -71,16 +71,16 @@ {?} >= {?} - + - + - + uarr := "123" - + sarr := "456" @@ -91,10 +91,10 @@ 0 == 0 - + uarr := "123" - + sarr := "456" @@ -105,16 +105,16 @@ 0 == 0 - + - +
- +
- +
@@ -125,24 +125,24 @@ [1403 helper] == [1403 helper] - + - + This info message starts with a linebreak - + This warning message starts with a linebreak - + 1514 - + This would not be caught previously @@ -160,7 +160,7 @@ Nor would this true - + @@ -187,7 +187,7 @@ Nor would this !false - +
@@ -215,7 +215,7 @@ Nor would this !false - +
@@ -226,9 +226,9 @@ Nor would this true - +
- +
@@ -247,7 +247,7 @@ Nor would this 6 < 7 - + @@ -282,11 +282,11 @@ Nor would this 2 != 4 - +
- +
@@ -297,7 +297,7 @@ Nor would this 1 - +
@@ -308,7 +308,7 @@ Nor would this 2 - +
@@ -319,9 +319,9 @@ Nor would this 3 - +
- +
@@ -333,7 +333,7 @@ Nor would this 1 - +
@@ -351,7 +351,7 @@ Nor would this 3 - +
@@ -378,100 +378,100 @@ Nor would this 3 - +
- +
- + i := 1 - + j := 3 - + k := 5
- +
- + i := 1 - + j := 3 - + k := 6
- +
- + i := 1 - + j := 4 - + k := 5 - + i := 1 - + j := 4 - + k := 6
- +
- + i := 2 - + j := 3 - + k := 5
- +
- + i := 2 - + j := 3 - + k := 6
- +
- + i := 2 - + j := 4 - + k := 5 - + i := 2 - + j := 4 - + k := 6 - +
@@ -618,16 +618,16 @@ Nor would this 3 - + - + - + - + @@ -646,7 +646,7 @@ Nor would this 0.0 not is within 1 ULPs of -4.9406564584124654e-324 ([-9.8813129168249309e-324, -0.0000000000000000e+00]) - + @@ -665,20 +665,26 @@ Nor would this 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0.00000000e+00]) - + + + + + failure to init + +
- + answer := 42 expected exception - +
- + answer := 42 @@ -692,10 +698,10 @@ Nor would this expected exception - +
- + answer := 42 @@ -706,9 +712,9 @@ Nor would this thisThrows() - +
- +
@@ -719,7 +725,7 @@ Nor would this 42 == {?} - + @@ -778,7 +784,7 @@ Nor would this true - + @@ -797,10 +803,10 @@ Nor would this 1 == 1 - + - + dummy := 0 @@ -811,25 +817,25 @@ Nor would this {?} == 4 - +
- +
- +
- +
- +
- +
- +
@@ -896,7 +902,7 @@ Nor would this !(1 == 1) - + @@ -963,7 +969,7 @@ Nor would this !(1 == 2) - +
@@ -983,7 +989,7 @@ Nor would this true == true - +
@@ -1002,7 +1008,7 @@ Nor would this false == false - +
@@ -1013,7 +1019,7 @@ Nor would this true - +
@@ -1024,7 +1030,7 @@ Nor would this true - +
@@ -1043,9 +1049,9 @@ Nor would this !false - +
- +
@@ -1696,7 +1702,7 @@ Nor would this 3 < 9 - + @@ -1707,7 +1713,7 @@ Nor would this "hello" == "world" - + @@ -1718,7 +1724,7 @@ Nor would this "hello" == "hello" - + @@ -1729,7 +1735,7 @@ Nor would this 0 == 1 - + @@ -1740,7 +1746,7 @@ Nor would this 0 == 1 - + @@ -1751,7 +1757,7 @@ Nor would this 0 == 1 - + @@ -1762,7 +1768,7 @@ Nor would this 0 == 1 - + @@ -1773,7 +1779,7 @@ Nor would this 0 == 0 - + @@ -1784,7 +1790,7 @@ Nor would this 0 == 0 - + @@ -1795,7 +1801,7 @@ Nor would this 0 == 0 - + @@ -1806,7 +1812,7 @@ Nor would this 0 == 0 - + @@ -1817,7 +1823,7 @@ Nor would this 6 < 2 - + @@ -1828,7 +1834,7 @@ Nor would this 2 < 2 - + @@ -1839,7 +1845,7 @@ Nor would this 6 < 2 - + @@ -1850,7 +1856,7 @@ Nor would this 2 < 2 - + @@ -1861,7 +1867,7 @@ Nor would this 6 >= 2 - + @@ -1872,7 +1878,7 @@ Nor would this 2 >= 2 - + @@ -1883,7 +1889,7 @@ Nor would this 6 >= 2 - + @@ -1894,7 +1900,7 @@ Nor would this 2 >= 2 - + @@ -1905,7 +1911,7 @@ Nor would this 1.0 == 2 - + @@ -1916,7 +1922,7 @@ Nor would this 1.0f == 2 - + @@ -1927,7 +1933,7 @@ Nor would this 1 == 2 - + @@ -1938,7 +1944,7 @@ Nor would this 1.0 == 1 - + @@ -1949,7 +1955,7 @@ Nor would this 1.0f == 1 - + @@ -1960,7 +1966,7 @@ Nor would this 1 == 1 - + @@ -1971,7 +1977,7 @@ Nor would this 1 == 0 - + @@ -1982,7 +1988,7 @@ Nor would this 3 == 0 - + @@ -1993,7 +1999,7 @@ Nor would this 6 == 0 - + @@ -2004,7 +2010,7 @@ Nor would this 1 > 0 - + @@ -2015,7 +2021,7 @@ Nor would this 3 > 0 - + @@ -2026,7 +2032,7 @@ Nor would this 6 > 0 - + @@ -2037,7 +2043,7 @@ Nor would this 1 == 2 - + @@ -2048,7 +2054,7 @@ Nor would this 1 == 1 - + @@ -2059,7 +2065,7 @@ Nor would this 0 == 0 - + @@ -2070,7 +2076,7 @@ Nor would this 0 == 0 - + @@ -2081,7 +2087,7 @@ Nor would this 0 == 0 - + @@ -2092,7 +2098,7 @@ Nor would this 0 == 0 - + @@ -2103,7 +2109,7 @@ Nor would this 42 > 0 - + @@ -2114,7 +2120,7 @@ Nor would this 9 > 0 - + @@ -2125,7 +2131,7 @@ Nor would this 42 > 0 - + @@ -2136,7 +2142,7 @@ Nor would this 9 > 0 - + @@ -2187,19 +2193,19 @@ Nor would this 1.23 == Approx( 1.0 ) - +
- +
- +
to infinity and beyond - +
@@ -2218,7 +2224,7 @@ Nor would this {?} == {?} - + @@ -2269,10 +2275,10 @@ Nor would this 100.3 == Approx( 100.0 ) - + - + @@ -2291,7 +2297,7 @@ Nor would this 8 == 8 - + @@ -2313,10 +2319,10 @@ Nor would this unexpected exception
- + - + @@ -2375,7 +2381,7 @@ Nor would this Approx(0).epsilon(1.0001), std::domain_error - + @@ -2418,7 +2424,7 @@ Nor would this 245.5f == Approx( 245.25 ) - + @@ -2437,7 +2443,7 @@ Nor would this 3.1428571429 != Approx( 3.141 ) - + @@ -2456,7 +2462,7 @@ Nor would this 1.23 == Approx( 1.231 ) - + @@ -2475,7 +2481,7 @@ Nor would this 0.0f == Approx( 0.0 ) - + @@ -2494,7 +2500,7 @@ Nor would this 0 == Approx( 0.0 ) - + @@ -2537,7 +2543,7 @@ Nor would this 1.234 == Approx( 1.2339999676 ) - +
@@ -2557,7 +2563,7 @@ Nor would this 1 not matches predicate: "always false" - +
@@ -2576,9 +2582,9 @@ Nor would this "This wouldn't pass" not matches undescribed predicate - +
- +
@@ -2621,7 +2627,7 @@ Nor would this !(Val: 1 ^ Val: 1) - + @@ -2650,9 +2656,9 @@ Nor would this true - + - + @@ -2680,11 +2686,11 @@ Nor would this true - + - + - +
@@ -2712,7 +2718,7 @@ Nor would this { 4, 5, 6 } not contains element 1 - +
@@ -2739,7 +2745,7 @@ Nor would this { 4, 5, 6 } not contains element 0 - +
@@ -2750,7 +2756,7 @@ Nor would this { "abc", "abcd", "abcde" } contains element 4 - +
@@ -2769,7 +2775,7 @@ Nor would this { 1, 2, 3, 4, 5 } not contains element 8 - +
@@ -2788,7 +2794,7 @@ Nor would this { 1, 2, 3 } not contains element 9 - +
@@ -2799,9 +2805,9 @@ Nor would this { 1.0, 2.0, 3.0, 0.0 } contains element matching is within 0.5 of 0.5 - +
- +
@@ -2853,7 +2859,7 @@ Nor would this { } is empty - +
@@ -2864,7 +2870,7 @@ Nor would this {?} not is empty - +
@@ -2875,97 +2881,97 @@ Nor would this {?} is empty - +
- +
- + a := 1 - + b := 2 - + c := 3 - + a + b := 3 - + a+b := 3 - + c > b := true - + a == 1 := true - + - - std::vector<int>{1, 2, 3}[0, 1, 2] := 3 + + custom_index_op<int>{1, 2, 3}[0, 1, 2] := 0 - - std::vector<int>{1, 2, 3}[(0, 1)] := 2 + + custom_index_op<int>{1, 2, 3}[(0, 1)] := 0 - - std::vector<int>{1, 2, 3}[0] := 1 + + custom_index_op<int>{1, 2, 3}[0] := 0 - + (helper_1436<int, int>{12, -12}) := { 12, -12 } - + (helper_1436<int, int>(-12, 12)) := { -12, 12 } - + (1, 2) := 2 - + (2, 3) := 3 - + - + ("comma, in string", "escaped, \", ") := "escaped, ", " - + "single quote in string,'," := "single quote in string,'," - + "some escapes, \\,\\\\" := "some escapes, \,\\" - + "some, ), unmatched, } prenheses {[<" := "some, ), unmatched, } prenheses {[<" - + '"' := '"' - + '\'' := ''' - + ',' := ',' - + '}' := '}' - + ')' := ')' - + '(' := '(' - + '{' := '{' - +
- + i := 2 @@ -2976,10 +2982,10 @@ Nor would this true - +
- + 3 @@ -2990,9 +2996,9 @@ Nor would this true - +
- +
@@ -3012,7 +3018,7 @@ Nor would this !false - +
@@ -3063,9 +3069,9 @@ Nor would this !false - +
- +
@@ -3093,7 +3099,7 @@ Nor would this !false - +
@@ -3128,9 +3134,9 @@ Nor would this true - +
- +
@@ -3166,7 +3172,7 @@ Nor would this '\f' == '\f' - +
@@ -3209,7 +3215,7 @@ Nor would this 'Z' == 'Z' - +
@@ -3252,9 +3258,9 @@ Nor would this 5 == 5 - +
- +
@@ -3273,7 +3279,7 @@ Nor would this "foo" == "foo" - +
@@ -3285,7 +3291,7 @@ Nor would this !{?} - +
@@ -3304,9 +3310,9 @@ Nor would this { "aaa", "bbb" } == { "aaa", "bbb" } - +
- +
@@ -3318,7 +3324,7 @@ Nor would this true - +
@@ -3341,7 +3347,7 @@ Using code: 0 " - +
@@ -3364,9 +3370,9 @@ C " - +
- +
@@ -3393,7 +3399,7 @@ C 1 ( equals: (int) 1 or (string) "1" and equals: (long long) 1 and equals: (T) 1 and equals: true ) - + @@ -3420,7 +3426,7 @@ C 1 ( equals: (int) 1 or (string) "1" or equals: (long long) 1 or equals: (T) 1 or equals: true ) - + @@ -3455,10 +3461,10 @@ C 1 equals: (int) 1 or (string) "1" - + - + @@ -3485,7 +3491,7 @@ C 1 ( equals: (int) 1 or (string) "1" or not equals: (long long) 1 ) - + @@ -3544,7 +3550,7 @@ C "foobar" ( ( starts with: "foo" and ends with: "bar" ) or Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } ) - + @@ -3555,7 +3561,7 @@ C { 1, 2, 3 } ( Equals: { 1, 2, 3 } or Equals: { 0, 1, 2 } or Equals: { 4, 5, 6 } ) - + @@ -3654,7 +3660,7 @@ C { 1, 2 } == { 1, 2 } - + @@ -3673,7 +3679,7 @@ C 0x == 0x - + @@ -3708,7 +3714,7 @@ C !({?} != {?}) - + @@ -3807,7 +3813,7 @@ C Approx( 11.0 ) >= StrongDoubleTypedef(10) - + @@ -3818,7 +3824,7 @@ C 54 == 54 - + @@ -3869,7 +3875,7 @@ C -2147483648 > 2 - + @@ -3976,7 +3982,7 @@ C 4294967295 (0x) > 4 - +
@@ -4004,7 +4010,7 @@ C true - +
@@ -4031,9 +4037,9 @@ C true - +
- +
@@ -4061,7 +4067,7 @@ C true - +
@@ -4088,9 +4094,9 @@ C true - +
- +
@@ -4109,7 +4115,7 @@ C "this string contains 'abc' as a substring" contains: "STRING" - +
@@ -4121,7 +4127,7 @@ C 1 == 1 - +
@@ -4132,7 +4138,7 @@ C 1 == 1 - +
@@ -4143,7 +4149,7 @@ C 1 == 1 - +
@@ -4154,7 +4160,7 @@ C 1 == 1 - +
@@ -4165,7 +4171,7 @@ C 1 == 1 - +
@@ -4176,7 +4182,7 @@ C 1 == 1 - +
@@ -4187,7 +4193,7 @@ C 1 == 1 - +
@@ -4198,7 +4204,7 @@ C 1 == 1 - +
@@ -4209,7 +4215,7 @@ C 1 == 1 - +
@@ -4220,7 +4226,7 @@ C 1 == 1 - +
@@ -4231,7 +4237,7 @@ C 1 == 1 - +
@@ -4242,7 +4248,7 @@ C 1 == 1 - +
@@ -4261,9 +4267,9 @@ C 6 == 6 - +
- +
@@ -4274,7 +4280,7 @@ C true - + @@ -4288,7 +4294,7 @@ C custom exception - not std
- + @@ -4302,13 +4308,13 @@ C custom exception - not std
- + custom std exception - + @@ -4327,7 +4333,7 @@ C 0.00001 != Approx( 0.0000001 ) - + @@ -4356,7 +4362,13 @@ C "{** unexpected enum value **}" - + + + + + This generator is empty + + @@ -4367,18 +4379,7 @@ C true - - - - - - Catch::TestCaseInfo( "", { "fake test name", "[]" }, dummySourceLineInfo ) - - - Catch::TestCaseInfo( "", { "fake test name", "[]" }, dummySourceLineInfo ) - - - + @@ -4397,7 +4398,7 @@ C "this string contains 'abc' as a substring" ends with: "this" (case insensitive) - + @@ -4442,7 +4443,7 @@ C "Value2" == "Value2" - + @@ -4461,7 +4462,7 @@ C "Blue" == "Blue" - + @@ -4472,7 +4473,7 @@ C 101.01 != Approx( 100.0 ) - + @@ -4579,7 +4580,7 @@ C 1.3 == Approx( 1.301 ) - + @@ -4638,7 +4639,7 @@ C 1.3 == Approx( 1.3 ) - + @@ -4657,7 +4658,7 @@ C "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" (case insensitive) - + @@ -4676,7 +4677,7 @@ C "this string contains 'abc' as a substring" equals: "something else" (case insensitive) - + @@ -4707,7 +4708,7 @@ C "StringMakerException" - +
@@ -4727,7 +4728,7 @@ C doesNotThrow(), SpecialException, ExceptionMatcher{ 1 } - +
@@ -4752,7 +4753,7 @@ C Unknown exception - +
@@ -4771,9 +4772,9 @@ C SpecialException::what special exception has value of 1 - +
- +
@@ -4792,7 +4793,42 @@ C SpecialException::what special exception has value of 2 - + + + + + + throwsDerivedException(), DerivedException, MessageMatches( StartsWith( "Derived" ) ) + + + DerivedException::what matches "starts with: "Derived"" + + + + + throwsDerivedException(), DerivedException, MessageMatches( EndsWith( "::what" ) ) + + + DerivedException::what matches "ends with: "::what"" + + + + + throwsDerivedException(), DerivedException, MessageMatches( !StartsWith( "::what" ) ) + + + DerivedException::what matches "not starts with: "::what"" + + + + + throwsSpecialException( 2 ), SpecialException, MessageMatches( StartsWith( "Special" ) ) + + + SpecialException::what matches "starts with: "Special"" + + +
@@ -4804,7 +4840,7 @@ C "expected exception" equals: "expected exception" - +
@@ -4815,7 +4851,7 @@ C "expected exception" equals: "expected exception" (case insensitive) - +
@@ -4850,9 +4886,9 @@ C "expected exception" contains: "except" (case insensitive) - +
- +
@@ -4887,7 +4923,7 @@ C SpecialException::what exception message matches "SpecialException::what" - + @@ -4920,26 +4956,26 @@ C expected exception
- + This is a failure - + - + This is a failure - + This message appears in the output - + @@ -4982,7 +5018,18 @@ C 3628800 (0x) == 3628800 (0x) - + + + + + + filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException + + + filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException + + +
@@ -5027,9 +5074,9 @@ C 0.0 and 2.22507e-308 are within 2.22045e-12% of each other - +
- +
@@ -5096,7 +5143,7 @@ C -10.0 is within 0.5 of -9.6 - +
@@ -5155,7 +5202,7 @@ C -0.0 is within 0 ULPs of 0.0000000000000000e+00 ([0.0000000000000000e+00, 0.0000000000000000e+00]) - +
@@ -5182,7 +5229,7 @@ C 0.0001 ( is within 0.001 of 0.0 or and 0 are within 10% of each other ) - +
@@ -5233,9 +5280,20 @@ C WithinRel( 1., 1. ), std::domain_error - +
- +
+ + + 1., !IsNaN() + + + 1.0 not is NaN + + + +
+
@@ -5280,9 +5338,9 @@ C 0.0f and 1.17549e-38 are within 0.00119209% of each other - +
- +
@@ -5357,7 +5415,7 @@ C -10.0f is within 0.5 of -9.6000003815 - +
@@ -5424,7 +5482,7 @@ C -0.0f is within 0 ULPs of 0.00000000e+00f ([0.00000000e+00, 0.00000000e+00]) - +
@@ -5451,7 +5509,7 @@ C 0.0001f ( is within 0.001 of 0.0 or and 0 are within 10% of each other ) - +
@@ -5510,9 +5568,55 @@ C WithinRel( 1.f, 1.f ), std::domain_error - +
- +
+ + + 1., !IsNaN() + + + 1.0 not is NaN + + + +
+ +
+ + + + i % 2 == 0 + + + 0 == 0 + + + + + i % 2 == 0 + + + 0 == 0 + + + + + i % 2 == 0 + + + 0 == 0 + + + + + i % 2 == 0 + + + 0 == 0 + + +
@@ -5525,9 +5629,9 @@ C 0 == 0 - +
- +
@@ -5539,9 +5643,9 @@ C 0 == 0 - +
- +
@@ -5553,9 +5657,9 @@ C 0 == 0 - +
- +
@@ -5567,9 +5671,9 @@ C filter([] (int) {return false; }, value(1)), Catch::GeneratorException - +
- +
@@ -5580,7 +5684,7 @@ C 1 < 4 - +
@@ -5591,7 +5695,7 @@ C 2 < 4 - +
@@ -5602,7 +5706,7 @@ C 3 < 4 - +
@@ -5614,9 +5718,9 @@ C 0 == 0 - +
- +
@@ -5628,9 +5732,9 @@ C 0 == 0 - +
- +
@@ -5642,9 +5746,9 @@ C 0 == 0 - +
- +
@@ -5656,9 +5760,9 @@ C 1 == 1 - +
- +
@@ -5670,9 +5774,9 @@ C 1 == 1 - +
- +
@@ -5684,9 +5788,9 @@ C 1 == 1 - +
- +
@@ -5698,9 +5802,9 @@ C 1 == 1 - +
- +
@@ -5712,9 +5816,9 @@ C 1 == 1 - +
- +
@@ -5726,9 +5830,9 @@ C 1 == 1 - +
- +
@@ -5739,7 +5843,7 @@ C 1 > 0 - +
@@ -5750,7 +5854,7 @@ C 2 > 0 - +
@@ -5761,7 +5865,7 @@ C 3 > 0 - +
@@ -5772,7 +5876,7 @@ C 1 > 0 - +
@@ -5783,7 +5887,7 @@ C 2 > 0 - +
@@ -5794,7 +5898,7 @@ C 3 > 0 - +
@@ -5814,9 +5918,9 @@ C 1 == 1 - +
- +
@@ -5836,9 +5940,9 @@ C 2 == 2 - +
- +
@@ -5858,9 +5962,9 @@ C 3 == 3 - +
- +
@@ -5888,9 +5992,9 @@ C 1 < 3 - +
- +
@@ -5918,9 +6022,9 @@ C 2 < 3 - +
- +
@@ -5932,9 +6036,9 @@ C 0 == 0 - +
- +
@@ -5946,9 +6050,9 @@ C 0 == 0 - +
- +
@@ -5960,9 +6064,9 @@ C 0 == 0 - +
- +
@@ -5974,11 +6078,11 @@ C chunk(2, value(1)), Catch::GeneratorException - +
- +
- +
@@ -5990,7 +6094,7 @@ C -3 < 1 - +
@@ -6001,7 +6105,7 @@ C -2 < 1 - +
@@ -6012,7 +6116,7 @@ C -1 < 1 - +
@@ -6023,7 +6127,7 @@ C 4 > 1 - +
@@ -6034,7 +6138,7 @@ C 4 > 2 - +
@@ -6045,7 +6149,7 @@ C 4 > 3 - +
@@ -6056,7 +6160,7 @@ C -3 < 2 - +
@@ -6067,7 +6171,7 @@ C -2 < 2 - +
@@ -6078,7 +6182,7 @@ C -1 < 2 - +
@@ -6089,7 +6193,7 @@ C 8 > 1 - +
@@ -6100,7 +6204,7 @@ C 8 > 2 - +
@@ -6111,7 +6215,7 @@ C 8 > 3 - +
@@ -6122,7 +6226,7 @@ C -3 < 3 - +
@@ -6133,7 +6237,7 @@ C -2 < 3 - +
@@ -6144,7 +6248,7 @@ C -1 < 3 - +
@@ -6155,7 +6259,7 @@ C 12 > 1 - +
@@ -6166,7 +6270,7 @@ C 12 > 2 - +
@@ -6177,9 +6281,9 @@ C 12 > 3 - +
- +
@@ -6199,7 +6303,7 @@ C !false - +
@@ -6250,7 +6354,7 @@ C !false - +
@@ -6333,7 +6437,7 @@ C !false - +
@@ -6392,7 +6496,7 @@ C !false - +
@@ -6428,9 +6532,9 @@ C !false - +
- +
@@ -6466,9 +6570,9 @@ C !false - +
- +
@@ -6488,9 +6592,9 @@ C filter([](int) { return false; }, values({ 1, 2, 3 })), Catch::GeneratorException - +
- +
@@ -6526,9 +6630,9 @@ C !false - +
- +
@@ -6548,9 +6652,9 @@ C !false - +
- +
@@ -6601,7 +6705,7 @@ C !false - +
@@ -6652,7 +6756,7 @@ C !false - +
@@ -6672,9 +6776,9 @@ C !false - +
- +
@@ -6774,9 +6878,9 @@ C !false - +
- +
@@ -6845,11 +6949,11 @@ C !false - +
- +
- +
@@ -6918,11 +7022,11 @@ C !false - +
- +
- +
@@ -6992,13 +7096,13 @@ C !false - +
- +
- + - +
@@ -7068,13 +7172,13 @@ C !false - +
- +
- + - +
@@ -7160,19 +7264,19 @@ C !false - +
- +
- + - +
- + Current expected value is -1 @@ -7183,7 +7287,7 @@ C -1.0 == Approx( -1.0 ) - + Current expected value is -1 @@ -7194,7 +7298,7 @@ C true - + Current expected value is -0.9 @@ -7205,7 +7309,7 @@ C -0.9 == Approx( -0.9 ) - + Current expected value is -0.9 @@ -7216,7 +7320,7 @@ C true - + Current expected value is -0.8 @@ -7227,7 +7331,7 @@ C -0.8 == Approx( -0.8 ) - + Current expected value is -0.8 @@ -7238,7 +7342,7 @@ C true - + Current expected value is -0.7 @@ -7249,7 +7353,7 @@ C -0.7 == Approx( -0.7 ) - + Current expected value is -0.7 @@ -7260,7 +7364,7 @@ C true - + Current expected value is -0.6 @@ -7271,7 +7375,7 @@ C -0.6 == Approx( -0.6 ) - + Current expected value is -0.6 @@ -7282,7 +7386,7 @@ C true - + Current expected value is -0.5 @@ -7293,7 +7397,7 @@ C -0.5 == Approx( -0.5 ) - + Current expected value is -0.5 @@ -7304,7 +7408,7 @@ C true - + Current expected value is -0.4 @@ -7315,7 +7419,7 @@ C -0.4 == Approx( -0.4 ) - + Current expected value is -0.4 @@ -7326,7 +7430,7 @@ C true - + Current expected value is -0.3 @@ -7337,7 +7441,7 @@ C -0.3 == Approx( -0.3 ) - + Current expected value is -0.3 @@ -7348,7 +7452,7 @@ C true - + Current expected value is -0.2 @@ -7359,7 +7463,7 @@ C -0.2 == Approx( -0.2 ) - + Current expected value is -0.2 @@ -7370,7 +7474,7 @@ C true - + Current expected value is -0.1 @@ -7381,7 +7485,7 @@ C -0.1 == Approx( -0.1 ) - + Current expected value is -0.1 @@ -7392,7 +7496,7 @@ C true - + Current expected value is -1.38778e-16 @@ -7403,7 +7507,7 @@ C -0.0 == Approx( -0.0 ) - + Current expected value is -1.38778e-16 @@ -7414,7 +7518,7 @@ C true - + Current expected value is 0.1 @@ -7425,7 +7529,7 @@ C 0.1 == Approx( 0.1 ) - + Current expected value is 0.1 @@ -7436,7 +7540,7 @@ C true - + Current expected value is 0.2 @@ -7447,7 +7551,7 @@ C 0.2 == Approx( 0.2 ) - + Current expected value is 0.2 @@ -7458,7 +7562,7 @@ C true - + Current expected value is 0.3 @@ -7469,7 +7573,7 @@ C 0.3 == Approx( 0.3 ) - + Current expected value is 0.3 @@ -7480,7 +7584,7 @@ C true - + Current expected value is 0.4 @@ -7491,7 +7595,7 @@ C 0.4 == Approx( 0.4 ) - + Current expected value is 0.4 @@ -7502,7 +7606,7 @@ C true - + Current expected value is 0.5 @@ -7513,7 +7617,7 @@ C 0.5 == Approx( 0.5 ) - + Current expected value is 0.5 @@ -7524,7 +7628,7 @@ C true - + Current expected value is 0.6 @@ -7535,7 +7639,7 @@ C 0.6 == Approx( 0.6 ) - + Current expected value is 0.6 @@ -7546,7 +7650,7 @@ C true - + Current expected value is 0.7 @@ -7557,7 +7661,7 @@ C 0.7 == Approx( 0.7 ) - + Current expected value is 0.7 @@ -7568,7 +7672,7 @@ C true - + Current expected value is 0.8 @@ -7579,7 +7683,7 @@ C 0.8 == Approx( 0.8 ) - + Current expected value is 0.8 @@ -7590,7 +7694,7 @@ C true - + Current expected value is 0.9 @@ -7601,7 +7705,7 @@ C 0.9 == Approx( 0.9 ) - + Current expected value is 0.9 @@ -7628,19 +7732,19 @@ C !false - +
- +
- +
- +
- + Current expected value is -1 @@ -7651,7 +7755,7 @@ C -1.0 == Approx( -1.0 ) - + Current expected value is -1 @@ -7662,7 +7766,7 @@ C true - + Current expected value is -0.7 @@ -7673,7 +7777,7 @@ C -0.7 == Approx( -0.7 ) - + Current expected value is -0.7 @@ -7684,7 +7788,7 @@ C true - + Current expected value is -0.4 @@ -7695,7 +7799,7 @@ C -0.4 == Approx( -0.4 ) - + Current expected value is -0.4 @@ -7706,7 +7810,7 @@ C true - + Current expected value is -0.1 @@ -7717,7 +7821,7 @@ C -0.1 == Approx( -0.1 ) - + Current expected value is -0.1 @@ -7728,7 +7832,7 @@ C true - + Current expected value is 0.2 @@ -7739,7 +7843,7 @@ C 0.2 == Approx( 0.2 ) - + Current expected value is 0.2 @@ -7750,7 +7854,7 @@ C true - + Current expected value is 0.5 @@ -7761,7 +7865,7 @@ C 0.5 == Approx( 0.5 ) - + Current expected value is 0.5 @@ -7780,19 +7884,19 @@ C !false - +
- +
- +
- +
- + Current expected value is -1 @@ -7803,7 +7907,7 @@ C -1.0 == Approx( -1.0 ) - + Current expected value is -1 @@ -7814,7 +7918,7 @@ C true - + Current expected value is -0.7 @@ -7825,7 +7929,7 @@ C -0.7 == Approx( -0.7 ) - + Current expected value is -0.7 @@ -7836,7 +7940,7 @@ C true - + Current expected value is -0.4 @@ -7847,7 +7951,7 @@ C -0.4 == Approx( -0.4 ) - + Current expected value is -0.4 @@ -7858,7 +7962,7 @@ C true - + Current expected value is -0.1 @@ -7869,7 +7973,7 @@ C -0.1 == Approx( -0.1 ) - + Current expected value is -0.1 @@ -7880,7 +7984,7 @@ C true - + Current expected value is 0.2 @@ -7891,7 +7995,7 @@ C 0.2 == Approx( 0.2 ) - + Current expected value is 0.2 @@ -7902,7 +8006,7 @@ C true - + Current expected value is 0.5 @@ -7913,7 +8017,7 @@ C 0.5 == Approx( 0.5 ) - + Current expected value is 0.5 @@ -7932,13 +8036,13 @@ C !false - +
- +
- +
- +
@@ -8008,13 +8112,13 @@ C !false - +
- +
- + - +
@@ -8084,13 +8188,13 @@ C !false - +
- +
- + - +
@@ -8176,15 +8280,15 @@ C !false - +
- +
- + - + - +
@@ -8219,7 +8323,7 @@ C 1.23 >= Approx( 1.24 ) - + @@ -8232,7 +8336,7 @@ C 130711275 (0x) - + @@ -8245,7 +8349,7 @@ C 3422778688 (0x) - +
@@ -8259,7 +8363,7 @@ C 2668622104 (0x) - +
@@ -8272,7 +8376,7 @@ C 3916075712 (0x) - +
@@ -8285,9 +8389,9 @@ C 3429949824 (0x) - +
- +
@@ -8300,22 +8404,34 @@ C 3422778688 (0x) - + + + + + This info has multiple parts. + + + This unscoped info has multiple parts. + + + Show infos! + + - + this is a message - + this is a warning - + - + this message should be logged - + so should this @@ -8326,10 +8442,10 @@ C 2 == 1 - + - + this message may be logged later @@ -8340,10 +8456,10 @@ C 2 == 2 - + this message may be logged later - + this message should be logged @@ -8354,13 +8470,13 @@ C 2 == 1 - + this message may be logged later - + this message should be logged - + and this, but later @@ -8371,16 +8487,16 @@ C 2 == 0 - + this message may be logged later - + this message should be logged - + and this, but later - + but not this @@ -8391,13 +8507,13 @@ C 2 == 2 - + - + current counter 0 - + i := 0 @@ -8408,10 +8524,10 @@ C 0 < 10 - + current counter 1 - + i := 1 @@ -8422,10 +8538,10 @@ C 1 < 10 - + current counter 2 - + i := 2 @@ -8436,10 +8552,10 @@ C 2 < 10 - + current counter 3 - + i := 3 @@ -8450,10 +8566,10 @@ C 3 < 10 - + current counter 4 - + i := 4 @@ -8464,10 +8580,10 @@ C 4 < 10 - + current counter 5 - + i := 5 @@ -8478,10 +8594,10 @@ C 5 < 10 - + current counter 6 - + i := 6 @@ -8492,10 +8608,10 @@ C 6 < 10 - + current counter 7 - + i := 7 @@ -8506,10 +8622,10 @@ C 7 < 10 - + current counter 8 - + i := 8 @@ -8520,10 +8636,10 @@ C 8 < 10 - + current counter 9 - + i := 9 @@ -8534,10 +8650,10 @@ C 9 < 10 - + current counter 10 - + i := 10 @@ -8548,7 +8664,21 @@ C 10 < 10 - + + + + + + Dummy + + + Dummy + + + Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE + + + @@ -8591,7 +8721,7 @@ C 5 != 5 - + @@ -8682,7 +8812,278 @@ C 5 != 6 - + + + +
+ + + stream.str() == "" + + + "" == "" + + + +
+
+ + + stream.str() == "{\n}" + + + "{ +}" +== +"{ +}" + + + +
+
+ + + stream.str(), ContainsSubstring( "\"int\": 1," ) && ContainsSubstring( "\"double\": 1.5," ) && ContainsSubstring( "\"true\": true," ) && ContainsSubstring( "\"false\": false," ) && ContainsSubstring( "\"string\": \"this is a string\"," ) && ContainsSubstring( "\"array\": [\n 1,\n 2\n ]\n}" ) + + + "{ + "int": 1, + "double": 1.5, + "true": true, + "false": false, + "string": "this is a string", + "array": [ + 1, + 2 + ] +}" ( contains: ""int": 1," and contains: ""double": 1.5," and contains: ""true": true," and contains: ""false": false," and contains: ""string": "this is a string"," and contains: ""array": [ + 1, + 2 + ] +}" ) + + + +
+
+ + + stream.str(), ContainsSubstring( "\"empty_object\": {\n }," ) && ContainsSubstring( "\"fully_object\": {\n \"key\": 1\n }" ) + + + "{ + "empty_object": { + }, + "fully_object": { + "key": 1 + } +}" ( contains: ""empty_object": { + }," and contains: ""fully_object": { + "key": 1 + }" ) + + + +
+
+ + + stream.str() == "[\n]" + + + "[ +]" +== +"[ +]" + + + +
+
+ + + stream.str() == "[\n 1,\n 1.5,\n true,\n false,\n \"this is a string\",\n {\n \"object\": 42\n },\n [\n \"array\",\n 42.5\n ]\n]" + + + "[ + 1, + 1.5, + true, + false, + "this is a string", + { + "object": 42 + }, + [ + "array", + 42.5 + ] +]" +== +"[ + 1, + 1.5, + true, + false, + "this is a string", + { + "object": 42 + }, + [ + "array", + 42.5 + ] +]" + + + +
+
+ + + stream.str() == "{\n}" + + + "{ +}" +== +"{ +}" + + + +
+
+ + + stream.str() == "[\n]" + + + "[ +]" +== +"[ +]" + + + +
+
+ + + stream.str() == "\"custom\"" + + + ""custom"" == ""custom"" + + + +
+ +
+ +
+ + + sstream.str() == "\"\\\"\"" + + + ""\""" == ""\""" + + + +
+
+ + + sstream.str() == "\"\\\\\"" + + + ""\\"" == ""\\"" + + + +
+
+ + + sstream.str() == "\"/\"" + + + ""/"" == ""/"" + + + +
+
+ + + sstream.str() == "\"\\b\"" + + + ""\b"" == ""\b"" + + + +
+
+ + + sstream.str() == "\"\\f\"" + + + ""\f"" == ""\f"" + + + +
+
+ + + sstream.str() == "\"\\n\"" + + + ""\n"" == ""\n"" + + + +
+
+ + + sstream.str() == "\"\\r\"" + + + ""\r"" == ""\r"" + + + +
+
+ + + sstream.str() == "\"\\t\"" + + + ""\t"" == ""\t"" + + + +
+
+ + + sstream.str() == "\"\\\\/\\t\\r\\n\"" + + + ""\\/\t\r\n"" == ""\\/\t\r\n"" + + + +
+
@@ -8693,7 +9094,7 @@ C true - + @@ -8728,10 +9129,10 @@ C 1.23 <= Approx( 1.22 ) - + - + @@ -8742,7 +9143,7 @@ C "this string contains 'abc' as a substring" ( contains: "string" and contains: "abc" and contains: "substring" and contains: "contains" ) - + @@ -8761,7 +9162,7 @@ C "some completely different text that contains one common word" ( contains: "string" or contains: "different" or contains: "random" ) - + @@ -8772,7 +9173,7 @@ C "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "substring" ) - + @@ -8783,7 +9184,7 @@ C "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" ) - + @@ -8794,7 +9195,7 @@ C "this string contains 'abc' as a substring" not contains: "different" - + @@ -8805,44 +9206,44 @@ C "this string contains 'abc' as a substring" not contains: "substring" - +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
@@ -8861,7 +9262,7 @@ C "expected exception" equals: "should fail" - + @@ -8874,7 +9275,7 @@ C { "Hello", "world", "Goodbye", "world" } - + @@ -8942,7 +9343,7 @@ C true == true - + @@ -9009,9 +9410,9 @@ C true == true - + - + @@ -9142,19 +9543,19 @@ C 99 > -6 - + - + This one ran - + custom exception - + @@ -9181,10 +9582,10 @@ C !{?} - + - + @@ -9339,7 +9740,7 @@ C "hello" <= "a" - + @@ -9478,7 +9879,7 @@ C "hello" > "a" - +
@@ -9532,7 +9933,7 @@ C 1827115164 (0x) - +
@@ -9635,24 +10036,24 @@ C 4261393167 (0x) - +
- +
Message from section one - +
Message from section two - +
- +
@@ -9687,7 +10088,7 @@ C ( EvilMatcher() && EvilMatcher() ) || !EvilMatcher() - +
@@ -9723,7 +10124,7 @@ C {?} == {?} - +
@@ -9782,9 +10183,9 @@ C !{?} - +
- +
@@ -9811,7 +10212,7 @@ C true - +
@@ -9831,7 +10232,7 @@ C 8 == 8 - +
@@ -9850,7 +10251,7 @@ C "Could not parse '-1' as shard count" contains: "Could not parse '-1' as shard count" - +
@@ -9869,7 +10270,7 @@ C "Shard count must be positive" contains: "Shard count must be positive" - +
@@ -9888,7 +10289,7 @@ C 2 == 2 - +
@@ -9907,7 +10308,7 @@ C "Could not parse '-12' as shard index" contains: "Could not parse '-12' as shard index" - +
@@ -9926,12 +10327,12 @@ C 0 == 0 - +
- +
- + tagString := "[tag with spaces]" @@ -9942,7 +10343,7 @@ C true - + tagString := "[tag with spaces]" @@ -9953,7 +10354,7 @@ C true - + tagString := "[tag with spaces]" @@ -9964,7 +10365,7 @@ C true - + tagString := "[I said "good day" sir!]" @@ -9975,7 +10376,7 @@ C true - + tagString := "[I said "good day" sir!]" @@ -9986,7 +10387,7 @@ C true - + tagString := "[I said "good day" sir!]" @@ -9997,7 +10398,7 @@ C true - +
@@ -10017,7 +10418,7 @@ C 1 == 1 - +
@@ -10028,7 +10429,7 @@ C !{?} - +
@@ -10047,9 +10448,9 @@ C 3 == 3 - +
- +
@@ -10116,7 +10517,7 @@ C 0 != 0x - +
@@ -10136,7 +10537,7 @@ C 13 == 13 - +
@@ -10155,9 +10556,9 @@ C 17 == 17 - +
- +
@@ -10168,7 +10569,7 @@ C "foo" matches undescribed predicate - +
@@ -10188,7 +10589,7 @@ C "" == "" - +
@@ -10279,7 +10680,7 @@ C {?} == {?} - +
@@ -10315,9 +10716,9 @@ C true - +
- +
@@ -10353,9 +10754,9 @@ C true - +
- +
@@ -10391,13 +10792,13 @@ C true - +
- +
- + result.errorMessage() := "" @@ -10408,7 +10809,7 @@ C {?} - + result.errorMessage() := "" @@ -10419,13 +10820,13 @@ C { {?} } == { {?} } - +
- +
- + result.errorMessage() := "" @@ -10436,7 +10837,7 @@ C {?} - + result.errorMessage() := "" @@ -10447,13 +10848,13 @@ C { {?} } == { {?} } - +
- +
- + result.errorMessage() := "" @@ -10464,7 +10865,7 @@ C {?} - + result.errorMessage() := "" @@ -10475,9 +10876,9 @@ C { {?} } == { {?} } - +
- +
@@ -10497,13 +10898,13 @@ C "Unrecognized reporter, 'unsupported'. Check available with --list-reporters" contains: "Unrecognized reporter" - +
- +
- + result.errorMessage() := "" @@ -10514,7 +10915,7 @@ C {?} - + result.errorMessage() := "" @@ -10525,13 +10926,13 @@ C { {?} } == { {?} } - +
- +
- + result.errorMessage() := "" @@ -10542,7 +10943,7 @@ C {?} - + result.errorMessage() := "" @@ -10553,9 +10954,9 @@ C { {?} } == { {?} } - +
- +
@@ -10576,11 +10977,11 @@ C { {?}, {?} } == { {?}, {?} } - +
- +
- +
@@ -10601,11 +11002,11 @@ C { {?}, {?} } == { {?}, {?} } - +
- +
- +
@@ -10626,11 +11027,11 @@ C "Only one reporter may have unspecified output file." contains: "Only one reporter may have unspecified output file." - +
- +
- +
@@ -10650,9 +11051,9 @@ C true == true - +
- +
@@ -10672,9 +11073,9 @@ C true - +
- +
@@ -10694,9 +11095,9 @@ C 1 == 1 - +
- +
@@ -10716,9 +11117,9 @@ C 2 == 2 - +
- +
@@ -10738,9 +11139,9 @@ C "Unable to convert 'oops' to destination type" ( contains: "convert" and contains: "oops" ) - +
- +
@@ -10761,11 +11162,11 @@ C 0 == 0 - +
- +
- +
@@ -10786,11 +11187,11 @@ C 1 == 1 - +
- +
- +
@@ -10811,11 +11212,11 @@ C 2 == 2 - +
- +
- +
@@ -10836,11 +11237,11 @@ C 3 == 3 - +
- +
- +
@@ -10861,11 +11262,11 @@ C "keypress argument must be one of: never, start, exit or both. 'sometimes' not recognised" ( contains: "never" and contains: "both" ) - +
- +
- +
@@ -10885,9 +11286,9 @@ C true - +
- +
@@ -10907,9 +11308,9 @@ C true - +
- +
@@ -10929,9 +11330,9 @@ C "filename.ext" == "filename.ext" - +
- +
@@ -10951,9 +11352,9 @@ C "filename.ext" == "filename.ext" - +
- +
@@ -10989,9 +11390,9 @@ C true == true - +
- +
@@ -11011,9 +11412,9 @@ C 0 == 0 - +
- +
@@ -11033,9 +11434,9 @@ C 0 == 0 - +
- +
@@ -11055,9 +11456,9 @@ C 1 == 1 - +
- +
@@ -11077,9 +11478,9 @@ C 3 == 3 - +
- +
@@ -11099,9 +11500,9 @@ C "colour mode must be one of: default, ansi, win32, or none. 'wrong' is not recognised" contains: "colour mode must be one of" - +
- +
@@ -11121,9 +11522,9 @@ C 200 == 200 - +
- +
@@ -11143,9 +11544,9 @@ C 20000 (0x) == 20000 (0x) - +
- +
@@ -11165,9 +11566,9 @@ C 0.99 == Approx( 0.99 ) - +
- +
@@ -11187,9 +11588,9 @@ C true - +
- +
@@ -11209,11 +11610,11 @@ C 10 == 10 - +
- +
- +
@@ -11224,7 +11625,7 @@ C 3 >= 1 - + @@ -11235,7 +11636,7 @@ C 2 >= 1 - + @@ -11246,7 +11647,7 @@ C 1 >= 1 - + @@ -11273,7 +11674,7 @@ C Catch::generateRandomSeed(method) - + @@ -11284,7 +11685,7 @@ C Catch::generateRandomSeed(static_cast<Catch::GenerateFrom>(77)) - + @@ -11295,7 +11696,7 @@ C "{ }" == "{ }" - + @@ -11306,7 +11707,7 @@ C Hey, its truthy! - + @@ -11333,7 +11734,7 @@ C "this string contains 'abc' as a substring" matches "this string contains 'abc' as a" case sensitively - + @@ -11344,7 +11745,7 @@ C "'::' is not allowed in reporter name: 'with::doublecolons'" equals: "'::' is not allowed in reporter name: 'with::doublecolons'" - + @@ -11355,7 +11756,7 @@ C { 'a', 'b' } not UnorderedEquals: { 'c', 'b' } - + @@ -11367,7 +11768,7 @@ C
- + Tested reporter: Automake @@ -11382,7 +11783,7 @@ C " contains: "fakeTag" - +
@@ -11393,7 +11794,7 @@ C
- + Tested reporter: Automake @@ -11407,7 +11808,7 @@ C " contains: "fake reporter" - +
@@ -11418,7 +11819,7 @@ C
- + Tested reporter: Automake @@ -11434,7 +11835,7 @@ C " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -11445,7 +11846,7 @@ C
- + Tested reporter: compact @@ -11460,7 +11861,7 @@ C " contains: "fakeTag" - +
@@ -11471,7 +11872,7 @@ C
- + Tested reporter: compact @@ -11485,7 +11886,7 @@ C " contains: "fake reporter" - +
@@ -11496,7 +11897,7 @@ C
- + Tested reporter: compact @@ -11512,7 +11913,7 @@ C " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -11523,7 +11924,7 @@ C
- + Tested reporter: console @@ -11538,7 +11939,7 @@ C " contains: "fakeTag" - +
@@ -11549,7 +11950,7 @@ C
- + Tested reporter: console @@ -11563,7 +11964,7 @@ C " contains: "fake reporter" - +
@@ -11574,7 +11975,7 @@ C
- + Tested reporter: console @@ -11590,7 +11991,121 @@ C " ( contains: "fake test name" and contains: "fakeTestTag" ) - + +
+ + + !(factories.empty()) + + + !false + + +
+ + Tested reporter: JSON + + + + listingString, ContainsSubstring("fakeTag"s) + + + "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "tags": [ + { + "aliases": [ + "fakeTag" + ], + "count": 1 + } + ]" contains: "fakeTag" + + + +
+ + + !(factories.empty()) + + + !false + + +
+ + Tested reporter: JSON + + + + listingString, ContainsSubstring("fake reporter"s) + + + "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "reporters": [ + { + "name": "fake reporter", + "description": "fake description" + } + ]" contains: "fake reporter" + + + +
+ + + !(factories.empty()) + + + !false + + +
+ + Tested reporter: JSON + + + + listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) + + + "{ + "version": 1, + "metadata": { + "name": "", + "rng-seed": 1234, + "catch2-version": "" + }, + "listings": { + "tests": [ + { + "name": "fake test name", + "class-name": "", + "tags": [ + "fakeTestTag" + ], + "source-location": { + "filename": "fake-file.cpp", + "line": 123456789 + } + } + ]" ( contains: "fake test name" and contains: "fakeTestTag" ) + + +
@@ -11601,7 +12116,7 @@ C
- + Tested reporter: JUnit @@ -11617,7 +12132,7 @@ All available tags: " contains: "fakeTag" - +
@@ -11628,7 +12143,7 @@ All available tags:
- + Tested reporter: JUnit @@ -11643,7 +12158,7 @@ Available reporters: " contains: "fake reporter" - +
@@ -11654,7 +12169,7 @@ Available reporters:
- + Tested reporter: JUnit @@ -11671,7 +12186,7 @@ All available test cases: " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -11682,7 +12197,7 @@ All available test cases:
- + Tested reporter: SonarQube @@ -11698,7 +12213,7 @@ All available tags: " contains: "fakeTag" - +
@@ -11709,7 +12224,7 @@ All available tags:
- + Tested reporter: SonarQube @@ -11724,7 +12239,7 @@ Available reporters: " contains: "fake reporter" - +
@@ -11735,7 +12250,7 @@ Available reporters:
- + Tested reporter: SonarQube @@ -11752,7 +12267,7 @@ All available test cases: " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -11763,7 +12278,7 @@ All available test cases:
- + Tested reporter: TAP @@ -11778,7 +12293,7 @@ All available test cases: " contains: "fakeTag" - +
@@ -11789,7 +12304,7 @@ All available test cases:
- + Tested reporter: TAP @@ -11803,7 +12318,7 @@ All available test cases: " contains: "fake reporter" - +
@@ -11814,7 +12329,7 @@ All available test cases:
- + Tested reporter: TAP @@ -11830,7 +12345,7 @@ All available test cases: " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -11841,7 +12356,7 @@ All available test cases:
- + Tested reporter: TeamCity @@ -11856,7 +12371,7 @@ All available test cases: " contains: "fakeTag" - +
@@ -11867,7 +12382,7 @@ All available test cases:
- + Tested reporter: TeamCity @@ -11881,7 +12396,7 @@ All available test cases: " contains: "fake reporter" - +
@@ -11892,7 +12407,7 @@ All available test cases:
- + Tested reporter: TeamCity @@ -11908,7 +12423,7 @@ All available test cases: " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -11919,7 +12434,7 @@ All available test cases:
- + Tested reporter: XML @@ -11938,7 +12453,7 @@ All available test cases: </TagsFromMatchingTests>" contains: "fakeTag" - +
@@ -11949,7 +12464,7 @@ All available test cases:
- + Tested reporter: XML @@ -11966,7 +12481,7 @@ All available test cases: </AvailableReporters>" contains: "fake reporter" - +
@@ -11977,7 +12492,7 @@ All available test cases:
- + Tested reporter: XML @@ -11999,18 +12514,18 @@ All available test cases: </MatchingTests>" ( contains: "fake test name" and contains: "fakeTestTag" ) - +
- +
- + - + - +
@@ -12032,13 +12547,13 @@ All available test cases: 1 > 0 - +
- + - + - +
@@ -12062,29 +12577,29 @@ All available test cases: true - +
- + - + - + - + - +
- +
- +
- +
- +
@@ -12132,15 +12647,15 @@ All available test cases: 10 >= 10 - +
- + - + - + - +
@@ -12169,16 +12684,16 @@ All available test cases: 0 == 0 - +
- + - + - +
- + A string sent directly to stdout @@ -12253,16 +12768,16 @@ A string sent to stderr via clog Approx( 1.23 ) != 1.24 - +
- +
- +
- + Message from section one Message from section two @@ -12286,7 +12801,7 @@ Message from section two "this string contains 'abc' as a substring" starts with: "string" (case insensitive) - +
@@ -12298,7 +12813,7 @@ Message from section two "{ 1 }" == "{ 1 }" - +
@@ -12309,7 +12824,7 @@ Message from section two "{ 3, 2, 1 }" == "{ 3, 2, 1 }" - +
@@ -12322,9 +12837,9 @@ Message from section two "{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }" - +
- +
@@ -12391,7 +12906,7 @@ Message from section two "this string contains 'abc' as a substring" ends with: " substring" (case insensitive) - +
@@ -12419,7 +12934,7 @@ Message from section two 0 == 0 - +
@@ -12454,7 +12969,7 @@ Message from section two "hello" == "hello" - +
@@ -12473,7 +12988,7 @@ Message from section two original.data() - +
@@ -12484,7 +12999,7 @@ Message from section two "original string" == "original string" - +
@@ -12495,7 +13010,7 @@ Message from section two "original string" == "original string" - +
@@ -12531,9 +13046,9 @@ Message from section two hello == "hello" - +
- +
@@ -12553,9 +13068,9 @@ Message from section two 0 == 0 - +
- +
@@ -12567,9 +13082,9 @@ Message from section two "hello world!" == "hello world!" - +
- +
@@ -12581,9 +13096,9 @@ Message from section two "hello world!" == "hello world!" - +
- +
@@ -12595,9 +13110,9 @@ Message from section two true - +
- +
@@ -12609,9 +13124,9 @@ Message from section two 0 == 0 - +
- +
@@ -12623,9 +13138,9 @@ Message from section two true - +
- +
@@ -12652,7 +13167,7 @@ Message from section two Hello != Hel - +
@@ -12672,9 +13187,9 @@ Message from section two 17 == 17 - +
- +
@@ -12694,9 +13209,9 @@ Message from section two 17 == 17 - +
- +
@@ -12716,9 +13231,9 @@ Message from section two 17 == 17 - +
- +
@@ -12738,9 +13253,9 @@ Message from section two 11 == 11 - +
- +
@@ -12760,9 +13275,9 @@ Message from section two 11 == 11 - +
- +
@@ -12775,7 +13290,7 @@ Message from section two "some string += the stringref contents" - +
@@ -12786,18 +13301,18 @@ Message from section two "abrakadabra" == "abrakadabra" - +
- +
- +
- +
- +
@@ -12816,7 +13331,7 @@ Message from section two ""abc"" == ""abc"" - + @@ -12835,7 +13350,7 @@ Message from section two ""abc"" == ""abc"" - + @@ -12854,7 +13369,7 @@ Message from section two ""abc"" == ""abc"" - + @@ -12889,7 +13404,7 @@ Message from section two 1 ns != 1 us - + @@ -12908,7 +13423,7 @@ Message from section two 1 ps != 1 as - + @@ -12921,7 +13436,7 @@ Message from section two {iso8601-timestamp} - + @@ -12939,7 +13454,7 @@ Message from section two " - +
@@ -12983,7 +13498,7 @@ Message from section two Redefined at: file:10" contains: "10" - +
@@ -13018,9 +13533,9 @@ Message from section two registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) - +
- +
@@ -13039,7 +13554,7 @@ Message from section two { {?}, {?} } ( Contains: {?} and Contains: {?} ) - + @@ -13050,7 +13565,7 @@ Message from section two 1 == 1 - + @@ -13061,7 +13576,7 @@ Message from section two 1 == 1 - + @@ -13072,7 +13587,7 @@ Message from section two 1.0 == 1 - + @@ -13083,7 +13598,7 @@ Message from section two 1 > 0 - + @@ -13094,7 +13609,7 @@ Message from section two 4 > 0 - + @@ -13105,7 +13620,7 @@ Message from section two 1 > 0 - + @@ -13116,7 +13631,7 @@ Message from section two 4 > 0 - + @@ -13127,7 +13642,7 @@ Message from section two 4 > 0 - + @@ -13138,7 +13653,7 @@ Message from section two 1 > 0 - + @@ -13149,7 +13664,7 @@ Message from section two 4 > 0 - + @@ -13185,7 +13700,7 @@ Message from section two 10 >= 10 - + @@ -13229,9 +13744,9 @@ Message from section two 0 == 0 - + - + @@ -13266,7 +13781,7 @@ Message from section two 10 >= 10 - + @@ -13301,9 +13816,9 @@ Message from section two 5 >= 5 - + - + @@ -13339,7 +13854,7 @@ Message from section two 10 >= 10 - + @@ -13383,9 +13898,9 @@ Message from section two 0 == 0 - + - + @@ -13420,7 +13935,7 @@ Message from section two 10 >= 10 - + @@ -13455,9 +13970,9 @@ Message from section two 5 >= 5 - + - + @@ -13493,7 +14008,7 @@ Message from section two 10 >= 10 - + @@ -13537,9 +14052,9 @@ Message from section two 0 == 0 - + - + @@ -13574,7 +14089,7 @@ Message from section two 10 >= 10 - + @@ -13609,9 +14124,9 @@ Message from section two 5 >= 5 - + - + @@ -13647,7 +14162,7 @@ Message from section two 10 >= 10 - + @@ -13691,9 +14206,9 @@ Message from section two 0 == 0 - + - + @@ -13728,7 +14243,7 @@ Message from section two 10 >= 10 - + @@ -13763,9 +14278,9 @@ Message from section two 5 >= 5 - + - + @@ -13801,7 +14316,7 @@ Message from section two 12 >= 12 - + @@ -13845,9 +14360,9 @@ Message from section two 0 == 0 - + - + @@ -13882,7 +14397,7 @@ Message from section two 12 >= 12 - + @@ -13917,9 +14432,9 @@ Message from section two 6 >= 6 - + - + @@ -13955,7 +14470,7 @@ Message from section two 8 >= 8 - + @@ -13999,9 +14514,9 @@ Message from section two 0 == 0 - + - + @@ -14036,7 +14551,7 @@ Message from section two 8 >= 8 - + @@ -14071,9 +14586,9 @@ Message from section two 4 >= 4 - + - + @@ -14109,7 +14624,7 @@ Message from section two 10 >= 10 - + @@ -14153,9 +14668,9 @@ Message from section two 0 == 0 - + - + @@ -14190,7 +14705,7 @@ Message from section two 10 >= 10 - + @@ -14225,9 +14740,9 @@ Message from section two 5 >= 5 - + - + @@ -14263,7 +14778,7 @@ Message from section two 30 >= 30 - + @@ -14307,9 +14822,9 @@ Message from section two 0 == 0 - + - + @@ -14344,7 +14859,7 @@ Message from section two 30 >= 30 - + @@ -14379,9 +14894,9 @@ Message from section two 15 >= 15 - + - + @@ -14400,10 +14915,10 @@ Message from section two {?} == {?} - + - + @@ -14414,10 +14929,10 @@ Message from section two 3221225472 (0x) == 3221225472 - + - + @@ -14452,7 +14967,7 @@ Message from section two false - + @@ -14464,7 +14979,7 @@ Message from section two - + @@ -14476,7 +14991,51 @@ Message from section two - + + + + + + true + + + true + + + + + {Unknown expression after the reported line} + + + {Unknown expression after the reported line} + + + Uncaught exception should fail! + + + + + + + + false + + + false + + + + + {Unknown expression after the reported line} + + + {Unknown expression after the reported line} + + + Uncaught exception should fail! + + + @@ -14487,7 +15046,7 @@ Message from section two 1 == 2 - +
@@ -14503,7 +15062,7 @@ Message from section two " contains: "[fakeTag]" - +
@@ -14517,7 +15076,7 @@ Message from section two " ( contains: "fake reporter" and contains: "fake description" ) - +
@@ -14533,7 +15092,7 @@ Message from section two " ( contains: "fake test name" and contains: "fakeTestTag" ) - +
@@ -14547,18 +15106,18 @@ Message from section two " ( contains: "fakeListener" and contains: "fake description" ) - +
- +
- + For some reason someone is throwing a string literal! - + @@ -14610,7 +15169,7 @@ Message from section two true - + @@ -14710,9 +15269,9 @@ Message from section two true - + - + @@ -14820,9 +15379,9 @@ Message from section two true - + - + @@ -14923,11 +15482,11 @@ Message from section two true - + - + - + @@ -15060,11 +15619,11 @@ Message from section two true - + - + - + @@ -15131,9 +15690,9 @@ Message from section two true - + - + @@ -15216,13 +15775,189 @@ There is no extra whitespace here There is no extra whitespace here - + + + +
+
+ + + array_int_a, RangeEquals( c_array ) + + + { 1, 2, 3 } elements are { 1, 2, 3 } + + + + + array_int_a, UnorderedRangeEquals( c_array ) + + + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + + + +
+ +
+
+
+ + + array_int_3, !RangeEquals( array_int_4 ) + + + { 1, 2, 3 } not elements are { 1, 2, 3, 4 } + + + + + array_int_3, !UnorderedRangeEquals( array_int_4 ) + + + { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } + + + +
+ +
+
+
+ + + array_int_a, RangeEquals( vector_char_a ) + + + { 1, 2, 3 } elements are { 1, 2, 3 } + + + + + array_int_a, UnorderedRangeEquals( vector_char_a ) + + + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + + + +
+ +
+
+
+ + + array_int_a, RangeEquals( list_char_a ) + + + { 1, 2, 3 } elements are { 1, 2, 3 } + + + + + array_int_a, UnorderedRangeEquals( list_char_a ) + + + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + + + +
+ +
+
+
+ + + vector_int_a, RangeEquals( vector_char_a ) + + + { 1, 2, 3 } elements are { 1, 2, 3 } + + + + + vector_int_a, UnorderedRangeEquals( vector_char_a ) + + + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + + + +
+ +
+
+
+ + + vector_int_a, !RangeEquals( vector_char_b ) + + + { 1, 2, 3 } not elements are { 1, 2, 2 } + + + + + vector_int_a, !UnorderedRangeEquals( vector_char_b ) + + + { 1, 2, 3 } not unordered elements are { 1, 2, 2 } + + + +
+ +
+
+ + + a, !RangeEquals( b ) + + + { 1, 2, 3 } not elements are { 3, 2, 1 } + + + + + a, UnorderedRangeEquals( b ) + + + { 1, 2, 3 } unordered elements are { 3, 2, 1 } + + + +
+
+
+ + + vector_a, RangeEquals( array_a_plus_1, close_enough ) + + + { 1, 2, 3 } elements are { 2, 3, 4 } + + + + + vector_a, UnorderedRangeEquals( array_a_plus_1, close_enough ) + + + { 1, 2, 3 } unordered elements are { 2, 3, 4 } + + + +
+ +
+
3.14 - +
@@ -15234,7 +15969,7 @@ There is no extra whitespace here 3 == 3 - +
@@ -15245,9 +15980,9 @@ There is no extra whitespace here 3 == 3 - +
- +
@@ -15267,7 +16002,7 @@ There is no extra whitespace here { { 0, 1, 2, 3, 5 }, { 4, -3, -2, 5, 0 }, { 0, 0, 0, 5, 0 }, { 0, -5, 0, 5, 0 }, { 1, 0, 0, -1, 5 } } not all match ( contains element 0 and contains element 1 ) - +
@@ -15278,7 +16013,7 @@ There is no extra whitespace here { 1, 2, 3, 4, 5 } all match matches undescribed predicate - +
@@ -15330,9 +16065,9 @@ There is no extra whitespace here true - +
- +
@@ -15384,11 +16119,11 @@ There is no extra whitespace here !false - +
- +
- +
@@ -15401,9 +16136,9 @@ There is no extra whitespace here { true, true, true, true, true } contains only true - +
- +
@@ -15415,12 +16150,12 @@ There is no extra whitespace here { } contains only true - +
- +
-
+
data, !AllTrue() @@ -15429,9 +16164,9 @@ There is no extra whitespace here { true, true, false, true, true } not contains only true - +
- +
@@ -15443,9 +16178,9 @@ There is no extra whitespace here { false, false, false, false, false } not contains only true - +
- +
@@ -15457,12 +16192,12 @@ There is no extra whitespace here { true, true, true, true, true } contains only true - +
- +
-
+
data, !AllTrue() @@ -15471,9 +16206,9 @@ There is no extra whitespace here { true, true, false, true, true } not contains only true - +
- +
@@ -15485,9 +16220,9 @@ There is no extra whitespace here { false, false, false, false, false } not contains only true - +
- +
@@ -15539,9 +16274,9 @@ There is no extra whitespace here true - +
- +
@@ -15593,11 +16328,11 @@ There is no extra whitespace here !false - +
- +
- +
@@ -15617,7 +16352,7 @@ There is no extra whitespace here { { 0, 1, 2, 3, 5 }, { 4, -3, -2, 5, 0 }, { 0, 0, 0, 5, 0 }, { 0, -5, 0, 5, 0 }, { 1, 0, 0, -1, 5 } } not any match ( contains element 0 and contains element 10 ) - +
@@ -15628,7 +16363,7 @@ There is no extra whitespace here { 1, 2, 3, 4, 5 } any match matches undescribed predicate - +
@@ -15680,9 +16415,9 @@ There is no extra whitespace here true - +
- +
@@ -15734,11 +16469,11 @@ There is no extra whitespace here !false - +
- +
- +
@@ -15751,9 +16486,9 @@ There is no extra whitespace here { true, true, true, true, true } contains at least one true - +
- +
@@ -15765,12 +16500,12 @@ There is no extra whitespace here { } not contains at least one true - +
- +
-
+
data, AnyTrue() @@ -15779,9 +16514,9 @@ There is no extra whitespace here { false, false, true, false, false } contains at least one true - +
- +
@@ -15793,9 +16528,9 @@ There is no extra whitespace here { false, false, false, false, false } not contains at least one true - +
- +
@@ -15807,12 +16542,12 @@ There is no extra whitespace here { true, true, true, true, true } contains at least one true - +
- +
-
+
data, AnyTrue() @@ -15821,9 +16556,9 @@ There is no extra whitespace here { false, false, true, false, false } contains at least one true - +
- +
@@ -15835,9 +16570,9 @@ There is no extra whitespace here { false, false, false, false, false } not contains at least one true - +
- +
@@ -15889,9 +16624,9 @@ There is no extra whitespace here true - +
- +
@@ -15943,11 +16678,11 @@ There is no extra whitespace here !false - +
- +
- +
@@ -15967,7 +16702,7 @@ There is no extra whitespace here { { 0, 1, 2, 3, 5 }, { 4, -3, -2, 5, 0 }, { 0, 0, 0, 5, 0 }, { 0, -5, 0, 5, 0 }, { 1, 0, 0, -1, 5 } } not none match ( contains element 0 and contains element 1 ) - +
@@ -15978,7 +16713,7 @@ There is no extra whitespace here { 1, 2, 3, 4, 5 } none match matches undescribed predicate - +
@@ -16030,9 +16765,9 @@ There is no extra whitespace here true - +
- +
@@ -16084,11 +16819,11 @@ There is no extra whitespace here !false - +
- +
- +
@@ -16101,9 +16836,9 @@ There is no extra whitespace here { true, true, true, true, true } not contains no true - +
- +
@@ -16115,12 +16850,12 @@ There is no extra whitespace here { } contains no true - +
- +
-
+
data, !NoneTrue() @@ -16129,9 +16864,9 @@ There is no extra whitespace here { false, false, true, false, false } not contains no true - +
- +
@@ -16143,9 +16878,9 @@ There is no extra whitespace here { false, false, false, false, false } contains no true - +
- +
@@ -16157,12 +16892,12 @@ There is no extra whitespace here { true, true, true, true, true } not contains no true - +
- +
-
+
data, !NoneTrue() @@ -16171,9 +16906,9 @@ There is no extra whitespace here { false, false, true, false, false } not contains no true - +
- +
@@ -16185,9 +16920,9 @@ There is no extra whitespace here { false, false, false, false, false } contains no true - +
- +
@@ -16239,9 +16974,9 @@ There is no extra whitespace here true - +
- +
@@ -16293,11 +17028,387 @@ There is no extra whitespace here !false - +
- +
- + + + +
+
+ + + empty_vector, RangeEquals( empty_vector ) + + + { } elements are { } + + + +
+ +
+
+
+ + + empty_vector, !RangeEquals( non_empty_vector ) + + + { } not elements are { 1 } + + + + + non_empty_vector, !RangeEquals( empty_vector ) + + + { 1 } not elements are { } + + + +
+ +
+
+
+ + + non_empty_array, RangeEquals( non_empty_array ) + + + { 1 } elements are { 1 } + + + +
+ +
+
+
+ + + array_a, RangeEquals( array_a ) + + + { 1, 2, 3 } elements are { 1, 2, 3 } + + + +
+ +
+
+
+ + + array_a, !RangeEquals( array_b ) + + + { 1, 2, 3 } not elements are { 2, 2, 3 } + + + + + array_a, !RangeEquals( array_c ) + + + { 1, 2, 3 } not elements are { 1, 2, 2 } + + + +
+ +
+
+
+ + + vector_a, !RangeEquals( vector_b ) + + + { 1, 2, 3 } not elements are { 1, 2, 3, 4 } + + + +
+ +
+
+
+ + + vector_a, RangeEquals( vector_a_plus_1, close_enough ) + + + { 1, 2, 3 } elements are { 2, 3, 4 } + + + +
+ +
+
+
+ + + vector_a, !RangeEquals( vector_b, close_enough ) + + + { 1, 2, 3 } not elements are { 3, 3, 4 } + + + +
+ +
+
+ + + needs_adl1, RangeEquals( needs_adl2 ) + + + { 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 } + + + + + needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) + + + { 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 } + + + +
+
+
+ + + mocked1, !RangeEquals( arr ) + + + { 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 } + + + + + mocked1.m_derefed[0] + + + true + + + + + mocked1.m_derefed[1] + + + true + + + + + mocked1.m_derefed[2] + + + true + + + + + !(mocked1.m_derefed[3]) + + + !false + + + +
+ +
+
+
+ + + mocked1, RangeEquals( arr ) + + + { 1, 2, 3, 4 } elements are { 1, 2, 3, 4 } + + + + + mocked1.m_derefed[0] + + + true + + + + + mocked1.m_derefed[1] + + + true + + + + + mocked1.m_derefed[2] + + + true + + + + + mocked1.m_derefed[3] + + + true + + + +
+ +
+ +
+ +
+
+ + + empty_vector, UnorderedRangeEquals( empty_vector ) + + + { } unordered elements are { } + + + +
+ +
+
+
+ + + empty_vector, !UnorderedRangeEquals( non_empty_vector ) + + + { } not unordered elements are { 1 } + + + + + non_empty_vector, !UnorderedRangeEquals( empty_vector ) + + + { 1 } not unordered elements are { } + + + +
+ +
+
+
+ + + non_empty_array, UnorderedRangeEquals( non_empty_array ) + + + { 1 } unordered elements are { 1 } + + + +
+ +
+
+
+ + + array_a, UnorderedRangeEquals( array_a ) + + + { 1, 2, 3 } unordered elements are { 1, 2, 3 } + + + +
+ +
+
+
+ + + array_a, !UnorderedRangeEquals( array_b ) + + + { 1, 2, 3 } not unordered elements are { 2, 2, 3 } + + + +
+ +
+
+
+ + + vector_a, !UnorderedRangeEquals( vector_b ) + + + { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 } + + + +
+ +
+
+
+ + + vector_a, UnorderedRangeEquals( vector_a_plus_1, close_enough ) + + + { 1, 10, 20 } unordered elements are { 11, 21, 2 } + + + +
+ +
+
+
+ + + vector_a, !UnorderedRangeEquals( vector_b, close_enough ) + + + { 1, 10, 21 } not unordered elements are { 11, 21, 3 } + + + +
+ +
+
+ + + needs_adl1, UnorderedRangeEquals( needs_adl2 ) + + + { 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 } + + + +
+
@@ -16357,7 +17468,7 @@ There is no extra whitespace here { {?}, {?}, {?} } has size == 3 - +
@@ -16368,7 +17479,7 @@ There is no extra whitespace here {?} has size == 12 - +
@@ -16379,9 +17490,9 @@ There is no extra whitespace here {?} has size == 13 - +
- +
@@ -16448,13 +17559,13 @@ There is no extra whitespace here Approx( 1.23 ) != 1.25 - +
- +
- +
@@ -16466,7 +17577,7 @@ There is no extra whitespace here { } is approx: { } - +
@@ -16486,9 +17597,9 @@ There is no extra whitespace here { 1.0, 2.0, 3.0 } is approx: { 1.0, 2.0, 3.0 } - +
- +
@@ -16500,9 +17611,9 @@ There is no extra whitespace here { 1.0, 2.0, 3.0 } not is approx: { 1.0, 2.0, 3.0, 4.0 } - +
- +
@@ -16538,11 +17649,11 @@ There is no extra whitespace here { 1.0, 2.0, 3.0 } is approx: { 1.5, 2.5, 3.5 } - +
- +
- +
@@ -16554,7 +17665,7 @@ There is no extra whitespace here { } is approx: { 1.0, 2.0 } - +
@@ -16565,9 +17676,9 @@ There is no extra whitespace here { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 } - +
- +
@@ -16595,7 +17706,7 @@ There is no extra whitespace here { 1, 2, 3 } Contains: 2 - +
@@ -16662,7 +17773,7 @@ There is no extra whitespace here { 1, 2, 3 } Contains: { 1, 2 } - +
@@ -16673,7 +17784,7 @@ There is no extra whitespace here { 1, 2, 3 } ( Contains: 1 and Contains: 2 ) - +
@@ -16724,7 +17835,7 @@ There is no extra whitespace here { 1, 2, 3 } Equals: { 1, 2, 3 } - +
@@ -16783,9 +17894,9 @@ There is no extra whitespace here { 1, 3, 2 } UnorderedEquals: { 1, 2, 3 } - +
- +
@@ -16805,7 +17916,7 @@ There is no extra whitespace here { } Contains: 1 - +
@@ -16824,7 +17935,7 @@ There is no extra whitespace here { 1, 2, 3 } Contains: { 1, 2, 4 } - +
@@ -16859,7 +17970,7 @@ There is no extra whitespace here { 1, 2, 3 } Equals: { } - +
@@ -16894,9 +18005,9 @@ There is no extra whitespace here { 3, 1 } UnorderedEquals: { 1, 2, 3 } - +
- +
@@ -16923,13 +18034,13 @@ There is no extra whitespace here thisThrows() - + unexpected exception - + @@ -16943,7 +18054,7 @@ There is no extra whitespace here expected exception - + @@ -16957,7 +18068,7 @@ There is no extra whitespace here expected exception - + @@ -16971,31 +18082,31 @@ There is no extra whitespace here expected exception - +
unexpected exception - +
- +
- + - + - + - + - +
@@ -17007,7 +18118,7 @@ There is no extra whitespace here "normal string" == "normal string" - +
@@ -17018,7 +18129,7 @@ There is no extra whitespace here "" == "" - +
@@ -17029,7 +18140,7 @@ There is no extra whitespace here "smith &amp; jones" == "smith &amp; jones" - +
@@ -17040,7 +18151,7 @@ There is no extra whitespace here "smith &lt; jones" == "smith &lt; jones" - +
@@ -17061,7 +18172,7 @@ There is no extra whitespace here "smith ]]&gt; jones" - +
@@ -17084,7 +18195,7 @@ There is no extra whitespace here "don't &quot;quote&quot; me on that" - +
@@ -17095,7 +18206,7 @@ There is no extra whitespace here "[\x01]" == "[\x01]" - +
@@ -17106,9 +18217,9 @@ There is no extra whitespace here "[\x7F]" == "[\x7F]" - +
- +
@@ -17121,7 +18232,11 @@ There is no extra whitespace here " ( contains: "attr1="true"" and contains: "attr2="false"" ) - + + + + + @@ -17228,7 +18343,7 @@ There is no extra whitespace here 0.0 == 0 - + @@ -17255,7 +18370,7 @@ There is no extra whitespace here "{ 42, 250 }" == "{ 42, 250 }" - +
@@ -17299,7 +18414,7 @@ There is no extra whitespace here 1 == 1 - +
@@ -17342,9 +18457,9 @@ There is no extra whitespace here 1 == 1 - +
- +
@@ -17355,7 +18470,7 @@ There is no extra whitespace here 0x != 0 - + @@ -17374,7 +18489,7 @@ There is no extra whitespace here true - + @@ -17393,7 +18508,7 @@ There is no extra whitespace here false - + @@ -17412,7 +18527,7 @@ There is no extra whitespace here true - + @@ -17431,7 +18546,7 @@ There is no extra whitespace here false - +
@@ -17483,7 +18598,7 @@ There is no extra whitespace here 0 == 0 - +
@@ -17534,7 +18649,7 @@ There is no extra whitespace here 1 == 1 - +
@@ -17585,7 +18700,7 @@ There is no extra whitespace here 1 == 1 - +
@@ -17636,7 +18751,7 @@ There is no extra whitespace here 1 == 1 - +
@@ -17687,7 +18802,7 @@ There is no extra whitespace here 1 == 1 - +
@@ -17738,9 +18853,9 @@ There is no extra whitespace here 2 == 2 - +
- +
@@ -17775,7 +18890,7 @@ There is no extra whitespace here 1 == 1 - + @@ -17810,7 +18925,7 @@ There is no extra whitespace here 1 == 1 - + @@ -17865,7 +18980,16 @@ There is no extra whitespace here 1 == 1 - + + + + + skipping because answer = 41 + + + skipping because answer = 43 + + @@ -17876,7 +19000,7 @@ There is no extra whitespace here Catch::TestCaseInfo("", { "test with an empty tag", "[]" }, dummySourceLineInfo) - + @@ -17903,7 +19027,7 @@ There is no extra whitespace here 1.3859038243 == Approx( 1.3859038243 ) - + @@ -17922,52 +19046,82 @@ There is no extra whitespace here 0 == 0 - +
- +
- +
- +
- +
- +
- + +
+ + + + 3 == 4 + + + 3 == 4 + + + + + + + + + + + + + +
+ + +
+
+ + +
+
- + - + - + Previous info should not be seen - + previous unscoped info SHOULD not be seen - + - + - + @@ -17980,7 +19134,7 @@ There is no extra whitespace here 9223372036854775807 (0x) - +
@@ -17992,7 +19146,7 @@ There is no extra whitespace here 0 > 1 - +
@@ -18003,7 +19157,7 @@ There is no extra whitespace here 1 > 1 - +
@@ -18014,7 +19168,7 @@ There is no extra whitespace here 2 > 1 - +
@@ -18025,7 +19179,7 @@ There is no extra whitespace here 3 > 1 - +
@@ -18036,7 +19190,7 @@ There is no extra whitespace here 4 > 1 - +
@@ -18047,7 +19201,7 @@ There is no extra whitespace here 5 > 1 - +
@@ -18058,7 +19212,7 @@ There is no extra whitespace here 6 > 1 - +
@@ -18069,7 +19223,7 @@ There is no extra whitespace here 7 > 1 - +
@@ -18080,7 +19234,7 @@ There is no extra whitespace here 8 > 1 - +
@@ -18091,12 +19245,12 @@ There is no extra whitespace here 9 > 1 - +
- +
- + Testing if fib[0] (1) is even @@ -18107,7 +19261,7 @@ There is no extra whitespace here 1 == 0 - + Testing if fib[1] (1) is even @@ -18118,7 +19272,7 @@ There is no extra whitespace here 1 == 0 - + Testing if fib[2] (2) is even @@ -18129,7 +19283,7 @@ There is no extra whitespace here 0 == 0 - + Testing if fib[3] (3) is even @@ -18140,7 +19294,7 @@ There is no extra whitespace here 1 == 0 - + Testing if fib[4] (5) is even @@ -18151,7 +19305,7 @@ There is no extra whitespace here 1 == 0 - + Testing if fib[5] (8) is even @@ -18162,7 +19316,7 @@ There is no extra whitespace here 0 == 0 - + Testing if fib[6] (13) is even @@ -18173,7 +19327,7 @@ There is no extra whitespace here 1 == 0 - + Testing if fib[7] (21) is even @@ -18184,7 +19338,7 @@ There is no extra whitespace here 1 == 0 - + @@ -18195,7 +19349,7 @@ There is no extra whitespace here Catch::makeStream( "%debug" ) - +
@@ -18207,7 +19361,7 @@ There is no extra whitespace here !false - +
@@ -18218,7 +19372,7 @@ There is no extra whitespace here true - +
@@ -18229,9 +19383,9 @@ There is no extra whitespace here {?} == {?} - +
- +
@@ -18242,7 +19396,7 @@ There is no extra whitespace here 19.0 == 19.0 - + @@ -18309,28 +19463,28 @@ There is no extra whitespace here 1 == 1 - + - + info - + unscoped info - + and warn may mix - + info - + unscoped info - + they are not cleared after warnings - +
@@ -18343,9 +19497,9 @@ There is no extra whitespace here 1 == 2 - +
- +
@@ -18357,9 +19511,9 @@ There is no extra whitespace here 1 != 2 - +
- +
@@ -18371,11 +19525,11 @@ There is no extra whitespace here 1 < 2 - +
- +
- +
@@ -18404,11 +19558,39 @@ There is no extra whitespace here 1 != 2 - +
- +
- + + + +
+ +
+
+
+ +
+ +
+
+
+ + +
+ +
+
+ +
+ + +a! +b1! +! + +
@@ -18419,7 +19601,7 @@ There is no extra whitespace here "7" == "7" - + @@ -18430,7 +19612,7 @@ There is no extra whitespace here {?} == {?} - + @@ -18473,7 +19655,7 @@ There is no extra whitespace here 0.088096521 == Approx( 0.088096521 ) - + @@ -18500,13 +19682,13 @@ There is no extra whitespace here -1.9599639845 == Approx( -1.9599639845 ) - + - + - + this MAY be seen only for the FIRST assertion IF info is printed for passing assertions @@ -18517,7 +19699,7 @@ There is no extra whitespace here true - + this MAY be seen only for the SECOND assertion IF info is printed for passing assertions @@ -18528,7 +19710,7 @@ There is no extra whitespace here true - + this SHOULD be seen @@ -18539,7 +19721,7 @@ There is no extra whitespace here false - + @@ -18558,7 +19740,7 @@ There is no extra whitespace here {null string} == {null string} - + @@ -18569,7 +19751,7 @@ There is no extra whitespace here 0 == 0 - + @@ -18582,7 +19764,7 @@ There is no extra whitespace here "{ { 42, "Arthur" }, { "Ford", 24 } }" - +
@@ -18594,7 +19776,7 @@ There is no extra whitespace here { } Equals: { } - +
@@ -18621,7 +19803,7 @@ There is no extra whitespace here { Value1 } Equals: { Value1 } - +
@@ -18648,9 +19830,9 @@ There is no extra whitespace here { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 } - +
- +
@@ -18661,10 +19843,10 @@ There is no extra whitespace here 0 == 0 - + - + this MAY be seen IF info is printed for passing assertions @@ -18675,13 +19857,13 @@ There is no extra whitespace here true - + - + this SHOULD be seen - + this SHOULD also be seen @@ -18692,10 +19874,10 @@ There is no extra whitespace here false - + - + this SHOULD be seen only ONCE @@ -18714,7 +19896,7 @@ There is no extra whitespace here true - + this MAY also be seen only ONCE IF info is printed for passing assertions @@ -18733,7 +19915,7 @@ There is no extra whitespace here true - +
@@ -18753,7 +19935,7 @@ There is no extra whitespace here 2 != 1 - +
@@ -18764,9 +19946,9 @@ There is no extra whitespace here 1 != 2 - +
- +
@@ -18786,7 +19968,7 @@ There is no extra whitespace here "azcdefcg" == "azcdefcg" - +
@@ -18805,7 +19987,7 @@ There is no extra whitespace here "abzdefzg" == "abzdefzg" - +
@@ -18824,7 +20006,7 @@ There is no extra whitespace here "zbcdefcg" == "zbcdefcg" - +
@@ -18843,7 +20025,7 @@ There is no extra whitespace here "abcdefcz" == "abcdefcz" - +
@@ -18862,7 +20044,7 @@ There is no extra whitespace here "replaced" == "replaced" - +
@@ -18881,7 +20063,7 @@ There is no extra whitespace here "abcdefcg" == "abcdefcg" - +
@@ -18900,9 +20082,9 @@ There is no extra whitespace here "didn|'t" == "didn|'t" - +
- +
@@ -18913,7 +20095,7 @@ There is no extra whitespace here Catch::makeStream( "%somestream" ) - + @@ -18996,7 +20178,7 @@ There is no extra whitespace here 1000.0 == 1000 (0x) - + @@ -19087,7 +20269,7 @@ There is no extra whitespace here 128 >= 100 - + @@ -19178,13 +20360,26 @@ There is no extra whitespace here 128 >= 100 - + - + + + +
+ +
+
+ + +
+
+ +
+
- + 3 @@ -19195,13 +20390,13 @@ There is no extra whitespace here false - + - + hi - + i := 7 @@ -19212,7 +20407,7 @@ There is no extra whitespace here false - + @@ -19223,7 +20418,13 @@ There is no extra whitespace here { {?}, {?} } ( Contains: {?} and Contains: {?} ) - + + + + + skipping because answer = 43 + + @@ -19250,19 +20451,19 @@ There is no extra whitespace here { abc, def } Equals: { abc, def } - + - + Count 1 to 3... - + 1 - + 2 - + 3 @@ -19273,16 +20474,16 @@ There is no extra whitespace here false - + Count 4 to 6... - + 4 - + 5 - + 6 @@ -19293,7 +20494,7 @@ There is no extra whitespace here false - + @@ -19320,7 +20521,7 @@ There is no extra whitespace here true - +
@@ -19332,7 +20533,7 @@ There is no extra whitespace here "{ }" == "{ }" - +
@@ -19343,7 +20544,7 @@ There is no extra whitespace here "{ { "one", 1 } }" == "{ { "one", 1 } }" - +
@@ -19356,9 +20557,9 @@ There is no extra whitespace here "{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }" - +
- +
@@ -19369,7 +20570,7 @@ There is no extra whitespace here "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" - + @@ -19380,7 +20581,7 @@ There is no extra whitespace here "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" - +
@@ -19392,7 +20593,7 @@ There is no extra whitespace here "{ }" == "{ }" - +
@@ -19403,7 +20604,7 @@ There is no extra whitespace here "{ "one" }" == "{ "one" }" - +
@@ -19416,9 +20617,9 @@ There is no extra whitespace here "{ "abc", "def", "ghi" }" - +
- +
@@ -19431,7 +20632,7 @@ There is no extra whitespace here "{ { "green", 55 } }" - + @@ -19450,7 +20651,7 @@ There is no extra whitespace here true - + @@ -19489,7 +20690,7 @@ There is no extra whitespace here "{?}" == "{?}" - + @@ -19502,7 +20703,7 @@ There is no extra whitespace here "StringMaker<has_maker>" - + @@ -19515,7 +20716,7 @@ There is no extra whitespace here "StringMaker<has_maker_and_operator>" - + @@ -19526,7 +20727,7 @@ There is no extra whitespace here "{?}" == "{?}" - + @@ -19539,7 +20740,7 @@ There is no extra whitespace here "operator<<( has_operator )" - + @@ -19552,7 +20753,7 @@ There is no extra whitespace here "operator<<( has_template_operator )" - + @@ -19565,7 +20766,7 @@ There is no extra whitespace here "{ StringMaker<has_maker> }" - + @@ -19578,7 +20779,7 @@ There is no extra whitespace here "{ StringMaker<has_maker_and_operator> }" - + @@ -19591,7 +20792,7 @@ There is no extra whitespace here "{ operator<<( has_operator ) }" - + @@ -19626,7 +20827,7 @@ There is no extra whitespace here 4 == 4 - + @@ -19661,7 +20862,7 @@ There is no extra whitespace here 6 == 6 - + @@ -19680,13 +20881,17 @@ There is no extra whitespace here magic.tag == magic.tag - + + + + + Why would you throw a std::string? - + @@ -19697,7 +20902,7 @@ There is no extra whitespace here ""wide load"" == ""wide load"" - + @@ -19708,7 +20913,7 @@ There is no extra whitespace here ""wide load"" == ""wide load"" - + @@ -19719,7 +20924,7 @@ There is no extra whitespace here ""wide load"" == ""wide load"" - + @@ -19730,7 +20935,7 @@ There is no extra whitespace here ""wide load"" == ""wide load"" - + @@ -19759,7 +20964,7 @@ There is no extra whitespace here "Unknown enum value 10" - + @@ -19778,7 +20983,7 @@ There is no extra whitespace here "1" == "1" - + @@ -19797,7 +21002,7 @@ There is no extra whitespace here "E2{1}" == "E2{1}" - + @@ -19816,7 +21021,7 @@ There is no extra whitespace here "1" == "1" - + @@ -19835,7 +21040,7 @@ There is no extra whitespace here "{ }" == "{ }" - + @@ -19854,7 +21059,7 @@ There is no extra whitespace here "{ 1.2f, 0 }" == "{ 1.2f, 0 }" - + @@ -19865,7 +21070,7 @@ There is no extra whitespace here "{ 0 }" == "{ 0 }" - + @@ -19878,7 +21083,7 @@ There is no extra whitespace here "{ "hello", "world" }" - + @@ -19891,7 +21096,7 @@ There is no extra whitespace here "{ { 42 }, { }, 1.2f }" - + @@ -19926,7 +21131,26 @@ There is no extra whitespace here 0.95 == 0.95 - + + + + + + dist.a() == -10 + + + -10 == -10 + + + + + dist.b() == 10 + + + 10 == 10 + + +
@@ -19946,7 +21170,7 @@ There is no extra whitespace here 0 == 0 - +
@@ -19990,9 +21214,9 @@ There is no extra whitespace here 0 == 0 - +
- +
@@ -20044,9 +21268,9 @@ There is no extra whitespace here 2 == 2 - +
- +
@@ -20065,7 +21289,7 @@ There is no extra whitespace here 0 == 0 - +
@@ -20092,7 +21316,7 @@ There is no extra whitespace here 1 == 1 - +
@@ -20119,7 +21343,7 @@ There is no extra whitespace here 2 == 2 - +
@@ -20138,9 +21362,9 @@ There is no extra whitespace here 1 == 1 - +
- +
@@ -20161,7 +21385,7 @@ There is no extra whitespace here "{ { "hello" }, { "world" } }" - + @@ -20188,7 +21412,7 @@ There is no extra whitespace here "{ true, false }" == "{ true, false }" - + @@ -20215,7 +21439,7 @@ There is no extra whitespace here "{ 42, 250 }" == "{ 42, 250 }" - + @@ -20242,7 +21466,7 @@ There is no extra whitespace here "{ 42, 250 }" == "{ 42, 250 }" - + @@ -20271,7 +21495,7 @@ There is no extra whitespace here "{ "hello", "world" }" - + @@ -20307,7 +21531,7 @@ There is no extra whitespace here 10 >= 10 - + @@ -20351,9 +21575,9 @@ There is no extra whitespace here 0 == 0 - + - + @@ -20388,7 +21612,7 @@ There is no extra whitespace here 10 >= 10 - + @@ -20423,9 +21647,9 @@ There is no extra whitespace here 5 >= 5 - + - + @@ -20444,7 +21668,7 @@ There is no extra whitespace here 310016000 ns > 100 ms - + @@ -20471,17 +21695,17 @@ There is no extra whitespace here 23.0 == 23.0 - +
- +
- +
- +
- - + + diff --git a/tests/SelfTest/IntrospectiveTests/Algorithms.tests.cpp b/tests/SelfTest/IntrospectiveTests/Algorithms.tests.cpp new file mode 100644 index 00000000..fa17cf82 --- /dev/null +++ b/tests/SelfTest/IntrospectiveTests/Algorithms.tests.cpp @@ -0,0 +1,94 @@ + +// 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 +#include + +#include + +#include + +namespace { + template + static bool is_permutation(Range1 const& r1, Range2 const& r2) { + using std::begin; using std::end; + return Catch::Detail::is_permutation( + begin( r1 ), end( r1 ), begin( r2 ), end( r2 ), std::equal_to<>{} ); + } +} + +TEST_CASE("is_permutation", "[algorithms][approvals]") { + SECTION( "Handle empty ranges" ) { + std::array empty; + std::array non_empty{ { 2, 3 } }; + REQUIRE( is_permutation( empty, empty ) ); + REQUIRE_FALSE( is_permutation( empty, non_empty ) ); + REQUIRE_FALSE( is_permutation( non_empty, empty ) ); + } + SECTION( "Different length ranges" ) { + std::array arr1{ { 1, 3, 5, 7, 8, 9 } }; + // arr2 is prefix of arr1 + std::array arr2{ { 1, 3, 5, 7 } }; + // arr3 shares prefix with arr1 and arr2, but is not a permutation + std::array arr3{ { 1, 3, 5, 9, 8 } }; + REQUIRE_FALSE( is_permutation( arr1, arr2 ) ); + REQUIRE_FALSE( is_permutation( arr1, arr3 ) ); + REQUIRE_FALSE( is_permutation( arr2, arr3 ) ); + } + SECTION( "Same length ranges" ) { + SECTION( "Shared elements, but different counts" ) { + const std::array + arr1{ { 1, 1, 1, 1, 2, 2 } }, + arr2{ { 1, 1, 2, 2, 2, 2 } }; + REQUIRE_FALSE( is_permutation( arr1, arr2 ) ); + } + SECTION( "Identical ranges" ) { + const std::array + arr1{ { 1, 1, 1, 1, 2, 2 } }, + arr2{ { 1, 1, 2, 2, 2, 2 } }; + REQUIRE( is_permutation( arr1, arr1 ) ); + REQUIRE( is_permutation( arr2, arr2 ) ); + } + SECTION( "Completely distinct elements" ) { + // Completely distinct elements + const std::array + arr1{ { 1, 2, 3, 4 } }, + arr2{ { 10, 20, 30, 40 } }; + REQUIRE_FALSE( is_permutation( arr1, arr2 ) ); + } + SECTION( "Reverse ranges" ) { + const std::array + arr1{ { 1, 2, 3, 4, 5 } }, + arr2{ { 5, 4, 3, 2, 1 } }; + REQUIRE( is_permutation( arr1, arr2 ) ); + } + SECTION( "Shared prefix & permuted elements" ) { + const std::array + arr1{ { 1, 1, 2, 3, 4 } }, + arr2{ { 1, 1, 4, 2, 3 } }; + REQUIRE( is_permutation( arr1, arr2 ) ); + } + SECTION( "Permutations with element count > 1" ) { + const std::array + arr1{ { 2, 2, 3, 3, 3, 1, 1 } }, + arr2{ { 3, 2, 1, 3, 2, 1, 3 } }; + REQUIRE( is_permutation( arr1, arr2 ) ); + } + } +} + +TEST_CASE("is_permutation supports iterator + sentinel pairs", + "[algorithms][is-permutation][approvals]") { + const has_different_begin_end_types + range_1{ 1, 2, 3, 4 }, + range_2{ 4, 3, 2, 1 }; + REQUIRE( is_permutation( range_1, range_2 ) ); + + const has_different_begin_end_types range_3{ 3, 3, 2, 1 }; + REQUIRE_FALSE( is_permutation( range_1, range_3 ) ); +} diff --git a/tests/SelfTest/IntrospectiveTests/AssertionHandler.tests.cpp b/tests/SelfTest/IntrospectiveTests/AssertionHandler.tests.cpp new file mode 100644 index 00000000..ab096074 --- /dev/null +++ b/tests/SelfTest/IntrospectiveTests/AssertionHandler.tests.cpp @@ -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 + +TEST_CASE( "Incomplete AssertionHandler", "[assertion-handler][!shouldfail]" ) { + Catch::AssertionHandler catchAssertionHandler( + "REQUIRE"_catch_sr, + CATCH_INTERNAL_LINEINFO, + "Dummy", + Catch::ResultDisposition::Normal ); +} diff --git a/tests/SelfTest/IntrospectiveTests/Details.tests.cpp b/tests/SelfTest/IntrospectiveTests/Details.tests.cpp index a5a43926..d7175756 100644 --- a/tests/SelfTest/IntrospectiveTests/Details.tests.cpp +++ b/tests/SelfTest/IntrospectiveTests/Details.tests.cpp @@ -89,6 +89,47 @@ TEST_CASE("Optional comparison ops", "[optional][approvals]") { } } +namespace { + struct MoveChecker { + bool has_moved = false; + MoveChecker() = default; + MoveChecker( MoveChecker const& rhs ) = default; + MoveChecker& operator=( MoveChecker const& rhs ) = default; + MoveChecker( MoveChecker&& rhs ) noexcept { rhs.has_moved = true; } + MoveChecker& operator=( MoveChecker&& rhs ) noexcept { + rhs.has_moved = true; + return *this; + } + }; +} + +TEST_CASE( "Optional supports move ops", "[optional][approvals]" ) { + using Catch::Optional; + MoveChecker a; + Optional opt_A( a ); + REQUIRE_FALSE( a.has_moved ); + REQUIRE_FALSE( opt_A->has_moved ); + + SECTION( "Move construction from element" ) { + Optional opt_B( CATCH_MOVE( a ) ); + REQUIRE( a.has_moved ); + } + SECTION( "Move assignment from element" ) { + opt_A = CATCH_MOVE( a ); + REQUIRE( a.has_moved ); + } + SECTION( "Move construction from optional" ) { + Optional opt_B( CATCH_MOVE( opt_A ) ); + REQUIRE( opt_A->has_moved ); + } + SECTION( "Move assignment from optional" ) { + Optional opt_B( opt_A ); + REQUIRE_FALSE( opt_A->has_moved ); + opt_B = CATCH_MOVE( opt_A ); + REQUIRE( opt_A->has_moved ); + } +} + TEST_CASE( "Decomposer checks that the argument is 0 when handling " "only-0-comparable types", "[decomposition][approvals]" ) { diff --git a/tests/SelfTest/IntrospectiveTests/FloatingPoint.tests.cpp b/tests/SelfTest/IntrospectiveTests/FloatingPoint.tests.cpp index 08a579c9..eaf22a44 100644 --- a/tests/SelfTest/IntrospectiveTests/FloatingPoint.tests.cpp +++ b/tests/SelfTest/IntrospectiveTests/FloatingPoint.tests.cpp @@ -9,7 +9,9 @@ #include #include #include +#include +#include TEST_CASE("convertToBits", "[floating-point][conversion]") { using Catch::Detail::convertToBits; @@ -72,3 +74,60 @@ TEST_CASE("UlpDistance", "[floating-point][ulp][approvals]") { CHECK( ulpDistance( 1.f, 2.f ) == 0x80'00'00 ); CHECK( ulpDistance( -2.f, 2.f ) == 0x80'00'00'00 ); } + + + +TEMPLATE_TEST_CASE("gamma", "[approvals][floating-point][ulp][gamma]", float, double) { + using Catch::Detail::gamma; + using Catch::Detail::directCompare; + + // We need to butcher the equal tests with the directCompare helper, + // because the Wfloat-equal triggers in decomposer rather than here, + // so we cannot locally disable it. Goddamn GCC. + CHECK( directCompare( gamma( TestType( -1. ), TestType( 1. ) ), + gamma( TestType( 0.2332 ), TestType( 1.0 ) ) ) ); + CHECK( directCompare( gamma( TestType( -2. ), TestType( 0 ) ), + gamma( TestType( 1. ), TestType( 1.5 ) ) ) ); + CHECK( gamma( TestType( 0. ), TestType( 1.0 ) ) < + gamma( TestType( 1.0 ), TestType( 1.5 ) ) ); + CHECK( gamma( TestType( 0 ), TestType( 1. ) ) < + std::numeric_limits::epsilon() ); + CHECK( gamma( TestType( -1. ), TestType( -0. ) ) < + std::numeric_limits::epsilon() ); + CHECK( directCompare( gamma( TestType( 1. ), TestType( 2. ) ), + std::numeric_limits::epsilon() ) ); + CHECK( directCompare( gamma( TestType( -2. ), TestType( -1. ) ), + std::numeric_limits::epsilon() ) ); +} + +TEMPLATE_TEST_CASE("count_equidistant_floats", + "[approvals][floating-point][distance]", + float, + double) { + using Catch::Detail::count_equidistant_floats; + auto count_steps = []( TestType a, TestType b ) { + return count_equidistant_floats( a, b, Catch::Detail::gamma( a, b ) ); + }; + + CHECK( count_steps( TestType( -1. ), TestType( 1. ) ) == + 2 * count_steps( TestType( 0. ), TestType( 1. ) ) ); +} + +TEST_CASE( "count_equidistant_floats", + "[approvals][floating-point][distance]" ) { + using Catch::Detail::count_equidistant_floats; + auto count_floats_with_scaled_ulp = []( auto a, auto b ) { + return count_equidistant_floats( a, b, Catch::Detail::gamma( a, b ) ); + }; + + CHECK( count_floats_with_scaled_ulp( 1., 1.5 ) == 1ull << 51 ); + CHECK( count_floats_with_scaled_ulp( 1.25, 1.5 ) == 1ull << 50 ); + CHECK( count_floats_with_scaled_ulp( 1.f, 1.5f ) == 1 << 22 ); + + STATIC_REQUIRE( std::is_same::value ); + STATIC_REQUIRE( std::is_same::value ); +} diff --git a/tests/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp b/tests/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp index 1c203b6b..acfeebed 100644 --- a/tests/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp +++ b/tests/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp @@ -10,12 +10,15 @@ # pragma GCC diagnostic ignored "-Wfloat-equal" #endif +#include + #include #include #include #include #include #include +#include // Tests of generator implementation details TEST_CASE("Generators internals", "[generators][internals]") { @@ -411,6 +414,7 @@ TEST_CASE("GENERATE handles function (pointers)", "[generators][compilation][app TEST_CASE("GENERATE decays arrays", "[generators][compilation][approvals]") { auto str = GENERATE("abc", "def", "gh"); + (void)str; STATIC_REQUIRE(std::is_same::value); } @@ -534,3 +538,39 @@ TEST_CASE( "Random generators can be seeded", "[generators][approvals]" ) { } } } + +TEST_CASE("Filter generator throws exception for empty generator", + "[generators]") { + using namespace Catch::Generators; + + REQUIRE_THROWS_AS( + filter( []( int ) { return false; }, value( 3 ) ), + Catch::GeneratorException ); +} + +TEST_CASE("from_range(container) supports ADL begin/end and arrays", "[generators][from-range][approvals]") { + using namespace Catch::Generators; + + SECTION("C array") { + int arr[3]{ 5, 6, 7 }; + auto gen = from_range( arr ); + REQUIRE( gen.get() == 5 ); + REQUIRE( gen.next() ); + REQUIRE( gen.get() == 6 ); + REQUIRE( gen.next() ); + REQUIRE( gen.get() == 7 ); + REQUIRE_FALSE( gen.next() ); + } + + SECTION( "ADL range" ) { + unrelated::needs_ADL_begin range{ 1, 2, 3 }; + auto gen = from_range( range ); + REQUIRE( gen.get() == 1 ); + REQUIRE( gen.next() ); + REQUIRE( gen.get() == 2 ); + REQUIRE( gen.next() ); + REQUIRE( gen.get() == 3 ); + REQUIRE_FALSE( gen.next() ); + } + +} diff --git a/tests/SelfTest/IntrospectiveTests/Integer.tests.cpp b/tests/SelfTest/IntrospectiveTests/Integer.tests.cpp new file mode 100644 index 00000000..fd620ebb --- /dev/null +++ b/tests/SelfTest/IntrospectiveTests/Integer.tests.cpp @@ -0,0 +1,150 @@ + +// 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 +#include + +namespace { + template + static void + CommutativeMultCheck( Int a, Int b, Int upper_result, Int lower_result ) { + using Catch::Detail::extendedMult; + using Catch::Detail::ExtendedMultResult; + CHECK( extendedMult( a, b ) == + ExtendedMultResult{ upper_result, lower_result } ); + CHECK( extendedMult( b, a ) == + ExtendedMultResult{ upper_result, lower_result } ); + } +} // namespace + +TEST_CASE( "extendedMult 64x64", "[Integer][approvals]" ) { + // a x 0 == 0 + CommutativeMultCheck( 0x1234'5678'9ABC'DEFF, 0, 0, 0 ); + + // bit carried from low half to upper half + CommutativeMultCheck( uint64_t( 1 ) << 63, 2, 1, 0 ); + + // bits in upper half on one side, bits in lower half on other side + CommutativeMultCheck( 0xcdcd'dcdc'0000'0000, + 0x0000'0000'aeae'aeae, + 0x0000'0000'8c6e'5a77, + 0x7391'a588'0000'0000 ); + + // Some input numbers without interesting patterns + CommutativeMultCheck( 0xaaaa'aaaa'aaaa'aaaa, + 0xbbbb'bbbb'bbbb'bbbb, + 0x7d27'd27d'27d2'7d26, + 0xd82d'82d8'2d82'd82e ); + + CommutativeMultCheck( 0x7d27'd27d'27d2'7d26, + 0xd82d'82d8'2d82'd82e, + 0x69af'd991'8256'b953, + 0x8724'8909'fcb6'8cd4 ); + + CommutativeMultCheck( 0xdead'beef'dead'beef, + 0xfeed'feed'feed'feef, + 0xddbf'680b'2b0c'b558, + 0x7a36'b06f'2ce9'6321 ); + + CommutativeMultCheck( 0xddbf'680b'2b0c'b558, + 0x7a36'b06f'2ce9'6321, + 0x69dc'96c9'294b'fc7f, + 0xd038'39fa'a3dc'6858 ); + + CommutativeMultCheck( 0x61c8'8646'80b5'83eb, + 0x61c8'8646'80b5'83eb, + 0x2559'92d3'8220'8bbe, + 0xdf44'2d22'ce48'59b9 ); +} + +TEST_CASE( "SizedUnsignedType helpers", "[integer][approvals]" ) { + using Catch::Detail::SizedUnsignedType_t; + using Catch::Detail::DoubleWidthUnsignedType_t; + + STATIC_REQUIRE( sizeof( SizedUnsignedType_t<1> ) == 1 ); + STATIC_REQUIRE( sizeof( SizedUnsignedType_t<2> ) == 2 ); + STATIC_REQUIRE( sizeof( SizedUnsignedType_t<4> ) == 4 ); + STATIC_REQUIRE( sizeof( SizedUnsignedType_t<8> ) == 8 ); + + STATIC_REQUIRE( sizeof( DoubleWidthUnsignedType_t ) == 2 ); + STATIC_REQUIRE( std::is_unsigned>::value ); + STATIC_REQUIRE( sizeof( DoubleWidthUnsignedType_t ) == 4 ); + STATIC_REQUIRE( std::is_unsigned>::value ); + STATIC_REQUIRE( sizeof( DoubleWidthUnsignedType_t ) == 8 ); + STATIC_REQUIRE( std::is_unsigned>::value ); +} + +TEST_CASE( "extendedMult 32x32", "[integer][approvals]" ) { + // a x 0 == 0 + CommutativeMultCheck( 0x1234'5678, 0, 0, 0 ); + + // bit carried from low half to upper half + CommutativeMultCheck( uint32_t(1) << 31, 2, 1, 0 ); + + // bits in upper half on one side, bits in lower half on other side + CommutativeMultCheck( 0xdcdc'0000, 0x0000'aabb, 0x0000'934b, 0x6cb4'0000 ); + + // Some input numbers without interesting patterns + CommutativeMultCheck( + 0xaaaa'aaaa, 0xbbbb'bbbb, 0x7d27'd27c, 0x2d82'd82e ); + + CommutativeMultCheck( + 0x7d27'd27c, 0x2d82'd82e, 0x163f'f7e8, 0xc5b8'7248 ); + + CommutativeMultCheck( + 0xdead'beef, 0xfeed'feed, 0xddbf'6809, 0x6f8d'e543 ); + + CommutativeMultCheck( + 0xddbf'6809, 0x6f8d'e543, 0x60a0'e71e, 0x751d'475b ); +} + +TEST_CASE( "extendedMult 8x8", "[integer][approvals]" ) { + // a x 0 == 0 + CommutativeMultCheck( 0xcd, 0, 0, 0 ); + + // bit carried from low half to upper half + CommutativeMultCheck( uint8_t( 1 ) << 7, 2, 1, 0 ); + + // bits in upper half on one side, bits in lower half on other side + CommutativeMultCheck( 0x80, 0x03, 0x01, 0x80 ); + + // Some input numbers without interesting patterns + CommutativeMultCheck( 0xaa, 0xbb, 0x7c, 0x2e ); + CommutativeMultCheck( 0x7c, 0x2e, 0x16, 0x48 ); + CommutativeMultCheck( 0xdc, 0xcd, 0xb0, 0x2c ); + CommutativeMultCheck( 0xb0, 0x2c, 0x1e, 0x40 ); +} + + +TEST_CASE( "negative and positive signed integers keep their order after transposeToNaturalOrder", + "[integer][approvals]") { + using Catch::Detail::transposeToNaturalOrder; + int32_t negative( -1 ); + int32_t positive( 1 ); + uint32_t adjusted_negative = + transposeToNaturalOrder( static_cast( negative ) ); + uint32_t adjusted_positive = + transposeToNaturalOrder( static_cast( positive ) ); + REQUIRE( adjusted_negative < adjusted_positive ); + REQUIRE( adjusted_positive - adjusted_negative == 2 ); + + // Conversion has to be reversible + REQUIRE( negative == static_cast( transposeToNaturalOrder( + adjusted_negative ) ) ); + REQUIRE( positive == static_cast( transposeToNaturalOrder( + adjusted_positive ) ) ); +} + +TEST_CASE( "unsigned integers are unchanged by transposeToNaturalOrder", + "[integer][approvals]") { + using Catch::Detail::transposeToNaturalOrder; + uint32_t max = std::numeric_limits::max(); + uint32_t zero = 0; + REQUIRE( max == transposeToNaturalOrder( max ) ); + REQUIRE( zero == transposeToNaturalOrder( zero ) ); +} diff --git a/tests/SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp b/tests/SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp index 96c0977b..bc8d715b 100644 --- a/tests/SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp +++ b/tests/SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp @@ -22,6 +22,8 @@ #include #include +#include + namespace { struct manual_clock { public: @@ -154,8 +156,12 @@ TEST_CASE("uniform samples", "[benchmark]") { std::vector samples(100); std::fill(samples.begin(), samples.end(), 23); - using it = std::vector::iterator; - auto e = Catch::Benchmark::Detail::bootstrap(0.95, samples.begin(), samples.end(), samples, [](it a, it b) { + auto e = Catch::Benchmark::Detail::bootstrap( + 0.95, + samples.data(), + samples.data() + samples.size(), + samples, + []( double const* a, double const* b ) { auto sum = std::accumulate(a, b, 0.); return sum / (b - a); }); @@ -196,7 +202,7 @@ TEST_CASE("normal_quantile", "[benchmark]") { TEST_CASE("mean", "[benchmark]") { std::vector x{ 10., 20., 14., 16., 30., 24. }; - auto m = Catch::Benchmark::Detail::mean(x.begin(), x.end()); + auto m = Catch::Benchmark::Detail::mean(x.data(), x.data() + x.size()); REQUIRE(m == 19.); } @@ -204,9 +210,9 @@ TEST_CASE("mean", "[benchmark]") { TEST_CASE("weighted_average_quantile", "[benchmark]") { std::vector x{ 10., 20., 14., 16., 30., 24. }; - auto q1 = Catch::Benchmark::Detail::weighted_average_quantile(1, 4, x.begin(), x.end()); - auto med = Catch::Benchmark::Detail::weighted_average_quantile(1, 2, x.begin(), x.end()); - auto q3 = Catch::Benchmark::Detail::weighted_average_quantile(3, 4, x.begin(), x.end()); + auto q1 = Catch::Benchmark::Detail::weighted_average_quantile(1, 4, x.data(), x.data() + x.size()); + auto med = Catch::Benchmark::Detail::weighted_average_quantile(1, 2, x.data(), x.data() + x.size()); + auto q3 = Catch::Benchmark::Detail::weighted_average_quantile(3, 4, x.data(), x.data() + x.size()); REQUIRE(q1 == 14.5); REQUIRE(med == 18.); @@ -225,7 +231,8 @@ TEST_CASE("classify_outliers", "[benchmark]") { SECTION("none") { std::vector x{ 10., 20., 14., 16., 30., 24. }; - auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end()); + auto o = Catch::Benchmark::Detail::classify_outliers( + x.data(), x.data() + x.size() ); REQUIRE(o.samples_seen == static_cast(x.size())); require_outliers(o, 0, 0, 0, 0); @@ -233,7 +240,8 @@ TEST_CASE("classify_outliers", "[benchmark]") { SECTION("low severe") { std::vector x{ -12., 20., 14., 16., 30., 24. }; - auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end()); + auto o = Catch::Benchmark::Detail::classify_outliers( + x.data(), x.data() + x.size() ); REQUIRE(o.samples_seen == static_cast(x.size())); require_outliers(o, 1, 0, 0, 0); @@ -241,7 +249,8 @@ TEST_CASE("classify_outliers", "[benchmark]") { SECTION("low mild") { std::vector x{ 1., 20., 14., 16., 30., 24. }; - auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end()); + auto o = Catch::Benchmark::Detail::classify_outliers( + x.data(), x.data() + x.size() ); REQUIRE(o.samples_seen == static_cast(x.size())); require_outliers(o, 0, 1, 0, 0); @@ -249,7 +258,8 @@ TEST_CASE("classify_outliers", "[benchmark]") { SECTION("high mild") { std::vector x{ 10., 20., 14., 16., 36., 24. }; - auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end()); + auto o = Catch::Benchmark::Detail::classify_outliers( + x.data(), x.data() + x.size() ); REQUIRE(o.samples_seen == static_cast(x.size())); require_outliers(o, 0, 0, 1, 0); @@ -257,7 +267,8 @@ TEST_CASE("classify_outliers", "[benchmark]") { SECTION("high severe") { std::vector x{ 10., 20., 14., 16., 49., 24. }; - auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end()); + auto o = Catch::Benchmark::Detail::classify_outliers( + x.data(), x.data() + x.size() ); REQUIRE(o.samples_seen == static_cast(x.size())); require_outliers(o, 0, 0, 0, 1); @@ -265,7 +276,8 @@ TEST_CASE("classify_outliers", "[benchmark]") { SECTION("mixed") { std::vector x{ -20., 20., 14., 16., 39., 24. }; - auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end()); + auto o = Catch::Benchmark::Detail::classify_outliers( + x.data(), x.data() + x.size() ); REQUIRE(o.samples_seen == static_cast(x.size())); require_outliers(o, 1, 0, 1, 0); @@ -280,15 +292,13 @@ TEST_CASE("analyse", "[approvals][benchmark]") { data.benchmarkSamples = 99; Catch::Config config{data}; - using Duration = Catch::Benchmark::FloatDuration; - - Catch::Benchmark::Environment env; - std::vector samples(99); + using FDuration = Catch::Benchmark::FDuration; + std::vector samples(99); for (size_t i = 0; i < samples.size(); ++i) { - samples[i] = Duration(23 + (i % 3 - 1)); + samples[i] = FDuration(23 + (i % 3 - 1)); } - auto analysis = Catch::Benchmark::Detail::analyse(config, env, samples.begin(), samples.end()); + auto analysis = Catch::Benchmark::Detail::analyse(config, samples.data(), samples.data() + samples.size()); CHECK( analysis.mean.point.count() == 23 ); CHECK( analysis.mean.lower_bound.count() < 23 ); CHECK(analysis.mean.lower_bound.count() > 22); @@ -321,15 +331,13 @@ TEST_CASE("analyse no analysis", "[benchmark]") { data.benchmarkSamples = 99; Catch::Config config{ data }; - using Duration = Catch::Benchmark::FloatDuration; - - Catch::Benchmark::Environment env; - std::vector samples(99); + using FDuration = Catch::Benchmark::FDuration; + std::vector samples(99); for (size_t i = 0; i < samples.size(); ++i) { - samples[i] = Duration(23 + (i % 3 - 1)); + samples[i] = FDuration(23 + (i % 3 - 1)); } - auto analysis = Catch::Benchmark::Detail::analyse(config, env, samples.begin(), samples.end()); + auto analysis = Catch::Benchmark::Detail::analyse(config, samples.data(), samples.data() + samples.size()); CHECK(analysis.mean.point.count() == 23); CHECK(analysis.mean.lower_bound.count() == 23); CHECK(analysis.mean.upper_bound.count() == 23); @@ -442,6 +450,6 @@ TEST_CASE("Failing benchmarks", "[!benchmark][.approvals]") { } TEST_CASE( "Failing benchmark respects should-fail", - "[!shouldfail][!benchmark][.approvals]" ) { + "[!shouldfail][!benchmark][approvals]" ) { BENCHMARK( "Asserting benchmark" ) { REQUIRE( 1 == 2 ); }; } diff --git a/tests/SelfTest/IntrospectiveTests/Json.tests.cpp b/tests/SelfTest/IntrospectiveTests/Json.tests.cpp new file mode 100644 index 00000000..8204e3c4 --- /dev/null +++ b/tests/SelfTest/IntrospectiveTests/Json.tests.cpp @@ -0,0 +1,152 @@ + +// 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 +#include +#include + +#include + +namespace { + struct Custom {}; + static std::ostream& operator<<( std::ostream& os, Custom const& ) { + return os << "custom"; + } +} // namespace + +TEST_CASE( "JsonWriter", "[JSON][JsonWriter]" ) { + + std::stringstream stream; + SECTION( "Newly constructed JsonWriter does nothing" ) { + Catch::JsonValueWriter writer{ stream }; + REQUIRE( stream.str() == "" ); + } + + SECTION( "Calling writeObject will create an empty pair of braces" ) { + { auto writer = Catch::JsonValueWriter{ stream }.writeObject(); } + REQUIRE( stream.str() == "{\n}" ); + } + + SECTION( "Calling writeObject with key will create an object to write the " + "value" ) { + using Catch::Matchers::ContainsSubstring; + { + auto writer = Catch::JsonValueWriter{ stream }.writeObject(); + writer.write( "int" ).write( 1 ); + writer.write( "double" ).write( 1.5 ); + writer.write( "true" ).write( true ); + writer.write( "false" ).write( false ); + writer.write( "string" ).write( "this is a string" ); + writer.write( "array" ).writeArray().write( 1 ).write( 2 ); + } + REQUIRE_THAT( + stream.str(), + ContainsSubstring( "\"int\": 1," ) && + ContainsSubstring( "\"double\": 1.5," ) && + ContainsSubstring( "\"true\": true," ) && + ContainsSubstring( "\"false\": false," ) && + ContainsSubstring( "\"string\": \"this is a string\"," ) && + ContainsSubstring( "\"array\": [\n 1,\n 2\n ]\n}" ) ); + } + + SECTION( "nesting objects" ) { + using Catch::Matchers::ContainsSubstring; + { + auto writer = Catch::JsonValueWriter{ stream }.writeObject(); + writer.write( "empty_object" ).writeObject(); + writer.write( "fully_object" ) + .writeObject() + .write( "key" ) + .write( 1 ); + } + REQUIRE_THAT( stream.str(), + ContainsSubstring( "\"empty_object\": {\n }," ) && + ContainsSubstring( + "\"fully_object\": {\n \"key\": 1\n }" ) ); + } + + SECTION( "Calling writeArray will create an empty pair of braces" ) { + { auto writer = Catch::JsonValueWriter{ stream }.writeArray(); } + REQUIRE( stream.str() == "[\n]" ); + } + + SECTION( "Calling writeArray creates array to write the values to" ) { + { + auto writer = Catch::JsonValueWriter{ stream }.writeArray(); + writer.write( 1 ); + writer.write( 1.5 ); + writer.write( true ); + writer.write( false ); + writer.write( "this is a string" ); + writer.writeObject().write( "object" ).write( 42 ); + writer.writeArray().write( "array" ).write( 42.5 ); + } + REQUIRE( stream.str() == "[\n 1,\n 1.5,\n true,\n false,\n \"this is a string\",\n {\n \"object\": 42\n },\n [\n \"array\",\n 42.5\n ]\n]" ); + } + + SECTION( + "Moved from JsonObjectWriter shall not insert superfluous brace" ) { + { + auto writer = Catch::JsonObjectWriter{ stream }; + auto another_writer = std::move( writer ); + } + REQUIRE( stream.str() == "{\n}" ); + } + SECTION( + "Moved from JsonArrayWriter shall not insert superfluous bracket" ) { + { + auto writer = Catch::JsonArrayWriter{ stream }; + auto another_writer = std::move( writer ); + } + REQUIRE( stream.str() == "[\n]" ); + } + SECTION( "Custom class shall be quoted" ) { + Catch::JsonValueWriter{ stream }.write( Custom{} ); + REQUIRE( stream.str() == "\"custom\"" ); + } +} + +TEST_CASE( "JsonWriter escapes charaters in strings properly", "[JsonWriter]" ) { + std::stringstream sstream; + SECTION( "Quote in a string is escaped" ) { + Catch::JsonValueWriter{ sstream }.write( "\"" ); + REQUIRE( sstream.str() == "\"\\\"\"" ); + } + SECTION("Backslash in a string is escaped") { + Catch::JsonValueWriter{ sstream }.write( "\\" ); + REQUIRE( sstream.str() == "\"\\\\\"" ); + } + SECTION( "Forward slash in a string is **not** escaped" ) { + Catch::JsonValueWriter{ sstream }.write( "/" ); + REQUIRE( sstream.str() == "\"/\"" ); + } + SECTION( "Backspace in a string is escaped" ) { + Catch::JsonValueWriter{ sstream }.write( "\b" ); + REQUIRE( sstream.str() == "\"\\b\"" ); + } + SECTION( "Formfeed in a string is escaped" ) { + Catch::JsonValueWriter{ sstream }.write( "\f" ); + REQUIRE( sstream.str() == "\"\\f\"" ); + } + SECTION( "linefeed in a string is escaped" ) { + Catch::JsonValueWriter{ sstream }.write( "\n" ); + REQUIRE( sstream.str() == "\"\\n\"" ); + } + SECTION( "carriage return in a string is escaped" ) { + Catch::JsonValueWriter{ sstream }.write( "\r" ); + REQUIRE( sstream.str() == "\"\\r\"" ); + } + SECTION( "tab in a string is escaped" ) { + Catch::JsonValueWriter{ sstream }.write( "\t" ); + REQUIRE( sstream.str() == "\"\\t\"" ); + } + SECTION( "combination of characters is escaped" ) { + Catch::JsonValueWriter{ sstream }.write( "\\/\t\r\n" ); + REQUIRE( sstream.str() == "\"\\\\/\\t\\r\\n\"" ); + } +} diff --git a/tests/SelfTest/IntrospectiveTests/PartTracker.tests.cpp b/tests/SelfTest/IntrospectiveTests/PartTracker.tests.cpp index ac8be645..c13ec573 100644 --- a/tests/SelfTest/IntrospectiveTests/PartTracker.tests.cpp +++ b/tests/SelfTest/IntrospectiveTests/PartTracker.tests.cpp @@ -14,8 +14,8 @@ using namespace Catch; namespace { -Catch::TestCaseTracking::NameAndLocation makeNAL( std::string const& name ) { - return Catch::TestCaseTracking::NameAndLocation( name, Catch::SourceLineInfo("",0) ); +Catch::TestCaseTracking::NameAndLocationRef makeNAL( StringRef name ) { + return Catch::TestCaseTracking::NameAndLocationRef( name, Catch::SourceLineInfo("",0) ); } } diff --git a/tests/SelfTest/IntrospectiveTests/RandomNumberGeneration.tests.cpp b/tests/SelfTest/IntrospectiveTests/RandomNumberGeneration.tests.cpp index 8018b7eb..03be6c9c 100644 --- a/tests/SelfTest/IntrospectiveTests/RandomNumberGeneration.tests.cpp +++ b/tests/SelfTest/IntrospectiveTests/RandomNumberGeneration.tests.cpp @@ -7,9 +7,17 @@ // SPDX-License-Identifier: BSL-1.0 #include +#include +#include +#include #include #include +#include +#include #include +#include + +#include TEST_CASE("Our PCG implementation provides expected results for known seeds", "[rng]") { Catch::SimplePcg32 rng; @@ -60,3 +68,523 @@ TEST_CASE("Random seed generation accepts known methods", "[rng][seed]") { REQUIRE_NOTHROW(Catch::generateRandomSeed(method)); } + +TEMPLATE_TEST_CASE("uniform_floating_point_distribution never returns infs from finite range", + "[rng][distribution][floating-point][approvals]", float, double) { + std::random_device rd{}; + Catch::SimplePcg32 pcg( rd() ); + Catch::uniform_floating_point_distribution dist( + -std::numeric_limits::max(), + std::numeric_limits::max() ); + + for (size_t i = 0; i < 10'000; ++i) { + auto ret = dist( pcg ); + REQUIRE_FALSE( std::isinf( ret ) ); + REQUIRE_FALSE( std::isnan( ret ) ); + } +} + +TEST_CASE( "fillBitsFrom - shortening and stretching", "[rng][approvals]" ) { + using Catch::Detail::fillBitsFrom; + + // The seed is not important, but the numbers below have to be repeatable. + // They should also exhibit the same general pattern of being prefixes + Catch::SimplePcg32 pcg( 0xaabb'ccdd ); + + SECTION( "Shorten to 8 bits" ) { + // We cast the result to avoid dealing with char-like type in uint8_t + auto shortened = static_cast( fillBitsFrom( pcg ) ); + REQUIRE( shortened == 0xcc ); + } + SECTION( "Shorten to 16 bits" ) { + auto shortened = fillBitsFrom( pcg ); + REQUIRE( shortened == 0xccbe ); + } + SECTION( "Keep at 32 bits" ) { + auto n = fillBitsFrom( pcg ); + REQUIRE( n == 0xccbe'5f04 ); + } + SECTION( "Stretch to 64 bits" ) { + auto stretched = fillBitsFrom( pcg ); + REQUIRE( stretched == 0xccbe'5f04'a424'a486 ); + } +} + +TEST_CASE("uniform_integer_distribution can return the bounds", "[rng][distribution]") { + Catch::uniform_integer_distribution dist( -10, 10 ); + REQUIRE( dist.a() == -10 ); + REQUIRE( dist.b() == 10 ); +} + +namespace { + template + static void CheckReturnValue(Catch::uniform_integer_distribution& dist, + Catch::SimplePcg32& rng, + T target) { + REQUIRE( dist.a() == dist.b() ); + for (int i = 0; i < 1'000; ++i) { + REQUIRE( dist( rng ) == target ); + } + } +} + +TEMPLATE_TEST_CASE( "uniform_integer_distribution can handle unit ranges", + "[rng][distribution][approvals]", + unsigned char, + signed char, + char, + uint8_t, + int8_t, + uint16_t, + int16_t, + uint32_t, + int32_t, + uint64_t, + int64_t ) { + // We want random seed to sample different parts of the rng state, + // the output is predetermined anyway + std::random_device rd; + auto seed = rd(); + CAPTURE( seed ); + Catch::SimplePcg32 pcg( seed ); + + // We check unitary ranges of 3 different values, min for type, max for type, + // some value inbetween just to make sure + SECTION("lowest value") { + constexpr auto lowest = std::numeric_limits::min(); + Catch::uniform_integer_distribution dist( lowest, lowest ); + CheckReturnValue( dist, pcg, lowest ); + } + SECTION( "highest value" ) { + constexpr auto highest = std::numeric_limits::max(); + Catch::uniform_integer_distribution dist( highest, highest ); + CheckReturnValue( dist, pcg, highest ); + } + SECTION( "some value" ) { + constexpr auto some = TestType( 42 ); + Catch::uniform_integer_distribution dist( some, some ); + CheckReturnValue( dist, pcg, some ); + } +} + +// Bool needs its own test because it doesn't have a valid "third" value +TEST_CASE( "uniform_integer_distribution can handle boolean unit ranges", + "[rng][distribution][approvals]" ) { + // We want random seed to sample different parts of the rng state, + // the output is predetermined anyway + std::random_device rd; + auto seed = rd(); + CAPTURE( seed ); + Catch::SimplePcg32 pcg( seed ); + + // We check unitary ranges of 3 different values, min for type, max for + // type, some value inbetween just to make sure + SECTION( "lowest value" ) { + Catch::uniform_integer_distribution dist( false, false ); + CheckReturnValue( dist, pcg, false ); + } + SECTION( "highest value" ) { + Catch::uniform_integer_distribution dist( true, true ); + CheckReturnValue( dist, pcg, true ); + } +} + +TEMPLATE_TEST_CASE( "uniform_integer_distribution can handle full width ranges", + "[rng][distribution][approvals]", + unsigned char, + signed char, + char, + uint8_t, + int8_t, + uint16_t, + int16_t, + uint32_t, + int32_t, + uint64_t, + int64_t ) { + // We want random seed to sample different parts of the rng state, + // the output is predetermined anyway + std::random_device rd; + auto seed = rd(); + CAPTURE( seed ); + Catch::SimplePcg32 pcg( seed ); + + constexpr auto lowest = std::numeric_limits::min(); + constexpr auto highest = std::numeric_limits::max(); + Catch::uniform_integer_distribution dist( lowest, highest ); + STATIC_REQUIRE( std::is_same::value ); + + // We need to do bit operations on the results, so we will have to + // cast them to unsigned type. + using BitType = std::make_unsigned_t; + BitType ORs = 0; + BitType ANDs = BitType(-1); + for (int i = 0; i < 100; ++i) { + auto bits = static_cast( dist( pcg ) ); + ORs |= bits; + ANDs &= bits; + } + // Assuming both our RNG and distribution are unbiased, asking for + // the full range should essentially give us random bit generator. + // Over long run, OR of all the generated values should have all + // bits set to 1, while AND should have all bits set to 0. + // The chance of this test failing for unbiased pipeline is + // 1 / 2**iters, which for 100 iterations is astronomical. + REQUIRE( ORs == BitType( -1 ) ); + REQUIRE( ANDs == 0 ); +} + +namespace { + template + struct uniform_integer_test_params; + + template <> + struct uniform_integer_test_params { + static constexpr bool lowest = false; + static constexpr bool highest = true; + // This seems weird, but it is an artifact of the specific seed + static constexpr bool expected[] = { true, + true, + true, + true, + true, + true, + false, + true, + true, + true, + true, + true, + false, + true, + true }; + }; + + template <> + struct uniform_integer_test_params { + static constexpr char lowest = 32; + static constexpr char highest = 126; + static constexpr char expected[] = { 'k', + '\\', + 'Z', + 'X', + '`', + 'Q', + ';', + 'o', + ']', + 'T', + 'v', + 'p', + ':', + 'S', + 't' }; + }; + + template <> + struct uniform_integer_test_params { + static constexpr uint8_t lowest = 3; + static constexpr uint8_t highest = 123; + static constexpr uint8_t expected[] = { 'c', + 'P', + 'M', + 'J', + 'U', + 'A', + '%', + 'h', + 'Q', + 'F', + 'q', + 'i', + '$', + 'E', + 'o' }; + }; + + template <> + struct uniform_integer_test_params { + static constexpr int8_t lowest = -27; + static constexpr int8_t highest = 73; + static constexpr int8_t expected[] = { '5', + '%', + '#', + ' ', + '*', + 25, + 2, + '9', + '&', + 29, + 'A', + ':', + 1, + 28, + '?' }; + }; + + template <> + struct uniform_integer_test_params { + static constexpr uint16_t lowest = 123; + static constexpr uint16_t highest = 33333; + static constexpr uint16_t expected[] = { 26684, + 21417, + 20658, + 19791, + 22896, + 17433, + 9806, + 27948, + 21767, + 18588, + 30556, + 28244, + 9439, + 18293, + 29949 }; + }; + + template <> + struct uniform_integer_test_params { + static constexpr int16_t lowest = -17222; + static constexpr int16_t highest = 17222; + static constexpr int16_t expected[] = { 10326, + 4863, + 4076, + 3177, + 6397, + 731, + -7179, + 11637, + 5226, + 1929, + 14342, + 11944, + -7560, + 1623, + 13712 }; + }; + + template <> + struct uniform_integer_test_params { + static constexpr uint32_t lowest = 17222; + static constexpr uint32_t highest = 234234; + static constexpr uint32_t expected[] = { 190784, + 156367, + 151409, + 145743, + 166032, + 130337, + 80501, + 199046, + 158654, + 137883, + 216091, + 200981, + 78099, + 135954, + 212120 }; + }; + + template <> + struct uniform_integer_test_params { + static constexpr int32_t lowest = -237272; + static constexpr int32_t highest = 234234; + static constexpr int32_t expected[] = { 139829, + 65050, + 54278, + 41969, + 86051, + 8494, + -99785, + 157781, + 70021, + 24890, + 194815, + 161985, + -105004, + 20699, + 186186 }; + }; + + template <> + struct uniform_integer_test_params { + static constexpr uint64_t lowest = 1234; + static constexpr uint64_t highest = 1234567890; + static constexpr uint64_t expected[] = { 987382749, + 763380386, + 846572137, + 359990258, + 804599765, + 1131353566, + 346324913, + 1108760730, + 1141693933, + 856999148, + 879390623, + 1149485521, + 900556586, + 952385958, + 807916408 }; + }; + + template <> + struct uniform_integer_test_params { + static constexpr int64_t lowest = -1234567890; + static constexpr int64_t highest = 1234567890; + static constexpr int64_t expected[] = { 740197113, + 292191940, + 458575608, + -514589122, + 374630781, + 1028139036, + -541919840, + 982953318, + 1048819790, + 479429651, + 524212647, + 1064402981, + 566544615, + 670203462, + 381264073 }; + }; + + // We need these definitions for C++14 and earlier, but + // GCC will complain about them in newer C++ standards +#if __cplusplus <= 201402L + constexpr bool uniform_integer_test_params::expected[]; + constexpr char uniform_integer_test_params::expected[]; + constexpr uint8_t uniform_integer_test_params::expected[]; + constexpr int8_t uniform_integer_test_params::expected[]; + constexpr uint16_t uniform_integer_test_params::expected[]; + constexpr int16_t uniform_integer_test_params::expected[]; + constexpr uint32_t uniform_integer_test_params::expected[]; + constexpr int32_t uniform_integer_test_params::expected[]; + constexpr uint64_t uniform_integer_test_params::expected[]; + constexpr int64_t uniform_integer_test_params::expected[]; +#endif + +} + +TEMPLATE_TEST_CASE( "uniform_integer_distribution is reproducible", + "[rng][distribution][approvals]", + bool, + char, + uint8_t, + int8_t, + uint16_t, + int16_t, + uint32_t, + int32_t, + uint64_t, + int64_t) { + Catch::SimplePcg32 pcg( 0xaabb'ccdd ); + + constexpr auto lowest = uniform_integer_test_params::lowest; + constexpr auto highest = uniform_integer_test_params::highest; + Catch::uniform_integer_distribution dist(lowest, highest); + + constexpr auto iters = 15; + std::array generated; + for (int i = 0; i < iters; ++i) { + generated[i] = dist( pcg ); + } + + REQUIRE_THAT(generated, Catch::Matchers::RangeEquals(uniform_integer_test_params::expected)); +} + + +namespace { + template + struct uniform_fp_test_params; + + template<> + struct uniform_fp_test_params { + // These are exactly representable + static constexpr float lowest = -256.125f; + static constexpr float highest = 385.125f; + // These are just round-trip formatted + static constexpr float expected[] = { 92.56961f, + -23.170044f, + 310.81833f, + -53.023132f, + 105.03287f, + 198.77591f, + -172.72931f, + 51.805176f, + -241.10156f, + 64.66101f, + 212.12509f, + -49.24292f, + -177.1399f, + 245.23679f, + 173.22421f }; + }; + template <> + struct uniform_fp_test_params { + // These are exactly representable + static constexpr double lowest = -234582.9921875; + static constexpr double highest = 261238.015625; + // These are just round-trip formatted + static constexpr double expected[] = { 35031.207052832615, + 203783.3401838024, + 44667.940405848756, + -170100.5877224467, + -222966.7418051684, + 127472.72630072923, + -173510.88209096913, + 97394.16172239158, + 119123.6921592663, + 22595.741022785165, + 8988.68409120926, + 136906.86520606978, + 33369.19104222473, + 60912.7615841752, + -149060.05936760217 }; + }; + +// We need these definitions for C++14 and earlier, but +// GCC will complain about them in newer C++ standards +#if __cplusplus <= 201402L + constexpr float uniform_fp_test_params::expected[]; + constexpr double uniform_fp_test_params::expected[]; +#endif +} // namespace + +TEMPLATE_TEST_CASE( "uniform_floating_point_distribution is reproducible", + "[rng][distribution][floating-point][approvals]", + float, + double ) { + Catch::SimplePcg32 pcg( 0xaabb'aabb ); + + const auto lowest = uniform_fp_test_params::lowest; + const auto highest = uniform_fp_test_params::highest; + Catch::uniform_floating_point_distribution dist( lowest, highest ); + + constexpr auto iters = 15; + std::array generated; + for ( int i = 0; i < iters; ++i ) { + generated[i] = dist( pcg ); + } + + REQUIRE_THAT( generated, Catch::Matchers::RangeEquals( uniform_fp_test_params::expected ) ); +} + +TEMPLATE_TEST_CASE( "uniform_floating_point_distribution can handle unitary ranges", + "[rng][distribution][floating-point][approvals]", + float, + double ) { + std::random_device rd; + auto seed = rd(); + CAPTURE( seed ); + Catch::SimplePcg32 pcg( seed ); + + const auto highest = uniform_fp_test_params::highest; + Catch::uniform_floating_point_distribution dist( highest, + highest ); + + constexpr auto iters = 20; + for (int i = 0; i < iters; ++i) { + REQUIRE( Catch::Detail::directCompare( dist( pcg ), highest ) ); + } +} diff --git a/tests/SelfTest/IntrospectiveTests/Reporters.tests.cpp b/tests/SelfTest/IntrospectiveTests/Reporters.tests.cpp index 54c26a7a..e5a65bda 100644 --- a/tests/SelfTest/IntrospectiveTests/Reporters.tests.cpp +++ b/tests/SelfTest/IntrospectiveTests/Reporters.tests.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -110,7 +109,9 @@ TEST_CASE( "Reporter's write listings to provided stream", "[reporters]" ) { auto sstream = Catch::Detail::make_unique(); auto& sstreamRef = *sstream.get(); - Catch::Config config( Catch::ConfigData{} ); + Catch::ConfigData cfg_data; + cfg_data.rngSeed = 1234; + Catch::Config config( cfg_data ); auto reporter = factory.second->create( Catch::ReporterConfig{ &config, CATCH_MOVE( sstream ), Catch::ColourMode::None, {} } ); @@ -164,7 +165,7 @@ namespace { std::vector& recorder, Catch::IConfig const* config ): EventListenerBase( config ), - m_witness( witness ), + m_witness( CATCH_MOVE(witness) ), m_recorder( recorder ) {} @@ -182,7 +183,7 @@ namespace { std::vector& recorder, Catch::ReporterConfig&& config ): StreamingReporterBase( CATCH_MOVE(config) ), - m_witness( witness ), + m_witness( CATCH_MOVE(witness) ), m_recorder( recorder ) {} diff --git a/tests/SelfTest/IntrospectiveTests/String.tests.cpp b/tests/SelfTest/IntrospectiveTests/String.tests.cpp index 7a0b3b4a..43c58b49 100644 --- a/tests/SelfTest/IntrospectiveTests/String.tests.cpp +++ b/tests/SelfTest/IntrospectiveTests/String.tests.cpp @@ -177,7 +177,7 @@ TEST_CASE("StringRef at compilation time", "[Strings][StringRef][constexpr]") { STATIC_REQUIRE_FALSE(sr1.empty()); STATIC_REQUIRE(sr1.size() == 3); - using Catch::operator"" _sr; + using Catch::operator""_sr; constexpr auto sr2 = ""_sr; STATIC_REQUIRE(sr2.empty()); STATIC_REQUIRE(sr2.size() == 0); diff --git a/tests/SelfTest/IntrospectiveTests/Tag.tests.cpp b/tests/SelfTest/IntrospectiveTests/Tag.tests.cpp index ef321b27..43723758 100644 --- a/tests/SelfTest/IntrospectiveTests/Tag.tests.cpp +++ b/tests/SelfTest/IntrospectiveTests/Tag.tests.cpp @@ -98,7 +98,20 @@ TEST_CASE( "Test case with identical tags keeps just one", "[tags]" ) { REQUIRE( testCase.tags[0] == Tag( "tag1" ) ); } -TEST_CASE( "Empty tag is not allowed" ) { - REQUIRE_THROWS( Catch::TestCaseInfo( - "", { "fake test name", "[]" }, dummySourceLineInfo ) ); +TEST_CASE("Mismatched square brackets in tags are caught and reported", + "[tags][approvals]") { + using Catch::TestCaseInfo; + using Catch::Matchers::ContainsSubstring; + REQUIRE_THROWS_WITH( TestCaseInfo( "", + { "test with unclosed tag", "[abc" }, + dummySourceLineInfo ), + ContainsSubstring("registering test case 'test with unclosed tag'") ); + REQUIRE_THROWS_WITH( TestCaseInfo( "", + { "test with nested tags", "[abc[def]]" }, + dummySourceLineInfo ), + ContainsSubstring("registering test case 'test with nested tags'") ); + REQUIRE_THROWS_WITH( TestCaseInfo( "", + { "test with superfluous close tags", "[abc][def]]" }, + dummySourceLineInfo ), + ContainsSubstring("registering test case 'test with superfluous close tags'") ); } diff --git a/tests/SelfTest/UsageTests/Exception.tests.cpp b/tests/SelfTest/UsageTests/Exception.tests.cpp index f917932f..4f91a30c 100644 --- a/tests/SelfTest/UsageTests/Exception.tests.cpp +++ b/tests/SelfTest/UsageTests/Exception.tests.cpp @@ -20,7 +20,7 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wweak-vtables" #pragma clang diagnostic ignored "-Wmissing-noreturn" -#pragma clang diagnostic ignored "-Wunreachable-code" +#pragma clang diagnostic ignored "-Wunreachable-code-return" #endif namespace { diff --git a/tests/SelfTest/UsageTests/Generators.tests.cpp b/tests/SelfTest/UsageTests/Generators.tests.cpp index 3b691247..f04cf4f0 100644 --- a/tests/SelfTest/UsageTests/Generators.tests.cpp +++ b/tests/SelfTest/UsageTests/Generators.tests.cpp @@ -261,6 +261,10 @@ TEST_CASE("Copy and then generate a range", "[generators]") { } } +#if defined( __clang__ ) +# pragma clang diagnostic pop +#endif + TEST_CASE("#1913 - GENERATE inside a for loop should not keep recreating the generator", "[regression][generators]") { static int counter = 0; for (int i = 0; i < 3; ++i) { @@ -277,6 +281,43 @@ TEST_CASE("#1913 - GENERATEs can share a line", "[regression][generators]") { REQUIRE(i != j); } -#if defined(__clang__) -#pragma clang diagnostic pop -#endif +namespace { + class test_generator : public Catch::Generators::IGenerator { + public: + [[noreturn]] explicit test_generator() { + // removing the following line will cause the program to terminate + // gracefully. + throw Catch::GeneratorException( "failure to init" ); + } + + auto get() const -> int const& override { + static constexpr int value = 1; + return value; + } + + auto next() -> bool override { return false; } + }; + + static auto make_test_generator() + -> Catch::Generators::GeneratorWrapper { + return { new test_generator() }; + } + +} // namespace + +TEST_CASE( "#2615 - Throwing in constructor generator fails test case but does not abort", + "[!shouldfail][regression][generators]" ) { + // this should fail the test case, but not abort the application + auto sample = GENERATE( make_test_generator() ); + // this assertion shouldn't trigger + REQUIRE( sample == 0 ); +} + +TEST_CASE( "GENERATE can combine literals and generators", "[generators]" ) { + auto i = GENERATE( 2, + 4, + take( 2, + filter( []( int val ) { return val % 2 == 0; }, + random( -100, 100 ) ) ) ); + REQUIRE( i % 2 == 0 ); +} diff --git a/tests/SelfTest/UsageTests/Matchers.tests.cpp b/tests/SelfTest/UsageTests/Matchers.tests.cpp index 1ce3158b..74bedf5e 100644 --- a/tests/SelfTest/UsageTests/Matchers.tests.cpp +++ b/tests/SelfTest/UsageTests/Matchers.tests.cpp @@ -406,6 +406,25 @@ TEST_CASE( "Vector matchers that fail", "[matchers][vector][.][failing]" ) { } } +namespace { + struct SomeType { + int i; + friend bool operator==( SomeType lhs, SomeType rhs ) { + return lhs.i == rhs.i; + } + }; +} // end anonymous namespace + +TEST_CASE( "Vector matcher with elements without !=", "[matchers][vector][approvals]" ) { + std::vector lhs, rhs; + lhs.push_back( { 1 } ); + lhs.push_back( { 2 } ); + rhs.push_back( { 1 } ); + rhs.push_back( { 1 } ); + + REQUIRE_THAT( lhs, !Equals(rhs) ); +} + TEST_CASE( "Exception matchers that succeed", "[matchers][exceptions][!throws]" ) { CHECK_THROWS_MATCHES( @@ -497,6 +516,9 @@ TEST_CASE( "Floating point matchers: float", "[matchers][floating-point]" ) { REQUIRE_THROWS_AS( WithinRel( 1.f, -0.2f ), std::domain_error ); REQUIRE_THROWS_AS( WithinRel( 1.f, 1.f ), std::domain_error ); } + SECTION( "IsNaN" ) { + REQUIRE_THAT( 1., !IsNaN() ); + } } TEST_CASE( "Floating point matchers: double", "[matchers][floating-point]" ) { @@ -552,6 +574,9 @@ TEST_CASE( "Floating point matchers: double", "[matchers][floating-point]" ) { REQUIRE_THROWS_AS( WithinRel( 1., -0.2 ), std::domain_error ); REQUIRE_THROWS_AS( WithinRel( 1., 1. ), std::domain_error ); } + SECTION("IsNaN") { + REQUIRE_THAT( 1., !IsNaN() ); + } } TEST_CASE( "Floating point matchers that are problematic in approvals", @@ -566,6 +591,8 @@ TEST_CASE( "Floating point matchers that are problematic in approvals", REQUIRE_THAT( NAN, !WithinRel( NAN ) ); REQUIRE_THAT( 1., !WithinRel( NAN ) ); REQUIRE_THAT( NAN, !WithinRel( 1. ) ); + REQUIRE_THAT( NAN, IsNaN() ); + REQUIRE_THAT( static_cast(NAN), IsNaN() ); } TEST_CASE( "Arbitrary predicate matcher", "[matchers][generic]" ) { @@ -660,6 +687,21 @@ TEST_CASE( "Exceptions matchers", "[matchers][exceptions][!throws]" ) { Message( "SpecialException::what" ) ); } +TEST_CASE( "Exception message can be matched", "[matchers][exceptions][!throws]" ) { + REQUIRE_THROWS_MATCHES( throwsDerivedException(), + DerivedException, + MessageMatches( StartsWith( "Derived" ) ) ); + REQUIRE_THROWS_MATCHES( throwsDerivedException(), + DerivedException, + MessageMatches( EndsWith( "::what" ) ) ); + REQUIRE_THROWS_MATCHES( throwsDerivedException(), + DerivedException, + MessageMatches( !StartsWith( "::what" ) ) ); + REQUIRE_THROWS_MATCHES( throwsSpecialException( 2 ), + SpecialException, + MessageMatches( StartsWith( "Special" ) ) ); +} + struct CheckedTestingMatcher : Catch::Matchers::MatcherBase { mutable bool matchCalled = false; bool matchSucceeds = false; @@ -848,7 +890,7 @@ struct MatcherA : Catch::Matchers::MatcherGenericBase { return "equals: (int) 1 or (string) \"1\""; } bool match( int i ) const { return i == 1; } - bool match( std::string s ) const { return s == "1"; } + bool match( std::string const& s ) const { return s == "1"; } }; struct MatcherB : Catch::Matchers::MatcherGenericBase { diff --git a/tests/SelfTest/UsageTests/MatchersRanges.tests.cpp b/tests/SelfTest/UsageTests/MatchersRanges.tests.cpp index f30af703..cc8c54f8 100644 --- a/tests/SelfTest/UsageTests/MatchersRanges.tests.cpp +++ b/tests/SelfTest/UsageTests/MatchersRanges.tests.cpp @@ -9,200 +9,21 @@ #include #include #include +#include #include #include #include #include +#include + #include -#include #include #include #include #include #include -namespace { - -namespace unrelated { - template - class needs_ADL_begin { - std::vector m_elements; - public: - using iterator = typename std::vector::iterator; - using const_iterator = typename std::vector::const_iterator; - - needs_ADL_begin(std::initializer_list init) : m_elements(init) {} - - const_iterator Begin() const { return m_elements.begin(); } - const_iterator End() const { return m_elements.end(); } - - friend const_iterator begin(needs_ADL_begin const& lhs) { - return lhs.Begin(); - } - friend const_iterator end(needs_ADL_begin const& rhs) { - return rhs.End(); - } - }; -} // end unrelated namespace - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunused-function" -#endif - -template -class has_different_begin_end_types { - // Using std::vector leads to annoying issues when T is bool - // so we just use list because the perf is not critical and ugh. - std::list m_elements; - - // Different type for the "end" iterator - struct iterator_end {}; - // Fake-ish forward iterator that only compares to a different type - class iterator { - using underlying_iter = typename std::list::const_iterator; - underlying_iter m_start; - underlying_iter m_end; - - public: - iterator( underlying_iter start, underlying_iter end ): - m_start( start ), m_end( end ) {} - - using iterator_category = std::forward_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = T; - using const_reference = T const&; - using pointer = T const*; - - - friend bool operator==( iterator iter, iterator_end ) { - return iter.m_start == iter.m_end; - } - friend bool operator!=( iterator iter, iterator_end ) { - return iter.m_start != iter.m_end; - } - iterator& operator++() { - ++m_start; - return *this; - } - iterator operator++(int) { - auto tmp(*this); - ++m_start; - return tmp; - } - const_reference operator*() const { - return *m_start; - } - pointer operator->() const { - return m_start; - } - }; - - -public: - explicit has_different_begin_end_types( std::initializer_list init ): - m_elements( init ) {} - - iterator begin() const { - return { m_elements.begin(), m_elements.end() }; - } - - iterator_end end() const { - return {}; - } -}; - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -template struct with_mocked_iterator_access { - std::vector m_elements; - - // use plain arrays to have nicer printouts with CHECK(...) - mutable std::unique_ptr m_derefed; - - // We want to check which elements were dereferenced when iterating, so - // we can check whether iterator-using code traverses range correctly - template class basic_iterator { - template - using constify_t = std::conditional_t, U>; - - constify_t* m_origin; - size_t m_origin_idx; - - public: - using iterator_category = std::forward_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = constify_t; - using const_reference = typename std::vector::const_reference; - using reference = typename std::vector::reference; - using pointer = typename std::vector::pointer; - - basic_iterator( constify_t* origin, - std::size_t origin_idx ): - m_origin{ origin }, m_origin_idx{ origin_idx } {} - - friend bool operator==( basic_iterator lhs, basic_iterator rhs ) { - return lhs.m_origin == rhs.m_origin && - lhs.m_origin_idx == rhs.m_origin_idx; - } - friend bool operator!=( basic_iterator lhs, basic_iterator rhs ) { - return !( lhs == rhs ); - } - basic_iterator& operator++() { - ++m_origin_idx; - return *this; - } - basic_iterator operator++( int ) { - auto tmp( *this ); - ++( *this ); - return tmp; - } - const_reference operator*() const { - assert( m_origin_idx < m_origin->m_elements.size() && "Attempted to deref invalid position" ); - m_origin->m_derefed[m_origin_idx] = true; - return m_origin->m_elements[m_origin_idx]; - } - pointer operator->() const { - assert( m_origin_idx < m_origin->m_elements.size() && "Attempted to deref invalid position" ); - return &m_origin->m_elements[m_origin_idx]; - } - }; - - using iterator = basic_iterator; - using const_iterator = basic_iterator; - - with_mocked_iterator_access( std::initializer_list init ): - m_elements( init ), - m_derefed( std::make_unique( m_elements.size() ) ) {} - - const_iterator begin() const { return { this, 0 }; } - const_iterator end() const { return { this, m_elements.size() }; } - iterator begin() { return { this, 0 }; } - iterator end() { return { this, m_elements.size() }; } -}; - -} // end anon namespace - -namespace Catch { - // make sure with_mocked_iterator_access is not considered a range by Catch, - // so that below StringMaker is used instead of the default one for ranges - template - struct is_range> : std::false_type {}; - - template - struct StringMaker> { - static std::string - convert( with_mocked_iterator_access const& access ) { - // We have to avoid the type's iterators, because we check - // their use in tests - return ::Catch::Detail::stringify( access.m_elements ); - } - }; -} // namespace Catch - struct MoveOnlyTestElement { int num = 0; MoveOnlyTestElement(int n) :num(n) {} @@ -286,16 +107,6 @@ namespace { bool empty() const { return false; } }; -namespace unrelated { - struct ADL_empty { - bool Empty() const { return true; } - - friend bool empty(ADL_empty e) { - return e.Empty(); - } - }; - -} // end namespace unrelated } // end unnamed namespace TEST_CASE("Basic use of the Empty range matcher", "[matchers][templated][empty]") { @@ -345,17 +156,6 @@ namespace { return LessThanMatcher{ sz }; } - namespace unrelated { - struct ADL_size { - size_t sz() const { - return 12; - } - friend size_t size(ADL_size s) { - return s.sz(); - } - }; - } // end namespace unrelated - struct has_size { size_t size() const { return 13; @@ -581,7 +381,7 @@ TEST_CASE("Usage of AllTrue range matcher", "[matchers][templated][quantifiers]" std::array const data{}; REQUIRE_THAT( data, AllTrue() ); } - SECTION( "One false evalutes to false" ) { + SECTION( "One false evaluates to false" ) { std::array const data{ { true, true, false, true, true } }; REQUIRE_THAT( data, !AllTrue() ); } @@ -598,7 +398,7 @@ TEST_CASE("Usage of AllTrue range matcher", "[matchers][templated][quantifiers]" { { true }, { true }, { true }, { true }, { true } } }; REQUIRE_THAT( data, AllTrue() ); } - SECTION( "One false evalutes to false" ) { + SECTION( "One false evaluates to false" ) { std::array const data{ { { true }, { true }, { false }, { true }, { true } } }; REQUIRE_THAT( data, !AllTrue() ); @@ -646,7 +446,7 @@ TEST_CASE( "Usage of NoneTrue range matcher", "[matchers][templated][quantifiers std::array const data{}; REQUIRE_THAT( data, NoneTrue() ); } - SECTION( "One true evalutes to false" ) { + SECTION( "One true evaluates to false" ) { std::array const data{ { false, false, true, false, false } }; REQUIRE_THAT( data, !NoneTrue() ); @@ -664,7 +464,7 @@ TEST_CASE( "Usage of NoneTrue range matcher", "[matchers][templated][quantifiers { { true }, { true }, { true }, { true }, { true } } }; REQUIRE_THAT( data, !NoneTrue() ); } - SECTION( "One true evalutes to false" ) { + SECTION( "One true evaluates to false" ) { std::array const data{ { { false }, { false }, { true }, { false }, { false } } }; REQUIRE_THAT( data, !NoneTrue() ); @@ -712,7 +512,7 @@ TEST_CASE( "Usage of AnyTrue range matcher", "[matchers][templated][quantifiers] std::array const data{}; REQUIRE_THAT( data, !AnyTrue() ); } - SECTION( "One true evalutes to true" ) { + SECTION( "One true evaluates to true" ) { std::array const data{ { false, false, true, false, false } }; REQUIRE_THAT( data, AnyTrue() ); @@ -730,7 +530,7 @@ TEST_CASE( "Usage of AnyTrue range matcher", "[matchers][templated][quantifiers] { { true }, { true }, { true }, { true }, { true } } }; REQUIRE_THAT( data, AnyTrue() ); } - SECTION( "One true evalutes to true" ) { + SECTION( "One true evaluates to true" ) { std::array const data{ { { false }, { false }, { true }, { false }, { false } } }; REQUIRE_THAT( data, AnyTrue() ); @@ -831,4 +631,287 @@ TEST_CASE( "The quantifier range matchers support types with different types ret } } +TEST_CASE( "RangeEquals supports ranges with different types returned from begin and end", + "[matchers][templated][range][approvals] ") { + using Catch::Matchers::RangeEquals; + using Catch::Matchers::UnorderedRangeEquals; + + has_different_begin_end_types diff_types{ 1, 2, 3, 4, 5 }; + std::array arr1{ { 1, 2, 3, 4, 5 } }, arr2{ { 2, 3, 4, 5, 6 } }; + + REQUIRE_THAT( diff_types, RangeEquals( arr1 ) ); + REQUIRE_THAT( diff_types, RangeEquals( arr2, []( int l, int r ) { + return l + 1 == r; + } ) ); + REQUIRE_THAT( diff_types, UnorderedRangeEquals( diff_types ) ); +} + +TEST_CASE( "RangeContains supports ranges with different types returned from " + "begin and end", + "[matchers][templated][range][approvals]" ) { + using Catch::Matchers::Contains; + + has_different_begin_end_types diff_types{ 1, 2, 3, 4, 5 }; + REQUIRE_THAT( diff_types, Contains( size_t( 3 ) ) ); + REQUIRE_THAT( diff_types, Contains( LessThanMatcher( size_t( 4 ) ) ) ); +} + #endif + +TEST_CASE( "Usage of RangeEquals range matcher", "[matchers][templated][quantifiers]" ) { + using Catch::Matchers::RangeEquals; + + // In these tests, the types are always the same - type conversion is in the next section + SECTION( "Basic usage" ) { + SECTION( "Empty container matches empty container" ) { + const std::vector empty_vector; + CHECK_THAT( empty_vector, RangeEquals( empty_vector ) ); + } + SECTION( "Empty container does not match non-empty container" ) { + const std::vector empty_vector; + const std::vector non_empty_vector{ 1 }; + CHECK_THAT( empty_vector, !RangeEquals( non_empty_vector ) ); + // ...and in reverse + CHECK_THAT( non_empty_vector, !RangeEquals( empty_vector ) ); + } + SECTION( "Two equal 1-length non-empty containers" ) { + const std::array non_empty_array{ { 1 } }; + CHECK_THAT( non_empty_array, RangeEquals( non_empty_array ) ); + } + SECTION( "Two equal-sized, equal, non-empty containers" ) { + const std::array array_a{ { 1, 2, 3 } }; + CHECK_THAT( array_a, RangeEquals( array_a ) ); + } + SECTION( "Two equal-sized, non-equal, non-empty containers" ) { + const std::array array_a{ { 1, 2, 3 } }; + const std::array array_b{ { 2, 2, 3 } }; + const std::array array_c{ { 1, 2, 2 } }; + CHECK_THAT( array_a, !RangeEquals( array_b ) ); + CHECK_THAT( array_a, !RangeEquals( array_c ) ); + } + SECTION( "Two non-equal-sized, non-empty containers (with same first " + "elements)" ) { + const std::vector vector_a{ 1, 2, 3 }; + const std::vector vector_b{ 1, 2, 3, 4 }; + CHECK_THAT( vector_a, !RangeEquals( vector_b ) ); + } + } + + SECTION( "Custom predicate" ) { + + auto close_enough = []( int lhs, int rhs ) { + return std::abs( lhs - rhs ) <= 1; + }; + + SECTION( "Two equal non-empty containers (close enough)" ) { + const std::vector vector_a{ { 1, 2, 3 } }; + const std::vector vector_a_plus_1{ { 2, 3, 4 } }; + CHECK_THAT( vector_a, RangeEquals( vector_a_plus_1, close_enough ) ); + } + SECTION( "Two non-equal non-empty containers (close enough)" ) { + const std::vector vector_a{ { 1, 2, 3 } }; + const std::vector vector_b{ { 3, 3, 4 } }; + CHECK_THAT( vector_a, !RangeEquals( vector_b, close_enough ) ); + } + } + + SECTION( "Ranges that need ADL begin/end" ) { + unrelated::needs_ADL_begin const + needs_adl1{ 1, 2, 3, 4, 5 }, + needs_adl2{ 1, 2, 3, 4, 5 }, + needs_adl3{ 2, 3, 4, 5, 6 }; + + REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl2 ) ); + REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { + return l + 1 == r; + } ) ); + } + + SECTION("Check short-circuiting behaviour") { + with_mocked_iterator_access const mocked1{ 1, 2, 3, 4 }; + + SECTION( "Check short-circuits on failure" ) { + std::array arr{ { 1, 2, 4, 4 } }; + + REQUIRE_THAT( mocked1, !RangeEquals( arr ) ); + REQUIRE( mocked1.m_derefed[0] ); + REQUIRE( mocked1.m_derefed[1] ); + REQUIRE( mocked1.m_derefed[2] ); + REQUIRE_FALSE( mocked1.m_derefed[3] ); + } + SECTION("All elements are checked on success") { + std::array arr{ { 1, 2, 3, 4 } }; + + REQUIRE_THAT( mocked1, RangeEquals( arr ) ); + REQUIRE( mocked1.m_derefed[0] ); + REQUIRE( mocked1.m_derefed[1] ); + REQUIRE( mocked1.m_derefed[2] ); + REQUIRE( mocked1.m_derefed[3] ); + } + } +} + +TEST_CASE( "Usage of UnorderedRangeEquals range matcher", + "[matchers][templated][quantifiers]" ) { + using Catch::Matchers::UnorderedRangeEquals; + + // In these tests, the types are always the same - type conversion is in the + // next section + SECTION( "Basic usage" ) { + SECTION( "Empty container matches empty container" ) { + const std::vector empty_vector; + CHECK_THAT( empty_vector, UnorderedRangeEquals( empty_vector ) ); + } + SECTION( "Empty container does not match non-empty container" ) { + const std::vector empty_vector; + const std::vector non_empty_vector{ 1 }; + CHECK_THAT( empty_vector, + !UnorderedRangeEquals( non_empty_vector ) ); + // ...and in reverse + CHECK_THAT( non_empty_vector, + !UnorderedRangeEquals( empty_vector ) ); + } + SECTION( "Two equal 1-length non-empty containers" ) { + const std::array non_empty_array{ { 1 } }; + CHECK_THAT( non_empty_array, + UnorderedRangeEquals( non_empty_array ) ); + } + SECTION( "Two equal-sized, equal, non-empty containers" ) { + const std::array array_a{ { 1, 2, 3 } }; + CHECK_THAT( array_a, UnorderedRangeEquals( array_a ) ); + } + SECTION( "Two equal-sized, non-equal, non-empty containers" ) { + const std::array array_a{ { 1, 2, 3 } }; + const std::array array_b{ { 2, 2, 3 } }; + CHECK_THAT( array_a, !UnorderedRangeEquals( array_b ) ); + } + SECTION( "Two non-equal-sized, non-empty containers" ) { + const std::vector vector_a{ 1, 2, 3 }; + const std::vector vector_b{ 1, 2, 3, 4 }; + CHECK_THAT( vector_a, !UnorderedRangeEquals( vector_b ) ); + } + } + + SECTION( "Custom predicate" ) { + + auto close_enough = []( int lhs, int rhs ) { + return std::abs( lhs - rhs ) <= 1; + }; + + SECTION( "Two equal non-empty containers (close enough)" ) { + const std::vector vector_a{ { 1, 10, 20 } }; + const std::vector vector_a_plus_1{ { 11, 21, 2 } }; + CHECK_THAT( vector_a, + UnorderedRangeEquals( vector_a_plus_1, close_enough ) ); + } + SECTION( "Two non-equal non-empty containers (close enough)" ) { + const std::vector vector_a{ { 1, 10, 21 } }; + const std::vector vector_b{ { 11, 21, 3 } }; + CHECK_THAT( vector_a, + !UnorderedRangeEquals( vector_b, close_enough ) ); + } + } + + + SECTION( "Ranges that need ADL begin/end" ) { + unrelated::needs_ADL_begin const + needs_adl1{ 1, 2, 3, 4, 5 }, + needs_adl2{ 1, 2, 3, 4, 5 }; + + REQUIRE_THAT( needs_adl1, UnorderedRangeEquals( needs_adl2 ) ); + } +} + +/** + * Return true if the type given has a random access iterator type. + */ +template +static constexpr bool ContainerIsRandomAccess( const Container& ) { + using array_iter_category = typename std::iterator_traits< + typename Container::iterator>::iterator_category; + + return std::is_base_of::value; +} + +TEST_CASE( "Type conversions of RangeEquals and similar", + "[matchers][templated][quantifiers]" ) { + using Catch::Matchers::RangeEquals; + using Catch::Matchers::UnorderedRangeEquals; + + // In these test, we can always test RangeEquals and + // UnorderedRangeEquals in the same way, since we're mostly + // testing the template type deductions (and RangeEquals + // implies UnorderedRangeEquals) + + SECTION( "Container conversions" ) { + SECTION( "Two equal containers of different container types" ) { + const std::array array_int_a{ { 1, 2, 3 } }; + const int c_array[3] = { 1, 2, 3 }; + CHECK_THAT( array_int_a, RangeEquals( c_array ) ); + CHECK_THAT( array_int_a, UnorderedRangeEquals( c_array ) ); + } + SECTION( "Two equal containers of different container types " + "(differ in array N)" ) { + const std::array array_int_3{ { 1, 2, 3 } }; + const std::array array_int_4{ { 1, 2, 3, 4 } }; + CHECK_THAT( array_int_3, !RangeEquals( array_int_4 ) ); + CHECK_THAT( array_int_3, !UnorderedRangeEquals( array_int_4 ) ); + } + SECTION( "Two equal containers of different container types and value " + "types" ) { + const std::array array_int_a{ { 1, 2, 3 } }; + const std::vector vector_char_a{ 1, 2, 3 }; + CHECK_THAT( array_int_a, RangeEquals( vector_char_a ) ); + CHECK_THAT( array_int_a, UnorderedRangeEquals( vector_char_a ) ); + } + SECTION( "Two equal containers, one random access, one not" ) { + const std::array array_int_a{ { 1, 2, 3 } }; + const std::list list_char_a{ 1, 2, 3 }; + + // Verify these types really are different in random access nature + STATIC_REQUIRE( ContainerIsRandomAccess( array_int_a ) != + ContainerIsRandomAccess( list_char_a ) ); + + CHECK_THAT( array_int_a, RangeEquals( list_char_a ) ); + CHECK_THAT( array_int_a, UnorderedRangeEquals( list_char_a ) ); + } + } + + SECTION( "Value type" ) { + SECTION( "Two equal containers of different value types" ) { + const std::vector vector_int_a{ 1, 2, 3 }; + const std::vector vector_char_a{ 1, 2, 3 }; + CHECK_THAT( vector_int_a, RangeEquals( vector_char_a ) ); + CHECK_THAT( vector_int_a, UnorderedRangeEquals( vector_char_a ) ); + } + SECTION( "Two non-equal containers of different value types" ) { + const std::vector vector_int_a{ 1, 2, 3 }; + const std::vector vector_char_b{ 1, 2, 2 }; + CHECK_THAT( vector_int_a, !RangeEquals( vector_char_b ) ); + CHECK_THAT( vector_int_a, !UnorderedRangeEquals( vector_char_b ) ); + } + } + + SECTION( "Ranges with begin that needs ADL" ) { + unrelated::needs_ADL_begin a{ 1, 2, 3 }, b{ 3, 2, 1 }; + REQUIRE_THAT( a, !RangeEquals( b ) ); + REQUIRE_THAT( a, UnorderedRangeEquals( b ) ); + } + + SECTION( "Custom predicate" ) { + + auto close_enough = []( int lhs, int rhs ) { + return std::abs( lhs - rhs ) <= 1; + }; + + SECTION( "Two equal non-empty containers (close enough)" ) { + const std::vector vector_a{ { 1, 2, 3 } }; + const std::array array_a_plus_1{ { 2, 3, 4 } }; + CHECK_THAT( vector_a, + RangeEquals( array_a_plus_1, close_enough ) ); + CHECK_THAT( vector_a, + UnorderedRangeEquals( array_a_plus_1, close_enough ) ); + } + } +} \ No newline at end of file diff --git a/tests/SelfTest/UsageTests/Message.tests.cpp b/tests/SelfTest/UsageTests/Message.tests.cpp index a5e69582..6367bf59 100644 --- a/tests/SelfTest/UsageTests/Message.tests.cpp +++ b/tests/SelfTest/UsageTests/Message.tests.cpp @@ -255,10 +255,24 @@ std::ostream& operator<<(std::ostream& out, helper_1436 const& helper) { #pragma clang diagnostic ignored "-Wunused-value" #endif +namespace { + template + struct custom_index_op { + constexpr custom_index_op( std::initializer_list ) {} + constexpr T operator[]( size_t ) { return T{}; } +#if defined( __cpp_multidimensional_subscript ) && \ + __cpp_multidimensional_subscript >= 202110L + constexpr T operator[]( size_t, size_t, size_t ) const noexcept { + return T{}; + } +#endif + }; +} + TEST_CASE("CAPTURE can deal with complex expressions involving commas", "[messages][capture]") { - CAPTURE(std::vector{1, 2, 3}[0, 1, 2], - std::vector{1, 2, 3}[(0, 1)], - std::vector{1, 2, 3}[0]); + CAPTURE(custom_index_op{1, 2, 3}[0, 1, 2], + custom_index_op{1, 2, 3}[(0, 1)], + custom_index_op{1, 2, 3}[0]); CAPTURE((helper_1436{12, -12}), (helper_1436(-12, 12))); CAPTURE( (1, 2), (2, 3) ); @@ -285,3 +299,14 @@ TEST_CASE("CAPTURE parses string and character constants", "[messages][capture]" #ifdef _MSC_VER #pragma warning(pop) #endif + +TEST_CASE( "INFO and UNSCOPED_INFO can stream multiple arguments", + "[messages][info][.failing]" ) { + INFO( "This info" + << " has multiple" + << " parts." ); + UNSCOPED_INFO( "This unscoped info" + << " has multiple" + << " parts." ); + FAIL( "Show infos!" ); +} diff --git a/tests/SelfTest/UsageTests/Misc.tests.cpp b/tests/SelfTest/UsageTests/Misc.tests.cpp index 6c1fd68f..7f06704b 100644 --- a/tests/SelfTest/UsageTests/Misc.tests.cpp +++ b/tests/SelfTest/UsageTests/Misc.tests.cpp @@ -217,6 +217,18 @@ TEST_CASE("Testing checked-if 3", "[checked-if][!shouldfail]") { SUCCEED(); } +[[noreturn]] +TEST_CASE("Testing checked-if 4", "[checked-if][!shouldfail]") { + CHECKED_ELSE(true) {} + throw std::runtime_error("Uncaught exception should fail!"); +} + +[[noreturn]] +TEST_CASE("Testing checked-if 5", "[checked-if][!shouldfail]") { + CHECKED_ELSE(false) {} + throw std::runtime_error("Uncaught exception should fail!"); +} + TEST_CASE( "xmlentitycheck" ) { SECTION( "embedded xml: it should be possible to embed xml characters, such as <, \" or &, or even whole documents within an attribute" ) { SUCCEED(); // We need this here to stop it failing due to no tests diff --git a/tests/SelfTest/UsageTests/Skip.tests.cpp b/tests/SelfTest/UsageTests/Skip.tests.cpp new file mode 100644 index 00000000..661795e1 --- /dev/null +++ b/tests/SelfTest/UsageTests/Skip.tests.cpp @@ -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 + +#include +#include + +#include + +TEST_CASE( "tests can be skipped dynamically at runtime", "[skipping]" ) { + SKIP(); + FAIL( "this is not reached" ); +} + +TEST_CASE( "skipped tests can optionally provide a reason", "[skipping]" ) { + const int answer = 43; + SKIP( "skipping because answer = " << answer ); + FAIL( "this is not reached" ); +} + +TEST_CASE( "sections can be skipped dynamically at runtime", "[skipping]" ) { + SECTION( "not skipped" ) { SUCCEED(); } + SECTION( "skipped" ) { SKIP(); } + SECTION( "also not skipped" ) { SUCCEED(); } +} + +TEST_CASE( "nested sections can be skipped dynamically at runtime", + "[skipping]" ) { + SECTION( "A" ) { std::cout << "a"; } + SECTION( "B" ) { + SECTION( "B1" ) { std::cout << "b1"; } + SECTION( "B2" ) { SKIP(); } + } + std::cout << "!\n"; +} + +TEST_CASE( "dynamic skipping works with generators", "[skipping]" ) { + const int answer = GENERATE( 41, 42, 43 ); + if ( answer != 42 ) { SKIP( "skipping because answer = " << answer ); } + SUCCEED(); +} + +TEST_CASE( "failed assertions before SKIP cause test case to fail", + "[skipping][!shouldfail]" ) { + CHECK( 3 == 4 ); + SKIP(); +} + +TEST_CASE( "a succeeding test can still be skipped", + "[skipping][!shouldfail]" ) { + SUCCEED(); + SKIP(); +} + +TEST_CASE( "failing in some unskipped sections causes entire test case to fail", + "[skipping][!shouldfail]" ) { + SECTION( "skipped" ) { SKIP(); } + SECTION( "not skipped" ) { FAIL(); } +} + +TEST_CASE( "failing for some generator values causes entire test case to fail", + "[skipping][!shouldfail]" ) { + int i = GENERATE( 1, 2, 3, 4 ); + if ( i % 2 == 0 ) { + SKIP(); + } else { + FAIL(); + } +} + +namespace { + class test_skip_generator : public Catch::Generators::IGenerator { + public: + explicit test_skip_generator() { SKIP( "This generator is empty" ); } + + auto get() const -> int const& override { + static constexpr int value = 1; + return value; + } + + auto next() -> bool override { return false; } + }; + + static auto make_test_skip_generator() + -> Catch::Generators::GeneratorWrapper { + return { new test_skip_generator() }; + } + +} // namespace + +TEST_CASE( "Empty generators can SKIP in constructor", "[skipping]" ) { + // The generator signals emptiness with `SKIP` + auto sample = GENERATE( make_test_skip_generator() ); + // This assertion would fail, but shouldn't trigger + REQUIRE( sample == 0 ); +} diff --git a/tests/SelfTest/UsageTests/ToStringOptional.tests.cpp b/tests/SelfTest/UsageTests/ToStringOptional.tests.cpp index 9fd9d6b4..3671771a 100644 --- a/tests/SelfTest/UsageTests/ToStringOptional.tests.cpp +++ b/tests/SelfTest/UsageTests/ToStringOptional.tests.cpp @@ -28,4 +28,8 @@ TEST_CASE( "std::vector > -> toString", "[toString][optional] REQUIRE( "{ 0, { }, 2 }" == ::Catch::Detail::stringify( type{ 0, {}, 2 } ) ); } +TEST_CASE( "std::nullopt -> toString", "[toString][optional][approvals]" ) { + REQUIRE( "{ }" == ::Catch::Detail::stringify( std::nullopt ) ); +} + #endif // CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL diff --git a/tests/SelfTest/helpers/range_test_helpers.hpp b/tests/SelfTest/helpers/range_test_helpers.hpp new file mode 100644 index 00000000..22c2c3cd --- /dev/null +++ b/tests/SelfTest/helpers/range_test_helpers.hpp @@ -0,0 +1,210 @@ + +// 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_HELPERS_RANGE_TEST_HELPERS_HPP_INCLUDED +#define CATCH_TEST_HELPERS_RANGE_TEST_HELPERS_HPP_INCLUDED + +#include + +#include +#include +#include +#include + +namespace unrelated { + template + class needs_ADL_begin { + std::vector m_elements; + + public: + using iterator = typename std::vector::iterator; + using const_iterator = typename std::vector::const_iterator; + + needs_ADL_begin( std::initializer_list init ): m_elements( init ) {} + + const_iterator Begin() const { return m_elements.begin(); } + const_iterator End() const { return m_elements.end(); } + + friend const_iterator begin( needs_ADL_begin const& lhs ) { + return lhs.Begin(); + } + friend const_iterator end( needs_ADL_begin const& rhs ) { + return rhs.End(); + } + }; + + struct ADL_empty { + bool Empty() const { return true; } + + friend bool empty( ADL_empty e ) { return e.Empty(); } + }; + + struct ADL_size { + size_t sz() const { return 12; } + friend size_t size( ADL_size s ) { return s.sz(); } + }; + +} // namespace unrelated + +#if defined( __clang__ ) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-function" +#endif + +template +class has_different_begin_end_types { + // Using std::vector leads to annoying issues when T is bool + // so we just use list because the perf is not critical and ugh. + std::list m_elements; + + // Different type for the "end" iterator + struct iterator_end {}; + // Fake-ish forward iterator that only compares to a different type + class iterator { + using underlying_iter = typename std::list::const_iterator; + underlying_iter m_start; + underlying_iter m_end; + + public: + iterator( underlying_iter start, underlying_iter end ): + m_start( start ), m_end( end ) {} + + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = T; + using const_reference = T const&; + using pointer = T const*; + + friend bool operator==( iterator iter, iterator_end ) { + return iter.m_start == iter.m_end; + } + friend bool operator==(iterator lhs, iterator rhs) { + return lhs.m_start == rhs.m_start && lhs.m_end == rhs.m_end; + } + friend bool operator!=( iterator iter, iterator_end ) { + return iter.m_start != iter.m_end; + } + friend bool operator!=( iterator lhs, iterator rhs ) { + return !( lhs == rhs ); + } + iterator& operator++() { + ++m_start; + return *this; + } + iterator operator++( int ) { + auto tmp( *this ); + ++m_start; + return tmp; + } + const_reference operator*() const { return *m_start; } + pointer operator->() const { return m_start; } + }; + +public: + explicit has_different_begin_end_types( std::initializer_list init ): + m_elements( init ) {} + + iterator begin() const { return { m_elements.begin(), m_elements.end() }; } + + iterator_end end() const { return {}; } +}; + +#if defined( __clang__ ) +# pragma clang diagnostic pop +#endif + +template +struct with_mocked_iterator_access { + std::vector m_elements; + + // use plain arrays to have nicer printouts with CHECK(...) + mutable std::unique_ptr m_derefed; + + // We want to check which elements were dereferenced when iterating, so + // we can check whether iterator-using code traverses range correctly + template + class basic_iterator { + template + using constify_t = std::conditional_t, U>; + + constify_t* m_origin; + size_t m_origin_idx; + + public: + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = constify_t; + using const_reference = typename std::vector::const_reference; + using reference = typename std::vector::reference; + using pointer = typename std::vector::pointer; + + basic_iterator( constify_t* origin, + std::size_t origin_idx ): + m_origin{ origin }, m_origin_idx{ origin_idx } {} + + friend bool operator==( basic_iterator lhs, basic_iterator rhs ) { + return lhs.m_origin == rhs.m_origin && + lhs.m_origin_idx == rhs.m_origin_idx; + } + friend bool operator!=( basic_iterator lhs, basic_iterator rhs ) { + return !( lhs == rhs ); + } + basic_iterator& operator++() { + ++m_origin_idx; + return *this; + } + basic_iterator operator++( int ) { + auto tmp( *this ); + ++( *this ); + return tmp; + } + const_reference operator*() const { + assert( m_origin_idx < m_origin->m_elements.size() && + "Attempted to deref invalid position" ); + m_origin->m_derefed[m_origin_idx] = true; + return m_origin->m_elements[m_origin_idx]; + } + pointer operator->() const { + assert( m_origin_idx < m_origin->m_elements.size() && + "Attempted to deref invalid position" ); + return &m_origin->m_elements[m_origin_idx]; + } + }; + + using iterator = basic_iterator; + using const_iterator = basic_iterator; + + with_mocked_iterator_access( std::initializer_list init ): + m_elements( init ), + m_derefed( std::make_unique( m_elements.size() ) ) {} + + const_iterator begin() const { return { this, 0 }; } + const_iterator end() const { return { this, m_elements.size() }; } + iterator begin() { return { this, 0 }; } + iterator end() { return { this, m_elements.size() }; } +}; + + +namespace Catch { + // make sure with_mocked_iterator_access is not considered a range by Catch, + // so that below StringMaker is used instead of the default one for ranges + template + struct is_range> : std::false_type {}; + + template + struct StringMaker> { + static std::string + convert( with_mocked_iterator_access const& access ) { + // We have to avoid the type's iterators, because we check + // their use in tests + return ::Catch::Detail::stringify( access.m_elements ); + } + }; +} // namespace Catch + +#endif // CATCH_TEST_HELPERS_RANGE_TEST_HELPERS_HPP_INCLUDED diff --git a/tests/TestScripts/DiscoverTests/CMakeLists.txt b/tests/TestScripts/DiscoverTests/CMakeLists.txt new file mode 100644 index 00000000..d19f2f88 --- /dev/null +++ b/tests/TestScripts/DiscoverTests/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.10) + +project(discover-tests-test + LANGUAGES CXX +) + +add_executable(tests + register-tests.cpp +) + +add_subdirectory(${CATCH2_PATH} catch2-build) +target_link_libraries(tests PRIVATE Catch2::Catch2WithMain) + +include(CTest) +include(Catch) +catch_discover_tests(tests) diff --git a/tests/TestScripts/DiscoverTests/VerifyRegistration.py b/tests/TestScripts/DiscoverTests/VerifyRegistration.py new file mode 100644 index 00000000..9ec42f24 --- /dev/null +++ b/tests/TestScripts/DiscoverTests/VerifyRegistration.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 + +# 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 + +import os +import subprocess +import sys + + +def build_project(sources_dir, output_base_path, catch2_path): + build_dir = os.path.join(output_base_path, 'ctest-registration-test') + config_cmd = ['cmake', + '-B', build_dir, + '-S', sources_dir, + f'-DCATCH2_PATH={catch2_path}', + '-DCMAKE_BUILD_TYPE=Debug'] + + build_cmd = ['cmake', + '--build', build_dir, + '--config', 'Debug'] + + try: + subprocess.run(config_cmd, + capture_output = True, + check = True, + text = True) + subprocess.run(build_cmd, + capture_output = True, + check = True, + text = True) + except subprocess.CalledProcessError as err: + print('Error when building the test project') + print(f'cmd: {err.cmd}') + print(f'stderr: {err.stderr}') + print(f'stdout: {err.stdout}') + exit(3) + + return build_dir + + + +def get_test_names(build_path): + # For now we assume that Windows builds are done using MSBuild under + # Debug configuration. This means that we need to add "Debug" folder + # to the path when constructing it. On Linux, we don't add anything. + config_path = "Debug" if os.name == 'nt' else "" + full_path = os.path.join(build_path, config_path, 'tests') + + + cmd = [full_path, '--reporter', 'xml', '--list-tests'] + result = subprocess.run(cmd, + capture_output = True, + check = True, + text = True) + + import xml.etree.ElementTree as ET + root = ET.fromstring(result.stdout) + return [tc.text for tc in root.findall('TestCase/Name')] + + +def list_ctest_tests(build_path): + old_path = os.getcwd() + os.chdir(build_path) + + cmd = ['ctest', '-C', 'debug', '--show-only=json-v1'] + result = subprocess.run(cmd, + capture_output = True, + check = True, + text = True) + os.chdir(old_path) + + import json + + ctest_response = json.loads(result.stdout) + tests = ctest_response['tests'] + test_names = [] + for test in tests: + test_command = test['command'] + # First part of the command is the binary, second is the filter. + # If there are less, registration has failed. If there are more, + # registration has changed and the script needs updating. + assert len(test_command) == 2 + test_names.append(test_command[1]) + test_name = test_command[1] + + return test_names + +def escape_catch2_test_name(name): + for char in ('\\', ',', '[', ']'): + name = name.replace(char, f"\\{char}") + return name + +if __name__ == '__main__': + if len(sys.argv) != 3: + print(f'Usage: {sys.argv[0]} path-to-catch2-cml output-path') + exit(2) + catch2_path = sys.argv[1] + output_base_path = sys.argv[2] + sources_dir = os.path.dirname(os.path.abspath(sys.argv[0])) + + build_path = build_project(sources_dir, output_base_path, catch2_path) + + catch_test_names = [escape_catch2_test_name(name) for name in get_test_names(build_path)] + ctest_test_names = list_ctest_tests(build_path) + + mismatched = 0 + for catch_test in catch_test_names: + if catch_test not in ctest_test_names: + print(f"Catch2 test '{catch_test}' not found in CTest") + mismatched += 1 + for ctest_test in ctest_test_names: + if ctest_test not in catch_test_names: + print(f"CTest test '{ctest_test}' not found in Catch2") + mismatched += 1 + + if mismatched: + print(f"Found {mismatched} mismatched tests catch test names and ctest test commands!") + exit(1) diff --git a/tests/TestScripts/DiscoverTests/register-tests.cpp b/tests/TestScripts/DiscoverTests/register-tests.cpp new file mode 100644 index 00000000..aa603df1 --- /dev/null +++ b/tests/TestScripts/DiscoverTests/register-tests.cpp @@ -0,0 +1,16 @@ + +// 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 + +TEST_CASE("@Script[C:\\EPM1A]=x;\"SCALA_ZERO:\"", "[script regressions]"){} +TEST_CASE("Some test") {} +TEST_CASE( "Let's have a test case with a long name. Longer. No, even longer. " + "Really looooooooooooong. Even longer than that. Multiple lines " + "worth of test name. Yep, like this." ) {} +TEST_CASE( "And now a test case with weird tags.", "[tl;dr][tl;dw][foo,bar]" ) {} diff --git a/tests/meson.build b/tests/meson.build index c8bdfb4b..58302b7a 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -9,6 +9,7 @@ # Please keep these ordered alphabetically self_test_sources = files( 'SelfTest/helpers/parse_test_spec.cpp', + 'SelfTest/IntrospectiveTests/Algorithms.tests.cpp', 'SelfTest/IntrospectiveTests/Clara.tests.cpp', 'SelfTest/IntrospectiveTests/CmdLine.tests.cpp', 'SelfTest/IntrospectiveTests/CmdLineHelpers.tests.cpp', @@ -16,6 +17,7 @@ self_test_sources = files( 'SelfTest/IntrospectiveTests/Details.tests.cpp', 'SelfTest/IntrospectiveTests/FloatingPoint.tests.cpp', 'SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp', + 'SelfTest/IntrospectiveTests/Integer.tests.cpp', 'SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp', 'SelfTest/IntrospectiveTests/Parse.tests.cpp', 'SelfTest/IntrospectiveTests/PartTracker.tests.cpp', diff --git a/tools/scripts/approvalTests.py b/tools/scripts/approvalTests.py index 592be36e..4146b646 100755 --- a/tools/scripts/approvalTests.py +++ b/tools/scripts/approvalTests.py @@ -48,11 +48,11 @@ def get_unapprovedResultsPath(baseName): langFilenameParser = re.compile(r'(.+\.[ch]pp)') filelocParser = re.compile(r''' - .*/ - (.+\.[ch]pp) # filename - (?::|\() # : is starting separator between filename and line number on Linux, ( on Windows - ([0-9]*) # line number - \)? # Windows also has an ending separator, ) + (?Ptests/SelfTest/(?:\w+/)*) # We separate prefix and fname, so that + (?P\w+\.tests\.[ch]pp) # we can keep only filename + (?::|\() # Linux has : as separator between fname and line number, Windows uses ( + (\d*) # line number + \)? # Windows also uses an ending separator, ) ''', re.VERBOSE) lineNumberParser = re.compile(r' line="[0-9]*"') hexParser = re.compile(r'\b(0[xX][0-9a-fA-F]+)\b') @@ -119,14 +119,11 @@ def filterLine(line, isCompact): line = normalizeFilepath(line) # strip source line numbers - m = filelocParser.match(line) - if m: - # note that this also strips directories, leaving only the filename - filename, lnum = m.groups() - lnum = ":" if lnum else "" - line = filename + lnum + line[m.end():] - else: - line = lineNumberParser.sub(" ", line) + # Note that this parser assumes an already normalized filepath from above, + # and might break terribly if it is moved around before the normalization. + line = filelocParser.sub('\g:', line) + + line = lineNumberParser.sub(" ", line) if isCompact: line = line.replace(': FAILED', ': failed') diff --git a/tools/scripts/buildAndTest.cmd b/tools/scripts/buildAndTest.cmd index e5222a01..7c10e564 100644 --- a/tools/scripts/buildAndTest.cmd +++ b/tools/scripts/buildAndTest.cmd @@ -6,7 +6,7 @@ rem 1. Regenerate the amalgamated distribution python tools\scripts\generateAmalgamatedFiles.py rem 2. Configure the full test build -cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug -DCATCH_DEVELOPMENT_BUILD=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_ENABLE_CONFIGURE_TESTS=ON +cmake -B debug-build -S . -DCMAKE_BUILD_TYPE=Debug --preset all-tests rem 3. Run the actual build cmake --build debug-build diff --git a/tools/scripts/buildAndTest.sh b/tools/scripts/buildAndTest.sh index 4a741598..01a82837 100755 --- a/tools/scripts/buildAndTest.sh +++ b/tools/scripts/buildAndTest.sh @@ -8,7 +8,7 @@ ./tools/scripts/generateAmalgamatedFiles.py # 2. Configure the full test build -cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug -DCATCH_DEVELOPMENT_BUILD=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_ENABLE_CONFIGURE_TESTS=ON +cmake -B debug-build -S . -DCMAKE_BUILD_TYPE=Debug --preset all-tests # 3. Run the actual build cmake --build debug-build diff --git a/tools/scripts/checkLicense.py b/tools/scripts/checkLicense.py index 9a949769..7078d3ec 100755 --- a/tools/scripts/checkLicense.py +++ b/tools/scripts/checkLicense.py @@ -33,7 +33,8 @@ def check_licences_in_path(path: str) -> int: def check_licences(): failed = 0 - roots = ['src/catch2', 'tests'] + # Add 'extras' after the amalgamted files are regenerated with the new script (past 3.4.0) + roots = ['src/catch2', 'tests', 'examples', 'fuzzing'] for root in roots: failed += check_licences_in_path(root) diff --git a/tools/scripts/generateAmalgamatedFiles.py b/tools/scripts/generateAmalgamatedFiles.py index 99fc446b..e3e86aab 100755 --- a/tools/scripts/generateAmalgamatedFiles.py +++ b/tools/scripts/generateAmalgamatedFiles.py @@ -1,4 +1,9 @@ #!/usr/bin/env python3 +# 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 import os import re @@ -12,6 +17,8 @@ starting_header = os.path.join(root_path, 'catch2', 'catch_all.hpp') output_header = os.path.join(catchPath, 'extras', 'catch_amalgamated.hpp') output_cpp = os.path.join(catchPath, 'extras', 'catch_amalgamated.cpp') +# REUSE-IgnoreStart + # These are the copyright comments in each file, we want to ignore them copyright_lines = [ '// Copyright Catch2 Authors\n', @@ -24,6 +31,7 @@ copyright_lines = [ # The header of the amalgamated file: copyright information + explanation # what this file is. file_header = '''\ + // Copyright Catch2 Authors // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at @@ -39,6 +47,8 @@ file_header = '''\ // ---------------------------------------------------------- ''' +# REUSE-IgnoreEnd + # Returns file header with proper version string and generation time def formatted_file_header(version): return file_header.format(version_string=version.getVersionString(), diff --git a/tools/scripts/releaseCommon.py b/tools/scripts/releaseCommon.py index 0d995eaf..1ff4af29 100644 --- a/tools/scripts/releaseCommon.py +++ b/tools/scripts/releaseCommon.py @@ -114,8 +114,8 @@ def updateVersionDefine(version): def updateVersionPlaceholder(filename, version): with open(filename, 'rb') as file: lines = file.readlines() - placeholderRegex = re.compile(b'in Catch[0-9]? X.Y.Z') - replacement = 'in Catch2 {}.{}.{}'.format(version.majorVersion, version.minorVersion, version.patchNumber).encode('ascii') + placeholderRegex = re.compile(b'Catch[0-9]? X.Y.Z') + replacement = 'Catch2 {}.{}.{}'.format(version.majorVersion, version.minorVersion, version.patchNumber).encode('ascii') with open(filename, 'wb') as file: for line in lines: file.write(placeholderRegex.sub(replacement, line)) diff --git a/tools/scripts/updateDocumentToC.py b/tools/scripts/updateDocumentToC.py index 7b56cfc7..1840cecc 100755 --- a/tools/scripts/updateDocumentToC.py +++ b/tools/scripts/updateDocumentToC.py @@ -287,7 +287,7 @@ def markdownToclify( Path to the markdown output file. min_toc_len: int (default: 2) - Miniumum number of entries to create a table of contents for. + Minimum number of entries to create a table of contents for. github: bool (default: False) Uses GitHub TOC syntax if True.