vendor Catch2 and ETL
This commit is contained in:
@ -0,0 +1,168 @@
|
||||
:test-result: PASS # A test name that starts with a #
|
||||
:test-result: PASS #542
|
||||
:test-result: PASS #809
|
||||
:test-result: FAIL 'Not' checks that should fail
|
||||
:test-result: PASS 'Not' checks that should succeed
|
||||
:test-result: PASS (unimplemented) static bools can be evaluated
|
||||
:test-result: FAIL A METHOD_AS_TEST_CASE based test run that fails
|
||||
:test-result: PASS A METHOD_AS_TEST_CASE based test run that succeeds
|
||||
:test-result: FAIL A TEST_CASE_METHOD based test run that fails
|
||||
:test-result: PASS A TEST_CASE_METHOD based test run that succeeds
|
||||
:test-result: FAIL A couple of nested sections followed by a failure
|
||||
:test-result: FAIL A failing expression with a non streamable type is still captured
|
||||
:test-result: PASS AllOf matcher
|
||||
:test-result: PASS An empty test with no assertions
|
||||
:test-result: PASS An expression with side-effects should only be evaluated once
|
||||
:test-result: FAIL An unchecked exception reports the line of the last assertion
|
||||
:test-result: PASS Anonymous test case 1
|
||||
:test-result: PASS AnyOf matcher
|
||||
:test-result: PASS Approximate PI
|
||||
:test-result: PASS Approximate comparisons with different epsilons
|
||||
:test-result: PASS Approximate comparisons with floats
|
||||
:test-result: PASS Approximate comparisons with ints
|
||||
:test-result: PASS Approximate comparisons with mixed numeric types
|
||||
:test-result: PASS Assertions then sections
|
||||
:test-result: PASS Character pretty printing
|
||||
:test-result: PASS Comparing function pointers
|
||||
:test-result: PASS Comparing member function pointers
|
||||
:test-result: PASS Comparisons between ints where one side is computed
|
||||
:test-result: PASS Comparisons between unsigned ints and negative signed ints match c++ standard behaviour
|
||||
:test-result: PASS Comparisons with int literals don't warn when mixing signed/ unsigned
|
||||
:test-result: FAIL Contains string matcher
|
||||
:test-result: FAIL Custom exceptions can be translated when testing for nothrow
|
||||
:test-result: FAIL Custom exceptions can be translated when testing for throwing as something else
|
||||
:test-result: FAIL Custom std-exceptions can be custom translated
|
||||
:test-result: PASS Demonstrate that a non-const == is not used
|
||||
:test-result: FAIL EndsWith string matcher
|
||||
:test-result: XFAIL Equality checks that should fail
|
||||
:test-result: PASS Equality checks that should succeed
|
||||
:test-result: PASS Equals
|
||||
:test-result: FAIL Equals string matcher
|
||||
:test-result: PASS Exception messages can be tested for
|
||||
:test-result: FAIL Expected exceptions that don't throw or unexpected exceptions fail the test
|
||||
:test-result: FAIL FAIL aborts the test
|
||||
:test-result: FAIL FAIL does not require an argument
|
||||
:test-result: PASS Factorials are computed
|
||||
:test-result: PASS Generator over a range of pairs
|
||||
:test-result: PASS Generators over two ranges
|
||||
:test-result: PASS Greater-than inequalities with different epsilons
|
||||
:test-result: PASS 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: XFAIL Inequality checks that should fail
|
||||
:test-result: PASS Inequality checks that should succeed
|
||||
:test-result: PASS Less-than inequalities with different epsilons
|
||||
:test-result: PASS Long strings can be wrapped
|
||||
:test-result: PASS Long text is truncated
|
||||
:test-result: PASS ManuallyRegistered
|
||||
:test-result: PASS Matchers can be (AllOf) composed with the && operator
|
||||
:test-result: PASS Matchers can be (AnyOf) composed with the || operator
|
||||
:test-result: PASS Matchers can be composed with both && and ||
|
||||
:test-result: FAIL Matchers can be composed with both && and || - failing
|
||||
:test-result: PASS Matchers can be negated (Not) with the ! operator
|
||||
:test-result: FAIL Matchers can be negated (Not) with the ! operator - failing
|
||||
:test-result: FAIL Mismatching exception messages failing the test
|
||||
:test-result: PASS Nice descriptive name
|
||||
:test-result: FAIL Non-std exceptions can be translated
|
||||
:test-result: PASS NotImplemented exception
|
||||
:test-result: PASS Objects that evaluated in boolean contexts can be checked
|
||||
:test-result: PASS Operators at different namespace levels not hijacked by Koenig lookup
|
||||
:test-result: FAIL Ordering comparison checks that should fail
|
||||
:test-result: PASS Ordering comparison checks that should succeed
|
||||
:test-result: FAIL Output from all sections is reported
|
||||
:test-result: PASS Parse test names and tags
|
||||
:test-result: PASS Parsing a std::pair
|
||||
:test-result: PASS Pointers can be compared to null
|
||||
:test-result: PASS Pointers can be converted to strings
|
||||
:test-result: PASS Process can be configured on command line
|
||||
:test-result: FAIL SCOPED_INFO is reset for each loop
|
||||
:test-result: PASS SUCCEED counts as a test pass
|
||||
:test-result: PASS SUCCESS does not require an argument
|
||||
:test-result: PASS Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods
|
||||
:test-result: PASS Scenario: Do that thing with the thing
|
||||
:test-result: PASS Scenario: This is a really long scenario name to see how the list command deals with wrapping
|
||||
:test-result: PASS Scenario: Vector resizing affects size and capacity
|
||||
A string sent directly to stdout
|
||||
A string sent directly to stderr
|
||||
:test-result: PASS Sends stuff to stdout and stderr
|
||||
:test-result: PASS Some simple comparisons between doubles
|
||||
Message from section one
|
||||
Message from section two
|
||||
:test-result: PASS Standard output from all sections is reported
|
||||
:test-result: FAIL StartsWith string matcher
|
||||
:test-result: PASS String matchers
|
||||
hello
|
||||
hello
|
||||
:test-result: PASS Strings can be rendered with colour
|
||||
:test-result: FAIL Tabs and newlines show in output
|
||||
:test-result: PASS Tag alias can be registered against tag patterns
|
||||
:test-result: PASS Test case with one argument
|
||||
:test-result: PASS Test enum bit values
|
||||
:test-result: PASS Text can be formatted using the Text class
|
||||
:test-result: PASS The NO_FAIL macro reports a failure but does not fail the test
|
||||
:test-result: FAIL This test 'should' fail but doesn't
|
||||
:test-result: PASS Tracker
|
||||
:test-result: FAIL Unexpected exceptions can be translated
|
||||
:test-result: PASS Use a custom approx
|
||||
:test-result: PASS Variadic macros
|
||||
:test-result: PASS When checked exceptions are thrown they can be expected or unexpected
|
||||
:test-result: FAIL When unchecked exceptions are thrown directly they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown during a CHECK the test should continue
|
||||
:test-result: FAIL When unchecked exceptions are thrown during a REQUIRE the test should abort fail
|
||||
:test-result: FAIL When unchecked exceptions are thrown from functions they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown from sections they are always failures
|
||||
:test-result: PASS When unchecked exceptions are thrown, but caught, they do not affect the test
|
||||
:test-result: PASS Where the LHS is not a simple value
|
||||
:test-result: PASS Where there is more to the expression after the RHS
|
||||
:test-result: PASS X/level/0/a
|
||||
:test-result: PASS X/level/0/b
|
||||
:test-result: PASS X/level/1/a
|
||||
:test-result: PASS X/level/1/b
|
||||
:test-result: PASS XmlEncode
|
||||
:test-result: PASS atomic if
|
||||
:test-result: PASS boolean member
|
||||
:test-result: PASS checkedElse
|
||||
:test-result: FAIL checkedElse, failing
|
||||
:test-result: PASS checkedIf
|
||||
:test-result: FAIL checkedIf, failing
|
||||
:test-result: PASS comparisons between const int variables
|
||||
:test-result: PASS comparisons between int variables
|
||||
:test-result: PASS even more nested SECTION tests
|
||||
:test-result: PASS first tag
|
||||
spanner:test-result: PASS has printf
|
||||
:test-result: FAIL just failure
|
||||
:test-result: PASS just info
|
||||
:test-result: FAIL looped SECTION tests
|
||||
:test-result: FAIL looped tests
|
||||
:test-result: FAIL more nested SECTION tests
|
||||
:test-result: PASS nested SECTION tests
|
||||
:test-result: PASS non streamable - with conv. op
|
||||
:test-result: PASS not allowed
|
||||
:test-result: PASS null strings
|
||||
:test-result: PASS pair<pair<int,const char *,pair<std::string,int> > -> toString
|
||||
:test-result: PASS pointer to class
|
||||
:test-result: PASS random SECTION tests
|
||||
:test-result: PASS replaceInPlace
|
||||
:test-result: PASS second tag
|
||||
:test-result: FAIL send a single char to INFO
|
||||
:test-result: FAIL sends information to INFO
|
||||
:test-result: PASS std::pair<int,const std::string> -> toString
|
||||
:test-result: PASS std::pair<int,std::string> -> toString
|
||||
:test-result: PASS std::vector<std::pair<std::string,int> > -> toString
|
||||
:test-result: FAIL string literals of different sizes can be compared
|
||||
: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
|
||||
:test-result: PASS toString on wchar_t const pointer returns the string contents
|
||||
:test-result: PASS toString on wchar_t returns the string contents
|
||||
:test-result: PASS toString( has_maker )
|
||||
:test-result: PASS toString( has_maker_and_toString )
|
||||
:test-result: PASS toString( has_toString )
|
||||
:test-result: PASS toString( vectors<has_maker )
|
||||
:test-result: SKIP toString( vectors<has_maker_and_toString )
|
||||
:test-result: SKIP toString( vectors<has_toString )
|
||||
:test-result: PASS toString(enum w/operator<<)
|
||||
:test-result: PASS toString(enum)
|
||||
:test-result: PASS vector<int> -> toString
|
||||
:test-result: PASS vector<string> -> toString
|
||||
:test-result: PASS vectors can be sized and resized
|
||||
:test-result: PASS xmlentitycheck
|
@ -0,0 +1,430 @@
|
||||
:test-result: PASS # A test name that starts with a #
|
||||
:test-result: PASS #1027: Bitfields can be captured
|
||||
:test-result: PASS #1147
|
||||
:test-result: PASS #1175 - Hidden Test
|
||||
:test-result: PASS #1238
|
||||
:test-result: PASS #1245
|
||||
:test-result: PASS #1319: Sections can have description (even if it is not saved
|
||||
:test-result: PASS #1403
|
||||
:test-result: FAIL #1455 - INFO and WARN can start with a linebreak
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
:test-result: FAIL #1514: stderr/stdout is not captured in tests aborted by an exception
|
||||
:test-result: PASS #1548
|
||||
:test-result: PASS #1905 -- test spec parser properly clears internal state between compound tests
|
||||
:test-result: PASS #1912 -- test spec parser handles escaping
|
||||
:test-result: PASS #1913 - GENERATE inside a for loop should not keep recreating the generator
|
||||
:test-result: PASS #1913 - GENERATEs can share a line
|
||||
:test-result: PASS #1938 - GENERATE after a section
|
||||
:test-result: PASS #1938 - Section followed by flat generate
|
||||
:test-result: PASS #1938 - flat generate
|
||||
:test-result: PASS #1938 - mixed sections and generates
|
||||
:test-result: PASS #1938 - nested generate
|
||||
:test-result: PASS #1954 - 7 arg template test case sig compiles - 1, 1, 1, 1, 1, 0, 0
|
||||
:test-result: PASS #1954 - 7 arg template test case sig compiles - 5, 1, 1, 1, 1, 0, 0
|
||||
: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
|
||||
:test-result: XFAIL #835 -- errno should not be touched by Catch2
|
||||
:test-result: PASS #872
|
||||
:test-result: PASS #961 -- Dynamically created sections should all be reported
|
||||
:test-result: FAIL 'Not' checks that should fail
|
||||
:test-result: PASS 'Not' checks that should succeed
|
||||
:test-result: PASS (unimplemented) static bools can be evaluated
|
||||
:test-result: PASS 3x3x3 ints
|
||||
:test-result: FAIL A METHOD_AS_TEST_CASE based test run that fails
|
||||
:test-result: PASS A METHOD_AS_TEST_CASE based test run that succeeds
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<float>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<int>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<float>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<int>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<float>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<int>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<float>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<int>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2<float, 6>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2<int, 2>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array<float, 6>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array<int, 2>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2<float,6>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2<int,2>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array<float,6>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array<int,2>
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD based test run that fails - double
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD based test run that fails - float
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD based test run that fails - int
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - double
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - float
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - int
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 3
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6
|
||||
:test-result: FAIL A TEST_CASE_METHOD based test run that fails
|
||||
:test-result: PASS A TEST_CASE_METHOD based test run that succeeds
|
||||
:test-result: FAIL A TEST_CASE_PERSISTENT_FIXTURE based test run that fails
|
||||
:test-result: PASS A TEST_CASE_PERSISTENT_FIXTURE based test run that succeeds
|
||||
:test-result: PASS A Template product test case - Foo<float>
|
||||
:test-result: PASS A Template product test case - Foo<int>
|
||||
:test-result: PASS A Template product test case - std::vector<float>
|
||||
:test-result: PASS A Template product test case - std::vector<int>
|
||||
:test-result: PASS A Template product test case with array signature - Bar<float, 42>
|
||||
:test-result: PASS A Template product test case with array signature - Bar<int, 9>
|
||||
:test-result: PASS A Template product test case with array signature - std::array<float, 42>
|
||||
:test-result: PASS A Template product test case with array signature - std::array<int, 9>
|
||||
:test-result: PASS A comparison that uses literals instead of the normal constructor
|
||||
:test-result: FAIL A couple of nested sections followed by a failure
|
||||
:test-result: FAIL A failing expression with a non streamable type is still captured
|
||||
:test-result: PASS Absolute margin
|
||||
:test-result: FAIL An empty test with no assertions
|
||||
:test-result: PASS An expression with side-effects should only be evaluated once
|
||||
:test-result: FAIL An unchecked exception reports the line of the last assertion
|
||||
:test-result: PASS Anonymous test case 1
|
||||
:test-result: PASS Approx setters validate their arguments
|
||||
:test-result: PASS Approx with exactly-representable margin
|
||||
:test-result: PASS Approximate PI
|
||||
:test-result: PASS Approximate comparisons with different epsilons
|
||||
:test-result: PASS Approximate comparisons with floats
|
||||
:test-result: PASS Approximate comparisons with ints
|
||||
:test-result: PASS Approximate comparisons with mixed numeric types
|
||||
:test-result: PASS Arbitrary predicate matcher
|
||||
:test-result: PASS Assertion macros support bit operators and bool conversions
|
||||
:test-result: PASS Assertions then sections
|
||||
:test-result: PASS Basic use of the Contains range matcher
|
||||
:test-result: PASS Basic use of the Empty range matcher
|
||||
:test-result: PASS CAPTURE can deal with complex expressions
|
||||
:test-result: PASS CAPTURE can deal with complex expressions involving commas
|
||||
:test-result: PASS CAPTURE parses string and character constants
|
||||
:test-result: PASS Capture and info messages
|
||||
:test-result: PASS CaseInsensitiveEqualsTo is case insensitive
|
||||
:test-result: PASS CaseInsensitiveLess is case insensitive
|
||||
:test-result: PASS Character pretty printing
|
||||
:test-result: PASS Clara::Arg does not crash on incomplete input
|
||||
:test-result: PASS Clara::Arg supports single-arg parse the way Opt does
|
||||
:test-result: PASS Clara::Opt supports accept-many lambdas
|
||||
:test-result: PASS ColourGuard behaviour
|
||||
:test-result: PASS Combining MatchAllOfGeneric does not nest
|
||||
:test-result: PASS Combining MatchAnyOfGeneric does not nest
|
||||
:test-result: PASS Combining MatchNotOfGeneric does not nest
|
||||
:test-result: PASS Combining concrete matchers does not use templated matchers
|
||||
:test-result: PASS Combining only templated matchers
|
||||
:test-result: PASS Combining templated and concrete matchers
|
||||
:test-result: PASS Combining templated matchers
|
||||
:test-result: PASS Commas in various macros are allowed
|
||||
:test-result: PASS Comparing function pointers
|
||||
:test-result: PASS Comparison ops
|
||||
:test-result: PASS Comparison with explicitly convertible types
|
||||
:test-result: PASS Comparisons between ints where one side is computed
|
||||
:test-result: PASS Comparisons between unsigned ints and negative signed ints match c++ standard behaviour
|
||||
:test-result: PASS Comparisons with int literals don't warn when mixing signed/ unsigned
|
||||
:test-result: PASS Composed generic matchers shortcircuit
|
||||
:test-result: PASS Composed matchers shortcircuit
|
||||
:test-result: FAIL Contains string matcher
|
||||
:test-result: PASS Copy and then generate a range
|
||||
:test-result: PASS Cout stream properly declares it writes to stdout
|
||||
:test-result: FAIL Custom exceptions can be translated when testing for nothrow
|
||||
:test-result: FAIL Custom exceptions can be translated when testing for throwing as something else
|
||||
: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: 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
|
||||
:test-result: PASS Epsilon only applies to Approx's value
|
||||
:test-result: XFAIL Equality checks that should fail
|
||||
:test-result: PASS Equality checks that should succeed
|
||||
:test-result: PASS Equals
|
||||
:test-result: FAIL Equals string matcher
|
||||
: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
|
||||
:test-result: FAIL FAIL aborts the test
|
||||
: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
|
||||
:test-result: PASS Greater-than inequalities with different epsilons
|
||||
:test-result: PASS Hashers with different seed produce different hash with same test case
|
||||
: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
|
||||
:test-result: PASS Matchers can be (AllOf) composed with the && operator
|
||||
:test-result: PASS Matchers can be (AnyOf) composed with the || operator
|
||||
:test-result: PASS Matchers can be composed with both && and ||
|
||||
:test-result: FAIL Matchers can be composed with both && and || - failing
|
||||
:test-result: PASS Matchers can be negated (Not) with the ! operator
|
||||
:test-result: FAIL Matchers can be negated (Not) with the ! operator - failing
|
||||
:test-result: XFAIL Mayfail test case with nested sections
|
||||
:test-result: FAIL Mismatching exception messages failing the test
|
||||
:test-result: PASS Multireporter calls reporters and listeners in correct order
|
||||
:test-result: PASS Multireporter updates ReporterPreferences properly
|
||||
:test-result: PASS Nested generators and captured variables
|
||||
:test-result: FAIL Nice descriptive name
|
||||
:test-result: FAIL Non-std exceptions can be translated
|
||||
:test-result: PASS Objects that evaluated in boolean contexts can be checked
|
||||
:test-result: PASS Optionally static assertions
|
||||
:test-result: FAIL Ordering comparison checks that should fail
|
||||
:test-result: PASS Ordering comparison checks that should succeed
|
||||
:test-result: PASS Our PCG implementation provides expected results for known seeds
|
||||
:test-result: FAIL Output from all sections is reported
|
||||
:test-result: PASS Overloaded comma or address-of operators are not used
|
||||
:test-result: PASS Parse uints
|
||||
:test-result: PASS Parsed tags are matched case insensitive
|
||||
:test-result: PASS Parsing sharding-related cli flags
|
||||
:test-result: PASS Parsing tags with non-alphabetical characters is pass-through
|
||||
:test-result: PASS Parsing warnings
|
||||
:test-result: PASS Pointers can be compared to null
|
||||
:test-result: PASS Precision of floating point stringification can be set
|
||||
:test-result: PASS Predicate matcher can accept const char*
|
||||
:test-result: PASS Process can be configured on command line
|
||||
:test-result: PASS Product with differing arities - std::tuple<int, double, float>
|
||||
:test-result: PASS Product with differing arities - std::tuple<int, double>
|
||||
:test-result: PASS Product with differing arities - std::tuple<int>
|
||||
:test-result: PASS Random seed generation accepts known methods
|
||||
:test-result: PASS Random seed generation reports unknown methods
|
||||
:test-result: PASS Range type with sentinel
|
||||
:test-result: FAIL Reconstruction should be based on stringification: #914
|
||||
:test-result: FAIL Regex string matcher
|
||||
:test-result: PASS Registering reporter with '::' in name fails
|
||||
:test-result: PASS Regression test #1
|
||||
:test-result: PASS Reporter's write listings to provided stream
|
||||
:test-result: PASS Reproducer for #2309 - a very long description past 80 chars (default console width) with a late colon : blablabla
|
||||
:test-result: PASS SUCCEED counts as a test pass
|
||||
:test-result: PASS SUCCEED does not require an argument
|
||||
:test-result: PASS Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods
|
||||
:test-result: PASS Scenario: Do that thing with the thing
|
||||
:test-result: PASS Scenario: This is a really long scenario name to see how the list command deals with wrapping
|
||||
:test-result: PASS Scenario: Vector resizing affects size and capacity
|
||||
A string sent directly to stdout
|
||||
A string sent directly to stderr
|
||||
A string sent to stderr via clog
|
||||
:test-result: FAIL Sends stuff to stdout and stderr
|
||||
:test-result: PASS Some simple comparisons between doubles
|
||||
Message from section one
|
||||
Message from section two
|
||||
:test-result: FAIL Standard output from all sections is reported
|
||||
:test-result: FAIL StartsWith string matcher
|
||||
:test-result: PASS Static arrays are convertible to string
|
||||
:test-result: PASS String matchers
|
||||
:test-result: PASS StringRef
|
||||
:test-result: PASS StringRef at compilation time
|
||||
:test-result: PASS Stringifying char arrays with statically known sizes - char
|
||||
:test-result: PASS Stringifying char arrays with statically known sizes - signed char
|
||||
:test-result: PASS Stringifying char arrays with statically known sizes - unsigned char
|
||||
:test-result: PASS Stringifying std::chrono::duration helpers
|
||||
:test-result: PASS Stringifying std::chrono::duration with weird ratios
|
||||
:test-result: PASS Stringifying std::chrono::time_point<system_clock>
|
||||
:test-result: FAIL Tabs and newlines show in output
|
||||
:test-result: PASS Tag alias can be registered against tag patterns
|
||||
:test-result: PASS Tags with spaces and non-alphanumerical characters are accepted
|
||||
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 0
|
||||
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 1
|
||||
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 2
|
||||
:test-result: PASS Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 0
|
||||
:test-result: PASS Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 1
|
||||
:test-result: PASS Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 0
|
||||
:test-result: PASS Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 1
|
||||
:test-result: PASS Template test case with test types specified inside std::tuple - MyTypes - 0
|
||||
:test-result: PASS Template test case with test types specified inside std::tuple - MyTypes - 1
|
||||
:test-result: PASS Template test case with test types specified inside std::tuple - MyTypes - 2
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - float
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - int
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - std::string
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - std::tuple<int,float>
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - float,4
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - int,5
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - std::string,15
|
||||
:test-result: PASS Test case with identical tags keeps just one
|
||||
:test-result: PASS Test case with one argument
|
||||
:test-result: PASS Test enum bit values
|
||||
:test-result: PASS Test with special, characters "in name
|
||||
: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
|
||||
:test-result: PASS Usage of AllTrue range matcher
|
||||
:test-result: PASS Usage of AnyMatch range matcher
|
||||
: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
|
||||
:test-result: PASS Vector Approx matcher
|
||||
:test-result: FAIL Vector Approx matcher -- failing
|
||||
:test-result: PASS Vector matchers
|
||||
:test-result: FAIL Vector matchers that fail
|
||||
:test-result: PASS When checked exceptions are thrown they can be expected or unexpected
|
||||
:test-result: FAIL When unchecked exceptions are thrown directly they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown during a CHECK the test should continue
|
||||
:test-result: FAIL When unchecked exceptions are thrown during a REQUIRE the test should abort fail
|
||||
:test-result: FAIL When unchecked exceptions are thrown from functions they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown from sections they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown, but caught, they do not affect the test
|
||||
:test-result: PASS X/level/0/a
|
||||
:test-result: PASS X/level/0/b
|
||||
:test-result: PASS X/level/1/a
|
||||
: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<int, N> -> toString
|
||||
:test-result: PASS benchmark function call
|
||||
:test-result: PASS boolean member
|
||||
:test-result: PASS checkedElse
|
||||
:test-result: FAIL checkedElse, failing
|
||||
:test-result: PASS checkedIf
|
||||
:test-result: FAIL checkedIf, failing
|
||||
:test-result: PASS classify_outliers
|
||||
: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
|
||||
:test-result: PASS is_unary_function
|
||||
:test-result: FAIL just failure
|
||||
:test-result: FAIL just failure after unscoped info
|
||||
:test-result: FAIL just info
|
||||
:test-result: FAIL just unscoped info
|
||||
:test-result: PASS long long
|
||||
:test-result: FAIL looped SECTION tests
|
||||
:test-result: FAIL looped tests
|
||||
:test-result: PASS makeStream recognizes %debug stream name
|
||||
:test-result: PASS make_unique reimplementation
|
||||
:test-result: PASS mean
|
||||
:test-result: PASS measure
|
||||
: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_quantile
|
||||
:test-result: PASS not allowed
|
||||
:test-result: FAIL not prints unscoped info from previous failures
|
||||
:test-result: PASS null strings
|
||||
:test-result: PASS null_ptr
|
||||
:test-result: PASS pair<pair<int,const char *,pair<std::string,int> > -> toString
|
||||
:test-result: PASS parseEnums
|
||||
:test-result: PASS pointer to class
|
||||
:test-result: PASS print unscoped info if passing unscoped info is printed
|
||||
:test-result: FAIL prints unscoped info on failure
|
||||
:test-result: FAIL prints unscoped info only for the first assertion
|
||||
:test-result: PASS random SECTION tests
|
||||
:test-result: PASS replaceInPlace
|
||||
:test-result: PASS request an unknown %-starting stream fails
|
||||
:test-result: PASS resolution
|
||||
: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
|
||||
:test-result: PASS std::map is convertible string
|
||||
:test-result: PASS std::pair<int,const std::string> -> toString
|
||||
:test-result: PASS std::pair<int,std::string> -> toString
|
||||
:test-result: PASS std::set is convertible string
|
||||
:test-result: PASS std::vector<std::pair<std::string,int> > -> toString
|
||||
:test-result: PASS stdout and stderr streams have %-starting name
|
||||
:test-result: PASS stringify ranges
|
||||
:test-result: PASS stringify( has_maker )
|
||||
:test-result: PASS stringify( has_maker_and_operator )
|
||||
:test-result: PASS stringify( has_neither )
|
||||
:test-result: PASS stringify( has_operator )
|
||||
:test-result: PASS stringify( has_template_operator )
|
||||
:test-result: PASS stringify( vectors<has_maker> )
|
||||
:test-result: PASS stringify( vectors<has_maker_and_operator> )
|
||||
:test-result: PASS stringify( vectors<has_operator> )
|
||||
: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
|
||||
:test-result: PASS toString on wchar_t const pointer returns the string contents
|
||||
:test-result: PASS toString on wchar_t returns the string contents
|
||||
:test-result: PASS toString(enum class w/operator<<)
|
||||
:test-result: PASS toString(enum class)
|
||||
:test-result: PASS toString(enum w/operator<<)
|
||||
:test-result: PASS toString(enum)
|
||||
:test-result: PASS tuple<>
|
||||
:test-result: PASS tuple<float,int>
|
||||
:test-result: PASS tuple<int>
|
||||
:test-result: PASS tuple<string,string>
|
||||
:test-result: PASS tuple<tuple<int>,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<vec<string,alloc>> -> toString
|
||||
:test-result: PASS vector<bool> -> toString
|
||||
:test-result: PASS vector<int,allocator> -> toString
|
||||
:test-result: PASS vector<int> -> toString
|
||||
:test-result: PASS vector<string> -> toString
|
||||
:test-result: PASS vectors can be sized and resized
|
||||
:test-result: PASS warmup
|
||||
:test-result: PASS weighted_average_quantile
|
||||
:test-result: PASS xmlentitycheck
|
@ -0,0 +1,419 @@
|
||||
:test-result: PASS # A test name that starts with a #
|
||||
:test-result: PASS #1027: Bitfields can be captured
|
||||
:test-result: PASS #1147
|
||||
:test-result: PASS #1175 - Hidden Test
|
||||
:test-result: PASS #1238
|
||||
:test-result: PASS #1245
|
||||
:test-result: PASS #1319: Sections can have description (even if it is not saved
|
||||
:test-result: PASS #1403
|
||||
:test-result: FAIL #1455 - INFO and WARN can start with a linebreak
|
||||
:test-result: FAIL #1514: stderr/stdout is not captured in tests aborted by an exception
|
||||
:test-result: PASS #1548
|
||||
:test-result: PASS #1905 -- test spec parser properly clears internal state between compound tests
|
||||
:test-result: PASS #1912 -- test spec parser handles escaping
|
||||
:test-result: PASS #1913 - GENERATE inside a for loop should not keep recreating the generator
|
||||
:test-result: PASS #1913 - GENERATEs can share a line
|
||||
:test-result: PASS #1938 - GENERATE after a section
|
||||
:test-result: PASS #1938 - Section followed by flat generate
|
||||
:test-result: PASS #1938 - flat generate
|
||||
:test-result: PASS #1938 - mixed sections and generates
|
||||
:test-result: PASS #1938 - nested generate
|
||||
:test-result: PASS #1954 - 7 arg template test case sig compiles - 1, 1, 1, 1, 1, 0, 0
|
||||
:test-result: PASS #1954 - 7 arg template test case sig compiles - 5, 1, 1, 1, 1, 0, 0
|
||||
: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
|
||||
:test-result: XFAIL #835 -- errno should not be touched by Catch2
|
||||
:test-result: PASS #872
|
||||
:test-result: PASS #961 -- Dynamically created sections should all be reported
|
||||
:test-result: FAIL 'Not' checks that should fail
|
||||
:test-result: PASS 'Not' checks that should succeed
|
||||
:test-result: PASS (unimplemented) static bools can be evaluated
|
||||
:test-result: PASS 3x3x3 ints
|
||||
:test-result: FAIL A METHOD_AS_TEST_CASE based test run that fails
|
||||
:test-result: PASS A METHOD_AS_TEST_CASE based test run that succeeds
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<float>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<int>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<float>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<int>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<float>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<int>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<float>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<int>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2<float, 6>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2<int, 2>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array<float, 6>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array<int, 2>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2<float,6>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2<int,2>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array<float,6>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array<int,2>
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD based test run that fails - double
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD based test run that fails - float
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD based test run that fails - int
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - double
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - float
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - int
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 3
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6
|
||||
:test-result: FAIL A TEST_CASE_METHOD based test run that fails
|
||||
:test-result: PASS A TEST_CASE_METHOD based test run that succeeds
|
||||
:test-result: FAIL A TEST_CASE_PERSISTENT_FIXTURE based test run that fails
|
||||
:test-result: PASS A TEST_CASE_PERSISTENT_FIXTURE based test run that succeeds
|
||||
:test-result: PASS A Template product test case - Foo<float>
|
||||
:test-result: PASS A Template product test case - Foo<int>
|
||||
:test-result: PASS A Template product test case - std::vector<float>
|
||||
:test-result: PASS A Template product test case - std::vector<int>
|
||||
:test-result: PASS A Template product test case with array signature - Bar<float, 42>
|
||||
:test-result: PASS A Template product test case with array signature - Bar<int, 9>
|
||||
:test-result: PASS A Template product test case with array signature - std::array<float, 42>
|
||||
:test-result: PASS A Template product test case with array signature - std::array<int, 9>
|
||||
:test-result: PASS A comparison that uses literals instead of the normal constructor
|
||||
:test-result: FAIL A couple of nested sections followed by a failure
|
||||
:test-result: FAIL A failing expression with a non streamable type is still captured
|
||||
:test-result: PASS Absolute margin
|
||||
:test-result: FAIL An empty test with no assertions
|
||||
:test-result: PASS An expression with side-effects should only be evaluated once
|
||||
:test-result: FAIL An unchecked exception reports the line of the last assertion
|
||||
:test-result: PASS Anonymous test case 1
|
||||
:test-result: PASS Approx setters validate their arguments
|
||||
:test-result: PASS Approx with exactly-representable margin
|
||||
:test-result: PASS Approximate PI
|
||||
:test-result: PASS Approximate comparisons with different epsilons
|
||||
:test-result: PASS Approximate comparisons with floats
|
||||
:test-result: PASS Approximate comparisons with ints
|
||||
:test-result: PASS Approximate comparisons with mixed numeric types
|
||||
:test-result: PASS Arbitrary predicate matcher
|
||||
:test-result: PASS Assertion macros support bit operators and bool conversions
|
||||
:test-result: PASS Assertions then sections
|
||||
:test-result: PASS Basic use of the Contains range matcher
|
||||
:test-result: PASS Basic use of the Empty range matcher
|
||||
:test-result: PASS CAPTURE can deal with complex expressions
|
||||
:test-result: PASS CAPTURE can deal with complex expressions involving commas
|
||||
:test-result: PASS CAPTURE parses string and character constants
|
||||
:test-result: PASS Capture and info messages
|
||||
:test-result: PASS CaseInsensitiveEqualsTo is case insensitive
|
||||
:test-result: PASS CaseInsensitiveLess is case insensitive
|
||||
:test-result: PASS Character pretty printing
|
||||
:test-result: PASS Clara::Arg does not crash on incomplete input
|
||||
:test-result: PASS Clara::Arg supports single-arg parse the way Opt does
|
||||
:test-result: PASS Clara::Opt supports accept-many lambdas
|
||||
:test-result: PASS ColourGuard behaviour
|
||||
:test-result: PASS Combining MatchAllOfGeneric does not nest
|
||||
:test-result: PASS Combining MatchAnyOfGeneric does not nest
|
||||
:test-result: PASS Combining MatchNotOfGeneric does not nest
|
||||
:test-result: PASS Combining concrete matchers does not use templated matchers
|
||||
:test-result: PASS Combining only templated matchers
|
||||
:test-result: PASS Combining templated and concrete matchers
|
||||
:test-result: PASS Combining templated matchers
|
||||
:test-result: PASS Commas in various macros are allowed
|
||||
:test-result: PASS Comparing function pointers
|
||||
:test-result: PASS Comparison ops
|
||||
:test-result: PASS Comparison with explicitly convertible types
|
||||
:test-result: PASS Comparisons between ints where one side is computed
|
||||
:test-result: PASS Comparisons between unsigned ints and negative signed ints match c++ standard behaviour
|
||||
:test-result: PASS Comparisons with int literals don't warn when mixing signed/ unsigned
|
||||
:test-result: PASS Composed generic matchers shortcircuit
|
||||
:test-result: PASS Composed matchers shortcircuit
|
||||
:test-result: FAIL Contains string matcher
|
||||
:test-result: PASS Copy and then generate a range
|
||||
:test-result: PASS Cout stream properly declares it writes to stdout
|
||||
:test-result: FAIL Custom exceptions can be translated when testing for nothrow
|
||||
:test-result: FAIL Custom exceptions can be translated when testing for throwing as something else
|
||||
: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: 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
|
||||
:test-result: PASS Epsilon only applies to Approx's value
|
||||
:test-result: XFAIL Equality checks that should fail
|
||||
:test-result: PASS Equality checks that should succeed
|
||||
:test-result: PASS Equals
|
||||
:test-result: FAIL Equals string matcher
|
||||
: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
|
||||
:test-result: FAIL FAIL aborts the test
|
||||
: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
|
||||
:test-result: PASS Greater-than inequalities with different epsilons
|
||||
:test-result: PASS Hashers with different seed produce different hash with same test case
|
||||
: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
|
||||
:test-result: PASS Matchers can be (AllOf) composed with the && operator
|
||||
:test-result: PASS Matchers can be (AnyOf) composed with the || operator
|
||||
:test-result: PASS Matchers can be composed with both && and ||
|
||||
:test-result: FAIL Matchers can be composed with both && and || - failing
|
||||
:test-result: PASS Matchers can be negated (Not) with the ! operator
|
||||
:test-result: FAIL Matchers can be negated (Not) with the ! operator - failing
|
||||
:test-result: XFAIL Mayfail test case with nested sections
|
||||
:test-result: FAIL Mismatching exception messages failing the test
|
||||
:test-result: PASS Multireporter calls reporters and listeners in correct order
|
||||
:test-result: PASS Multireporter updates ReporterPreferences properly
|
||||
:test-result: PASS Nested generators and captured variables
|
||||
:test-result: FAIL Nice descriptive name
|
||||
:test-result: FAIL Non-std exceptions can be translated
|
||||
:test-result: PASS Objects that evaluated in boolean contexts can be checked
|
||||
:test-result: PASS Optionally static assertions
|
||||
:test-result: FAIL Ordering comparison checks that should fail
|
||||
:test-result: PASS Ordering comparison checks that should succeed
|
||||
:test-result: PASS Our PCG implementation provides expected results for known seeds
|
||||
:test-result: FAIL Output from all sections is reported
|
||||
:test-result: PASS Overloaded comma or address-of operators are not used
|
||||
:test-result: PASS Parse uints
|
||||
:test-result: PASS Parsed tags are matched case insensitive
|
||||
:test-result: PASS Parsing sharding-related cli flags
|
||||
:test-result: PASS Parsing tags with non-alphabetical characters is pass-through
|
||||
:test-result: PASS Parsing warnings
|
||||
:test-result: PASS Pointers can be compared to null
|
||||
:test-result: PASS Precision of floating point stringification can be set
|
||||
:test-result: PASS Predicate matcher can accept const char*
|
||||
:test-result: PASS Process can be configured on command line
|
||||
:test-result: PASS Product with differing arities - std::tuple<int, double, float>
|
||||
:test-result: PASS Product with differing arities - std::tuple<int, double>
|
||||
:test-result: PASS Product with differing arities - std::tuple<int>
|
||||
:test-result: PASS Random seed generation accepts known methods
|
||||
:test-result: PASS Random seed generation reports unknown methods
|
||||
:test-result: PASS Range type with sentinel
|
||||
:test-result: FAIL Reconstruction should be based on stringification: #914
|
||||
:test-result: FAIL Regex string matcher
|
||||
:test-result: PASS Registering reporter with '::' in name fails
|
||||
:test-result: PASS Regression test #1
|
||||
:test-result: PASS Reporter's write listings to provided stream
|
||||
:test-result: PASS Reproducer for #2309 - a very long description past 80 chars (default console width) with a late colon : blablabla
|
||||
:test-result: PASS SUCCEED counts as a test pass
|
||||
:test-result: PASS SUCCEED does not require an argument
|
||||
:test-result: PASS Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods
|
||||
:test-result: PASS Scenario: Do that thing with the thing
|
||||
:test-result: PASS Scenario: This is a really long scenario name to see how the list command deals with wrapping
|
||||
:test-result: PASS Scenario: Vector resizing affects size and capacity
|
||||
:test-result: FAIL Sends stuff to stdout and stderr
|
||||
:test-result: PASS Some simple comparisons between doubles
|
||||
:test-result: FAIL Standard output from all sections is reported
|
||||
:test-result: FAIL StartsWith string matcher
|
||||
:test-result: PASS Static arrays are convertible to string
|
||||
:test-result: PASS String matchers
|
||||
:test-result: PASS StringRef
|
||||
:test-result: PASS StringRef at compilation time
|
||||
:test-result: PASS Stringifying char arrays with statically known sizes - char
|
||||
:test-result: PASS Stringifying char arrays with statically known sizes - signed char
|
||||
:test-result: PASS Stringifying char arrays with statically known sizes - unsigned char
|
||||
:test-result: PASS Stringifying std::chrono::duration helpers
|
||||
:test-result: PASS Stringifying std::chrono::duration with weird ratios
|
||||
:test-result: PASS Stringifying std::chrono::time_point<system_clock>
|
||||
:test-result: FAIL Tabs and newlines show in output
|
||||
:test-result: PASS Tag alias can be registered against tag patterns
|
||||
:test-result: PASS Tags with spaces and non-alphanumerical characters are accepted
|
||||
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 0
|
||||
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 1
|
||||
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 2
|
||||
:test-result: PASS Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 0
|
||||
:test-result: PASS Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 1
|
||||
:test-result: PASS Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 0
|
||||
:test-result: PASS Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 1
|
||||
:test-result: PASS Template test case with test types specified inside std::tuple - MyTypes - 0
|
||||
:test-result: PASS Template test case with test types specified inside std::tuple - MyTypes - 1
|
||||
:test-result: PASS Template test case with test types specified inside std::tuple - MyTypes - 2
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - float
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - int
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - std::string
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - std::tuple<int,float>
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - float,4
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - int,5
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - std::string,15
|
||||
:test-result: PASS Test case with identical tags keeps just one
|
||||
:test-result: PASS Test case with one argument
|
||||
:test-result: PASS Test enum bit values
|
||||
:test-result: PASS Test with special, characters "in name
|
||||
: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
|
||||
:test-result: PASS Usage of AllTrue range matcher
|
||||
:test-result: PASS Usage of AnyMatch range matcher
|
||||
: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
|
||||
:test-result: PASS Vector Approx matcher
|
||||
:test-result: FAIL Vector Approx matcher -- failing
|
||||
:test-result: PASS Vector matchers
|
||||
:test-result: FAIL Vector matchers that fail
|
||||
:test-result: PASS When checked exceptions are thrown they can be expected or unexpected
|
||||
:test-result: FAIL When unchecked exceptions are thrown directly they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown during a CHECK the test should continue
|
||||
:test-result: FAIL When unchecked exceptions are thrown during a REQUIRE the test should abort fail
|
||||
:test-result: FAIL When unchecked exceptions are thrown from functions they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown from sections they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown, but caught, they do not affect the test
|
||||
:test-result: PASS X/level/0/a
|
||||
:test-result: PASS X/level/0/b
|
||||
:test-result: PASS X/level/1/a
|
||||
: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<int, N> -> toString
|
||||
:test-result: PASS benchmark function call
|
||||
:test-result: PASS boolean member
|
||||
:test-result: PASS checkedElse
|
||||
:test-result: FAIL checkedElse, failing
|
||||
:test-result: PASS checkedIf
|
||||
:test-result: FAIL checkedIf, failing
|
||||
:test-result: PASS classify_outliers
|
||||
: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
|
||||
:test-result: FAIL just failure
|
||||
:test-result: FAIL just failure after unscoped info
|
||||
:test-result: FAIL just info
|
||||
:test-result: FAIL just unscoped info
|
||||
:test-result: PASS long long
|
||||
:test-result: FAIL looped SECTION tests
|
||||
:test-result: FAIL looped tests
|
||||
:test-result: PASS makeStream recognizes %debug stream name
|
||||
:test-result: PASS make_unique reimplementation
|
||||
:test-result: PASS mean
|
||||
:test-result: PASS measure
|
||||
: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_quantile
|
||||
:test-result: PASS not allowed
|
||||
:test-result: FAIL not prints unscoped info from previous failures
|
||||
:test-result: PASS null strings
|
||||
:test-result: PASS null_ptr
|
||||
:test-result: PASS pair<pair<int,const char *,pair<std::string,int> > -> toString
|
||||
:test-result: PASS parseEnums
|
||||
:test-result: PASS pointer to class
|
||||
:test-result: PASS print unscoped info if passing unscoped info is printed
|
||||
:test-result: FAIL prints unscoped info on failure
|
||||
:test-result: FAIL prints unscoped info only for the first assertion
|
||||
:test-result: PASS random SECTION tests
|
||||
:test-result: PASS replaceInPlace
|
||||
:test-result: PASS request an unknown %-starting stream fails
|
||||
:test-result: PASS resolution
|
||||
: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
|
||||
:test-result: PASS std::map is convertible string
|
||||
:test-result: PASS std::pair<int,const std::string> -> toString
|
||||
:test-result: PASS std::pair<int,std::string> -> toString
|
||||
:test-result: PASS std::set is convertible string
|
||||
:test-result: PASS std::vector<std::pair<std::string,int> > -> toString
|
||||
:test-result: PASS stdout and stderr streams have %-starting name
|
||||
:test-result: PASS stringify ranges
|
||||
:test-result: PASS stringify( has_maker )
|
||||
:test-result: PASS stringify( has_maker_and_operator )
|
||||
:test-result: PASS stringify( has_neither )
|
||||
:test-result: PASS stringify( has_operator )
|
||||
:test-result: PASS stringify( has_template_operator )
|
||||
:test-result: PASS stringify( vectors<has_maker> )
|
||||
:test-result: PASS stringify( vectors<has_maker_and_operator> )
|
||||
:test-result: PASS stringify( vectors<has_operator> )
|
||||
: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
|
||||
:test-result: PASS toString on wchar_t const pointer returns the string contents
|
||||
:test-result: PASS toString on wchar_t returns the string contents
|
||||
:test-result: PASS toString(enum class w/operator<<)
|
||||
:test-result: PASS toString(enum class)
|
||||
:test-result: PASS toString(enum w/operator<<)
|
||||
:test-result: PASS toString(enum)
|
||||
:test-result: PASS tuple<>
|
||||
:test-result: PASS tuple<float,int>
|
||||
:test-result: PASS tuple<int>
|
||||
:test-result: PASS tuple<string,string>
|
||||
:test-result: PASS tuple<tuple<int>,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<vec<string,alloc>> -> toString
|
||||
:test-result: PASS vector<bool> -> toString
|
||||
:test-result: PASS vector<int,allocator> -> toString
|
||||
:test-result: PASS vector<int> -> toString
|
||||
:test-result: PASS vector<string> -> toString
|
||||
:test-result: PASS vectors can be sized and resized
|
||||
:test-result: PASS warmup
|
||||
:test-result: PASS weighted_average_quantile
|
||||
:test-result: PASS xmlentitycheck
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,956 @@
|
||||
Filters: "*" ~[!nonportable] ~[!benchmark] ~[approvals]
|
||||
Randomness seeded to: 1
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
<exe-name> is a Catch2 v<version> host application.
|
||||
Run with -? for options
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
# A test name that starts with a #
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
yay
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1027: Bitfields can be captured
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( y.v == 0 )
|
||||
with expansion:
|
||||
0 == 0
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( 0 == y.v )
|
||||
with expansion:
|
||||
0 == 0
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1147
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( t1 == t2 )
|
||||
with expansion:
|
||||
{?} == {?}
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( t1 != t2 )
|
||||
with expansion:
|
||||
{?} != {?}
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( t1 < t2 )
|
||||
with expansion:
|
||||
{?} < {?}
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( t1 > t2 )
|
||||
with expansion:
|
||||
{?} > {?}
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( t1 <= t2 )
|
||||
with expansion:
|
||||
{?} <= {?}
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( t1 >= t2 )
|
||||
with expansion:
|
||||
{?} >= {?}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1175 - Hidden Test
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1238
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( std::memcmp(uarr, "123", sizeof(uarr)) == 0 )
|
||||
with expansion:
|
||||
0 == 0
|
||||
with messages:
|
||||
uarr := "123"
|
||||
sarr := "456"
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( std::memcmp(sarr, "456", sizeof(sarr)) == 0 )
|
||||
with expansion:
|
||||
0 == 0
|
||||
with messages:
|
||||
uarr := "123"
|
||||
sarr := "456"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1245
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1319: Sections can have description (even if it is not saved
|
||||
SectionName
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1403
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( h1 == h2 )
|
||||
with expansion:
|
||||
[1403 helper] == [1403 helper]
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1455 - INFO and WARN can start with a linebreak
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: warning:
|
||||
|
||||
This info message starts with a linebreak
|
||||
|
||||
This warning message starts with a linebreak
|
||||
|
||||
|
||||
No assertions in test case '#1455 - INFO and WARN can start with a linebreak'
|
||||
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
-------------------------------------------------------------------------------
|
||||
#1514: stderr/stdout is not captured in tests aborted by an exception
|
||||
-------------------------------------------------------------------------------
|
||||
Tricky.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Tricky.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
1514
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1548
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( std::is_same<TypeList<int>, TypeList<int>>::value )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1905 -- test spec parser properly clears internal state between compound tests
|
||||
-------------------------------------------------------------------------------
|
||||
TestSpec.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( spec.matches(*fakeTestCase("spec . char")) )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( spec.matches(*fakeTestCase("spec , char")) )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( spec.matches(*fakeTestCase(R"(spec \, char)")) )
|
||||
with expansion:
|
||||
!false
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1912 -- test spec parser handles escaping
|
||||
Various parentheses
|
||||
-------------------------------------------------------------------------------
|
||||
TestSpec.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( spec.matches(*fakeTestCase(R"(spec {a} char)")) )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( spec.matches(*fakeTestCase(R"(spec [a] char)")) )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( spec.matches(*fakeTestCase("differs but has similar tag", "[a]")) )
|
||||
with expansion:
|
||||
!false
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1912 -- test spec parser handles escaping
|
||||
backslash in test name
|
||||
-------------------------------------------------------------------------------
|
||||
TestSpec.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( spec.matches(*fakeTestCase(R"(spec \ char)")) )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1913 - GENERATE inside a for loop should not keep recreating the generator
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( counter < 7 )
|
||||
with expansion:
|
||||
3 < 7
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1913 - GENERATE inside a for loop should not keep recreating the generator
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( counter < 7 )
|
||||
with expansion:
|
||||
6 < 7
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1913 - GENERATEs can share a line
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( i != j )
|
||||
with expansion:
|
||||
1 != 3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1913 - GENERATEs can share a line
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( i != j )
|
||||
with expansion:
|
||||
1 != 4
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1913 - GENERATEs can share a line
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( i != j )
|
||||
with expansion:
|
||||
2 != 3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1913 - GENERATEs can share a line
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( i != j )
|
||||
with expansion:
|
||||
2 != 4
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - GENERATE after a section
|
||||
A
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
A
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - GENERATE after a section
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - GENERATE after a section
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - GENERATE after a section
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - Section followed by flat generate
|
||||
A
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( 1 )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - Section followed by flat generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - Section followed by flat generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - flat generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - flat generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - flat generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
A
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
A
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 1
|
||||
j := 3
|
||||
k := 5
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
B
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 1
|
||||
j := 3
|
||||
k := 6
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
B
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 1
|
||||
j := 4
|
||||
k := 5
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 1
|
||||
j := 4
|
||||
k := 6
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
A
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
A
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 2
|
||||
j := 3
|
||||
k := 5
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
B
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 2
|
||||
j := 3
|
||||
k := 6
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
B
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 2
|
||||
j := 4
|
||||
k := 5
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 2
|
||||
j := 4
|
||||
k := 6
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1954 - 7 arg template test case sig compiles - 1, 1, 1, 1, 1, 0, 0
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1954 - 7 arg template test case sig compiles - 5, 1, 1, 1, 1, 0, 0
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1954 - 7 arg template test case sig compiles - 5, 3, 1, 1, 1, 0, 0
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#2152 - ULP checks between differently signed values were wrong - double
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
CHECK_THAT( smallest_non_zero, WithinULP( -smallest_non_zero, 2 ) )
|
||||
with expansion:
|
||||
0.0 is within 2 ULPs of -4.9406564584124654e-324 ([-1.4821969375237396e-323,
|
||||
4.9406564584124654e-324])
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
CHECK_THAT( smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) )
|
||||
with expansion:
|
||||
0.0 not is within 1 ULPs of -4.9406564584124654e-324 ([-9.8813129168249309e-
|
||||
324, -0.0000000000000000e+00])
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#2152 - ULP checks between differently signed values were wrong - float
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
CHECK_THAT( smallest_non_zero, WithinULP( -smallest_non_zero, 2 ) )
|
||||
with expansion:
|
||||
0.0f is within 2 ULPs of -1.40129846e-45f ([-4.20389539e-45, 1.40129846e-45])
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
CHECK_THAT( smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) )
|
||||
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:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: FAILED:
|
||||
due to unexpected exception with message:
|
||||
failure to init
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
outside assertions
|
||||
-------------------------------------------------------------------------------
|
||||
Exception.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Exception.tests.cpp:<line number>: FAILED:
|
||||
due to unexpected exception with messages:
|
||||
answer := 42
|
||||
expected exception
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
inside REQUIRE_NOTHROW
|
||||
-------------------------------------------------------------------------------
|
||||
Exception.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Exception.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE_NOTHROW( thisThrows() )
|
||||
due to unexpected exception with messages:
|
||||
answer := 42
|
||||
expected exception
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
inside REQUIRE_THROWS
|
||||
-------------------------------------------------------------------------------
|
||||
Exception.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Exception.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THROWS( thisThrows() )
|
||||
with message:
|
||||
answer := 42
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#809
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( 42 == f )
|
||||
with expansion:
|
||||
42 == {?}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#833
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( a == t )
|
||||
with expansion:
|
||||
3 == 3
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
CHECK( a == t )
|
||||
with expansion:
|
||||
3 == 3
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THROWS( throws_int(true) )
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
CHECK_THROWS_AS( throws_int(true), int )
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_NOTHROW( throws_int(false) )
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( "aaa", Catch::Matchers::EndsWith("aaa") )
|
||||
with expansion:
|
||||
"aaa" ends with: "aaa"
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( templated_tests<int>(3) )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#835 -- errno should not be touched by Catch2
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: FAILED:
|
||||
CHECK( f() == 0 )
|
||||
with expansion:
|
||||
1 == 0
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( errno_after == 1 )
|
||||
with expansion:
|
||||
1 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#872
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( x == 4 )
|
||||
with expansion:
|
||||
{?} == 4
|
||||
with message:
|
||||
dummy := 0
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#961 -- Dynamically created sections should all be reported
|
||||
Looped section 0
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
Everything is OK
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#961 -- Dynamically created sections should all be reported
|
||||
Looped section 1
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
Everything is OK
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#961 -- Dynamically created sections should all be reported
|
||||
Looped section 2
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
Everything is OK
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#961 -- Dynamically created sections should all be reported
|
||||
Looped section 3
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
Everything is OK
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#961 -- Dynamically created sections should all be reported
|
||||
Looped section 4
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
Everything is OK
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
'Not' checks that should fail
|
||||
-------------------------------------------------------------------------------
|
||||
Condition.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Condition.tests.cpp:<line number>: FAILED:
|
||||
CHECK( false != false )
|
||||
|
||||
Condition.tests.cpp:<line number>: FAILED:
|
||||
CHECK( true != true )
|
||||
|
||||
===============================================================================
|
||||
test cases: 33 | 27 passed | 3 failed | 3 failed as expected
|
||||
assertions: 102 | 94 passed | 4 failed | 4 failed as expected
|
||||
|
@ -0,0 +1,11 @@
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
A string sent directly to stdout
|
||||
A string sent directly to stderr
|
||||
A string sent to stderr via clog
|
||||
Message from section one
|
||||
Message from section two
|
||||
loose text artifact
|
||||
a!
|
||||
b1!
|
||||
!
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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 <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_is_permutation.hpp>
|
||||
|
||||
#include <helpers/range_test_helpers.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace {
|
||||
template <typename Range1, typename Range2>
|
||||
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<int, 0> empty;
|
||||
std::array<int, 2> 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<int, 6> arr1{ { 1, 3, 5, 7, 8, 9 } };
|
||||
// arr2 is prefix of arr1
|
||||
std::array<int, 4> arr2{ { 1, 3, 5, 7 } };
|
||||
// arr3 shares prefix with arr1 and arr2, but is not a permutation
|
||||
std::array<int, 5> 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<int, 6>
|
||||
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<int, 6>
|
||||
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<int, 4>
|
||||
arr1{ { 1, 2, 3, 4 } },
|
||||
arr2{ { 10, 20, 30, 40 } };
|
||||
REQUIRE_FALSE( is_permutation( arr1, arr2 ) );
|
||||
}
|
||||
SECTION( "Reverse ranges" ) {
|
||||
const std::array<int, 5>
|
||||
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<int, 5>
|
||||
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<int, 7>
|
||||
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<int>
|
||||
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<int> range_3{ 3, 3, 2, 1 };
|
||||
REQUIRE_FALSE( is_permutation( range_1, range_3 ) );
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
TEST_CASE( "Incomplete AssertionHandler", "[assertion-handler][!shouldfail]" ) {
|
||||
Catch::AssertionHandler catchAssertionHandler(
|
||||
"REQUIRE"_catch_sr,
|
||||
CATCH_INTERNAL_LINEINFO,
|
||||
"Dummy",
|
||||
Catch::ResultDisposition::Normal );
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_clara.hpp>
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
TEST_CASE("is_unary_function", "[clara][compilation]") {
|
||||
auto unary1 = [](int) {};
|
||||
auto unary2 = [](std::string const&) {};
|
||||
auto const unary3 = [](std::string const&) {};
|
||||
auto unary4 = [](int) { return 42; };
|
||||
void unary5(char);
|
||||
double unary6(long);
|
||||
|
||||
double binary1(long, int);
|
||||
auto binary2 = [](int, char) {};
|
||||
auto nullary1 = []() {};
|
||||
auto nullary2 = []() {return 42;};
|
||||
|
||||
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary1)>::value);
|
||||
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary2)>::value);
|
||||
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary3)>::value);
|
||||
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary4)>::value);
|
||||
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary5)>::value);
|
||||
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary6)>::value);
|
||||
|
||||
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<decltype(binary1)>::value);
|
||||
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<decltype(binary2)>::value);
|
||||
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<decltype(nullary1)>::value);
|
||||
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<decltype(nullary2)>::value);
|
||||
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<int>::value);
|
||||
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<std::string const&>::value);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Clara::Arg supports single-arg parse the way Opt does", "[clara][arg][compilation]") {
|
||||
std::string name;
|
||||
auto p = Catch::Clara::Arg(name, "just one arg");
|
||||
|
||||
CHECK(name.empty());
|
||||
|
||||
p.parse( Catch::Clara::Args{ "UnitTest", "foo" } );
|
||||
REQUIRE(name == "foo");
|
||||
}
|
||||
|
||||
TEST_CASE("Clara::Arg does not crash on incomplete input", "[clara][arg][compilation]") {
|
||||
std::string name;
|
||||
auto p = Catch::Clara::Arg(name, "-");
|
||||
|
||||
CHECK(name.empty());
|
||||
|
||||
auto result = p.parse( Catch::Clara::Args{ "UnitTest", "-" } );
|
||||
CHECK( result );
|
||||
CHECK( result.type() == Catch::Clara::Detail::ResultType::Ok );
|
||||
const auto& parsed = result.value();
|
||||
CHECK( parsed.type() == Catch::Clara::ParseResultType::NoMatch );
|
||||
CHECK( parsed.remainingTokens().count() == 2 );
|
||||
CHECK( name.empty() );
|
||||
}
|
||||
|
||||
TEST_CASE("Clara::Opt supports accept-many lambdas", "[clara][opt]") {
|
||||
using namespace Catch::Clara;
|
||||
std::vector<std::string> res;
|
||||
const auto push_to_res = [&](std::string const& s) {
|
||||
res.push_back(s);
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
|
||||
SECTION("Parsing fails on multiple options without accept_many") {
|
||||
auto p = Parser() | Opt(push_to_res, "value")["-o"];
|
||||
auto parse_result = p.parse( Args{ "UnitTest", "-o", "aaa", "-o", "bbb" } );
|
||||
CHECK_FALSE(parse_result);
|
||||
}
|
||||
SECTION("Parsing succeeds on multiple options with accept_many") {
|
||||
auto p = Parser() | Opt(accept_many, push_to_res, "value")["-o"];
|
||||
auto parse_result = p.parse( Args{ "UnitTest", "-o", "aaa", "-o", "bbb" } );
|
||||
CHECK(parse_result);
|
||||
CHECK(res == std::vector<std::string>{ "aaa", "bbb" });
|
||||
}
|
||||
}
|
@ -0,0 +1,467 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/internal/catch_commandline.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
|
||||
|
||||
namespace {
|
||||
auto fakeTestCase(const char* name, const char* desc = "") { return Catch::makeTestCaseInfo("", { name, desc }, CATCH_INTERNAL_LINEINFO); }
|
||||
}
|
||||
|
||||
TEST_CASE( "Process can be configured on command line", "[config][command-line]" ) {
|
||||
|
||||
using namespace Catch::Matchers;
|
||||
|
||||
Catch::ConfigData config;
|
||||
auto cli = Catch::makeCommandLineParser(config);
|
||||
|
||||
SECTION("empty args don't cause a crash") {
|
||||
auto result = cli.parse({""});
|
||||
CHECK(result);
|
||||
CHECK(config.processName == "");
|
||||
}
|
||||
|
||||
SECTION("default - no arguments") {
|
||||
auto result = cli.parse({"test"});
|
||||
CHECK(result);
|
||||
CHECK(config.processName == "test");
|
||||
CHECK(config.shouldDebugBreak == false);
|
||||
CHECK(config.abortAfter == -1);
|
||||
CHECK(config.noThrow == false);
|
||||
CHECK( config.reporterSpecifications.empty() );
|
||||
|
||||
Catch::Config cfg(config);
|
||||
CHECK_FALSE(cfg.hasTestFilters());
|
||||
|
||||
// The Config is responsible for mixing in the default reporter
|
||||
auto expectedReporter =
|
||||
#if defined( CATCH_CONFIG_DEFAULT_REPORTER )
|
||||
CATCH_CONFIG_DEFAULT_REPORTER
|
||||
#else
|
||||
"console"
|
||||
#endif
|
||||
;
|
||||
|
||||
CHECK( cfg.getReporterSpecs().size() == 1 );
|
||||
CHECK( cfg.getReporterSpecs()[0] ==
|
||||
Catch::ReporterSpec{ expectedReporter, {}, {}, {} } );
|
||||
CHECK( cfg.getProcessedReporterSpecs().size() == 1 );
|
||||
CHECK( cfg.getProcessedReporterSpecs()[0] ==
|
||||
Catch::ProcessedReporterSpec{ expectedReporter,
|
||||
std::string{},
|
||||
Catch::ColourMode::PlatformDefault,
|
||||
{} } );
|
||||
}
|
||||
|
||||
SECTION("test lists") {
|
||||
SECTION("Specify one test case using") {
|
||||
auto result = cli.parse({"test", "test1"});
|
||||
CHECK(result);
|
||||
|
||||
Catch::Config cfg(config);
|
||||
REQUIRE(cfg.hasTestFilters());
|
||||
REQUIRE(cfg.testSpec().matches(*fakeTestCase("notIncluded")) == false);
|
||||
REQUIRE(cfg.testSpec().matches(*fakeTestCase("test1")));
|
||||
}
|
||||
SECTION("Specify one test case exclusion using exclude:") {
|
||||
auto result = cli.parse({"test", "exclude:test1"});
|
||||
CHECK(result);
|
||||
|
||||
Catch::Config cfg(config);
|
||||
REQUIRE(cfg.hasTestFilters());
|
||||
REQUIRE(cfg.testSpec().matches(*fakeTestCase("test1")) == false);
|
||||
REQUIRE(cfg.testSpec().matches(*fakeTestCase("alwaysIncluded")));
|
||||
}
|
||||
|
||||
SECTION("Specify one test case exclusion using ~") {
|
||||
auto result = cli.parse({"test", "~test1"});
|
||||
CHECK(result);
|
||||
|
||||
Catch::Config cfg(config);
|
||||
REQUIRE(cfg.hasTestFilters());
|
||||
REQUIRE(cfg.testSpec().matches(*fakeTestCase("test1")) == false);
|
||||
REQUIRE(cfg.testSpec().matches(*fakeTestCase("alwaysIncluded")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECTION("reporter") {
|
||||
using vec_Specs = std::vector<Catch::ReporterSpec>;
|
||||
using namespace std::string_literals;
|
||||
SECTION("-r/console") {
|
||||
auto result = cli.parse({"test", "-r", "console"});
|
||||
CAPTURE(result.errorMessage());
|
||||
CHECK(result);
|
||||
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "console", {}, {}, {} } } );
|
||||
}
|
||||
SECTION("-r/xml") {
|
||||
auto result = cli.parse({"test", "-r", "xml"});
|
||||
CAPTURE(result.errorMessage());
|
||||
CHECK(result);
|
||||
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "xml", {}, {}, {} } } );
|
||||
}
|
||||
SECTION("--reporter/junit") {
|
||||
auto result = cli.parse({"test", "--reporter", "junit"});
|
||||
CAPTURE(result.errorMessage());
|
||||
CHECK(result);
|
||||
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "junit", {}, {}, {} } } );
|
||||
}
|
||||
SECTION("must match one of the available ones") {
|
||||
auto result = cli.parse({"test", "--reporter", "unsupported"});
|
||||
CHECK(!result);
|
||||
|
||||
REQUIRE_THAT(result.errorMessage(), ContainsSubstring("Unrecognized reporter"));
|
||||
}
|
||||
SECTION("With output file") {
|
||||
auto result = cli.parse({ "test", "-r", "console::out=out.txt" });
|
||||
CAPTURE(result.errorMessage());
|
||||
CHECK(result);
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "console", "out.txt"s, {}, {} } } );
|
||||
}
|
||||
SECTION("With Windows-like absolute path as output file") {
|
||||
auto result = cli.parse({ "test", "-r", "console::out=C:\\Temp\\out.txt" });
|
||||
CAPTURE(result.errorMessage());
|
||||
CHECK(result);
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {} } } );
|
||||
}
|
||||
SECTION("Multiple reporters") {
|
||||
SECTION("All with output files") {
|
||||
CHECK(cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "junit::out=output-junit.xml" }));
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "xml", "output.xml"s, {}, {} },
|
||||
{ "junit", "output-junit.xml"s, {}, {} } } );
|
||||
}
|
||||
SECTION("Mixed output files and default output") {
|
||||
CHECK(cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "console" }));
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "xml", "output.xml"s, {}, {} },
|
||||
{ "console", {}, {}, {} } } );
|
||||
}
|
||||
SECTION("cannot have multiple reporters with default output") {
|
||||
auto result = cli.parse({ "test", "-r", "console", "-r", "xml::out=output.xml", "-r", "junit" });
|
||||
CHECK(!result);
|
||||
REQUIRE_THAT(result.errorMessage(), ContainsSubstring("Only one reporter may have unspecified output file."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("debugger") {
|
||||
SECTION("-b") {
|
||||
CHECK(cli.parse({"test", "-b"}));
|
||||
|
||||
REQUIRE(config.shouldDebugBreak == true);
|
||||
}
|
||||
SECTION("--break") {
|
||||
CHECK(cli.parse({"test", "--break"}));
|
||||
|
||||
REQUIRE(config.shouldDebugBreak);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SECTION("abort") {
|
||||
SECTION("-a aborts after first failure") {
|
||||
CHECK(cli.parse({"test", "-a"}));
|
||||
|
||||
REQUIRE(config.abortAfter == 1);
|
||||
}
|
||||
SECTION("-x 2 aborts after two failures") {
|
||||
CHECK(cli.parse({"test", "-x", "2"}));
|
||||
|
||||
REQUIRE(config.abortAfter == 2);
|
||||
}
|
||||
SECTION("-x must be numeric") {
|
||||
auto result = cli.parse({"test", "-x", "oops"});
|
||||
CHECK(!result);
|
||||
REQUIRE_THAT(result.errorMessage(), ContainsSubstring("convert") && ContainsSubstring("oops"));
|
||||
}
|
||||
|
||||
SECTION("wait-for-keypress") {
|
||||
SECTION("Accepted options") {
|
||||
using tuple_type = std::tuple<char const*, Catch::WaitForKeypress::When>;
|
||||
auto input = GENERATE(table<char const*, Catch::WaitForKeypress::When>({
|
||||
tuple_type{"never", Catch::WaitForKeypress::Never},
|
||||
tuple_type{"start", Catch::WaitForKeypress::BeforeStart},
|
||||
tuple_type{"exit", Catch::WaitForKeypress::BeforeExit},
|
||||
tuple_type{"both", Catch::WaitForKeypress::BeforeStartAndExit},
|
||||
}));
|
||||
CHECK(cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}));
|
||||
|
||||
REQUIRE(config.waitForKeypress == std::get<1>(input));
|
||||
}
|
||||
|
||||
SECTION("invalid options are reported") {
|
||||
auto result = cli.parse({"test", "--wait-for-keypress", "sometimes"});
|
||||
CHECK(!result);
|
||||
|
||||
#ifndef CATCH_CONFIG_DISABLE_MATCHERS
|
||||
REQUIRE_THAT(result.errorMessage(), ContainsSubstring("never") && ContainsSubstring("both"));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("nothrow") {
|
||||
SECTION("-e") {
|
||||
CHECK(cli.parse({"test", "-e"}));
|
||||
|
||||
REQUIRE(config.noThrow);
|
||||
}
|
||||
SECTION("--nothrow") {
|
||||
CHECK(cli.parse({"test", "--nothrow"}));
|
||||
|
||||
REQUIRE(config.noThrow);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("output filename") {
|
||||
SECTION("-o filename") {
|
||||
CHECK(cli.parse({"test", "-o", "filename.ext"}));
|
||||
|
||||
REQUIRE(config.defaultOutputFilename == "filename.ext");
|
||||
}
|
||||
SECTION("--out") {
|
||||
CHECK(cli.parse({"test", "--out", "filename.ext"}));
|
||||
|
||||
REQUIRE(config.defaultOutputFilename == "filename.ext");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("combinations") {
|
||||
SECTION("Single character flags can be combined") {
|
||||
CHECK(cli.parse({"test", "-abe"}));
|
||||
|
||||
CHECK(config.abortAfter == 1);
|
||||
CHECK(config.shouldDebugBreak);
|
||||
CHECK(config.noThrow == true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SECTION( "use-colour") {
|
||||
|
||||
using Catch::ColourMode;
|
||||
|
||||
SECTION( "without option" ) {
|
||||
CHECK(cli.parse({"test"}));
|
||||
|
||||
REQUIRE( config.defaultColourMode == ColourMode::PlatformDefault );
|
||||
}
|
||||
|
||||
SECTION( "auto" ) {
|
||||
CHECK( cli.parse( { "test", "--colour-mode", "default" } ) );
|
||||
|
||||
REQUIRE( config.defaultColourMode == ColourMode::PlatformDefault );
|
||||
}
|
||||
|
||||
SECTION( "yes" ) {
|
||||
CHECK(cli.parse({"test", "--colour-mode", "ansi"}));
|
||||
|
||||
REQUIRE( config.defaultColourMode == ColourMode::ANSI );
|
||||
}
|
||||
|
||||
SECTION( "no" ) {
|
||||
CHECK(cli.parse({"test", "--colour-mode", "none"}));
|
||||
|
||||
REQUIRE( config.defaultColourMode == ColourMode::None );
|
||||
}
|
||||
|
||||
SECTION( "error" ) {
|
||||
auto result = cli.parse({"test", "--colour-mode", "wrong"});
|
||||
CHECK( !result );
|
||||
CHECK_THAT( result.errorMessage(), ContainsSubstring( "colour mode must be one of" ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Benchmark options") {
|
||||
SECTION("samples") {
|
||||
CHECK(cli.parse({ "test", "--benchmark-samples=200" }));
|
||||
|
||||
REQUIRE(config.benchmarkSamples == 200);
|
||||
}
|
||||
|
||||
SECTION("resamples") {
|
||||
CHECK(cli.parse({ "test", "--benchmark-resamples=20000" }));
|
||||
|
||||
REQUIRE(config.benchmarkResamples == 20000);
|
||||
}
|
||||
|
||||
SECTION("confidence-interval") {
|
||||
CHECK(cli.parse({ "test", "--benchmark-confidence-interval=0.99" }));
|
||||
|
||||
REQUIRE(config.benchmarkConfidenceInterval == Catch::Approx(0.99));
|
||||
}
|
||||
|
||||
SECTION("no-analysis") {
|
||||
CHECK(cli.parse({ "test", "--benchmark-no-analysis" }));
|
||||
|
||||
REQUIRE(config.benchmarkNoAnalysis);
|
||||
}
|
||||
|
||||
SECTION("warmup-time") {
|
||||
CHECK(cli.parse({ "test", "--benchmark-warmup-time=10" }));
|
||||
|
||||
REQUIRE(config.benchmarkWarmupTime == 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Parsing sharding-related cli flags", "[sharding]") {
|
||||
using namespace Catch::Matchers;
|
||||
|
||||
Catch::ConfigData config;
|
||||
auto cli = Catch::makeCommandLineParser(config);
|
||||
|
||||
SECTION("shard-count") {
|
||||
CHECK(cli.parse({ "test", "--shard-count=8" }));
|
||||
|
||||
REQUIRE(config.shardCount == 8);
|
||||
}
|
||||
|
||||
SECTION("Negative shard count reports error") {
|
||||
auto result = cli.parse({ "test", "--shard-count=-1" });
|
||||
|
||||
CHECK_FALSE(result);
|
||||
REQUIRE_THAT(
|
||||
result.errorMessage(),
|
||||
ContainsSubstring( "Could not parse '-1' as shard count" ) );
|
||||
}
|
||||
|
||||
SECTION("Zero shard count reports error") {
|
||||
auto result = cli.parse({ "test", "--shard-count=0" });
|
||||
|
||||
CHECK_FALSE(result);
|
||||
REQUIRE_THAT(
|
||||
result.errorMessage(),
|
||||
ContainsSubstring( "Shard count must be positive" ) );
|
||||
}
|
||||
|
||||
SECTION("shard-index") {
|
||||
CHECK(cli.parse({ "test", "--shard-index=2" }));
|
||||
|
||||
REQUIRE(config.shardIndex == 2);
|
||||
}
|
||||
|
||||
SECTION("Negative shard index reports error") {
|
||||
auto result = cli.parse({ "test", "--shard-index=-12" });
|
||||
|
||||
CHECK_FALSE(result);
|
||||
REQUIRE_THAT(
|
||||
result.errorMessage(),
|
||||
ContainsSubstring( "Could not parse '-12' as shard index" ) );
|
||||
}
|
||||
|
||||
SECTION("Shard index 0 is accepted") {
|
||||
CHECK(cli.parse({ "test", "--shard-index=0" }));
|
||||
|
||||
REQUIRE(config.shardIndex == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Parsing warnings", "[cli][warnings]" ) {
|
||||
using Catch::WarnAbout;
|
||||
|
||||
Catch::ConfigData config;
|
||||
auto cli = Catch::makeCommandLineParser( config );
|
||||
|
||||
SECTION( "NoAssertions" ) {
|
||||
REQUIRE(cli.parse( { "test", "-w", "NoAssertions" } ));
|
||||
REQUIRE( config.warnings == WarnAbout::NoAssertions );
|
||||
}
|
||||
SECTION( "NoTests is no longer supported" ) {
|
||||
REQUIRE_FALSE(cli.parse( { "test", "-w", "NoTests" } ));
|
||||
}
|
||||
SECTION( "Combining multiple warnings" ) {
|
||||
REQUIRE( cli.parse( { "test",
|
||||
"--warn", "NoAssertions",
|
||||
"--warn", "UnmatchedTestSpec" } ) );
|
||||
|
||||
REQUIRE( config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test with special, characters \"in name", "[cli][regression]") {
|
||||
// This test case succeeds if we can invoke it from the CLI
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE("Various suspicious reporter specs are rejected",
|
||||
"[cli][reporter-spec][approvals]") {
|
||||
Catch::ConfigData config;
|
||||
auto cli = Catch::makeCommandLineParser( config );
|
||||
|
||||
auto spec = GENERATE( as<std::string>{},
|
||||
"",
|
||||
"::console",
|
||||
"console::",
|
||||
"console::some-file::",
|
||||
"::console::some-file::" );
|
||||
CAPTURE( spec );
|
||||
|
||||
auto result = cli.parse( { "test", "--reporter", spec } );
|
||||
REQUIRE_FALSE( result );
|
||||
}
|
||||
|
||||
TEST_CASE("Win32 colour implementation is compile-time optional",
|
||||
"[approvals][cli][colours]") {
|
||||
Catch::ConfigData config;
|
||||
auto cli = Catch::makeCommandLineParser( config );
|
||||
|
||||
auto result = cli.parse( { "test", "--colour-mode", "win32" } );
|
||||
|
||||
#if defined( CATCH_CONFIG_COLOUR_WIN32 )
|
||||
REQUIRE( result );
|
||||
#else
|
||||
REQUIRE_FALSE( result );
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE( "Parse rng seed in different formats", "[approvals][cli][rng-seed]" ) {
|
||||
Catch::ConfigData config;
|
||||
auto cli = Catch::makeCommandLineParser( config );
|
||||
|
||||
SECTION("well formed cases") {
|
||||
char const* seed_string;
|
||||
uint32_t seed_value;
|
||||
// GCC-5 workaround
|
||||
using gen_type = std::tuple<char const*, uint32_t>;
|
||||
std::tie( seed_string, seed_value ) = GENERATE( table<char const*, uint32_t>({
|
||||
gen_type{ "0xBEEF", 0xBEEF },
|
||||
gen_type{ "12345678", 12345678 }
|
||||
} ) );
|
||||
CAPTURE( seed_string );
|
||||
|
||||
auto result = cli.parse( { "tests", "--rng-seed", seed_string } );
|
||||
|
||||
REQUIRE( result );
|
||||
REQUIRE( config.rngSeed == seed_value );
|
||||
}
|
||||
SECTION( "Error cases" ) {
|
||||
auto seed_string =
|
||||
GENERATE( "0xSEED", "999999999999", "08888", "BEEF", "123 456" );
|
||||
CAPTURE( seed_string );
|
||||
REQUIRE_FALSE( cli.parse( { "tests", "--rng-seed", seed_string } ) );
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_reporter_spec_parser.hpp>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
|
||||
TEST_CASE("Reporter spec splitting", "[reporter-spec][cli][approvals]") {
|
||||
using Catch::Detail::splitReporterSpec;
|
||||
using Catch::Matchers::Equals;
|
||||
using namespace std::string_literals;
|
||||
|
||||
SECTION("Various edge cases") {
|
||||
REQUIRE_THAT( splitReporterSpec( "" ),
|
||||
Equals( std::vector<std::string>{ ""s } ) );
|
||||
REQUIRE_THAT( splitReporterSpec( "::" ),
|
||||
Equals( std::vector<std::string>{ "", "" } ) );
|
||||
REQUIRE_THAT( splitReporterSpec( "::rep" ),
|
||||
Equals( std::vector<std::string>{ "", "rep" } ) );
|
||||
REQUIRE_THAT( splitReporterSpec( "rep::" ),
|
||||
Equals( std::vector<std::string>{ "rep", "" } ) );
|
||||
|
||||
}
|
||||
|
||||
SECTION("Validish specs") {
|
||||
REQUIRE_THAT( splitReporterSpec( "newReporter" ),
|
||||
Equals( std::vector<std::string>{ "newReporter"s } ) );
|
||||
REQUIRE_THAT(
|
||||
splitReporterSpec( "foo-reporter::key1=value1::key2=value with "
|
||||
"space::key with space=some-value" ),
|
||||
Equals(
|
||||
std::vector<std::string>{ "foo-reporter"s,
|
||||
"key1=value1"s,
|
||||
"key2=value with space"s,
|
||||
"key with space=some-value"s } ) );
|
||||
REQUIRE_THAT(
|
||||
splitReporterSpec( "spaced reporter name::key:key=value:value" ),
|
||||
Equals( std::vector<std::string>{ "spaced reporter name"s,
|
||||
"key:key=value:value"s } ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Parsing colour mode", "[cli][colour][approvals]" ) {
|
||||
using Catch::Detail::stringToColourMode;
|
||||
using Catch::ColourMode;
|
||||
SECTION("Valid strings") {
|
||||
REQUIRE( stringToColourMode( "none" ) == ColourMode::None );
|
||||
REQUIRE( stringToColourMode( "ansi" ) == ColourMode::ANSI );
|
||||
REQUIRE( stringToColourMode( "win32" ) == ColourMode::Win32 );
|
||||
REQUIRE( stringToColourMode( "default" ) ==
|
||||
ColourMode::PlatformDefault );
|
||||
}
|
||||
SECTION("Wrong strings") {
|
||||
REQUIRE_FALSE( stringToColourMode( "NONE" ) );
|
||||
REQUIRE_FALSE( stringToColourMode( "-" ) );
|
||||
REQUIRE_FALSE( stringToColourMode( "asdbjsdb kasbd" ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Parsing reporter specs", "[cli][reporter-spec][approvals]") {
|
||||
using Catch::parseReporterSpec;
|
||||
using Catch::ReporterSpec;
|
||||
using namespace std::string_literals;
|
||||
|
||||
SECTION( "Correct specs" ) {
|
||||
REQUIRE( parseReporterSpec( "someReporter" ) ==
|
||||
ReporterSpec( "someReporter"s, {}, {}, {} ) );
|
||||
REQUIRE( parseReporterSpec( "otherReporter::Xk=v::out=c:\\blah" ) ==
|
||||
ReporterSpec(
|
||||
"otherReporter"s, "c:\\blah"s, {}, { { "Xk"s, "v"s } } ) );
|
||||
REQUIRE( parseReporterSpec( "diffReporter::Xk1=v1::Xk2==v2" ) ==
|
||||
ReporterSpec( "diffReporter",
|
||||
{},
|
||||
{},
|
||||
{ { "Xk1"s, "v1"s }, { "Xk2"s, "=v2"s } } ) );
|
||||
REQUIRE( parseReporterSpec(
|
||||
"Foo:bar:reporter::colour-mode=ansi::Xk 1=v 1::Xk2=v:3" ) ==
|
||||
ReporterSpec( "Foo:bar:reporter",
|
||||
{},
|
||||
Catch::ColourMode::ANSI,
|
||||
{ { "Xk 1"s, "v 1"s }, { "Xk2"s, "v:3"s } } ) );
|
||||
}
|
||||
|
||||
SECTION( "Bad specs" ) {
|
||||
REQUIRE_FALSE( parseReporterSpec( "::" ) );
|
||||
// Unknown Catch2 arg (should be "out")
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::output=filename" ) );
|
||||
// Wrong colour spec
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::colour-mode=custom" ) );
|
||||
// Duplicated colour spec
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::colour-mode=ansi::colour-mode=ansi" ) );
|
||||
// Duplicated out arg
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::out=f.txt::out=z.txt" ) );
|
||||
// Duplicated custom arg
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::Xa=foo::Xa=bar" ) );
|
||||
// Empty key
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::X=foo" ) );
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::=foo" ) );
|
||||
// Empty value
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::Xa=" ) );
|
||||
// non-key value later field
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::Xab" ) );
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_console_colour.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace {
|
||||
class TestColourImpl : public Catch::ColourImpl {
|
||||
using Catch::ColourImpl::ColourImpl;
|
||||
// Inherited via ColourImpl
|
||||
void use( Catch::Colour::Code colourCode ) const override {
|
||||
m_stream->stream() << "Using code: " << colourCode << '\n';
|
||||
}
|
||||
};
|
||||
|
||||
class TestStringStream : public Catch::IStream {
|
||||
std::stringstream m_stream;
|
||||
public:
|
||||
std::ostream& stream() override {
|
||||
return m_stream;
|
||||
}
|
||||
|
||||
std::string str() const { return m_stream.str(); }
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("ColourGuard behaviour", "[console-colours]") {
|
||||
TestStringStream streamWrapper;
|
||||
TestColourImpl colourImpl( &streamWrapper );
|
||||
auto& stream = streamWrapper.stream();
|
||||
|
||||
SECTION("ColourGuard is disengaged by default") {
|
||||
{ auto guard = colourImpl.guardColour( Catch::Colour::Red ); }
|
||||
|
||||
REQUIRE( streamWrapper.str().empty() );
|
||||
}
|
||||
|
||||
SECTION("ColourGuard is engaged by op<<") {
|
||||
stream << "1\n" << colourImpl.guardColour( Catch::Colour::Red ) << "2\n";
|
||||
stream << "3\n";
|
||||
|
||||
REQUIRE( streamWrapper.str() == "1\nUsing code: 2\n2\nUsing code: 0\n3\n" );
|
||||
}
|
||||
|
||||
SECTION("ColourGuard can be engaged explicitly") {
|
||||
{
|
||||
auto guard =
|
||||
colourImpl.guardColour( Catch::Colour::Red ).engage( stream );
|
||||
stream << "A\n"
|
||||
<< "B\n";
|
||||
}
|
||||
stream << "C\n";
|
||||
REQUIRE( streamWrapper.str() ==
|
||||
"Using code: 2\nA\nB\nUsing code: 0\nC\n" );
|
||||
}
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_case_insensitive_comparisons.hpp>
|
||||
#include <catch2/internal/catch_optional.hpp>
|
||||
|
||||
#include <helpers/type_with_lit_0_comparisons.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4702) // unreachable code in the macro expansions
|
||||
#endif
|
||||
|
||||
TEST_CASE("Check that our error handling macros throw the right exceptions", "[!throws][internals][approvals]") {
|
||||
REQUIRE_THROWS_AS(CATCH_INTERNAL_ERROR(""), std::logic_error);
|
||||
REQUIRE_THROWS_AS(CATCH_ERROR(""), std::domain_error);
|
||||
REQUIRE_THROWS_AS(CATCH_RUNTIME_ERROR(""), std::runtime_error);
|
||||
REQUIRE_THROWS_AS([](){CATCH_ENFORCE(false, "");}(), std::domain_error);
|
||||
REQUIRE_NOTHROW([](){CATCH_ENFORCE(true, "");}());
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop) // unreachable code in the macro expansions
|
||||
#endif
|
||||
|
||||
TEST_CASE("CaseInsensitiveLess is case insensitive", "[comparisons][string-case]") {
|
||||
Catch::Detail::CaseInsensitiveLess lt;
|
||||
SECTION( "Degenerate cases" ) {
|
||||
REQUIRE( lt( "", "a" ) );
|
||||
REQUIRE_FALSE( lt( "a", "a" ) );
|
||||
REQUIRE_FALSE( lt( "", "" ) );
|
||||
}
|
||||
SECTION("Plain comparisons") {
|
||||
REQUIRE( lt( "a", "b" ) );
|
||||
REQUIRE( lt( "a", "B" ) );
|
||||
REQUIRE( lt( "A", "b" ) );
|
||||
REQUIRE( lt( "A", "B" ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "CaseInsensitiveEqualsTo is case insensitive",
|
||||
"[comparisons][string-case]" ) {
|
||||
Catch::Detail::CaseInsensitiveEqualTo eq;
|
||||
SECTION( "Degenerate cases" ) {
|
||||
REQUIRE( eq( "", "" ) );
|
||||
REQUIRE_FALSE( eq( "", "a" ) );
|
||||
}
|
||||
SECTION( "Plain comparisons" ) {
|
||||
REQUIRE( eq( "a", "a" ) );
|
||||
REQUIRE( eq( "a", "A" ) );
|
||||
REQUIRE( eq( "A", "a" ) );
|
||||
REQUIRE( eq( "A", "A" ) );
|
||||
REQUIRE_FALSE( eq( "a", "b" ) );
|
||||
REQUIRE_FALSE( eq( "a", "B" ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Optional comparison ops", "[optional][approvals]") {
|
||||
using Catch::Optional;
|
||||
|
||||
Optional<int> a, b;
|
||||
|
||||
SECTION( "Empty optionals are equal" ) {
|
||||
REQUIRE( a == b );
|
||||
REQUIRE_FALSE( a != b );
|
||||
}
|
||||
SECTION( "Empty and non-empty optionals are never equal" ) {
|
||||
a = 1;
|
||||
REQUIRE_FALSE( a == b );
|
||||
REQUIRE( a != b );
|
||||
}
|
||||
SECTION(
|
||||
"non-empty optionals are equal if the contained elements are equal") {
|
||||
a = 1;
|
||||
b = 2;
|
||||
REQUIRE( a != b );
|
||||
REQUIRE_FALSE( a == b );
|
||||
|
||||
a = 2;
|
||||
REQUIRE( a == b );
|
||||
REQUIRE_FALSE( a != b );
|
||||
}
|
||||
}
|
||||
|
||||
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<MoveChecker> opt_A( a );
|
||||
REQUIRE_FALSE( a.has_moved );
|
||||
REQUIRE_FALSE( opt_A->has_moved );
|
||||
|
||||
SECTION( "Move construction from element" ) {
|
||||
Optional<MoveChecker> 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<MoveChecker> opt_B( CATCH_MOVE( opt_A ) );
|
||||
REQUIRE( opt_A->has_moved ); // NOLINT(clang-analyzer-cplusplus.Move)
|
||||
}
|
||||
SECTION( "Move assignment from optional" ) {
|
||||
Optional<MoveChecker> opt_B( opt_A );
|
||||
REQUIRE_FALSE( opt_A->has_moved );
|
||||
opt_B = CATCH_MOVE( opt_A );
|
||||
REQUIRE( opt_A->has_moved ); // NOLINT(clang-analyzer-cplusplus.Move)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Decomposer checks that the argument is 0 when handling "
|
||||
"only-0-comparable types",
|
||||
"[decomposition][approvals]" ) {
|
||||
TypeWithLit0Comparisons t{};
|
||||
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
|
||||
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
||||
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= t == 42 );
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= 42 == t );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= t == 0 );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= 0 == t );
|
||||
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= t != 42 );
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= 42 != t );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= t != 0 );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= 0 != t );
|
||||
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= t < 42 );
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= 42 < t );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= t < 0 );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= 0 < t );
|
||||
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= t <= 42 );
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= 42 <= t );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= t <= 0 );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= 0 <= t );
|
||||
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= t > 42 );
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= 42 > t );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= t > 0 );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= 0 > t );
|
||||
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= t >= 42 );
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= 42 >= t );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= t >= 0 );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= 0 >= t );
|
||||
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
#include <catch2/internal/catch_floating_point_helpers.hpp>
|
||||
#include <catch2/internal/catch_random_floating_point_helpers.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
TEST_CASE("convertToBits", "[floating-point][conversion]") {
|
||||
using Catch::Detail::convertToBits;
|
||||
|
||||
CHECK( convertToBits( 0.f ) == 0 );
|
||||
CHECK( convertToBits( -0.f ) == ( 1ULL << 31 ) );
|
||||
CHECK( convertToBits( 0. ) == 0 );
|
||||
CHECK( convertToBits( -0. ) == ( 1ULL << 63 ) );
|
||||
CHECK( convertToBits( std::numeric_limits<float>::denorm_min() ) == 1 );
|
||||
CHECK( convertToBits( std::numeric_limits<double>::denorm_min() ) == 1 );
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE("type-shared ulpDistance tests", "[floating-point][ulp][approvals]", float, double) {
|
||||
using FP = TestType;
|
||||
using Catch::ulpDistance;
|
||||
|
||||
// Distance between zeros is zero
|
||||
CHECK( ulpDistance( FP{}, FP{} ) == 0 );
|
||||
CHECK( ulpDistance( FP{}, -FP{} ) == 0 );
|
||||
CHECK( ulpDistance( -FP{}, -FP{} ) == 0 );
|
||||
|
||||
// Distance between same-sign infinities is zero
|
||||
static constexpr FP infinity = std::numeric_limits<FP>::infinity();
|
||||
CHECK( ulpDistance( infinity, infinity ) == 0 );
|
||||
CHECK( ulpDistance( -infinity, -infinity ) == 0 );
|
||||
|
||||
// Distance between max-finite-val and same sign infinity is 1
|
||||
static constexpr FP max_finite = std::numeric_limits<FP>::max();
|
||||
CHECK( ulpDistance( max_finite, infinity ) == 1 );
|
||||
CHECK( ulpDistance( -max_finite, -infinity ) == 1 );
|
||||
|
||||
// Distance between X and 0 is half of distance between X and -X
|
||||
CHECK( ulpDistance( -infinity, infinity ) ==
|
||||
2 * ulpDistance( infinity, FP{} ) );
|
||||
CHECK( 2 * ulpDistance( FP{ -2. }, FP{} ) ==
|
||||
ulpDistance( FP{ -2. }, FP{ 2. } ) );
|
||||
CHECK( 2 * ulpDistance( FP{ 2. }, FP{} ) ==
|
||||
ulpDistance( FP{ -2. }, FP{ 2. } ) );
|
||||
|
||||
// Denorms are supported
|
||||
CHECK( ulpDistance( std::numeric_limits<FP>::denorm_min(), FP{} ) == 1 );
|
||||
CHECK( ulpDistance( std::numeric_limits<FP>::denorm_min(), -FP{} ) == 1 );
|
||||
CHECK( ulpDistance( -std::numeric_limits<FP>::denorm_min(), FP{} ) == 1 );
|
||||
CHECK( ulpDistance( -std::numeric_limits<FP>::denorm_min(), -FP{} ) == 1 );
|
||||
CHECK( ulpDistance( std::numeric_limits<FP>::denorm_min(),
|
||||
-std::numeric_limits<FP>::denorm_min() ) == 2 );
|
||||
|
||||
// Machine epsilon
|
||||
CHECK( ulpDistance( FP{ 1. },
|
||||
FP{ 1. } + std::numeric_limits<FP>::epsilon() ) == 1 );
|
||||
CHECK( ulpDistance( -FP{ 1. },
|
||||
-FP{ 1. } - std::numeric_limits<FP>::epsilon() ) == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE("UlpDistance", "[floating-point][ulp][approvals]") {
|
||||
using Catch::ulpDistance;
|
||||
|
||||
CHECK( ulpDistance( 1., 2. ) == 0x10'00'00'00'00'00'00 );
|
||||
CHECK( ulpDistance( -2., 2. ) == 0x80'00'00'00'00'00'00'00 );
|
||||
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<TestType>::epsilon() );
|
||||
CHECK( gamma( TestType( -1. ), TestType( -0. ) ) <
|
||||
std::numeric_limits<TestType>::epsilon() );
|
||||
CHECK( directCompare( gamma( TestType( 1. ), TestType( 2. ) ),
|
||||
std::numeric_limits<TestType>::epsilon() ) );
|
||||
CHECK( directCompare( gamma( TestType( -2. ), TestType( -1. ) ),
|
||||
std::numeric_limits<TestType>::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 );
|
||||
CHECK( count_floats_with_scaled_ulp( -std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::max() ) ==
|
||||
33554430 ); // (1 << 25) - 2 due to not including infinities
|
||||
CHECK( count_floats_with_scaled_ulp( -std::numeric_limits<double>::max(),
|
||||
std::numeric_limits<double>::max() ) ==
|
||||
18014398509481982 ); // (1 << 54) - 2 due to not including infinities
|
||||
|
||||
STATIC_REQUIRE( std::is_same<std::uint64_t,
|
||||
decltype( count_floats_with_scaled_ulp(
|
||||
0., 1. ) )>::value );
|
||||
STATIC_REQUIRE( std::is_same<std::uint32_t,
|
||||
decltype( count_floats_with_scaled_ulp(
|
||||
0.f, 1.f ) )>::value );
|
||||
}
|
@ -0,0 +1,575 @@
|
||||
|
||||
// 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
|
||||
|
||||
#if defined( __GNUC__ ) || defined( __clang__ )
|
||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
|
||||
#include <helpers/range_test_helpers.hpp>
|
||||
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generator_exception.hpp>
|
||||
#include <catch2/generators/catch_generators_adapters.hpp>
|
||||
#include <catch2/generators/catch_generators_random.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
|
||||
// Tests of generator implementation details
|
||||
TEST_CASE("Generators internals", "[generators][internals]") {
|
||||
using namespace Catch::Generators;
|
||||
|
||||
SECTION("Single value") {
|
||||
auto gen = value(123);
|
||||
REQUIRE(gen.get() == 123);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Preset values") {
|
||||
auto gen = values({ 1, 3, 5 });
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Generator combinator") {
|
||||
auto gen = makeGenerators(1, 5, values({ 2, 4 }), 0);
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 0);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Explicitly typed generator sequence") {
|
||||
auto gen = makeGenerators(as<std::string>{}, "aa", "bb", "cc");
|
||||
// This just checks that the type is std::string:
|
||||
REQUIRE(gen.get().size() == 2);
|
||||
// Iterate over the generator
|
||||
REQUIRE(gen.get() == "aa");
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == "bb");
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == "cc");
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Filter generator") {
|
||||
// Normal usage
|
||||
SECTION("Simple filtering") {
|
||||
auto gen = filter([](int i) { return i != 2; }, values({ 2, 1, 2, 3, 2, 2 }));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Filter out multiple elements at the start and end") {
|
||||
auto gen = filter([](int i) { return i != 2; }, values({ 2, 2, 1, 3, 2, 2 }));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
|
||||
SECTION("Throws on construction if it can't get initial element") {
|
||||
REQUIRE_THROWS_AS(filter([](int) { return false; }, value(1)), Catch::GeneratorException);
|
||||
REQUIRE_THROWS_AS(
|
||||
filter([](int) { return false; }, values({ 1, 2, 3 })),
|
||||
Catch::GeneratorException);
|
||||
}
|
||||
}
|
||||
SECTION("Take generator") {
|
||||
SECTION("Take less") {
|
||||
auto gen = take(2, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Take more") {
|
||||
auto gen = take(2, value(1));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Map with explicit return type") {
|
||||
auto gen = map<double>([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 2.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 4.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 6.0);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Map with deduced return type") {
|
||||
auto gen = map([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 2.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 4.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 6.0);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Repeat") {
|
||||
SECTION("Singular repeat") {
|
||||
auto gen = repeat(1, value(3));
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Actual repeat") {
|
||||
auto gen = repeat(2, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Range") {
|
||||
SECTION("Positive auto step") {
|
||||
SECTION("Integer") {
|
||||
auto gen = range(-2, 2);
|
||||
REQUIRE(gen.get() == -2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Negative auto step") {
|
||||
SECTION("Integer") {
|
||||
auto gen = range(2, -2);
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Positive manual step") {
|
||||
SECTION("Integer") {
|
||||
SECTION("Exact") {
|
||||
auto gen = range(-7, 5, 3);
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly over end") {
|
||||
auto gen = range(-7, 4, 3);
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly under end") {
|
||||
auto gen = range(-7, 6, 3);
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Floating Point") {
|
||||
using Catch::Approx;
|
||||
SECTION("Exact") {
|
||||
const auto rangeStart = -1.;
|
||||
const auto rangeEnd = 1.;
|
||||
const auto step = .1;
|
||||
|
||||
auto gen = range(rangeStart, rangeEnd, step);
|
||||
auto expected = rangeStart;
|
||||
while( (rangeEnd - expected) > step ) {
|
||||
INFO( "Current expected value is " << expected );
|
||||
REQUIRE(gen.get() == Approx(expected));
|
||||
REQUIRE(gen.next());
|
||||
|
||||
expected += step;
|
||||
}
|
||||
REQUIRE(gen.get() == Approx( rangeEnd ) );
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly over end") {
|
||||
const auto rangeStart = -1.;
|
||||
const auto rangeEnd = 1.;
|
||||
const auto step = .3;
|
||||
|
||||
auto gen = range(rangeStart, rangeEnd, step);
|
||||
auto expected = rangeStart;
|
||||
while( (rangeEnd - expected) > step ) {
|
||||
INFO( "Current expected value is " << expected );
|
||||
REQUIRE(gen.get() == Approx(expected));
|
||||
REQUIRE(gen.next());
|
||||
|
||||
expected += step;
|
||||
}
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly under end") {
|
||||
const auto rangeStart = -1.;
|
||||
const auto rangeEnd = .9;
|
||||
const auto step = .3;
|
||||
|
||||
auto gen = range(rangeStart, rangeEnd, step);
|
||||
auto expected = rangeStart;
|
||||
while( (rangeEnd - expected) > step ) {
|
||||
INFO( "Current expected value is " << expected );
|
||||
REQUIRE(gen.get() == Approx(expected));
|
||||
REQUIRE(gen.next());
|
||||
|
||||
expected += step;
|
||||
}
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("Negative manual step") {
|
||||
SECTION("Integer") {
|
||||
SECTION("Exact") {
|
||||
auto gen = range(5, -7, -3);
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly over end") {
|
||||
auto gen = range(5, -6, -3);
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly under end") {
|
||||
auto gen = range(5, -8, -3);
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// todo: uncopyable type used in a generator
|
||||
// idea: uncopyable tag type for a stupid generator
|
||||
|
||||
namespace {
|
||||
struct non_copyable {
|
||||
non_copyable() = default;
|
||||
non_copyable(non_copyable const&) = delete;
|
||||
non_copyable& operator=(non_copyable const&) = delete;
|
||||
int value = -1;
|
||||
};
|
||||
|
||||
// This class shows how to implement a simple generator for Catch tests
|
||||
class TestGen : public Catch::Generators::IGenerator<int> {
|
||||
int current_number;
|
||||
public:
|
||||
|
||||
TestGen(non_copyable const& nc):
|
||||
current_number(nc.value) {}
|
||||
|
||||
int const& get() const override;
|
||||
bool next() override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Avoids -Wweak-vtables
|
||||
int const& TestGen::get() const {
|
||||
return current_number;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("GENERATE capture macros", "[generators][internals][approvals]") {
|
||||
auto value = GENERATE(take(10, random(0, 10)));
|
||||
|
||||
non_copyable nc; nc.value = value;
|
||||
// neither `GENERATE_COPY` nor plain `GENERATE` would compile here
|
||||
auto value2 = GENERATE_REF(Catch::Generators::GeneratorWrapper<int>(Catch::Detail::make_unique<TestGen>(nc)));
|
||||
REQUIRE(value == value2);
|
||||
}
|
||||
|
||||
TEST_CASE("#1809 - GENERATE_COPY and SingleValueGenerator does not compile", "[generators][compilation][approvals]") {
|
||||
// Verify Issue #1809 fix, only needs to compile.
|
||||
auto a = GENERATE_COPY(1, 2);
|
||||
(void)a;
|
||||
auto b = GENERATE_COPY(as<long>{}, 1, 2);
|
||||
(void)b;
|
||||
int i = 1;
|
||||
int j = 2;
|
||||
auto c = GENERATE_COPY(i, j);
|
||||
(void)c;
|
||||
auto d = GENERATE_COPY(as<long>{}, i, j);
|
||||
(void)d;
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE("Multiple random generators in one test case output different values", "[generators][internals][approvals]") {
|
||||
SECTION("Integer") {
|
||||
auto random1 = Catch::Generators::random(0, 1000);
|
||||
auto random2 = Catch::Generators::random(0, 1000);
|
||||
size_t same = 0;
|
||||
for (size_t i = 0; i < 1000; ++i) {
|
||||
same += random1.get() == random2.get();
|
||||
random1.next(); random2.next();
|
||||
}
|
||||
// Because the previous low bound failed CI couple of times,
|
||||
// we use a very high threshold of 20% before failure is reported.
|
||||
REQUIRE(same < 200);
|
||||
}
|
||||
SECTION("Float") {
|
||||
auto random1 = Catch::Generators::random(0., 1000.);
|
||||
auto random2 = Catch::Generators::random(0., 1000.);
|
||||
size_t same = 0;
|
||||
for (size_t i = 0; i < 1000; ++i) {
|
||||
same += random1.get() == random2.get();
|
||||
random1.next(); random2.next();
|
||||
}
|
||||
// Because the previous low bound failed CI couple of times,
|
||||
// we use a very high threshold of 20% before failure is reported.
|
||||
REQUIRE(same < 200);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("#2040 - infinite compilation recursion in GENERATE with MSVC", "[generators][compilation][approvals]") {
|
||||
int x = 42;
|
||||
auto test = GENERATE_COPY(1, x, 2 * x);
|
||||
CHECK(test < 100);
|
||||
}
|
||||
|
||||
namespace {
|
||||
static bool always_true(int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_even(int n) {
|
||||
return n % 2 == 0;
|
||||
}
|
||||
|
||||
static bool is_multiple_of_3(int n) {
|
||||
return n % 3 == 0;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("GENERATE handles function (pointers)", "[generators][compilation][approvals]") {
|
||||
auto f = GENERATE(always_true, is_even, is_multiple_of_3);
|
||||
REQUIRE(f(6));
|
||||
}
|
||||
|
||||
TEST_CASE("GENERATE decays arrays", "[generators][compilation][approvals]") {
|
||||
auto str = GENERATE("abc", "def", "gh");
|
||||
(void)str;
|
||||
STATIC_REQUIRE(std::is_same<decltype(str), const char*>::value);
|
||||
}
|
||||
|
||||
TEST_CASE("Generators count returned elements", "[generators][approvals]") {
|
||||
auto generator = Catch::Generators::FixedValuesGenerator<int>( { 1, 2, 3 } );
|
||||
REQUIRE( generator.currentElementIndex() == 0 );
|
||||
REQUIRE( generator.countedNext() );
|
||||
REQUIRE( generator.currentElementIndex() == 1 );
|
||||
REQUIRE( generator.countedNext() );
|
||||
REQUIRE( generator.currentElementIndex() == 2 );
|
||||
REQUIRE_FALSE( generator.countedNext() );
|
||||
REQUIRE( generator.currentElementIndex() == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Generators can stringify their elements",
|
||||
"[generators][approvals]" ) {
|
||||
auto generator =
|
||||
Catch::Generators::FixedValuesGenerator<int>( { 1, 2, 3 } );
|
||||
|
||||
REQUIRE( generator.currentElementAsString() == "1"_catch_sr );
|
||||
REQUIRE( generator.countedNext() );
|
||||
REQUIRE( generator.currentElementAsString() == "2"_catch_sr );
|
||||
REQUIRE( generator.countedNext() );
|
||||
REQUIRE( generator.currentElementAsString() == "3"_catch_sr );
|
||||
}
|
||||
|
||||
namespace {
|
||||
class CustomStringifyGenerator
|
||||
: public Catch::Generators::IGenerator<bool> {
|
||||
bool m_first = true;
|
||||
|
||||
std::string stringifyImpl() const override {
|
||||
return m_first ? "first" : "second";
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
if ( m_first ) {
|
||||
m_first = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
bool const& get() const override;
|
||||
};
|
||||
|
||||
// Avoids -Wweak-vtables
|
||||
bool const& CustomStringifyGenerator::get() const { return m_first; }
|
||||
} // namespace
|
||||
|
||||
TEST_CASE( "Generators can override element stringification",
|
||||
"[generators][approvals]" ) {
|
||||
CustomStringifyGenerator generator;
|
||||
REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
|
||||
REQUIRE( generator.countedNext() );
|
||||
REQUIRE( generator.currentElementAsString() == "second"_catch_sr );
|
||||
}
|
||||
|
||||
namespace {
|
||||
class StringifyCountingGenerator
|
||||
: public Catch::Generators::IGenerator<bool> {
|
||||
bool m_first = true;
|
||||
mutable size_t m_stringificationCalls = 0;
|
||||
|
||||
std::string stringifyImpl() const override {
|
||||
++m_stringificationCalls;
|
||||
return m_first ? "first" : "second";
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
if ( m_first ) {
|
||||
m_first = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool const& get() const override;
|
||||
size_t stringificationCalls() const { return m_stringificationCalls; }
|
||||
};
|
||||
|
||||
// Avoids -Wweak-vtables
|
||||
bool const& StringifyCountingGenerator::get() const { return m_first; }
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE( "Generator element stringification is cached",
|
||||
"[generators][approvals]" ) {
|
||||
StringifyCountingGenerator generator;
|
||||
REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
|
||||
REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
|
||||
REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
|
||||
REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
|
||||
REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
|
||||
|
||||
REQUIRE( generator.stringificationCalls() == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Random generators can be seeded", "[generators][approvals]" ) {
|
||||
SECTION( "Integer generator" ) {
|
||||
using Catch::Generators::RandomIntegerGenerator;
|
||||
RandomIntegerGenerator<int> rng1( 0, 100, 0x1234 ),
|
||||
rng2( 0, 100, 0x1234 );
|
||||
|
||||
for ( size_t i = 0; i < 10; ++i ) {
|
||||
REQUIRE( rng1.get() == rng2.get() );
|
||||
rng1.next(); rng2.next();
|
||||
}
|
||||
}
|
||||
SECTION("Float generator") {
|
||||
using Catch::Generators::RandomFloatingGenerator;
|
||||
RandomFloatingGenerator<double> rng1( 0., 100., 0x1234 ),
|
||||
rng2( 0., 100., 0x1234 );
|
||||
for ( size_t i = 0; i < 10; ++i ) {
|
||||
REQUIRE( rng1.get() == rng2.get() );
|
||||
rng1.next();
|
||||
rng2.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<int> 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() );
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_random_integer_helpers.hpp>
|
||||
#include <random>
|
||||
|
||||
namespace {
|
||||
template <typename Int>
|
||||
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<Int>{ upper_result, lower_result } );
|
||||
CHECK( extendedMult( b, a ) ==
|
||||
ExtendedMultResult<Int>{ upper_result, lower_result } );
|
||||
}
|
||||
|
||||
// Simple (and slow) implmentation of extended multiplication for tests
|
||||
constexpr Catch::Detail::ExtendedMultResult<std::uint64_t>
|
||||
extendedMultNaive( std::uint64_t lhs, std::uint64_t rhs ) {
|
||||
// This is a simple long multiplication, where we split lhs and rhs
|
||||
// into two 32-bit "digits", so that we can do ops with carry in 64-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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE( "extendedMult 64x64", "[Integer][approvals]" ) {
|
||||
// a x 0 == 0
|
||||
CommutativeMultCheck<uint64_t>( 0x1234'5678'9ABC'DEFF, 0, 0, 0 );
|
||||
|
||||
// bit carried from low half to upper half
|
||||
CommutativeMultCheck<uint64_t>( uint64_t( 1 ) << 63, 2, 1, 0 );
|
||||
|
||||
// bits in upper half on one side, bits in lower half on other side
|
||||
CommutativeMultCheck<uint64_t>( 0xcdcd'dcdc'0000'0000,
|
||||
0x0000'0000'aeae'aeae,
|
||||
0x0000'0000'8c6e'5a77,
|
||||
0x7391'a588'0000'0000 );
|
||||
|
||||
// Some input numbers without interesting patterns
|
||||
CommutativeMultCheck<uint64_t>( 0xaaaa'aaaa'aaaa'aaaa,
|
||||
0xbbbb'bbbb'bbbb'bbbb,
|
||||
0x7d27'd27d'27d2'7d26,
|
||||
0xd82d'82d8'2d82'd82e );
|
||||
|
||||
CommutativeMultCheck<uint64_t>( 0x7d27'd27d'27d2'7d26,
|
||||
0xd82d'82d8'2d82'd82e,
|
||||
0x69af'd991'8256'b953,
|
||||
0x8724'8909'fcb6'8cd4 );
|
||||
|
||||
CommutativeMultCheck<uint64_t>( 0xdead'beef'dead'beef,
|
||||
0xfeed'feed'feed'feef,
|
||||
0xddbf'680b'2b0c'b558,
|
||||
0x7a36'b06f'2ce9'6321 );
|
||||
|
||||
CommutativeMultCheck<uint64_t>( 0xddbf'680b'2b0c'b558,
|
||||
0x7a36'b06f'2ce9'6321,
|
||||
0x69dc'96c9'294b'fc7f,
|
||||
0xd038'39fa'a3dc'6858 );
|
||||
|
||||
CommutativeMultCheck<uint64_t>( 0x61c8'8646'80b5'83eb,
|
||||
0x61c8'8646'80b5'83eb,
|
||||
0x2559'92d3'8220'8bbe,
|
||||
0xdf44'2d22'ce48'59b9 );
|
||||
}
|
||||
|
||||
TEST_CASE("extendedMult 64x64 - all implementations", "[integer][approvals]") {
|
||||
using Catch::Detail::extendedMult;
|
||||
using Catch::Detail::extendedMultPortable;
|
||||
using Catch::Detail::fillBitsFrom;
|
||||
|
||||
std::random_device rng;
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
auto a = fillBitsFrom<std::uint64_t>( rng );
|
||||
auto b = fillBitsFrom<std::uint64_t>( rng );
|
||||
CAPTURE( a, b );
|
||||
|
||||
auto naive_ab = extendedMultNaive( a, b );
|
||||
|
||||
REQUIRE( naive_ab == extendedMultNaive( b, a ) );
|
||||
REQUIRE( naive_ab == extendedMultPortable( a, b ) );
|
||||
REQUIRE( naive_ab == extendedMultPortable( b, a ) );
|
||||
REQUIRE( naive_ab == extendedMult( a, b ) );
|
||||
REQUIRE( naive_ab == extendedMult( b, a ) );
|
||||
}
|
||||
}
|
||||
|
||||
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<std::uint8_t> ) == 2 );
|
||||
STATIC_REQUIRE( std::is_unsigned<DoubleWidthUnsignedType_t<std::uint8_t>>::value );
|
||||
STATIC_REQUIRE( sizeof( DoubleWidthUnsignedType_t<std::uint16_t> ) == 4 );
|
||||
STATIC_REQUIRE( std::is_unsigned<DoubleWidthUnsignedType_t<std::uint16_t>>::value );
|
||||
STATIC_REQUIRE( sizeof( DoubleWidthUnsignedType_t<std::uint32_t> ) == 8 );
|
||||
STATIC_REQUIRE( std::is_unsigned<DoubleWidthUnsignedType_t<std::uint32_t>>::value );
|
||||
}
|
||||
|
||||
TEST_CASE( "extendedMult 32x32", "[integer][approvals]" ) {
|
||||
// a x 0 == 0
|
||||
CommutativeMultCheck<uint32_t>( 0x1234'5678, 0, 0, 0 );
|
||||
|
||||
// bit carried from low half to upper half
|
||||
CommutativeMultCheck<uint32_t>( uint32_t(1) << 31, 2, 1, 0 );
|
||||
|
||||
// bits in upper half on one side, bits in lower half on other side
|
||||
CommutativeMultCheck<uint32_t>( 0xdcdc'0000, 0x0000'aabb, 0x0000'934b, 0x6cb4'0000 );
|
||||
|
||||
// Some input numbers without interesting patterns
|
||||
CommutativeMultCheck<uint32_t>(
|
||||
0xaaaa'aaaa, 0xbbbb'bbbb, 0x7d27'd27c, 0x2d82'd82e );
|
||||
|
||||
CommutativeMultCheck<uint32_t>(
|
||||
0x7d27'd27c, 0x2d82'd82e, 0x163f'f7e8, 0xc5b8'7248 );
|
||||
|
||||
CommutativeMultCheck<uint32_t>(
|
||||
0xdead'beef, 0xfeed'feed, 0xddbf'6809, 0x6f8d'e543 );
|
||||
|
||||
CommutativeMultCheck<uint32_t>(
|
||||
0xddbf'6809, 0x6f8d'e543, 0x60a0'e71e, 0x751d'475b );
|
||||
}
|
||||
|
||||
TEST_CASE( "extendedMult 8x8", "[integer][approvals]" ) {
|
||||
// a x 0 == 0
|
||||
CommutativeMultCheck<uint8_t>( 0xcd, 0, 0, 0 );
|
||||
|
||||
// bit carried from low half to upper half
|
||||
CommutativeMultCheck<uint8_t>( uint8_t( 1 ) << 7, 2, 1, 0 );
|
||||
|
||||
// bits in upper half on one side, bits in lower half on other side
|
||||
CommutativeMultCheck<uint8_t>( 0x80, 0x03, 0x01, 0x80 );
|
||||
|
||||
// Some input numbers without interesting patterns
|
||||
CommutativeMultCheck<uint8_t>( 0xaa, 0xbb, 0x7c, 0x2e );
|
||||
CommutativeMultCheck<uint8_t>( 0x7c, 0x2e, 0x16, 0x48 );
|
||||
CommutativeMultCheck<uint8_t>( 0xdc, 0xcd, 0xb0, 0x2c );
|
||||
CommutativeMultCheck<uint8_t>( 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<int32_t>( static_cast<uint32_t>( negative ) );
|
||||
uint32_t adjusted_positive =
|
||||
transposeToNaturalOrder<int32_t>( static_cast<uint32_t>( positive ) );
|
||||
REQUIRE( adjusted_negative < adjusted_positive );
|
||||
REQUIRE( adjusted_positive - adjusted_negative == 2 );
|
||||
|
||||
// Conversion has to be reversible
|
||||
REQUIRE( negative == static_cast<int32_t>( transposeToNaturalOrder<int32_t>(
|
||||
adjusted_negative ) ) );
|
||||
REQUIRE( positive == static_cast<int32_t>( transposeToNaturalOrder<int32_t>(
|
||||
adjusted_positive ) ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "unsigned integers are unchanged by transposeToNaturalOrder",
|
||||
"[integer][approvals]") {
|
||||
using Catch::Detail::transposeToNaturalOrder;
|
||||
uint32_t max = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t zero = 0;
|
||||
REQUIRE( max == transposeToNaturalOrder<uint32_t>( max ) );
|
||||
REQUIRE( zero == transposeToNaturalOrder<uint32_t>( zero ) );
|
||||
}
|
@ -0,0 +1,455 @@
|
||||
|
||||
// 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.
|
||||
|
||||
|
||||
#if defined( __GNUC__ ) || defined( __clang__ )
|
||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||
#include <catch2/benchmark/detail/catch_analyse.hpp>
|
||||
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||
#include <catch2/benchmark/detail/catch_estimate_clock.hpp>
|
||||
|
||||
#include <numeric>
|
||||
|
||||
namespace {
|
||||
struct manual_clock {
|
||||
public:
|
||||
using duration = std::chrono::nanoseconds;
|
||||
using time_point = std::chrono::time_point<manual_clock, duration>;
|
||||
using rep = duration::rep;
|
||||
using period = duration::period;
|
||||
enum { is_steady = true };
|
||||
|
||||
static time_point now() {
|
||||
return time_point(duration(tick()));
|
||||
}
|
||||
|
||||
static void advance(int ticks = 1) {
|
||||
tick() += ticks;
|
||||
}
|
||||
|
||||
private:
|
||||
static rep& tick() {
|
||||
static rep the_tick = 0;
|
||||
return the_tick;
|
||||
}
|
||||
};
|
||||
|
||||
struct counting_clock {
|
||||
public:
|
||||
using duration = std::chrono::nanoseconds;
|
||||
using time_point = std::chrono::time_point<counting_clock, duration>;
|
||||
using rep = duration::rep;
|
||||
using period = duration::period;
|
||||
enum { is_steady = true };
|
||||
|
||||
static time_point now() {
|
||||
static rep ticks = 0;
|
||||
return time_point(duration(ticks += rate()));
|
||||
}
|
||||
|
||||
static void set_rate(rep new_rate) { rate() = new_rate; }
|
||||
|
||||
private:
|
||||
static rep& rate() {
|
||||
static rep the_rate = 1;
|
||||
return the_rate;
|
||||
}
|
||||
};
|
||||
|
||||
struct TestChronometerModel : Catch::Benchmark::Detail::ChronometerConcept {
|
||||
int started = 0;
|
||||
int finished = 0;
|
||||
|
||||
void start() override { ++started; }
|
||||
void finish() override { ++finished; }
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("warmup", "[benchmark]") {
|
||||
auto rate = 1000;
|
||||
counting_clock::set_rate(rate);
|
||||
|
||||
auto start = counting_clock::now();
|
||||
auto iterations = Catch::Benchmark::Detail::warmup<counting_clock>();
|
||||
auto end = counting_clock::now();
|
||||
|
||||
REQUIRE((iterations * rate) > Catch::Benchmark::Detail::warmup_time.count());
|
||||
REQUIRE((end - start) > Catch::Benchmark::Detail::warmup_time);
|
||||
}
|
||||
|
||||
TEST_CASE("resolution", "[benchmark]") {
|
||||
auto rate = 1000;
|
||||
counting_clock::set_rate(rate);
|
||||
|
||||
size_t count = 10;
|
||||
auto res = Catch::Benchmark::Detail::resolution<counting_clock>(static_cast<int>(count));
|
||||
|
||||
REQUIRE(res.size() == count);
|
||||
|
||||
for (size_t i = 1; i < count; ++i) {
|
||||
REQUIRE(res[i] == rate);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("estimate_clock_resolution", "[benchmark]") {
|
||||
auto rate = 2'000;
|
||||
counting_clock::set_rate(rate);
|
||||
|
||||
int iters = 160'000;
|
||||
auto res = Catch::Benchmark::Detail::estimate_clock_resolution<counting_clock>(iters);
|
||||
|
||||
REQUIRE(res.mean.count() == rate);
|
||||
REQUIRE(res.outliers.total() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("benchmark function call", "[benchmark]") {
|
||||
SECTION("without chronometer") {
|
||||
auto called = 0;
|
||||
auto model = TestChronometerModel{};
|
||||
auto meter = Catch::Benchmark::Chronometer{ model, 1 };
|
||||
auto fn = Catch::Benchmark::Detail::BenchmarkFunction{ [&] {
|
||||
CHECK(model.started == 1);
|
||||
CHECK(model.finished == 0);
|
||||
++called;
|
||||
} };
|
||||
|
||||
fn(meter);
|
||||
|
||||
CHECK(model.started == 1);
|
||||
CHECK(model.finished == 1);
|
||||
CHECK(called == 1);
|
||||
}
|
||||
|
||||
SECTION("with chronometer") {
|
||||
auto called = 0;
|
||||
auto model = TestChronometerModel{};
|
||||
auto meter = Catch::Benchmark::Chronometer{ model, 1 };
|
||||
auto fn = Catch::Benchmark::Detail::BenchmarkFunction{ [&](Catch::Benchmark::Chronometer) {
|
||||
CHECK(model.started == 0);
|
||||
CHECK(model.finished == 0);
|
||||
++called;
|
||||
} };
|
||||
|
||||
fn(meter);
|
||||
|
||||
CHECK(model.started == 0);
|
||||
CHECK(model.finished == 0);
|
||||
CHECK(called == 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("uniform samples", "[benchmark]") {
|
||||
std::vector<double> samples(100);
|
||||
std::fill(samples.begin(), samples.end(), 23);
|
||||
|
||||
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);
|
||||
});
|
||||
CHECK(e.point == 23);
|
||||
CHECK(e.upper_bound == 23);
|
||||
CHECK(e.lower_bound == 23);
|
||||
CHECK(e.confidence_interval == 0.95);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("normal_cdf", "[benchmark][approvals]") {
|
||||
using Catch::Benchmark::Detail::normal_cdf;
|
||||
using Catch::Approx;
|
||||
CHECK(normal_cdf(0.000000) == Approx(0.50000000000000000));
|
||||
CHECK(normal_cdf(1.000000) == Approx(0.84134474606854293));
|
||||
CHECK(normal_cdf(-1.000000) == Approx(0.15865525393145705));
|
||||
CHECK(normal_cdf(2.809729) == Approx(0.99752083845315409));
|
||||
CHECK(normal_cdf(-1.352570) == Approx(0.08809652095066035));
|
||||
}
|
||||
|
||||
TEST_CASE("erfc_inv", "[benchmark]") {
|
||||
using Catch::Benchmark::Detail::erfc_inv;
|
||||
using Catch::Approx;
|
||||
CHECK(erfc_inv(1.103560) == Approx(-0.09203687623843015));
|
||||
CHECK(erfc_inv(1.067400) == Approx(-0.05980291115763361));
|
||||
CHECK(erfc_inv(0.050000) == Approx(1.38590382434967796));
|
||||
}
|
||||
|
||||
TEST_CASE("normal_quantile", "[benchmark]") {
|
||||
using Catch::Benchmark::Detail::normal_quantile;
|
||||
using Catch::Approx;
|
||||
CHECK(normal_quantile(0.551780) == Approx(0.13015979861484198));
|
||||
CHECK(normal_quantile(0.533700) == Approx(0.08457408802851875));
|
||||
CHECK(normal_quantile(0.025000) == Approx(-1.95996398454005449));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("mean", "[benchmark]") {
|
||||
std::vector<double> x{ 10., 20., 14., 16., 30., 24. };
|
||||
|
||||
auto m = Catch::Benchmark::Detail::mean(x.data(), x.data() + x.size());
|
||||
|
||||
REQUIRE(m == 19.);
|
||||
}
|
||||
|
||||
TEST_CASE("weighted_average_quantile", "[benchmark]") {
|
||||
std::vector<double> x{ 10., 20., 14., 16., 30., 24. };
|
||||
|
||||
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.);
|
||||
REQUIRE(q3 == 23.);
|
||||
}
|
||||
|
||||
TEST_CASE("classify_outliers", "[benchmark]") {
|
||||
auto require_outliers = [](Catch::Benchmark::OutlierClassification o, int los, int lom, int him, int his) {
|
||||
REQUIRE(o.low_severe == los);
|
||||
REQUIRE(o.low_mild == lom);
|
||||
REQUIRE(o.high_mild == him);
|
||||
REQUIRE(o.high_severe == his);
|
||||
REQUIRE(o.total() == los + lom + him + his);
|
||||
};
|
||||
|
||||
SECTION("none") {
|
||||
std::vector<double> x{ 10., 20., 14., 16., 30., 24. };
|
||||
|
||||
auto o = Catch::Benchmark::Detail::classify_outliers(
|
||||
x.data(), x.data() + x.size() );
|
||||
|
||||
REQUIRE(o.samples_seen == static_cast<int>(x.size()));
|
||||
require_outliers(o, 0, 0, 0, 0);
|
||||
}
|
||||
SECTION("low severe") {
|
||||
std::vector<double> x{ -12., 20., 14., 16., 30., 24. };
|
||||
|
||||
auto o = Catch::Benchmark::Detail::classify_outliers(
|
||||
x.data(), x.data() + x.size() );
|
||||
|
||||
REQUIRE(o.samples_seen == static_cast<int>(x.size()));
|
||||
require_outliers(o, 1, 0, 0, 0);
|
||||
}
|
||||
SECTION("low mild") {
|
||||
std::vector<double> x{ 1., 20., 14., 16., 30., 24. };
|
||||
|
||||
auto o = Catch::Benchmark::Detail::classify_outliers(
|
||||
x.data(), x.data() + x.size() );
|
||||
|
||||
REQUIRE(o.samples_seen == static_cast<int>(x.size()));
|
||||
require_outliers(o, 0, 1, 0, 0);
|
||||
}
|
||||
SECTION("high mild") {
|
||||
std::vector<double> x{ 10., 20., 14., 16., 36., 24. };
|
||||
|
||||
auto o = Catch::Benchmark::Detail::classify_outliers(
|
||||
x.data(), x.data() + x.size() );
|
||||
|
||||
REQUIRE(o.samples_seen == static_cast<int>(x.size()));
|
||||
require_outliers(o, 0, 0, 1, 0);
|
||||
}
|
||||
SECTION("high severe") {
|
||||
std::vector<double> x{ 10., 20., 14., 16., 49., 24. };
|
||||
|
||||
auto o = Catch::Benchmark::Detail::classify_outliers(
|
||||
x.data(), x.data() + x.size() );
|
||||
|
||||
REQUIRE(o.samples_seen == static_cast<int>(x.size()));
|
||||
require_outliers(o, 0, 0, 0, 1);
|
||||
}
|
||||
SECTION("mixed") {
|
||||
std::vector<double> x{ -20., 20., 14., 16., 39., 24. };
|
||||
|
||||
auto o = Catch::Benchmark::Detail::classify_outliers(
|
||||
x.data(), x.data() + x.size() );
|
||||
|
||||
REQUIRE(o.samples_seen == static_cast<int>(x.size()));
|
||||
require_outliers(o, 1, 0, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("analyse", "[approvals][benchmark]") {
|
||||
Catch::ConfigData data{};
|
||||
data.benchmarkConfidenceInterval = 0.95;
|
||||
data.benchmarkNoAnalysis = false;
|
||||
data.benchmarkResamples = 1000;
|
||||
data.benchmarkSamples = 99;
|
||||
Catch::Config config{data};
|
||||
|
||||
using FDuration = Catch::Benchmark::FDuration;
|
||||
std::vector<FDuration> samples(99);
|
||||
for (size_t i = 0; i < samples.size(); ++i) {
|
||||
samples[i] = FDuration(23 + (i % 3 - 1));
|
||||
}
|
||||
|
||||
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);
|
||||
CHECK(analysis.mean.upper_bound.count() > 23);
|
||||
CHECK(analysis.mean.upper_bound.count() < 24);
|
||||
|
||||
CHECK(analysis.standard_deviation.point.count() > 0.5);
|
||||
CHECK(analysis.standard_deviation.point.count() < 1);
|
||||
CHECK(analysis.standard_deviation.lower_bound.count() > 0.5);
|
||||
CHECK(analysis.standard_deviation.lower_bound.count() < 1);
|
||||
CHECK(analysis.standard_deviation.upper_bound.count() > 0.5);
|
||||
CHECK(analysis.standard_deviation.upper_bound.count() < 1);
|
||||
|
||||
CHECK(analysis.outliers.total() == 0);
|
||||
CHECK(analysis.outliers.low_mild == 0);
|
||||
CHECK(analysis.outliers.low_severe == 0);
|
||||
CHECK(analysis.outliers.high_mild == 0);
|
||||
CHECK(analysis.outliers.high_severe == 0);
|
||||
CHECK(analysis.outliers.samples_seen == static_cast<int>(samples.size()));
|
||||
|
||||
CHECK(analysis.outlier_variance < 0.5);
|
||||
CHECK(analysis.outlier_variance > 0);
|
||||
}
|
||||
|
||||
TEST_CASE("analyse no analysis", "[benchmark]") {
|
||||
Catch::ConfigData data{};
|
||||
data.benchmarkConfidenceInterval = 0.95;
|
||||
data.benchmarkNoAnalysis = true;
|
||||
data.benchmarkResamples = 1000;
|
||||
data.benchmarkSamples = 99;
|
||||
Catch::Config config{ data };
|
||||
|
||||
using FDuration = Catch::Benchmark::FDuration;
|
||||
std::vector<FDuration> samples(99);
|
||||
for (size_t i = 0; i < samples.size(); ++i) {
|
||||
samples[i] = FDuration(23 + (i % 3 - 1));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
CHECK(analysis.standard_deviation.point.count() == 0);
|
||||
CHECK(analysis.standard_deviation.lower_bound.count() == 0);
|
||||
CHECK(analysis.standard_deviation.upper_bound.count() == 0);
|
||||
|
||||
CHECK(analysis.outliers.total() == 0);
|
||||
CHECK(analysis.outliers.low_mild == 0);
|
||||
CHECK(analysis.outliers.low_severe == 0);
|
||||
CHECK(analysis.outliers.high_mild == 0);
|
||||
CHECK(analysis.outliers.high_severe == 0);
|
||||
CHECK(analysis.outliers.samples_seen == 0);
|
||||
|
||||
CHECK(analysis.outlier_variance == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("run_for_at_least, int", "[benchmark]") {
|
||||
manual_clock::duration time(100);
|
||||
|
||||
int old_x = 1;
|
||||
auto Timing = Catch::Benchmark::Detail::run_for_at_least<manual_clock>(time, 1, [&old_x](int x) -> int {
|
||||
CHECK(x >= old_x);
|
||||
manual_clock::advance(x);
|
||||
old_x = x;
|
||||
return x + 17;
|
||||
});
|
||||
|
||||
REQUIRE(Timing.elapsed >= time);
|
||||
REQUIRE(Timing.result == Timing.iterations + 17);
|
||||
REQUIRE(Timing.iterations >= time.count());
|
||||
}
|
||||
|
||||
TEST_CASE("run_for_at_least, chronometer", "[benchmark]") {
|
||||
manual_clock::duration time(100);
|
||||
|
||||
int old_runs = 1;
|
||||
auto Timing = Catch::Benchmark::Detail::run_for_at_least<manual_clock>(time, 1, [&old_runs](Catch::Benchmark::Chronometer meter) -> int {
|
||||
CHECK(meter.runs() >= old_runs);
|
||||
manual_clock::advance(100);
|
||||
meter.measure([] {
|
||||
manual_clock::advance(1);
|
||||
});
|
||||
old_runs = meter.runs();
|
||||
return meter.runs() + 17;
|
||||
});
|
||||
|
||||
REQUIRE(Timing.elapsed >= time);
|
||||
REQUIRE(Timing.result == Timing.iterations + 17);
|
||||
REQUIRE(Timing.iterations >= time.count());
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("measure", "[benchmark]") {
|
||||
auto r = Catch::Benchmark::Detail::measure<manual_clock>([](int x) -> int {
|
||||
CHECK(x == 17);
|
||||
manual_clock::advance(42);
|
||||
return 23;
|
||||
}, 17);
|
||||
auto s = Catch::Benchmark::Detail::measure<manual_clock>([](int x) -> int {
|
||||
CHECK(x == 23);
|
||||
manual_clock::advance(69);
|
||||
return 17;
|
||||
}, 23);
|
||||
|
||||
CHECK(r.elapsed.count() == 42);
|
||||
CHECK(r.result == 23);
|
||||
CHECK(r.iterations == 1);
|
||||
|
||||
CHECK(s.elapsed.count() == 69);
|
||||
CHECK(s.result == 17);
|
||||
CHECK(s.iterations == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("run benchmark", "[benchmark][approvals]") {
|
||||
counting_clock::set_rate(1000);
|
||||
auto start = counting_clock::now();
|
||||
|
||||
Catch::Benchmark::Benchmark bench{ "Test Benchmark", [](Catch::Benchmark::Chronometer meter) {
|
||||
counting_clock::set_rate(100000);
|
||||
meter.measure([] { return counting_clock::now(); });
|
||||
} };
|
||||
|
||||
bench.run<counting_clock>();
|
||||
auto end = counting_clock::now();
|
||||
|
||||
CHECK((end - start).count() == 2867251000);
|
||||
}
|
||||
|
||||
TEST_CASE("Failing benchmarks", "[!benchmark][.approvals]") {
|
||||
SECTION("empty", "Benchmark that has been optimized away (because it is empty)") {
|
||||
BENCHMARK("Empty benchmark") {};
|
||||
}
|
||||
SECTION("throw", "Benchmark that throws an exception") {
|
||||
BENCHMARK("Throwing benchmark") {
|
||||
throw "just a plain literal, bleh";
|
||||
};
|
||||
}
|
||||
SECTION("assert", "Benchmark that asserts inside") {
|
||||
BENCHMARK("Asserting benchmark") {
|
||||
REQUIRE(1 == 2);
|
||||
};
|
||||
}
|
||||
SECTION("fail", "Benchmark that fails inside") {
|
||||
BENCHMARK("FAIL'd benchmark") {
|
||||
FAIL("This benchmark only fails, nothing else");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Failing benchmark respects should-fail",
|
||||
"[!shouldfail][!benchmark][approvals]" ) {
|
||||
BENCHMARK( "Asserting benchmark" ) { REQUIRE( 1 == 2 ); };
|
||||
}
|
@ -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 <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_jsonwriter.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
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\"" );
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <catch2/internal/catch_parse_numbers.hpp>
|
||||
|
||||
TEST_CASE("Parse uints", "[parse-numbers]") {
|
||||
using Catch::parseUInt;
|
||||
using Catch::Optional;
|
||||
|
||||
SECTION("proper inputs") {
|
||||
REQUIRE( parseUInt( "0" ) == Optional<unsigned int>{ 0 } );
|
||||
REQUIRE( parseUInt( "100" ) == Optional<unsigned int>{ 100 } );
|
||||
REQUIRE( parseUInt( "4294967295" ) ==
|
||||
Optional<unsigned int>{ 4294967295 } );
|
||||
REQUIRE( parseUInt( "0xFF", 16 ) == Optional<unsigned int>{ 255 } );
|
||||
}
|
||||
SECTION( "Bad inputs" ) {
|
||||
// empty
|
||||
REQUIRE_FALSE( parseUInt( "" ) );
|
||||
// random noise
|
||||
REQUIRE_FALSE( parseUInt( "!!KJHF*#" ) );
|
||||
// negative
|
||||
REQUIRE_FALSE( parseUInt( "-1" ) );
|
||||
// too large
|
||||
REQUIRE_FALSE( parseUInt( "4294967296" ) );
|
||||
REQUIRE_FALSE( parseUInt( "42949672964294967296429496729642949672964294967296" ) );
|
||||
REQUIRE_FALSE( parseUInt( "2 4" ) );
|
||||
// hex with base 10
|
||||
REQUIRE_FALSE( parseUInt( "0xFF", 10 ) );
|
||||
}
|
||||
}
|
@ -0,0 +1,254 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_test_case_tracker.hpp>
|
||||
|
||||
|
||||
using namespace Catch;
|
||||
|
||||
namespace {
|
||||
Catch::TestCaseTracking::NameAndLocationRef makeNAL( StringRef name ) {
|
||||
return Catch::TestCaseTracking::NameAndLocationRef( name, Catch::SourceLineInfo("",0) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Tracker" ) {
|
||||
|
||||
TrackerContext ctx;
|
||||
ctx.startRun();
|
||||
ctx.startCycle();
|
||||
|
||||
|
||||
ITracker& testCase = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase.isOpen() );
|
||||
|
||||
ITracker& s1 = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1.isOpen() );
|
||||
|
||||
SECTION( "successfully close one section" ) {
|
||||
s1.close();
|
||||
REQUIRE( s1.isSuccessfullyCompleted() );
|
||||
REQUIRE( testCase.isComplete() == false );
|
||||
|
||||
testCase.close();
|
||||
REQUIRE( ctx.completedCycle() );
|
||||
REQUIRE( testCase.isSuccessfullyCompleted() );
|
||||
}
|
||||
|
||||
SECTION( "fail one section" ) {
|
||||
s1.fail();
|
||||
REQUIRE( s1.isComplete() );
|
||||
REQUIRE( s1.isSuccessfullyCompleted() == false );
|
||||
REQUIRE( testCase.isComplete() == false );
|
||||
|
||||
testCase.close();
|
||||
REQUIRE( ctx.completedCycle() );
|
||||
REQUIRE( testCase.isSuccessfullyCompleted() == false );
|
||||
|
||||
SECTION( "re-enter after failed section" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() == false );
|
||||
|
||||
testCase2.close();
|
||||
REQUIRE( ctx.completedCycle() );
|
||||
REQUIRE( testCase.isComplete() );
|
||||
REQUIRE( testCase.isSuccessfullyCompleted() );
|
||||
}
|
||||
SECTION( "re-enter after failed section and find next section" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() == false );
|
||||
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() );
|
||||
|
||||
s2.close();
|
||||
REQUIRE( ctx.completedCycle() );
|
||||
|
||||
testCase2.close();
|
||||
REQUIRE( testCase.isComplete() );
|
||||
REQUIRE( testCase.isSuccessfullyCompleted() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "successfully close one section, then find another" ) {
|
||||
s1.close();
|
||||
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() == false );
|
||||
|
||||
testCase.close();
|
||||
REQUIRE( testCase.isComplete() == false );
|
||||
|
||||
SECTION( "Re-enter - skips S1 and enters S2" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() == false );
|
||||
|
||||
ITracker& s2b = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2b.isOpen() );
|
||||
|
||||
REQUIRE( ctx.completedCycle() == false );
|
||||
|
||||
SECTION ("Successfully close S2") {
|
||||
s2b.close();
|
||||
REQUIRE( ctx.completedCycle() );
|
||||
|
||||
REQUIRE( s2b.isSuccessfullyCompleted() );
|
||||
REQUIRE( testCase2.isComplete() == false );
|
||||
|
||||
testCase2.close();
|
||||
REQUIRE( testCase2.isSuccessfullyCompleted() );
|
||||
}
|
||||
SECTION ("fail S2") {
|
||||
s2b.fail();
|
||||
REQUIRE( ctx.completedCycle() );
|
||||
|
||||
REQUIRE( s2b.isComplete() );
|
||||
REQUIRE( s2b.isSuccessfullyCompleted() == false );
|
||||
|
||||
testCase2.close();
|
||||
REQUIRE( testCase2.isSuccessfullyCompleted() == false );
|
||||
|
||||
// Need a final cycle
|
||||
ctx.startCycle();
|
||||
ITracker& testCase3 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase3.isOpen() );
|
||||
|
||||
ITracker& s1c = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1c.isOpen() == false );
|
||||
|
||||
ITracker& s2c = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2c.isOpen() == false );
|
||||
|
||||
testCase3.close();
|
||||
REQUIRE( testCase3.isSuccessfullyCompleted() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "open a nested section" ) {
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() );
|
||||
|
||||
s2.close();
|
||||
REQUIRE( s2.isComplete() );
|
||||
REQUIRE( s1.isComplete() == false );
|
||||
|
||||
s1.close();
|
||||
REQUIRE( s1.isComplete() );
|
||||
REQUIRE( testCase.isComplete() == false );
|
||||
|
||||
testCase.close();
|
||||
REQUIRE( testCase.isComplete() );
|
||||
}
|
||||
}
|
||||
|
||||
static bool previouslyRun = false;
|
||||
static bool previouslyRunNested = false;
|
||||
|
||||
TEST_CASE( "#1394", "[.][approvals][tracker]" ) {
|
||||
// -- Don't re-run after specified section is done
|
||||
REQUIRE(previouslyRun == false);
|
||||
|
||||
SECTION( "RunSection" ) {
|
||||
previouslyRun = true;
|
||||
}
|
||||
SECTION( "SkipSection" ) {
|
||||
// cause an error if this section is called because it shouldn't be
|
||||
REQUIRE(1 == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "#1394 nested", "[.][approvals][tracker]" ) {
|
||||
REQUIRE(previouslyRunNested == false);
|
||||
|
||||
SECTION( "NestedRunSection" ) {
|
||||
SECTION( "s1" ) {
|
||||
previouslyRunNested = true;
|
||||
}
|
||||
}
|
||||
SECTION( "NestedSkipSection" ) {
|
||||
// cause an error if this section is called because it shouldn't be
|
||||
REQUIRE(1 == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Selecting a "not last" section inside a test case via -c "section" would
|
||||
// previously only run the first subsection, instead of running all of them.
|
||||
// This allows us to check that `"#1670 regression check" -c A` leads to
|
||||
// 2 successful assertions.
|
||||
TEST_CASE("#1670 regression check", "[.approvals][tracker]") {
|
||||
SECTION("A") {
|
||||
SECTION("1") SUCCEED();
|
||||
SECTION("2") SUCCEED();
|
||||
}
|
||||
SECTION("B") {
|
||||
SECTION("1") SUCCEED();
|
||||
SECTION("2") SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
// #1938 required a rework on how generator tracking works, so that `GENERATE`
|
||||
// supports being sandwiched between two `SECTION`s. The following tests check
|
||||
// various other scenarios through checking output in approval tests.
|
||||
TEST_CASE("#1938 - GENERATE after a section", "[.][regression][generators]") {
|
||||
SECTION("A") {
|
||||
SUCCEED("A");
|
||||
}
|
||||
auto m = GENERATE(1, 2, 3);
|
||||
SECTION("B") {
|
||||
REQUIRE(m);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("#1938 - flat generate", "[.][regression][generators]") {
|
||||
auto m = GENERATE(1, 2, 3);
|
||||
REQUIRE(m);
|
||||
}
|
||||
|
||||
TEST_CASE("#1938 - nested generate", "[.][regression][generators]") {
|
||||
auto m = GENERATE(1, 2, 3);
|
||||
auto n = GENERATE(1, 2, 3);
|
||||
REQUIRE(m);
|
||||
REQUIRE(n);
|
||||
}
|
||||
|
||||
TEST_CASE("#1938 - mixed sections and generates", "[.][regression][generators]") {
|
||||
auto i = GENERATE(1, 2);
|
||||
SECTION("A") {
|
||||
SUCCEED("A");
|
||||
}
|
||||
auto j = GENERATE(3, 4);
|
||||
SECTION("B") {
|
||||
SUCCEED("B");
|
||||
}
|
||||
auto k = GENERATE(5, 6);
|
||||
CAPTURE(i, j, k);
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE("#1938 - Section followed by flat generate", "[.][regression][generators]") {
|
||||
SECTION("A") {
|
||||
REQUIRE(1);
|
||||
}
|
||||
auto m = GENERATE(2, 3);
|
||||
REQUIRE(m);
|
||||
}
|
@ -0,0 +1,609 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
#include <catch2/internal/catch_floating_point_helpers.hpp>
|
||||
#include <catch2/internal/catch_random_integer_helpers.hpp>
|
||||
#include <catch2/internal/catch_random_number_generator.hpp>
|
||||
#include <catch2/internal/catch_random_seed_generation.hpp>
|
||||
#include <catch2/internal/catch_uniform_floating_point_distribution.hpp>
|
||||
#include <catch2/internal/catch_uniform_integer_distribution.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/matchers/catch_matchers_range_equals.hpp>
|
||||
|
||||
#include <random>
|
||||
|
||||
TEST_CASE("Our PCG implementation provides expected results for known seeds", "[rng]") {
|
||||
Catch::SimplePcg32 rng;
|
||||
SECTION("Default seeded") {
|
||||
REQUIRE(rng() == 0xfcdb943b);
|
||||
REQUIRE(rng() == 0x6f55b921);
|
||||
REQUIRE(rng() == 0x4c17a916);
|
||||
REQUIRE(rng() == 0x71eae25f);
|
||||
REQUIRE(rng() == 0x6ce7909c);
|
||||
}
|
||||
SECTION("Specific seed") {
|
||||
rng.seed(0xabcd1234);
|
||||
REQUIRE(rng() == 0x57c08495);
|
||||
REQUIRE(rng() == 0x33c956ac);
|
||||
REQUIRE(rng() == 0x2206fd76);
|
||||
REQUIRE(rng() == 0x3501a35b);
|
||||
REQUIRE(rng() == 0xfdffb30f);
|
||||
|
||||
// Also check repeated output after reseeding
|
||||
rng.seed(0xabcd1234);
|
||||
REQUIRE(rng() == 0x57c08495);
|
||||
REQUIRE(rng() == 0x33c956ac);
|
||||
REQUIRE(rng() == 0x2206fd76);
|
||||
REQUIRE(rng() == 0x3501a35b);
|
||||
REQUIRE(rng() == 0xfdffb30f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Comparison ops", "[rng]") {
|
||||
using Catch::SimplePcg32;
|
||||
REQUIRE(SimplePcg32{} == SimplePcg32{});
|
||||
REQUIRE(SimplePcg32{ 0 } != SimplePcg32{});
|
||||
REQUIRE_FALSE(SimplePcg32{ 1 } == SimplePcg32{ 2 });
|
||||
REQUIRE_FALSE(SimplePcg32{ 1 } != SimplePcg32{ 1 });
|
||||
}
|
||||
|
||||
TEST_CASE("Random seed generation reports unknown methods", "[rng][seed]") {
|
||||
REQUIRE_THROWS(Catch::generateRandomSeed(static_cast<Catch::GenerateFrom>(77)));
|
||||
}
|
||||
|
||||
TEST_CASE("Random seed generation accepts known methods", "[rng][seed]") {
|
||||
using Catch::GenerateFrom;
|
||||
const auto method = GENERATE(
|
||||
GenerateFrom::Time,
|
||||
GenerateFrom::RandomDevice,
|
||||
GenerateFrom::Default
|
||||
);
|
||||
|
||||
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<TestType> dist(
|
||||
-std::numeric_limits<TestType>::max(),
|
||||
std::numeric_limits<TestType>::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<uint32_t>( fillBitsFrom<uint8_t>( pcg ) );
|
||||
REQUIRE( shortened == 0xcc );
|
||||
}
|
||||
SECTION( "Shorten to 16 bits" ) {
|
||||
auto shortened = fillBitsFrom<uint16_t>( pcg );
|
||||
REQUIRE( shortened == 0xccbe );
|
||||
}
|
||||
SECTION( "Keep at 32 bits" ) {
|
||||
auto n = fillBitsFrom<uint32_t>( pcg );
|
||||
REQUIRE( n == 0xccbe'5f04 );
|
||||
}
|
||||
SECTION( "Stretch to 64 bits" ) {
|
||||
auto stretched = fillBitsFrom<uint64_t>( pcg );
|
||||
REQUIRE( stretched == 0xccbe'5f04'a424'a486 );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("uniform_integer_distribution can return the bounds", "[rng][distribution]") {
|
||||
Catch::uniform_integer_distribution<int32_t> dist( -10, 10 );
|
||||
REQUIRE( dist.a() == -10 );
|
||||
REQUIRE( dist.b() == 10 );
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
static void CheckReturnValue(Catch::uniform_integer_distribution<T>& 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,
|
||||
size_t,
|
||||
ptrdiff_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<TestType>::min();
|
||||
Catch::uniform_integer_distribution<TestType> dist( lowest, lowest );
|
||||
CheckReturnValue( dist, pcg, lowest );
|
||||
}
|
||||
SECTION( "highest value" ) {
|
||||
constexpr auto highest = std::numeric_limits<TestType>::max();
|
||||
Catch::uniform_integer_distribution<TestType> dist( highest, highest );
|
||||
CheckReturnValue( dist, pcg, highest );
|
||||
}
|
||||
SECTION( "some value" ) {
|
||||
constexpr auto some = TestType( 42 );
|
||||
Catch::uniform_integer_distribution<TestType> 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<bool> dist( false, false );
|
||||
CheckReturnValue( dist, pcg, false );
|
||||
}
|
||||
SECTION( "highest value" ) {
|
||||
Catch::uniform_integer_distribution<bool> 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<TestType>::min();
|
||||
constexpr auto highest = std::numeric_limits<TestType>::max();
|
||||
Catch::uniform_integer_distribution<TestType> dist( lowest, highest );
|
||||
STATIC_REQUIRE( std::is_same<TestType, decltype( dist( pcg ) )>::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<TestType>;
|
||||
BitType ORs = 0;
|
||||
BitType ANDs = BitType(-1);
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
auto bits = static_cast<BitType>( 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 <typename T>
|
||||
struct uniform_integer_test_params;
|
||||
|
||||
template <>
|
||||
struct uniform_integer_test_params<bool> {
|
||||
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<char> {
|
||||
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<uint8_t> {
|
||||
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<int8_t> {
|
||||
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<uint16_t> {
|
||||
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<int16_t> {
|
||||
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<uint32_t> {
|
||||
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<int32_t> {
|
||||
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<uint64_t> {
|
||||
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<int64_t> {
|
||||
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<bool>::expected[];
|
||||
constexpr char uniform_integer_test_params<char>::expected[];
|
||||
constexpr uint8_t uniform_integer_test_params<uint8_t>::expected[];
|
||||
constexpr int8_t uniform_integer_test_params<int8_t>::expected[];
|
||||
constexpr uint16_t uniform_integer_test_params<uint16_t>::expected[];
|
||||
constexpr int16_t uniform_integer_test_params<int16_t>::expected[];
|
||||
constexpr uint32_t uniform_integer_test_params<uint32_t>::expected[];
|
||||
constexpr int32_t uniform_integer_test_params<int32_t>::expected[];
|
||||
constexpr uint64_t uniform_integer_test_params<uint64_t>::expected[];
|
||||
constexpr int64_t uniform_integer_test_params<int64_t>::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<TestType>::lowest;
|
||||
constexpr auto highest = uniform_integer_test_params<TestType>::highest;
|
||||
Catch::uniform_integer_distribution<TestType> dist(lowest, highest);
|
||||
|
||||
constexpr auto iters = 15;
|
||||
std::array<TestType, iters> generated;
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
generated[i] = dist( pcg );
|
||||
}
|
||||
|
||||
REQUIRE_THAT(generated, Catch::Matchers::RangeEquals(uniform_integer_test_params<TestType>::expected));
|
||||
}
|
||||
|
||||
// The reproducibility tests assume that operations on `float`/`double`
|
||||
// happen in the same precision as the operated-upon type. This is
|
||||
// generally true, unless the code is compiled for 32 bit targets without
|
||||
// SSE2 enabled, in which case the operations are done in the x87 FPU,
|
||||
// which usually implies doing math in 80 bit floats, and then rounding
|
||||
// into smaller type when the type is saved into memory. This obviously
|
||||
// leads to a different answer, than doing the math in the correct precision.
|
||||
#if ( defined( _MSC_VER ) && _M_IX86_FP < 2 ) || \
|
||||
( defined( __GNUC__ ) && \
|
||||
( ( defined( __i386__ ) || defined( __x86_64__ ) ) ) && \
|
||||
!defined( __SSE2_MATH__ ) )
|
||||
# define CATCH_TEST_CONFIG_DISABLE_FLOAT_REPRODUCIBILITY_TESTS
|
||||
#endif
|
||||
|
||||
#if !defined( CATCH_TEST_CONFIG_DISABLE_FLOAT_REPRODUCIBILITY_TESTS )
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
struct uniform_fp_test_params;
|
||||
|
||||
template<>
|
||||
struct uniform_fp_test_params<float> {
|
||||
// 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<double> {
|
||||
// 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<float>::expected[];
|
||||
constexpr double uniform_fp_test_params<double>::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<TestType>::lowest;
|
||||
const auto highest = uniform_fp_test_params<TestType>::highest;
|
||||
Catch::uniform_floating_point_distribution<TestType> dist( lowest, highest );
|
||||
|
||||
constexpr auto iters = 15;
|
||||
std::array<TestType, iters> generated;
|
||||
for ( int i = 0; i < iters; ++i ) {
|
||||
generated[i] = dist( pcg );
|
||||
}
|
||||
|
||||
REQUIRE_THAT( generated, Catch::Matchers::RangeEquals( uniform_fp_test_params<TestType>::expected ) );
|
||||
}
|
||||
|
||||
#endif // ^^ float reproducibility tests are enabled
|
||||
|
||||
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 = TestType(385.125);
|
||||
Catch::uniform_floating_point_distribution<TestType> dist( highest,
|
||||
highest );
|
||||
|
||||
constexpr auto iters = 20;
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
REQUIRE( Catch::Detail::directCompare( dist( pcg ), highest ) );
|
||||
}
|
||||
}
|
@ -0,0 +1,330 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||
#include <catch2/internal/catch_console_colour.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_list.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/reporters/catch_reporter_helpers.hpp>
|
||||
#include <catch2/reporters/catch_reporter_event_listener.hpp>
|
||||
#include <catch2/reporters/catch_reporter_streaming_base.hpp>
|
||||
#include <catch2/reporters/catch_reporter_multi.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace {
|
||||
class StringIStream : public Catch::IStream {
|
||||
public:
|
||||
std::ostream& stream() override { return sstr; }
|
||||
std::string str() const { return sstr.str(); }
|
||||
private:
|
||||
std::stringstream sstr;
|
||||
};
|
||||
|
||||
//! config must outlive the function
|
||||
Catch::ReporterConfig makeDummyRepConfig( Catch::Config const& config ) {
|
||||
return Catch::ReporterConfig{
|
||||
&config,
|
||||
Catch::Detail::make_unique<StringIStream>(),
|
||||
Catch::ColourMode::None,
|
||||
{} };
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "The default listing implementation write to provided stream",
|
||||
"[reporters][reporter-helpers]" ) {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
using namespace std::string_literals;
|
||||
|
||||
StringIStream sstream;
|
||||
SECTION( "Listing tags" ) {
|
||||
std::vector<Catch::TagInfo> tags(1);
|
||||
tags[0].add("fakeTag"_catch_sr);
|
||||
Catch::defaultListTags(sstream.stream(), tags, false);
|
||||
|
||||
auto listingString = sstream.str();
|
||||
REQUIRE_THAT(listingString, ContainsSubstring("[fakeTag]"s));
|
||||
}
|
||||
SECTION( "Listing reporters" ) {
|
||||
std::vector<Catch::ReporterDescription> reporters(
|
||||
{ { "fake reporter", "fake description" } } );
|
||||
Catch::defaultListReporters(sstream.stream(), reporters, Catch::Verbosity::Normal);
|
||||
|
||||
auto listingString = sstream.str();
|
||||
REQUIRE_THAT( listingString,
|
||||
ContainsSubstring( "fake reporter"s ) &&
|
||||
ContainsSubstring( "fake description"s ) );
|
||||
}
|
||||
SECTION( "Listing tests" ) {
|
||||
Catch::TestCaseInfo fakeInfo{
|
||||
""s,
|
||||
{ "fake test name"_catch_sr, "[fakeTestTag]"_catch_sr },
|
||||
{ "fake-file.cpp", 123456789 } };
|
||||
std::vector<Catch::TestCaseHandle> tests({ {&fakeInfo, nullptr} });
|
||||
auto colour = Catch::makeColourImpl( Catch::ColourMode::None, &sstream);
|
||||
Catch::defaultListTests(sstream.stream(), colour.get(), tests, false, Catch::Verbosity::Normal);
|
||||
|
||||
auto listingString = sstream.str();
|
||||
REQUIRE_THAT( listingString,
|
||||
ContainsSubstring( "fake test name"s ) &&
|
||||
ContainsSubstring( "fakeTestTag"s ) );
|
||||
}
|
||||
SECTION( "Listing listeners" ) {
|
||||
std::vector<Catch::ListenerDescription> listeners(
|
||||
{ { "fakeListener"_catch_sr, "fake description" } } );
|
||||
|
||||
Catch::defaultListListeners( sstream.stream(), listeners );
|
||||
auto listingString = sstream.str();
|
||||
REQUIRE_THAT( listingString,
|
||||
ContainsSubstring( "fakeListener"s ) &&
|
||||
ContainsSubstring( "fake description"s ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Reporter's write listings to provided stream", "[reporters]" ) {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
using namespace std::string_literals;
|
||||
|
||||
auto const& factories = Catch::getRegistryHub().getReporterRegistry().getFactories();
|
||||
// If there are no reporters, the test would pass falsely
|
||||
// while there is something obviously broken
|
||||
REQUIRE_FALSE(factories.empty());
|
||||
|
||||
for (auto const& factory : factories) {
|
||||
INFO("Tested reporter: " << factory.first);
|
||||
auto sstream = Catch::Detail::make_unique<StringIStream>();
|
||||
auto& sstreamRef = *sstream;
|
||||
|
||||
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, {} } );
|
||||
|
||||
DYNAMIC_SECTION( factory.first << " reporter lists tags" ) {
|
||||
std::vector<Catch::TagInfo> tags(1);
|
||||
tags[0].add("fakeTag"_catch_sr);
|
||||
reporter->listTags(tags);
|
||||
|
||||
auto listingString = sstreamRef.str();
|
||||
REQUIRE_THAT(listingString, ContainsSubstring("fakeTag"s));
|
||||
}
|
||||
|
||||
DYNAMIC_SECTION( factory.first << " reporter lists reporters" ) {
|
||||
std::vector<Catch::ReporterDescription> reporters(
|
||||
{ { "fake reporter", "fake description" } } );
|
||||
reporter->listReporters(reporters);
|
||||
|
||||
auto listingString = sstreamRef.str();
|
||||
REQUIRE_THAT(listingString, ContainsSubstring("fake reporter"s));
|
||||
}
|
||||
|
||||
DYNAMIC_SECTION( factory.first << " reporter lists tests" ) {
|
||||
Catch::TestCaseInfo fakeInfo{
|
||||
""s,
|
||||
{ "fake test name"_catch_sr, "[fakeTestTag]"_catch_sr },
|
||||
{ "fake-file.cpp", 123456789 } };
|
||||
std::vector<Catch::TestCaseHandle> tests({ {&fakeInfo, nullptr} });
|
||||
reporter->listTests(tests);
|
||||
|
||||
auto listingString = sstreamRef.str();
|
||||
REQUIRE_THAT( listingString,
|
||||
ContainsSubstring( "fake test name"s ) &&
|
||||
ContainsSubstring( "fakeTestTag"s ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Reproducer for #2309 - a very long description past 80 chars (default console width) with a late colon : blablabla", "[console-reporter]") {
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
namespace {
|
||||
// A listener that writes provided string into destination,
|
||||
// to record order of testRunStarting invocation.
|
||||
class MockListener : public Catch::EventListenerBase {
|
||||
std::string m_witness;
|
||||
std::vector<std::string>& m_recorder;
|
||||
public:
|
||||
MockListener( std::string witness,
|
||||
std::vector<std::string>& recorder,
|
||||
Catch::IConfig const* config ):
|
||||
EventListenerBase( config ),
|
||||
m_witness( CATCH_MOVE(witness) ),
|
||||
m_recorder( recorder )
|
||||
{}
|
||||
|
||||
void testRunStarting( Catch::TestRunInfo const& ) override {
|
||||
m_recorder.push_back( m_witness );
|
||||
}
|
||||
};
|
||||
// A reporter that writes provided string into destination,
|
||||
// to record order of testRunStarting invocation.
|
||||
class MockReporter : public Catch::StreamingReporterBase {
|
||||
std::string m_witness;
|
||||
std::vector<std::string>& m_recorder;
|
||||
public:
|
||||
MockReporter( std::string witness,
|
||||
std::vector<std::string>& recorder,
|
||||
Catch::ReporterConfig&& config ):
|
||||
StreamingReporterBase( CATCH_MOVE(config) ),
|
||||
m_witness( CATCH_MOVE(witness) ),
|
||||
m_recorder( recorder )
|
||||
{}
|
||||
|
||||
void testRunStarting( Catch::TestRunInfo const& ) override {
|
||||
m_recorder.push_back( m_witness );
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Multireporter calls reporters and listeners in correct order",
|
||||
"[reporters][multi-reporter]") {
|
||||
Catch::Config config( Catch::ConfigData{} );
|
||||
|
||||
// We add reporters before listeners, to check that internally they
|
||||
// get sorted properly, and listeners are called first anyway.
|
||||
Catch::MultiReporter multiReporter( &config );
|
||||
std::vector<std::string> records;
|
||||
multiReporter.addReporter( Catch::Detail::make_unique<MockReporter>(
|
||||
"Goodbye", records, makeDummyRepConfig(config) ) );
|
||||
multiReporter.addListener(
|
||||
Catch::Detail::make_unique<MockListener>( "Hello", records, &config ) );
|
||||
multiReporter.addListener(
|
||||
Catch::Detail::make_unique<MockListener>( "world", records, &config ) );
|
||||
multiReporter.addReporter( Catch::Detail::make_unique<MockReporter>(
|
||||
"world", records, makeDummyRepConfig(config) ) );
|
||||
multiReporter.testRunStarting( { "" } );
|
||||
|
||||
std::vector<std::string> expected( { "Hello", "world", "Goodbye", "world" } );
|
||||
REQUIRE( records == expected );
|
||||
}
|
||||
|
||||
namespace {
|
||||
// A listener that sets it preferences to test that multireporter,
|
||||
// properly sets up its own preferences
|
||||
class PreferenceListener : public Catch::EventListenerBase {
|
||||
public:
|
||||
PreferenceListener( bool redirectStdout,
|
||||
bool reportAllAssertions,
|
||||
Catch::IConfig const* config ):
|
||||
EventListenerBase( config ) {
|
||||
m_preferences.shouldRedirectStdOut = redirectStdout;
|
||||
m_preferences.shouldReportAllAssertions = reportAllAssertions;
|
||||
}
|
||||
};
|
||||
// A reporter that sets it preferences to test that multireporter,
|
||||
// properly sets up its own preferences
|
||||
class PreferenceReporter : public Catch::StreamingReporterBase {
|
||||
public:
|
||||
PreferenceReporter( bool redirectStdout,
|
||||
bool reportAllAssertions,
|
||||
Catch::ReporterConfig&& config ):
|
||||
StreamingReporterBase( CATCH_MOVE(config) ) {
|
||||
m_preferences.shouldRedirectStdOut = redirectStdout;
|
||||
m_preferences.shouldReportAllAssertions = reportAllAssertions;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Multireporter updates ReporterPreferences properly",
|
||||
"[reporters][multi-reporter]") {
|
||||
|
||||
Catch::Config config( Catch::ConfigData{} );
|
||||
Catch::MultiReporter multiReporter( &config );
|
||||
|
||||
// Post init defaults
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == false );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == false );
|
||||
|
||||
SECTION( "Adding listeners" ) {
|
||||
multiReporter.addListener(
|
||||
Catch::Detail::make_unique<PreferenceListener>(
|
||||
true, false, &config ) );
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == true );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == false );
|
||||
|
||||
multiReporter.addListener(
|
||||
Catch::Detail::make_unique<PreferenceListener>(
|
||||
false, true, &config ) );
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == true );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == true);
|
||||
|
||||
multiReporter.addListener(
|
||||
Catch::Detail::make_unique<PreferenceListener>(
|
||||
false, false, &config ) );
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == true );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == true );
|
||||
}
|
||||
SECTION( "Adding reporters" ) {
|
||||
multiReporter.addReporter(
|
||||
Catch::Detail::make_unique<PreferenceReporter>(
|
||||
true, false, makeDummyRepConfig(config) ) );
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == true );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == false );
|
||||
|
||||
multiReporter.addReporter(
|
||||
Catch::Detail::make_unique<PreferenceReporter>(
|
||||
false, true, makeDummyRepConfig( config ) ) );
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == true );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == true );
|
||||
|
||||
multiReporter.addReporter(
|
||||
Catch::Detail::make_unique<PreferenceReporter>(
|
||||
false, false, makeDummyRepConfig( config ) ) );
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == true );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == true );
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
class TestReporterFactory : public Catch::IReporterFactory {
|
||||
Catch::IEventListenerPtr create( Catch::ReporterConfig&& ) const override {
|
||||
CATCH_INTERNAL_ERROR(
|
||||
"This factory should never create a reporter" );
|
||||
}
|
||||
std::string getDescription() const override {
|
||||
return "Fake test factory";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("Registering reporter with '::' in name fails",
|
||||
"[reporters][registration]") {
|
||||
Catch::ReporterRegistry registry;
|
||||
|
||||
REQUIRE_THROWS_WITH( registry.registerReporter(
|
||||
"with::doublecolons",
|
||||
Catch::Detail::make_unique<TestReporterFactory>() ),
|
||||
"'::' is not allowed in reporter name: 'with::doublecolons'" );
|
||||
}
|
||||
|
||||
TEST_CASE("Registering multiple reporters with the same name fails",
|
||||
"[reporters][registration][approvals]") {
|
||||
Catch::ReporterRegistry registry;
|
||||
|
||||
registry.registerReporter(
|
||||
"some-reporter-name",
|
||||
Catch::Detail::make_unique<TestReporterFactory>() );
|
||||
|
||||
REQUIRE_THROWS_WITH(
|
||||
registry.registerReporter(
|
||||
"some-reporter-name",
|
||||
Catch::Detail::make_unique<TestReporterFactory>() ),
|
||||
"reporter using 'some-reporter-name' as name was already registered" );
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators_all.hpp>
|
||||
|
||||
#include <catch2/internal/catch_sharding.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
TEST_CASE("Sharding Function", "[approvals]") {
|
||||
std::vector<int> testContainer = { 0, 1, 2, 3, 4, 5, 6 };
|
||||
std::unordered_map<int, std::vector<std::size_t>> expectedShardSizes = {
|
||||
{1, {7}},
|
||||
{2, {4, 3}},
|
||||
{3, {3, 2, 2}},
|
||||
{4, {2, 2, 2, 1}},
|
||||
{5, {2, 2, 1, 1, 1}},
|
||||
{6, {2, 1, 1, 1, 1, 1}},
|
||||
{7, {1, 1, 1, 1, 1, 1, 1}},
|
||||
};
|
||||
|
||||
auto shardCount = GENERATE(range(1, 7));
|
||||
auto shardIndex = GENERATE_COPY(filter([=](int i) { return i < shardCount; }, range(0, 6)));
|
||||
|
||||
std::vector<int> result = Catch::createShard(testContainer, shardCount, shardIndex);
|
||||
|
||||
auto& sizes = expectedShardSizes[shardCount];
|
||||
REQUIRE(result.size() == sizes[shardIndex]);
|
||||
|
||||
std::size_t startIndex = 0;
|
||||
for(int i = 0; i < shardIndex; i++) {
|
||||
startIndex += sizes[i];
|
||||
}
|
||||
|
||||
for(std::size_t i = 0; i < sizes[shardIndex]; i++) {
|
||||
CHECK(result[i] == testContainer[i + startIndex]);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
|
||||
TEST_CASE( "Cout stream properly declares it writes to stdout", "[streams]" ) {
|
||||
REQUIRE( Catch::makeStream( "-" )->isConsole() );
|
||||
}
|
||||
|
||||
TEST_CASE( "Empty stream name opens cout stream", "[streams]" ) {
|
||||
REQUIRE( Catch::makeStream( "" )->isConsole() );
|
||||
}
|
||||
|
||||
TEST_CASE( "stdout and stderr streams have %-starting name", "[streams]" ) {
|
||||
REQUIRE( Catch::makeStream( "%stderr" )->isConsole() );
|
||||
REQUIRE( Catch::makeStream( "%stdout" )->isConsole() );
|
||||
}
|
||||
|
||||
TEST_CASE( "request an unknown %-starting stream fails", "[streams]" ) {
|
||||
REQUIRE_THROWS( Catch::makeStream( "%somestream" ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "makeStream recognizes %debug stream name", "[streams]" ) {
|
||||
REQUIRE_NOTHROW( Catch::makeStream( "%debug" ) );
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
|
||||
using Catch::StringRef;
|
||||
|
||||
SECTION( "Empty string" ) {
|
||||
StringRef empty;
|
||||
REQUIRE( empty.empty() );
|
||||
REQUIRE( empty.size() == 0 );
|
||||
REQUIRE( std::strcmp( empty.data(), "" ) == 0 );
|
||||
}
|
||||
|
||||
SECTION( "From string literal" ) {
|
||||
StringRef s = "hello";
|
||||
REQUIRE( s.empty() == false );
|
||||
REQUIRE( s.size() == 5 );
|
||||
|
||||
auto rawChars = s.data();
|
||||
REQUIRE( std::strcmp( rawChars, "hello" ) == 0 );
|
||||
|
||||
REQUIRE(s.data() == rawChars);
|
||||
}
|
||||
SECTION( "From sub-string" ) {
|
||||
StringRef original = StringRef( "original string" ).substr(0, 8);
|
||||
REQUIRE( original == "original" );
|
||||
|
||||
REQUIRE_NOTHROW(original.data());
|
||||
}
|
||||
SECTION( "Copy construction is shallow" ) {
|
||||
StringRef original = StringRef( "original string" );
|
||||
StringRef copy = original;
|
||||
REQUIRE(original.begin() == copy.begin());
|
||||
}
|
||||
SECTION( "Copy assignment is shallow" ) {
|
||||
StringRef original = StringRef( "original string" );
|
||||
StringRef copy;
|
||||
copy = original;
|
||||
REQUIRE(original.begin() == copy.begin());
|
||||
}
|
||||
|
||||
SECTION( "Substrings" ) {
|
||||
StringRef s = "hello world!";
|
||||
StringRef ss = s.substr(0, 5);
|
||||
|
||||
SECTION( "zero-based substring" ) {
|
||||
REQUIRE( ss.empty() == false );
|
||||
REQUIRE( ss.size() == 5 );
|
||||
REQUIRE( std::strncmp( ss.data(), "hello", 5 ) == 0 );
|
||||
REQUIRE( ss == "hello" );
|
||||
}
|
||||
|
||||
SECTION( "non-zero-based substring") {
|
||||
ss = s.substr( 6, 6 );
|
||||
REQUIRE( ss.size() == 6 );
|
||||
REQUIRE( std::strcmp( ss.data(), "world!" ) == 0 );
|
||||
}
|
||||
|
||||
SECTION( "Pointer values of full refs should match" ) {
|
||||
StringRef s2 = s;
|
||||
REQUIRE( s.data() == s2.data() );
|
||||
}
|
||||
|
||||
SECTION( "Pointer values of substring refs should also match" ) {
|
||||
REQUIRE( s.data() == ss.data() );
|
||||
}
|
||||
|
||||
SECTION("Past the end substring") {
|
||||
REQUIRE(s.substr(s.size() + 1, 123).empty());
|
||||
}
|
||||
|
||||
SECTION("Substring off the end are trimmed") {
|
||||
ss = s.substr(6, 123);
|
||||
REQUIRE(std::strcmp(ss.data(), "world!") == 0);
|
||||
}
|
||||
SECTION("substring start after the end is empty") {
|
||||
REQUIRE(s.substr(1'000'000, 1).empty());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Comparisons are deep" ) {
|
||||
char buffer1[] = "Hello";
|
||||
char buffer2[] = "Hello";
|
||||
CHECK(reinterpret_cast<char*>(buffer1) != reinterpret_cast<char*>(buffer2));
|
||||
|
||||
StringRef left(buffer1), right(buffer2);
|
||||
REQUIRE( left == right );
|
||||
REQUIRE(left != left.substr(0, 3));
|
||||
}
|
||||
|
||||
SECTION( "from std::string" ) {
|
||||
std::string stdStr = "a standard string";
|
||||
|
||||
SECTION( "implicitly constructed" ) {
|
||||
StringRef sr = stdStr;
|
||||
REQUIRE( sr == "a standard string" );
|
||||
REQUIRE( sr.size() == stdStr.size() );
|
||||
}
|
||||
SECTION( "explicitly constructed" ) {
|
||||
StringRef sr( stdStr );
|
||||
REQUIRE( sr == "a standard string" );
|
||||
REQUIRE( sr.size() == stdStr.size() );
|
||||
}
|
||||
SECTION( "assigned" ) {
|
||||
StringRef sr;
|
||||
sr = stdStr;
|
||||
REQUIRE( sr == "a standard string" );
|
||||
REQUIRE( sr.size() == stdStr.size() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "to std::string" ) {
|
||||
StringRef sr = "a stringref";
|
||||
|
||||
SECTION( "explicitly constructed" ) {
|
||||
std::string stdStr( sr );
|
||||
REQUIRE( stdStr == "a stringref" );
|
||||
REQUIRE( stdStr.size() == sr.size() );
|
||||
}
|
||||
SECTION( "assigned" ) {
|
||||
std::string stdStr;
|
||||
stdStr = static_cast<std::string>(sr);
|
||||
REQUIRE( stdStr == "a stringref" );
|
||||
REQUIRE( stdStr.size() == sr.size() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::string += StringRef") {
|
||||
StringRef sr = "the stringref contents";
|
||||
std::string lhs("some string += ");
|
||||
lhs += sr;
|
||||
REQUIRE(lhs == "some string += the stringref contents");
|
||||
}
|
||||
SECTION("StringRef + StringRef") {
|
||||
StringRef sr1 = "abraka", sr2 = "dabra";
|
||||
std::string together = sr1 + sr2;
|
||||
REQUIRE(together == "abrakadabra");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("StringRef at compilation time", "[Strings][StringRef][constexpr]") {
|
||||
using Catch::StringRef;
|
||||
SECTION("Simple constructors") {
|
||||
constexpr StringRef empty{};
|
||||
STATIC_REQUIRE(empty.size() == 0);
|
||||
STATIC_REQUIRE(empty.begin() == empty.end());
|
||||
|
||||
constexpr char const* const abc = "abc";
|
||||
|
||||
constexpr StringRef stringref(abc, 3);
|
||||
STATIC_REQUIRE(stringref.size() == 3);
|
||||
STATIC_REQUIRE(stringref.data() == abc);
|
||||
STATIC_REQUIRE(stringref.begin() == abc);
|
||||
STATIC_REQUIRE(stringref.begin() != stringref.end());
|
||||
STATIC_REQUIRE(stringref.substr(10, 0).empty());
|
||||
STATIC_REQUIRE(stringref.substr(2, 1).data() == abc + 2);
|
||||
STATIC_REQUIRE(stringref[1] == 'b');
|
||||
|
||||
|
||||
constexpr StringRef shortened(abc, 2);
|
||||
STATIC_REQUIRE(shortened.size() == 2);
|
||||
STATIC_REQUIRE(shortened.data() == abc);
|
||||
STATIC_REQUIRE(shortened.begin() != shortened.end());
|
||||
}
|
||||
SECTION("UDL construction") {
|
||||
constexpr auto sr1 = "abc"_catch_sr;
|
||||
STATIC_REQUIRE_FALSE(sr1.empty());
|
||||
STATIC_REQUIRE(sr1.size() == 3);
|
||||
|
||||
using Catch::operator""_sr;
|
||||
constexpr auto sr2 = ""_sr;
|
||||
STATIC_REQUIRE(sr2.empty());
|
||||
STATIC_REQUIRE(sr2.size() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("StringRef::compare", "[Strings][StringRef][approvals]") {
|
||||
using Catch::StringRef;
|
||||
|
||||
SECTION("Same length on both sides") {
|
||||
StringRef sr1("abcdc");
|
||||
StringRef sr2("abcdd");
|
||||
StringRef sr3("abcdc");
|
||||
|
||||
REQUIRE(sr1.compare(sr2) < 0);
|
||||
REQUIRE(sr2.compare(sr1) > 0);
|
||||
REQUIRE(sr1.compare(sr3) == 0);
|
||||
REQUIRE(sr3.compare(sr1) == 0);
|
||||
}
|
||||
SECTION("Different lengths") {
|
||||
StringRef sr1("def");
|
||||
StringRef sr2("deff");
|
||||
StringRef sr3("ab");
|
||||
|
||||
REQUIRE(sr1.compare(sr2) < 0);
|
||||
REQUIRE(sr2.compare(sr1) > 0);
|
||||
REQUIRE(sr1.compare(sr3) > 0);
|
||||
REQUIRE(sr2.compare(sr3) > 0);
|
||||
REQUIRE(sr3.compare(sr1) < 0);
|
||||
REQUIRE(sr3.compare(sr2) < 0);
|
||||
}
|
||||
}
|
@ -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 <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
|
||||
static const char * const no_whitespace = "There is no extra whitespace here";
|
||||
static const char * const leading_whitespace = " \r \t\n There is no extra whitespace here";
|
||||
static const char * const trailing_whitespace = "There is no extra whitespace here \t \n \r ";
|
||||
static const char * const whitespace_at_both_ends = " \r\n \t There is no extra whitespace here \t\t\t \n";
|
||||
|
||||
TEST_CASE("Trim strings", "[string-manip]") {
|
||||
using Catch::trim; using Catch::StringRef;
|
||||
static_assert(std::is_same<std::string, decltype(trim(std::string{}))>::value, "Trimming std::string should return std::string");
|
||||
static_assert(std::is_same<StringRef, decltype(trim(StringRef{}))>::value, "Trimming StringRef should return StringRef");
|
||||
|
||||
REQUIRE(trim(std::string(no_whitespace)) == no_whitespace);
|
||||
REQUIRE(trim(std::string(leading_whitespace)) == no_whitespace);
|
||||
REQUIRE(trim(std::string(trailing_whitespace)) == no_whitespace);
|
||||
REQUIRE(trim(std::string(whitespace_at_both_ends)) == no_whitespace);
|
||||
|
||||
REQUIRE(trim(StringRef(no_whitespace)) == StringRef(no_whitespace));
|
||||
REQUIRE(trim(StringRef(leading_whitespace)) == StringRef(no_whitespace));
|
||||
REQUIRE(trim(StringRef(trailing_whitespace)) == StringRef(no_whitespace));
|
||||
REQUIRE(trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace));
|
||||
}
|
||||
|
||||
TEST_CASE("replaceInPlace", "[string-manip]") {
|
||||
std::string letters = "abcdefcg";
|
||||
SECTION("replace single char") {
|
||||
CHECK(Catch::replaceInPlace(letters, "b", "z"));
|
||||
CHECK(letters == "azcdefcg");
|
||||
}
|
||||
SECTION("replace two chars") {
|
||||
CHECK(Catch::replaceInPlace(letters, "c", "z"));
|
||||
CHECK(letters == "abzdefzg");
|
||||
}
|
||||
SECTION("replace first char") {
|
||||
CHECK(Catch::replaceInPlace(letters, "a", "z"));
|
||||
CHECK(letters == "zbcdefcg");
|
||||
}
|
||||
SECTION("replace last char") {
|
||||
CHECK(Catch::replaceInPlace(letters, "g", "z"));
|
||||
CHECK(letters == "abcdefcz");
|
||||
}
|
||||
SECTION("replace all chars") {
|
||||
CHECK(Catch::replaceInPlace(letters, letters, "replaced"));
|
||||
CHECK(letters == "replaced");
|
||||
}
|
||||
SECTION("replace no chars") {
|
||||
CHECK_FALSE(Catch::replaceInPlace(letters, "x", "z"));
|
||||
CHECK(letters == letters);
|
||||
}
|
||||
SECTION("no replace in already-replaced string") {
|
||||
SECTION("lengthening") {
|
||||
CHECK(Catch::replaceInPlace(letters, "c", "cc"));
|
||||
CHECK(letters == "abccdefccg");
|
||||
}
|
||||
SECTION("shortening") {
|
||||
std::string s = "----";
|
||||
CHECK(Catch::replaceInPlace(s, "--", "-"));
|
||||
CHECK(s == "--");
|
||||
}
|
||||
}
|
||||
SECTION("escape '") {
|
||||
std::string s = "didn't";
|
||||
CHECK(Catch::replaceInPlace(s, "'", "|'"));
|
||||
CHECK(s == "didn|'t");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("splitString", "[string-manip]") {
|
||||
using namespace Catch::Matchers;
|
||||
using Catch::splitStringRef;
|
||||
using Catch::StringRef;
|
||||
|
||||
CHECK_THAT(splitStringRef("", ','), Equals(std::vector<StringRef>()));
|
||||
CHECK_THAT(splitStringRef("abc", ','), Equals(std::vector<StringRef>{"abc"}));
|
||||
CHECK_THAT(splitStringRef("abc,def", ','), Equals(std::vector<StringRef>{"abc", "def"}));
|
||||
}
|
||||
|
||||
TEST_CASE("startsWith", "[string-manip]") {
|
||||
using Catch::startsWith;
|
||||
|
||||
CHECK_FALSE(startsWith("", 'c'));
|
||||
CHECK(startsWith(std::string("abc"), 'a'));
|
||||
CHECK(startsWith("def"_catch_sr, 'd'));
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/internal/catch_tag_alias_registry.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
|
||||
TEST_CASE( "Tag alias can be registered against tag patterns" ) {
|
||||
|
||||
Catch::TagAliasRegistry registry;
|
||||
|
||||
registry.add( "[@zzz]", "[one][two]", Catch::SourceLineInfo( "file", 2 ) );
|
||||
|
||||
SECTION( "The same tag alias can only be registered once" ) {
|
||||
|
||||
try {
|
||||
registry.add( "[@zzz]", "[one][two]", Catch::SourceLineInfo( "file", 10 ) );
|
||||
FAIL( "expected exception" );
|
||||
}
|
||||
catch( std::exception& ex ) {
|
||||
std::string what = ex.what();
|
||||
using namespace Catch::Matchers;
|
||||
CHECK_THAT( what, ContainsSubstring( "[@zzz]" ) );
|
||||
CHECK_THAT( what, ContainsSubstring( "file" ) );
|
||||
CHECK_THAT( what, ContainsSubstring( "2" ) );
|
||||
CHECK_THAT( what, ContainsSubstring( "10" ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Tag aliases must be of the form [@name]" ) {
|
||||
CHECK_THROWS( registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) ) );
|
||||
CHECK_THROWS( registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) ) );
|
||||
CHECK_THROWS( registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) ) );
|
||||
CHECK_THROWS( registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Dummy line info for creating dummy test cases below
|
||||
static constexpr Catch::SourceLineInfo dummySourceLineInfo = CATCH_INTERNAL_LINEINFO;
|
||||
|
||||
TEST_CASE("shortened hide tags are split apart", "[tags]") {
|
||||
using Catch::StringRef;
|
||||
using Catch::Tag;
|
||||
using Catch::Matchers::VectorContains;
|
||||
|
||||
Catch::TestCaseInfo testcase("", {"fake test name", "[.magic-tag]"}, dummySourceLineInfo);
|
||||
REQUIRE_THAT( testcase.tags, VectorContains( Tag( "magic-tag" ) )
|
||||
&& VectorContains( Tag( "."_catch_sr ) ) );
|
||||
}
|
||||
|
||||
TEST_CASE("tags with dots in later positions are not parsed as hidden", "[tags]") {
|
||||
using Catch::StringRef;
|
||||
using Catch::Matchers::VectorContains;
|
||||
Catch::TestCaseInfo testcase("", { "fake test name", "[magic.tag]" }, dummySourceLineInfo);
|
||||
|
||||
REQUIRE(testcase.tags.size() == 1);
|
||||
REQUIRE(testcase.tags[0].original == "magic.tag"_catch_sr);
|
||||
}
|
||||
|
||||
TEST_CASE( "empty tags are not allowed", "[tags]" ) {
|
||||
REQUIRE_THROWS(
|
||||
Catch::TestCaseInfo("", { "test with an empty tag", "[]" }, dummySourceLineInfo)
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE( "Tags with spaces and non-alphanumerical characters are accepted",
|
||||
"[tags]" ) {
|
||||
using Catch::Tag;
|
||||
using Catch::Matchers::VectorContains;
|
||||
|
||||
Catch::TestCaseInfo testCase(
|
||||
"",
|
||||
{ "fake test name", "[tag with spaces][I said \"good day\" sir!]" },
|
||||
dummySourceLineInfo );
|
||||
|
||||
REQUIRE( testCase.tags.size() == 2 );
|
||||
REQUIRE_THAT( testCase.tags,
|
||||
VectorContains( Tag( "tag with spaces" ) ) &&
|
||||
VectorContains( Tag( "I said \"good day\" sir!"_catch_sr ) ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "Test case with identical tags keeps just one", "[tags]" ) {
|
||||
using Catch::Tag;
|
||||
|
||||
Catch::TestCaseInfo testCase(
|
||||
"",
|
||||
{ "fake test name", "[TaG1][tAg1][TAG1][tag1]" },
|
||||
dummySourceLineInfo );
|
||||
|
||||
REQUIRE( testCase.tags.size() == 1 );
|
||||
REQUIRE( testCase.tags[0] == Tag( "tag1" ) );
|
||||
}
|
||||
|
||||
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'") );
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/internal/catch_test_case_info_hasher.hpp>
|
||||
|
||||
static constexpr Catch::SourceLineInfo dummySourceLineInfo = CATCH_INTERNAL_LINEINFO;
|
||||
|
||||
using Catch::TestCaseInfo;
|
||||
using Catch::TestCaseInfoHasher;
|
||||
|
||||
TEST_CASE("Hashers with same seed produce same hash", "[test-case-hash]") {
|
||||
TestCaseInfo dummy( "", { "name", "[a-tag]" }, dummySourceLineInfo );
|
||||
|
||||
TestCaseInfoHasher h1( 0x12345678 );
|
||||
TestCaseInfoHasher h2( 0x12345678 );
|
||||
|
||||
REQUIRE( h1( dummy ) == h2( dummy ) );
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Hashers with different seed produce different hash with same test case",
|
||||
"[test-case-hash]") {
|
||||
TestCaseInfo dummy( "", { "name", "[a-tag]" }, dummySourceLineInfo );
|
||||
|
||||
TestCaseInfoHasher h1( 0x12345678 );
|
||||
TestCaseInfoHasher h2( 0x87654321 );
|
||||
|
||||
REQUIRE( h1( dummy ) != h2( dummy ) );
|
||||
}
|
||||
|
||||
TEST_CASE("Hashing test case produces same hash across multiple calls",
|
||||
"[test-case-hash]") {
|
||||
TestCaseInfo dummy( "", { "name", "[a-tag]" }, dummySourceLineInfo );
|
||||
|
||||
TestCaseInfoHasher h( 0x12345678 );
|
||||
|
||||
REQUIRE( h( dummy ) == h( dummy ) );
|
||||
}
|
||||
|
||||
TEST_CASE("Hashing different test cases produces different result", "[test-case-hash]") {
|
||||
TestCaseInfoHasher h( 0x12345678 );
|
||||
SECTION("Different test name") {
|
||||
TestCaseInfo dummy1( "class", { "name-1", "[a-tag]" }, dummySourceLineInfo );
|
||||
TestCaseInfo dummy2(
|
||||
"class", { "name-2", "[a-tag]" }, dummySourceLineInfo );
|
||||
|
||||
REQUIRE( h( dummy1 ) != h( dummy2 ) );
|
||||
}
|
||||
SECTION("Different classname") {
|
||||
TestCaseInfo dummy1(
|
||||
"class-1", { "name", "[a-tag]" }, dummySourceLineInfo );
|
||||
TestCaseInfo dummy2(
|
||||
"class-2", { "name", "[a-tag]" }, dummySourceLineInfo );
|
||||
|
||||
REQUIRE( h( dummy1 ) != h( dummy2 ) );
|
||||
}
|
||||
SECTION("Different tags") {
|
||||
TestCaseInfo dummy1(
|
||||
"class", { "name", "[a-tag]" }, dummySourceLineInfo );
|
||||
TestCaseInfo dummy2(
|
||||
"class", { "name", "[b-tag]" }, dummySourceLineInfo );
|
||||
|
||||
REQUIRE( h( dummy1 ) != h( dummy2 ) );
|
||||
}
|
||||
}
|
@ -0,0 +1,365 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/internal/catch_commandline.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
|
||||
#include <helpers/parse_test_spec.hpp>
|
||||
|
||||
namespace {
|
||||
auto fakeTestCase(const char* name, const char* desc = "") { return Catch::makeTestCaseInfo("", { name, desc }, CATCH_INTERNAL_LINEINFO); }
|
||||
}
|
||||
|
||||
TEST_CASE( "Parse test names and tags", "[command-line][test-spec][approvals]" ) {
|
||||
using Catch::parseTestSpec;
|
||||
using Catch::TestSpec;
|
||||
|
||||
auto tcA = fakeTestCase( "a" );
|
||||
auto tcB = fakeTestCase( "b", "[one][x]" );
|
||||
auto tcC = fakeTestCase( "longer name with spaces", "[two][three][.][x]" );
|
||||
auto tcD = fakeTestCase( "zlonger name with spacesz" );
|
||||
|
||||
SECTION( "Empty test spec should have no filters" ) {
|
||||
TestSpec spec;
|
||||
CHECK( spec.hasFilters() == false );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
}
|
||||
|
||||
SECTION( "Test spec from empty string should have no filters" ) {
|
||||
TestSpec spec = parseTestSpec( "" );
|
||||
CHECK( spec.hasFilters() == false );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
}
|
||||
|
||||
SECTION( "Test spec from just a comma should have no filters" ) {
|
||||
TestSpec spec = parseTestSpec( "," );
|
||||
CHECK( spec.hasFilters() == false );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
}
|
||||
|
||||
SECTION( "Test spec from name should have one filter" ) {
|
||||
TestSpec spec = parseTestSpec( "b" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
}
|
||||
|
||||
SECTION( "Test spec from quoted name should have one filter" ) {
|
||||
TestSpec spec = parseTestSpec( "\"b\"" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
}
|
||||
|
||||
SECTION( "Test spec from name should have one filter" ) {
|
||||
TestSpec spec = parseTestSpec( "b" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
}
|
||||
|
||||
SECTION( "Wildcard at the start" ) {
|
||||
TestSpec spec = parseTestSpec( "*spaces" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
CHECK( parseTestSpec( "*a" ).matches( *tcA ) == true );
|
||||
}
|
||||
SECTION( "Wildcard at the end" ) {
|
||||
TestSpec spec = parseTestSpec( "long*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
CHECK( parseTestSpec( "a*" ).matches( *tcA ) == true );
|
||||
}
|
||||
SECTION( "Wildcard at both ends" ) {
|
||||
TestSpec spec = parseTestSpec( "*name*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
CHECK( parseTestSpec( "*a*" ).matches( *tcA ) == true );
|
||||
}
|
||||
SECTION( "Redundant wildcard at the start" ) {
|
||||
TestSpec spec = parseTestSpec( "*a" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
}
|
||||
SECTION( "Redundant wildcard at the end" ) {
|
||||
TestSpec spec = parseTestSpec( "a*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
}
|
||||
SECTION( "Redundant wildcard at both ends" ) {
|
||||
TestSpec spec = parseTestSpec( "*a*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
}
|
||||
SECTION( "Wildcard at both ends, redundant at start" ) {
|
||||
TestSpec spec = parseTestSpec( "*longer*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
}
|
||||
SECTION( "Just wildcard" ) {
|
||||
TestSpec spec = parseTestSpec( "*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
}
|
||||
|
||||
SECTION( "Single tag" ) {
|
||||
TestSpec spec = parseTestSpec( "[one]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
}
|
||||
SECTION( "Single tag, two matches" ) {
|
||||
TestSpec spec = parseTestSpec( "[x]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
}
|
||||
SECTION( "Two tags" ) {
|
||||
TestSpec spec = parseTestSpec( "[two][x]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
}
|
||||
SECTION( "Two tags, spare separated" ) {
|
||||
TestSpec spec = parseTestSpec( "[two] [x]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
}
|
||||
SECTION( "Wildcarded name and tag" ) {
|
||||
TestSpec spec = parseTestSpec( "*name*[x]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "Single tag exclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "~[one]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
}
|
||||
SECTION( "One tag exclusion and one tag inclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "~[two][x]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
}
|
||||
SECTION( "One tag exclusion and one wldcarded name inclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "~[two]*name*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
}
|
||||
SECTION( "One tag exclusion, using exclude:, and one wldcarded name inclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "exclude:[two]*name*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
}
|
||||
SECTION( "name exclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "~b" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
}
|
||||
SECTION( "wildcarded name exclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "~*name*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "wildcarded name exclusion with tag inclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "~*name*,[three]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "wildcarded name exclusion, using exclude:, with tag inclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "exclude:*name*,[three]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "two wildcarded names" ) {
|
||||
TestSpec spec = parseTestSpec( R"("longer*""*spaces")" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "empty tag" ) {
|
||||
TestSpec spec = parseTestSpec( "[]" );
|
||||
CHECK( spec.hasFilters() == false );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "empty quoted name" ) {
|
||||
TestSpec spec = parseTestSpec( "\"\"" );
|
||||
CHECK( spec.hasFilters() == false );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "quoted string followed by tag exclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "\"*name*\"~[.]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
}
|
||||
SECTION( "Leading and trailing spaces in test spec" ) {
|
||||
TestSpec spec = parseTestSpec( "\" aardvark \"" );
|
||||
CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( " aardvark" ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( "aardvark " ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( "aardvark" ) ) );
|
||||
|
||||
}
|
||||
SECTION( "Leading and trailing spaces in test name" ) {
|
||||
TestSpec spec = parseTestSpec( "aardvark" );
|
||||
CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( " aardvark" ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( "aardvark " ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( "aardvark" ) ) );
|
||||
}
|
||||
SECTION("Shortened hide tags are split apart when parsing") {
|
||||
TestSpec spec = parseTestSpec("[.foo]");
|
||||
CHECK(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")));
|
||||
CHECK_FALSE(spec.matches(*fakeTestCase("only foo", "[foo]")));
|
||||
}
|
||||
SECTION("Shortened hide tags also properly handle exclusion") {
|
||||
TestSpec spec = parseTestSpec("~[.foo]");
|
||||
CHECK_FALSE(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")));
|
||||
CHECK_FALSE(spec.matches(*fakeTestCase("only foo", "[foo]")));
|
||||
CHECK_FALSE(spec.matches(*fakeTestCase("only hidden", "[.]")));
|
||||
CHECK(spec.matches(*fakeTestCase("neither foo nor hidden", "[bar]")));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("#1905 -- test spec parser properly clears internal state between compound tests", "[command-line][test-spec]") {
|
||||
using Catch::parseTestSpec;
|
||||
using Catch::TestSpec;
|
||||
// We ask for one of 2 different tests and the latter one of them has a , in name that needs escaping
|
||||
TestSpec spec = parseTestSpec(R"("spec . char","spec \, char")");
|
||||
|
||||
REQUIRE(spec.matches(*fakeTestCase("spec . char")));
|
||||
REQUIRE(spec.matches(*fakeTestCase("spec , char")));
|
||||
REQUIRE_FALSE(spec.matches(*fakeTestCase(R"(spec \, char)")));
|
||||
}
|
||||
|
||||
TEST_CASE("#1912 -- test spec parser handles escaping", "[command-line][test-spec]") {
|
||||
using Catch::parseTestSpec;
|
||||
using Catch::TestSpec;
|
||||
|
||||
SECTION("Various parentheses") {
|
||||
TestSpec spec = parseTestSpec(R"(spec {a} char,spec \[a] char)");
|
||||
|
||||
REQUIRE(spec.matches(*fakeTestCase(R"(spec {a} char)")));
|
||||
REQUIRE(spec.matches(*fakeTestCase(R"(spec [a] char)")));
|
||||
REQUIRE_FALSE(spec.matches(*fakeTestCase("differs but has similar tag", "[a]")));
|
||||
}
|
||||
SECTION("backslash in test name") {
|
||||
TestSpec spec = parseTestSpec(R"(spec \\ char)");
|
||||
|
||||
REQUIRE(spec.matches(*fakeTestCase(R"(spec \ char)")));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test spec serialization is round-trippable", "[test-spec][serialization][approvals]") {
|
||||
using Catch::parseTestSpec;
|
||||
using Catch::TestSpec;
|
||||
|
||||
auto serializedTestSpec = []( std::string const& spec ) {
|
||||
Catch::ReusableStringStream sstr;
|
||||
sstr << parseTestSpec( spec );
|
||||
return sstr.str();
|
||||
};
|
||||
|
||||
SECTION("Spaces are normalized") {
|
||||
CHECK( serializedTestSpec( "[abc][def]" ) == "[abc] [def]" );
|
||||
CHECK( serializedTestSpec( "[def] [abc]" ) == "[def] [abc]" );
|
||||
CHECK( serializedTestSpec( "[def] [abc]" ) == "[def] [abc]" );
|
||||
}
|
||||
SECTION("Output is order dependent") {
|
||||
CHECK( serializedTestSpec( "[abc][def]" ) == "[abc] [def]" );
|
||||
CHECK( serializedTestSpec( "[def][abc]" ) == "[def] [abc]" );
|
||||
}
|
||||
SECTION("Multiple disjunct filters") {
|
||||
CHECK( serializedTestSpec( "[abc],[def]" ) == "[abc],[def]" );
|
||||
CHECK( serializedTestSpec( "[def],[abc],[idkfa]" ) == "[def],[abc],[idkfa]" );
|
||||
}
|
||||
SECTION("Test names are enclosed in string") {
|
||||
CHECK( serializedTestSpec( "Some test" ) == "\"Some test\"" );
|
||||
CHECK( serializedTestSpec( "*Some test" ) == "\"*Some test\"" );
|
||||
CHECK( serializedTestSpec( "* Some test" ) == "\"* Some test\"" );
|
||||
CHECK( serializedTestSpec( "* Some test *" ) == "\"* Some test *\"" );
|
||||
}
|
||||
SECTION( "Mixing test names and tags" ) {
|
||||
CHECK( serializedTestSpec( "some test[abcd]" ) ==
|
||||
"\"some test\" [abcd]" );
|
||||
CHECK( serializedTestSpec( "[ab]some test[cd]" ) ==
|
||||
"[ab] \"some test\" [cd]" );
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/internal/catch_tag_alias_registry.hpp>
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
|
||||
namespace {
|
||||
static constexpr Catch::SourceLineInfo dummySourceLineInfo = CATCH_INTERNAL_LINEINFO;
|
||||
|
||||
static Catch::TestSpec parseAndCreateSpec(std::string const& str) {
|
||||
Catch::TagAliasRegistry registry;
|
||||
Catch::TestSpecParser parser( registry );
|
||||
|
||||
parser.parse( str );
|
||||
auto spec = parser.testSpec();
|
||||
REQUIRE( spec.hasFilters() );
|
||||
REQUIRE( spec.getInvalidSpecs().empty());
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE( "Parsing tags with non-alphabetical characters is pass-through",
|
||||
"[test-spec][test-spec-parser]" ) {
|
||||
auto const& tagString = GENERATE( as<std::string>{},
|
||||
"[tag with spaces]",
|
||||
"[I said \"good day\" sir!]" );
|
||||
CAPTURE(tagString);
|
||||
|
||||
auto spec = parseAndCreateSpec( tagString );
|
||||
|
||||
Catch::TestCaseInfo testCase(
|
||||
"", { "fake test name", tagString }, dummySourceLineInfo );
|
||||
|
||||
REQUIRE( spec.matches( testCase ) );
|
||||
}
|
||||
|
||||
TEST_CASE("Parsed tags are matched case insensitive",
|
||||
"[test-spec][test-spec-parser]") {
|
||||
auto spec = parseAndCreateSpec( "[CASED tag]" );
|
||||
|
||||
Catch::TestCaseInfo testCase(
|
||||
"", { "fake test name", "[cased TAG]" }, dummySourceLineInfo );
|
||||
|
||||
REQUIRE( spec.matches( testCase ) );
|
||||
}
|
@ -0,0 +1,400 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_textflow.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using Catch::TextFlow::Column;
|
||||
using Catch::TextFlow::AnsiSkippingString;
|
||||
|
||||
namespace {
|
||||
static std::string as_written(Column const& c) {
|
||||
std::stringstream sstr;
|
||||
sstr << c;
|
||||
return sstr.str();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column one simple line",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
Column col( "simple short line" );
|
||||
|
||||
REQUIRE(as_written(col) == "simple short line");
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column respects already present newlines",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
Column col( "abc\ndef" );
|
||||
REQUIRE( as_written( col ) == "abc\ndef" );
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column respects width setting",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
Column col( "The quick brown fox jumped over the lazy dog" );
|
||||
|
||||
SECTION( "width=20" ) {
|
||||
col.width( 20 );
|
||||
REQUIRE( as_written( col ) == "The quick brown fox\n"
|
||||
"jumped over the lazy\n"
|
||||
"dog" );
|
||||
}
|
||||
SECTION("width=10") {
|
||||
col.width( 10 );
|
||||
REQUIRE( as_written( col ) == "The quick\n"
|
||||
"brown fox\n"
|
||||
"jumped\n"
|
||||
"over the\n"
|
||||
"lazy dog" );
|
||||
}
|
||||
SECTION("width=5") {
|
||||
// This is so small some words will have to be split with hyphen
|
||||
col.width(5);
|
||||
REQUIRE( as_written( col ) == "The\n"
|
||||
"quick\n"
|
||||
"brown\n"
|
||||
"fox\n"
|
||||
"jump-\n"
|
||||
"ed\n"
|
||||
"over\n"
|
||||
"the\n"
|
||||
"lazy\n"
|
||||
"dog" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column respects indentation setting",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
Column col( "First line\nSecond line\nThird line" );
|
||||
|
||||
SECTION("Default: no indentation at all") {
|
||||
REQUIRE(as_written(col) == "First line\nSecond line\nThird line");
|
||||
}
|
||||
SECTION("Indentation on first line only") {
|
||||
col.initialIndent(3);
|
||||
REQUIRE(as_written(col) == " First line\nSecond line\nThird line");
|
||||
}
|
||||
SECTION("Indentation on all lines") {
|
||||
col.indent(3);
|
||||
REQUIRE(as_written(col) == " First line\n Second line\n Third line");
|
||||
}
|
||||
SECTION("Indentation on later lines only") {
|
||||
col.indent(5).initialIndent(0);
|
||||
REQUIRE(as_written(col) == "First line\n Second line\n Third line");
|
||||
}
|
||||
SECTION("Different indentation on first and later lines") {
|
||||
col.initialIndent(1).indent(2);
|
||||
REQUIRE(as_written(col) == " First line\n Second line\n Third line");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("TextFlow::Column indentation respects whitespace", "[TextFlow][column][approvals]") {
|
||||
Column col(" text with whitespace\n after newlines");
|
||||
|
||||
SECTION("No extra indentation") {
|
||||
col.initialIndent(0).indent(0);
|
||||
REQUIRE(as_written(col) == " text with whitespace\n after newlines");
|
||||
}
|
||||
SECTION("Different indentation on first and later lines") {
|
||||
col.initialIndent(1).indent(2);
|
||||
REQUIRE(as_written(col) == " text with whitespace\n after newlines");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column linebreaking prefers boundary characters",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
SECTION("parentheses") {
|
||||
Column col("(Hello)aaa(World)");
|
||||
SECTION("width=20") {
|
||||
col.width(20);
|
||||
REQUIRE(as_written(col) == "(Hello)aaa(World)");
|
||||
}
|
||||
SECTION("width=15") {
|
||||
col.width(15);
|
||||
REQUIRE(as_written(col) == "(Hello)aaa\n(World)");
|
||||
}
|
||||
SECTION("width=8") {
|
||||
col.width(8);
|
||||
REQUIRE(as_written(col) == "(Hello)\naaa\n(World)");
|
||||
}
|
||||
}
|
||||
SECTION("commas") {
|
||||
Column col("Hello, world");
|
||||
col.width(8);
|
||||
|
||||
REQUIRE(as_written(col) == "Hello,\nworld");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "TextFlow::Column respects indentation for empty lines",
|
||||
"[TextFlow][column][approvals][!shouldfail]" ) {
|
||||
// This is currently bugged and does not do what it should
|
||||
Column col("\n\nthird line");
|
||||
col.indent(2);
|
||||
|
||||
//auto b = col.begin();
|
||||
//auto e = col.end();
|
||||
|
||||
//auto b1 = *b;
|
||||
//++b;
|
||||
//auto b2 = *b;
|
||||
//++b;
|
||||
//auto b3 = *b;
|
||||
//++b;
|
||||
|
||||
//REQUIRE(b == e);
|
||||
|
||||
std::string written = as_written(col);
|
||||
|
||||
REQUIRE(written == " \n \n third line");
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column leading/trailing whitespace",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
SECTION("Trailing whitespace") {
|
||||
Column col("some trailing whitespace: \t");
|
||||
REQUIRE(as_written(col) == "some trailing whitespace: \t");
|
||||
}
|
||||
SECTION("Some leading whitespace") {
|
||||
Column col("\t \t whitespace wooo");
|
||||
REQUIRE(as_written(col) == "\t \t whitespace wooo");
|
||||
}
|
||||
SECTION("both") {
|
||||
Column col(" abc ");
|
||||
REQUIRE(as_written(col) == " abc ");
|
||||
}
|
||||
SECTION("whitespace only") {
|
||||
Column col("\t \t");
|
||||
REQUIRE(as_written(col) == "\t \t");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column can handle empty string",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
Column col("");
|
||||
REQUIRE(as_written(col) == "");
|
||||
}
|
||||
|
||||
TEST_CASE( "#1400 - TextFlow::Column wrapping would sometimes duplicate words",
|
||||
"[TextFlow][column][regression][approvals]" ) {
|
||||
const auto long_string = std::string(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nisl \n"
|
||||
"massa, luctus ut ligula vitae, suscipit tempus velit. Vivamus sodales, quam in \n"
|
||||
"convallis posuere, libero nisi ultricies orci, nec lobortis.\n");
|
||||
|
||||
auto col = Column(long_string)
|
||||
.width(79)
|
||||
.indent(2);
|
||||
|
||||
REQUIRE(as_written(col) ==
|
||||
" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nisl \n"
|
||||
" massa, luctus ut ligula vitae, suscipit tempus velit. Vivamus sodales, quam\n"
|
||||
" in \n"
|
||||
" convallis posuere, libero nisi ultricies orci, nec lobortis.");
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::AnsiSkippingString skips ansi sequences",
|
||||
"[TextFlow][ansiskippingstring][approvals]" ) {
|
||||
|
||||
SECTION("basic string") {
|
||||
std::string text = "a\033[38;2;98;174;239mb\033[38mc\033[0md\033[me";
|
||||
AnsiSkippingString str(text);
|
||||
|
||||
SECTION( "iterates forward" ) {
|
||||
auto it = str.begin();
|
||||
CHECK(*it == 'a');
|
||||
++it;
|
||||
CHECK(*it == 'b');
|
||||
++it;
|
||||
CHECK(*it == 'c');
|
||||
++it;
|
||||
CHECK(*it == 'd');
|
||||
++it;
|
||||
CHECK(*it == 'e');
|
||||
++it;
|
||||
CHECK(it == str.end());
|
||||
}
|
||||
SECTION( "iterates backwards" ) {
|
||||
auto it = str.end();
|
||||
--it;
|
||||
CHECK(*it == 'e');
|
||||
--it;
|
||||
CHECK(*it == 'd');
|
||||
--it;
|
||||
CHECK(*it == 'c');
|
||||
--it;
|
||||
CHECK(*it == 'b');
|
||||
--it;
|
||||
CHECK(*it == 'a');
|
||||
CHECK(it == str.begin());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "ansi escape sequences at the start" ) {
|
||||
std::string text = "\033[38;2;98;174;239ma\033[38;2;98;174;239mb\033[38mc\033[0md\033[me";
|
||||
AnsiSkippingString str(text);
|
||||
auto it = str.begin();
|
||||
CHECK(*it == 'a');
|
||||
++it;
|
||||
CHECK(*it == 'b');
|
||||
++it;
|
||||
CHECK(*it == 'c');
|
||||
++it;
|
||||
CHECK(*it == 'd');
|
||||
++it;
|
||||
CHECK(*it == 'e');
|
||||
++it;
|
||||
CHECK(it == str.end());
|
||||
--it;
|
||||
CHECK(*it == 'e');
|
||||
--it;
|
||||
CHECK(*it == 'd');
|
||||
--it;
|
||||
CHECK(*it == 'c');
|
||||
--it;
|
||||
CHECK(*it == 'b');
|
||||
--it;
|
||||
CHECK(*it == 'a');
|
||||
CHECK(it == str.begin());
|
||||
}
|
||||
|
||||
SECTION( "ansi escape sequences at the end" ) {
|
||||
std::string text = "a\033[38;2;98;174;239mb\033[38mc\033[0md\033[me\033[38;2;98;174;239m";
|
||||
AnsiSkippingString str(text);
|
||||
auto it = str.begin();
|
||||
CHECK(*it == 'a');
|
||||
++it;
|
||||
CHECK(*it == 'b');
|
||||
++it;
|
||||
CHECK(*it == 'c');
|
||||
++it;
|
||||
CHECK(*it == 'd');
|
||||
++it;
|
||||
CHECK(*it == 'e');
|
||||
++it;
|
||||
CHECK(it == str.end());
|
||||
--it;
|
||||
CHECK(*it == 'e');
|
||||
--it;
|
||||
CHECK(*it == 'd');
|
||||
--it;
|
||||
CHECK(*it == 'c');
|
||||
--it;
|
||||
CHECK(*it == 'b');
|
||||
--it;
|
||||
CHECK(*it == 'a');
|
||||
CHECK(it == str.begin());
|
||||
}
|
||||
|
||||
SECTION( "skips consecutive escapes" ) {
|
||||
std::string text = "\033[38;2;98;174;239m\033[38;2;98;174;239ma\033[38;2;98;174;239mb\033[38m\033[38m\033[38mc\033[0md\033[me";
|
||||
AnsiSkippingString str(text);
|
||||
auto it = str.begin();
|
||||
CHECK(*it == 'a');
|
||||
++it;
|
||||
CHECK(*it == 'b');
|
||||
++it;
|
||||
CHECK(*it == 'c');
|
||||
++it;
|
||||
CHECK(*it == 'd');
|
||||
++it;
|
||||
CHECK(*it == 'e');
|
||||
++it;
|
||||
CHECK(it == str.end());
|
||||
--it;
|
||||
CHECK(*it == 'e');
|
||||
--it;
|
||||
CHECK(*it == 'd');
|
||||
--it;
|
||||
CHECK(*it == 'c');
|
||||
--it;
|
||||
CHECK(*it == 'b');
|
||||
--it;
|
||||
CHECK(*it == 'a');
|
||||
CHECK(it == str.begin());
|
||||
}
|
||||
|
||||
SECTION( "handles incomplete ansi sequences" ) {
|
||||
std::string text = "a\033[b\033[30c\033[30;d\033[30;2e";
|
||||
AnsiSkippingString str(text);
|
||||
CHECK(std::string(str.begin(), str.end()) == text);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::AnsiSkippingString computes the size properly",
|
||||
"[TextFlow][ansiskippingstring][approvals]" ) {
|
||||
std::string text = "\033[38;2;98;174;239m\033[38;2;98;174;239ma\033[38;2;98;174;239mb\033[38m\033[38m\033[38mc\033[0md\033[me";
|
||||
AnsiSkippingString str(text);
|
||||
CHECK(str.size() == 5);
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::AnsiSkippingString substrings properly",
|
||||
"[TextFlow][ansiskippingstring][approvals]" ) {
|
||||
SECTION("basic test") {
|
||||
std::string text = "a\033[38;2;98;174;239mb\033[38mc\033[0md\033[me";
|
||||
AnsiSkippingString str(text);
|
||||
auto a = str.begin();
|
||||
auto b = str.begin();
|
||||
++b;
|
||||
++b;
|
||||
CHECK(str.substring(a, b) == "a\033[38;2;98;174;239mb\033[38m");
|
||||
++a;
|
||||
++b;
|
||||
CHECK(str.substring(a, b) == "b\033[38mc\033[0m");
|
||||
CHECK(str.substring(a, str.end()) == "b\033[38mc\033[0md\033[me");
|
||||
CHECK(str.substring(str.begin(), str.end()) == text);
|
||||
}
|
||||
SECTION("escapes at the start") {
|
||||
std::string text = "\033[38;2;98;174;239m\033[38;2;98;174;239ma\033[38;2;98;174;239mb\033[38m\033[38m\033[38mc\033[0md\033[me";
|
||||
AnsiSkippingString str(text);
|
||||
auto a = str.begin();
|
||||
auto b = str.begin();
|
||||
++b;
|
||||
++b;
|
||||
CHECK(str.substring(a, b) == "\033[38;2;98;174;239m\033[38;2;98;174;239ma\033[38;2;98;174;239mb\033[38m\033[38m\033[38m");
|
||||
++a;
|
||||
++b;
|
||||
CHECK(str.substring(a, b) == "b\033[38m\033[38m\033[38mc\033[0m");
|
||||
CHECK(str.substring(a, str.end()) == "b\033[38m\033[38m\033[38mc\033[0md\033[me");
|
||||
CHECK(str.substring(str.begin(), str.end()) == text);
|
||||
}
|
||||
SECTION("escapes at the end") {
|
||||
std::string text = "a\033[38;2;98;174;239mb\033[38mc\033[0md\033[me\033[38m";
|
||||
AnsiSkippingString str(text);
|
||||
auto a = str.begin();
|
||||
auto b = str.begin();
|
||||
++b;
|
||||
++b;
|
||||
CHECK(str.substring(a, b) == "a\033[38;2;98;174;239mb\033[38m");
|
||||
++a;
|
||||
++b;
|
||||
CHECK(str.substring(a, b) == "b\033[38mc\033[0m");
|
||||
CHECK(str.substring(a, str.end()) == "b\033[38mc\033[0md\033[me\033[38m");
|
||||
CHECK(str.substring(str.begin(), str.end()) == text);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column skips ansi escape sequences",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
std::string text = "\033[38;2;98;174;239m\033[38;2;198;120;221mThe quick brown \033[38;2;198;120;221mfox jumped over the lazy dog\033[0m";
|
||||
Column col(text);
|
||||
|
||||
SECTION( "width=20" ) {
|
||||
col.width( 20 );
|
||||
REQUIRE( as_written( col ) == "\033[38;2;98;174;239m\033[38;2;198;120;221mThe quick brown \033[38;2;198;120;221mfox\n"
|
||||
"jumped over the lazy\n"
|
||||
"dog\033[0m" );
|
||||
}
|
||||
|
||||
SECTION( "width=80" ) {
|
||||
col.width( 80 );
|
||||
REQUIRE( as_written( col ) == text );
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/internal/catch_enum_values_registry.hpp>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
|
||||
enum class EnumClass3 { Value1, Value2, Value3, Value4 };
|
||||
|
||||
struct UsesSentinel {
|
||||
using const_iterator = int const*;
|
||||
using const_sentinel = std::nullptr_t;
|
||||
|
||||
const_iterator begin() const { return nullptr; }
|
||||
const_iterator end() const { return nullptr; }
|
||||
};
|
||||
|
||||
TEST_CASE( "parseEnums", "[Strings][enums]" ) {
|
||||
using namespace Catch::Matchers;
|
||||
using Catch::Detail::parseEnums;
|
||||
|
||||
SECTION( "No enums" )
|
||||
CHECK_THAT( parseEnums( "" ), Equals( std::vector<Catch::StringRef>{} ) );
|
||||
|
||||
SECTION( "One enum value" ) {
|
||||
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1" ),
|
||||
Equals(std::vector<Catch::StringRef>{"Value1"} ) );
|
||||
CHECK_THAT( parseEnums( "Value1" ),
|
||||
Equals( std::vector<Catch::StringRef>{"Value1"} ) );
|
||||
CHECK_THAT( parseEnums( "EnumName::Value1" ),
|
||||
Equals(std::vector<Catch::StringRef>{"Value1"} ) );
|
||||
}
|
||||
|
||||
SECTION( "Multiple enum values" ) {
|
||||
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ),
|
||||
Equals( std::vector<Catch::StringRef>{"Value1", "Value2"} ) );
|
||||
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ),
|
||||
Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) );
|
||||
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ),
|
||||
Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Directly creating an EnumInfo" ) {
|
||||
|
||||
using namespace Catch::Detail;
|
||||
auto enumInfo = makeEnumInfo( "EnumName", "EnumName::Value1, EnumName::Value2", {0, 1} );
|
||||
|
||||
CHECK( enumInfo->lookup(0) == "Value1" );
|
||||
CHECK( enumInfo->lookup(1) == "Value2" );
|
||||
CHECK( enumInfo->lookup(3) == "{** unexpected enum value **}" );
|
||||
}
|
||||
|
||||
TEST_CASE("Range type with sentinel") {
|
||||
CHECK( Catch::Detail::stringify(UsesSentinel{}) == "{ }" );
|
||||
}
|
||||
|
||||
TEST_CASE("convertIntoString stringification helper", "[toString][approvals]") {
|
||||
using namespace std::string_literals;
|
||||
using Catch::Detail::convertIntoString;
|
||||
using namespace Catch;
|
||||
|
||||
SECTION("No escaping") {
|
||||
CHECK(convertIntoString(""_sr, false) == R"("")"s);
|
||||
CHECK(convertIntoString("abcd"_sr, false) == R"("abcd")"s);
|
||||
CHECK(convertIntoString("ab\ncd"_sr, false) == "\"ab\ncd\""s);
|
||||
CHECK(convertIntoString("ab\r\ncd"_sr, false) == "\"ab\r\ncd\""s);
|
||||
CHECK(convertIntoString("ab\"cd"_sr, false) == R"("ab"cd")"s);
|
||||
}
|
||||
SECTION("Escaping invisibles") {
|
||||
CHECK(convertIntoString(""_sr, true) == R"("")"s);
|
||||
CHECK(convertIntoString("ab\ncd"_sr, true) == R"("ab\ncd")"s);
|
||||
CHECK(convertIntoString("ab\r\ncd"_sr, true) == R"("ab\r\ncd")"s);
|
||||
CHECK(convertIntoString("ab\tcd"_sr, true) == R"("ab\tcd")"s);
|
||||
CHECK(convertIntoString("ab\fcd"_sr, true) == R"("ab\fcd")"s);
|
||||
CHECK(convertIntoString("ab\"cd"_sr, true) == R"("ab"cd")"s);
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE( "Stringifying char arrays with statically known sizes",
|
||||
"[toString]",
|
||||
char,
|
||||
signed char,
|
||||
unsigned char ) {
|
||||
using namespace std::string_literals;
|
||||
TestType with_null_terminator[10] = "abc";
|
||||
CHECK( ::Catch::Detail::stringify( with_null_terminator ) == R"("abc")"s );
|
||||
|
||||
TestType no_null_terminator[3] = { 'a', 'b', 'c' };
|
||||
CHECK( ::Catch::Detail::stringify( no_null_terminator ) == R"("abc")"s );
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_compare_traits.hpp>
|
||||
#include <helpers/type_with_lit_0_comparisons.hpp>
|
||||
|
||||
|
||||
#define ADD_TRAIT_TEST_CASE( op ) \
|
||||
TEST_CASE( "is_" #op "_comparable", \
|
||||
"[traits][is_comparable][approvals]" ) { \
|
||||
using Catch::Detail::is_##op##_0_comparable; \
|
||||
using Catch::Detail::is_##op##_comparable; \
|
||||
\
|
||||
STATIC_REQUIRE( is_##op##_comparable<int, int>::value ); \
|
||||
STATIC_REQUIRE( \
|
||||
is_##op##_comparable<std::string, std::string>::value ); \
|
||||
STATIC_REQUIRE( !is_##op##_comparable<int, std::string>::value ); \
|
||||
STATIC_REQUIRE( \
|
||||
!is_##op##_comparable<TypeWithLit0Comparisons, int>::value ); \
|
||||
STATIC_REQUIRE( \
|
||||
!is_##op##_comparable<int, TypeWithLit0Comparisons>::value ); \
|
||||
\
|
||||
STATIC_REQUIRE( is_##op##_0_comparable<int>::value ); \
|
||||
STATIC_REQUIRE( \
|
||||
is_##op##_0_comparable<TypeWithLit0Comparisons>::value ); \
|
||||
STATIC_REQUIRE( !is_##op##_0_comparable<std::string>::value ); \
|
||||
\
|
||||
/* This test fails with MSVC in permissive mode, because of course it does */ \
|
||||
/* STATIC_REQUIRE( !is_##op##_0_comparable<int*>::value ); */ \
|
||||
}
|
||||
|
||||
ADD_TRAIT_TEST_CASE(lt)
|
||||
ADD_TRAIT_TEST_CASE(gt)
|
||||
ADD_TRAIT_TEST_CASE(le)
|
||||
ADD_TRAIT_TEST_CASE(ge)
|
||||
ADD_TRAIT_TEST_CASE(eq)
|
||||
ADD_TRAIT_TEST_CASE(ne)
|
||||
|
||||
#undef ADD_TRAIT_TEST_CASE
|
@ -0,0 +1,141 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace {
|
||||
struct unique_ptr_test_helper {
|
||||
bool dummy = false;
|
||||
};
|
||||
} // end unnamed namespace
|
||||
|
||||
TEST_CASE("unique_ptr reimplementation: basic functionality", "[internals][unique-ptr]") {
|
||||
using Catch::Detail::unique_ptr;
|
||||
SECTION("Default constructed unique_ptr is empty") {
|
||||
unique_ptr<int> ptr;
|
||||
REQUIRE_FALSE(ptr);
|
||||
REQUIRE(ptr.get() == nullptr);
|
||||
}
|
||||
SECTION("Take ownership of allocation") {
|
||||
auto naked_ptr = new int{ 0 };
|
||||
unique_ptr<int> ptr(naked_ptr);
|
||||
REQUIRE(ptr);
|
||||
REQUIRE(*ptr == 0);
|
||||
REQUIRE(ptr.get() == naked_ptr);
|
||||
SECTION("Plain reset deallocates") {
|
||||
ptr.reset(); // this makes naked_ptr dangling!
|
||||
REQUIRE_FALSE(ptr);
|
||||
REQUIRE(ptr.get() == nullptr);
|
||||
}
|
||||
SECTION("Reset replaces ownership") {
|
||||
ptr.reset(new int{ 2 });
|
||||
REQUIRE(ptr);
|
||||
REQUIRE(ptr.get() != nullptr);
|
||||
REQUIRE(*ptr == 2);
|
||||
}
|
||||
}
|
||||
SECTION("Release releases ownership") {
|
||||
auto naked_ptr = new int{ 1 };
|
||||
unique_ptr<int> ptr(naked_ptr);
|
||||
ptr.release();
|
||||
CHECK_FALSE(ptr);
|
||||
CHECK(ptr.get() == nullptr);
|
||||
delete naked_ptr;
|
||||
}
|
||||
SECTION("Move constructor") {
|
||||
unique_ptr<int> ptr1(new int{ 1 });
|
||||
auto ptr2(std::move(ptr1));
|
||||
REQUIRE_FALSE(ptr1);
|
||||
REQUIRE(ptr2);
|
||||
REQUIRE(*ptr2 == 1);
|
||||
}
|
||||
SECTION("Move assignment") {
|
||||
unique_ptr<int> ptr1(new int{ 1 }), ptr2(new int{ 2 });
|
||||
ptr1 = std::move(ptr2);
|
||||
REQUIRE_FALSE(ptr2);
|
||||
REQUIRE(ptr1);
|
||||
REQUIRE(*ptr1 == 2);
|
||||
}
|
||||
SECTION("free swap") {
|
||||
unique_ptr<int> ptr1(new int{ 1 }), ptr2(new int{ 2 });
|
||||
swap(ptr1, ptr2);
|
||||
REQUIRE(*ptr1 == 2);
|
||||
REQUIRE(*ptr2 == 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
struct base {
|
||||
int i;
|
||||
base(int i_) :i(i_) {}
|
||||
};
|
||||
struct derived : base { using base::base; };
|
||||
struct unrelated {};
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
static_assert( std::is_constructible<Catch::Detail::unique_ptr<base>,
|
||||
Catch::Detail::unique_ptr<derived>>::value, "Upcasting is supported");
|
||||
static_assert(!std::is_constructible<Catch::Detail::unique_ptr<derived>,
|
||||
Catch::Detail::unique_ptr<base>>::value, "Downcasting is not supported");
|
||||
static_assert(!std::is_constructible<Catch::Detail::unique_ptr<base>,
|
||||
Catch::Detail::unique_ptr<unrelated>>::value, "Cannot just convert one ptr type to another");
|
||||
|
||||
TEST_CASE("Upcasting special member functions", "[internals][unique-ptr]") {
|
||||
using Catch::Detail::unique_ptr;
|
||||
|
||||
unique_ptr<derived> dptr(new derived{3});
|
||||
SECTION("Move constructor") {
|
||||
unique_ptr<base> bptr(std::move(dptr));
|
||||
REQUIRE(bptr->i == 3);
|
||||
}
|
||||
SECTION("move assignment") {
|
||||
unique_ptr<base> bptr(new base{ 1 });
|
||||
bptr = std::move(dptr);
|
||||
REQUIRE(bptr->i == 3);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct move_detector {
|
||||
bool has_moved = false;
|
||||
move_detector() = default;
|
||||
move_detector(move_detector const& rhs) = default;
|
||||
move_detector& operator=(move_detector const& rhs) = default;
|
||||
|
||||
move_detector(move_detector&& rhs) noexcept {
|
||||
rhs.has_moved = true;
|
||||
}
|
||||
move_detector& operator=(move_detector&& rhs) noexcept {
|
||||
rhs.has_moved = true;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
} // end unnamed namespace
|
||||
|
||||
TEST_CASE("make_unique reimplementation", "[internals][unique-ptr]") {
|
||||
using Catch::Detail::make_unique;
|
||||
SECTION("From lvalue copies") {
|
||||
move_detector lval;
|
||||
auto ptr = make_unique<move_detector>(lval);
|
||||
REQUIRE_FALSE(lval.has_moved);
|
||||
}
|
||||
SECTION("From rvalue moves") {
|
||||
move_detector rval;
|
||||
auto ptr = make_unique<move_detector>(std::move(rval));
|
||||
REQUIRE(rval.has_moved);
|
||||
}
|
||||
SECTION("Variadic constructor") {
|
||||
auto ptr = make_unique<std::tuple<int, double, int>>(1, 2., 3);
|
||||
REQUIRE(*ptr == std::tuple<int, double, int>{1, 2., 3});
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_xmlwriter.hpp>
|
||||
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
static std::string encode( std::string const& str, Catch::XmlEncode::ForWhat forWhat = Catch::XmlEncode::ForTextNodes ) {
|
||||
Catch::ReusableStringStream oss;
|
||||
oss << Catch::XmlEncode( str, forWhat );
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
TEST_CASE( "XmlEncode", "[XML]" ) {
|
||||
SECTION( "normal string" ) {
|
||||
REQUIRE( encode( "normal string" ) == "normal string" );
|
||||
}
|
||||
SECTION( "empty string" ) {
|
||||
REQUIRE( encode( "" ) == "" );
|
||||
}
|
||||
SECTION( "string with ampersand" ) {
|
||||
REQUIRE( encode( "smith & jones" ) == "smith & jones" );
|
||||
}
|
||||
SECTION( "string with less-than" ) {
|
||||
REQUIRE( encode( "smith < jones" ) == "smith < jones" );
|
||||
}
|
||||
SECTION( "string with greater-than" ) {
|
||||
REQUIRE( encode( "smith > jones" ) == "smith > jones" );
|
||||
REQUIRE( encode( "smith ]]> jones" ) == "smith ]]> jones" );
|
||||
}
|
||||
SECTION( "string with quotes" ) {
|
||||
std::string stringWithQuotes = "don't \"quote\" me on that";
|
||||
REQUIRE( encode( stringWithQuotes ) == stringWithQuotes );
|
||||
REQUIRE( encode( stringWithQuotes, Catch::XmlEncode::ForAttributes ) == "don't "quote" me on that" );
|
||||
}
|
||||
SECTION( "string with control char (1)" ) {
|
||||
REQUIRE( encode( "[\x01]" ) == "[\\x01]" );
|
||||
}
|
||||
SECTION( "string with control char (x7F)" ) {
|
||||
REQUIRE( encode( "[\x7F]" ) == "[\\x7F]" );
|
||||
}
|
||||
}
|
||||
|
||||
// Thanks to Peter Bindels (dascandy) for some of the tests
|
||||
TEST_CASE("XmlEncode: UTF-8", "[XML][UTF-8][approvals]") {
|
||||
SECTION("Valid utf-8 strings") {
|
||||
CHECK(encode("Here be 👾") == "Here be 👾");
|
||||
CHECK(encode("šš") == "šš");
|
||||
|
||||
CHECK(encode("\xDF\xBF") == "\xDF\xBF"); // 0x7FF
|
||||
CHECK(encode("\xE0\xA0\x80") == "\xE0\xA0\x80"); // 0x800
|
||||
CHECK(encode("\xED\x9F\xBF") == "\xED\x9F\xBF"); // 0xD7FF
|
||||
CHECK(encode("\xEE\x80\x80") == "\xEE\x80\x80"); // 0xE000
|
||||
CHECK(encode("\xEF\xBF\xBF") == "\xEF\xBF\xBF"); // 0xFFFF
|
||||
CHECK(encode("\xF0\x90\x80\x80") == "\xF0\x90\x80\x80"); // 0x10000
|
||||
CHECK(encode("\xF4\x8F\xBF\xBF") == "\xF4\x8F\xBF\xBF"); // 0x10FFFF
|
||||
}
|
||||
SECTION("Invalid utf-8 strings") {
|
||||
SECTION("Various broken strings") {
|
||||
CHECK(encode("Here \xFF be \xF0\x9F\x91\xBE") == "Here \\xFF be 👾");
|
||||
CHECK(encode("\xFF") == "\\xFF");
|
||||
CHECK(encode("\xC5\xC5\xA0") == "\\xC5Š");
|
||||
CHECK(encode("\xF4\x90\x80\x80") == "\\xF4\\x90\\x80\\x80"); // 0x110000 -- out of unicode range
|
||||
}
|
||||
|
||||
SECTION("Overlong encodings") {
|
||||
CHECK(encode("\xC0\x80") == "\\xC0\\x80"); // \0
|
||||
CHECK(encode("\xF0\x80\x80\x80") == "\\xF0\\x80\\x80\\x80"); // Super-over-long \0
|
||||
CHECK(encode("\xC1\xBF") == "\\xC1\\xBF"); // ASCII char as UTF-8 (0x7F)
|
||||
CHECK(encode("\xE0\x9F\xBF") == "\\xE0\\x9F\\xBF"); // 0x7FF
|
||||
CHECK(encode("\xF0\x8F\xBF\xBF") == "\\xF0\\x8F\\xBF\\xBF"); // 0xFFFF
|
||||
}
|
||||
|
||||
// Note that we actually don't modify surrogate pairs, as we do not do strict checking
|
||||
SECTION("Surrogate pairs") {
|
||||
CHECK(encode("\xED\xA0\x80") == "\xED\xA0\x80"); // Invalid surrogate half 0xD800
|
||||
CHECK(encode("\xED\xAF\xBF") == "\xED\xAF\xBF"); // Invalid surrogate half 0xDBFF
|
||||
CHECK(encode("\xED\xB0\x80") == "\xED\xB0\x80"); // Invalid surrogate half 0xDC00
|
||||
CHECK(encode("\xED\xBF\xBF") == "\xED\xBF\xBF"); // Invalid surrogate half 0xDFFF
|
||||
}
|
||||
|
||||
SECTION("Invalid start byte") {
|
||||
CHECK(encode("\x80") == "\\x80");
|
||||
CHECK(encode("\x81") == "\\x81");
|
||||
CHECK(encode("\xBC") == "\\xBC");
|
||||
CHECK(encode("\xBF") == "\\xBF");
|
||||
// Out of range
|
||||
CHECK(encode("\xF5\x80\x80\x80") == "\\xF5\\x80\\x80\\x80");
|
||||
CHECK(encode("\xF6\x80\x80\x80") == "\\xF6\\x80\\x80\\x80");
|
||||
CHECK(encode("\xF7\x80\x80\x80") == "\\xF7\\x80\\x80\\x80");
|
||||
}
|
||||
|
||||
SECTION("Missing continuation byte(s)") {
|
||||
// Missing first continuation byte
|
||||
CHECK(encode("\xDE") == "\\xDE");
|
||||
CHECK(encode("\xDF") == "\\xDF");
|
||||
CHECK(encode("\xE0") == "\\xE0");
|
||||
CHECK(encode("\xEF") == "\\xEF");
|
||||
CHECK(encode("\xF0") == "\\xF0");
|
||||
CHECK(encode("\xF4") == "\\xF4");
|
||||
|
||||
// Missing second continuation byte
|
||||
CHECK(encode("\xE0\x80") == "\\xE0\\x80");
|
||||
CHECK(encode("\xE0\xBF") == "\\xE0\\xBF");
|
||||
CHECK(encode("\xE1\x80") == "\\xE1\\x80");
|
||||
CHECK(encode("\xF0\x80") == "\\xF0\\x80");
|
||||
CHECK(encode("\xF4\x80") == "\\xF4\\x80");
|
||||
|
||||
// Missing third continuation byte
|
||||
CHECK(encode("\xF0\x80\x80") == "\\xF0\\x80\\x80");
|
||||
CHECK(encode("\xF4\x80\x80") == "\\xF4\\x80\\x80");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("XmlWriter writes boolean attributes as true/false", "[XML][XmlWriter]") {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
std::stringstream stream;
|
||||
{
|
||||
Catch::XmlWriter xml(stream);
|
||||
|
||||
xml.scopedElement("Element1")
|
||||
.writeAttribute("attr1", true)
|
||||
.writeAttribute("attr2", false);
|
||||
}
|
||||
|
||||
REQUIRE_THAT( stream.str(),
|
||||
ContainsSubstring(R"(attr1="true")") &&
|
||||
ContainsSubstring(R"(attr2="false")") );
|
||||
}
|
||||
|
||||
TEST_CASE("XmlWriter does not escape comments", "[XML][XmlWriter][approvals]") {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
std::stringstream stream;
|
||||
{
|
||||
Catch::XmlWriter xml(stream);
|
||||
|
||||
xml.writeComment(R"(unescaped special chars: < > ' " &)");
|
||||
}
|
||||
REQUIRE_THAT( stream.str(),
|
||||
ContainsSubstring(R"(<!-- unescaped special chars: < > ' " & -->)"));
|
||||
}
|
||||
|
||||
TEST_CASE("XmlWriter errors out when writing text without enclosing element", "[XmlWriter][approvals]") {
|
||||
std::stringstream stream;
|
||||
Catch::XmlWriter xml(stream);
|
||||
REQUIRE_THROWS(xml.writeText("some text"));
|
||||
}
|
||||
|
||||
TEST_CASE("XmlWriter escapes text properly", "[XML][XmlWriter][approvals]") {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
std::stringstream stream;
|
||||
{
|
||||
Catch::XmlWriter xml(stream);
|
||||
xml.scopedElement("root")
|
||||
.writeText(R"(Special chars need escaping: < > ' " &)");
|
||||
}
|
||||
|
||||
REQUIRE_THAT( stream.str(),
|
||||
ContainsSubstring(R"(Special chars need escaping: < > ' " &)"));
|
||||
}
|
||||
|
||||
TEST_CASE("XmlWriter escapes attributes properly", "[XML][XmlWriter][approvals]") {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
std::stringstream stream;
|
||||
{
|
||||
Catch::XmlWriter xml(stream);
|
||||
xml.scopedElement("root")
|
||||
.writeAttribute("some-attribute", R"(Special chars need escaping: < > ' " &)");
|
||||
}
|
||||
|
||||
REQUIRE_THAT(stream.str(),
|
||||
ContainsSubstring(R"(some-attribute="Special chars need escaping: < > ' " &")"));
|
||||
}
|
@ -0,0 +1 @@
|
||||
Test with special, characters in \" name
|
@ -0,0 +1,2 @@
|
||||
random SECTION tests
|
||||
nested SECTION tests
|
@ -0,0 +1 @@
|
||||
Test with special\, characters \"in name
|
@ -0,0 +1,180 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_tag_alias_autoregistrar.hpp>
|
||||
#include <catch2/reporters/catch_reporter_event_listener.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
|
||||
|
||||
// Some example tag aliases
|
||||
CATCH_REGISTER_TAG_ALIAS("[@nhf]", "[failing]~[.]")
|
||||
CATCH_REGISTER_TAG_ALIAS("[@tricky]", "[tricky]~[.]")
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic ignored "-Wpadded"
|
||||
# pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Event listener that internally counts and validates received events.
|
||||
*
|
||||
* Currently only performs validation by counting received events, rather
|
||||
* than performing full matching. This means that it won't fail if the *Ended
|
||||
* events are provided in wrong order, as long as they come in the right amount
|
||||
* and with the right nesting.
|
||||
*/
|
||||
class ValidatingTestListener : public Catch::EventListenerBase {
|
||||
struct EventCounter {
|
||||
int starting = 0;
|
||||
int ended = 0;
|
||||
|
||||
bool hasActiveEvent() const {
|
||||
return starting > ended;
|
||||
}
|
||||
bool hasSingleActiveEvent() const {
|
||||
return starting - 1 == ended;
|
||||
}
|
||||
bool allEventsEnded() const {
|
||||
return starting == ended;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
static std::string getDescription() {
|
||||
return "Validates ordering of Catch2's listener events";
|
||||
}
|
||||
|
||||
ValidatingTestListener(Catch::IConfig const* config) :
|
||||
EventListenerBase(config) {
|
||||
m_preferences.shouldReportAllAssertions = true;
|
||||
}
|
||||
|
||||
void testRunStarting( Catch::TestRunInfo const& ) override {
|
||||
CATCH_ENFORCE( m_testRunCounter.starting == 0,
|
||||
"Test run can only start once" );
|
||||
++m_testRunCounter.starting;
|
||||
}
|
||||
void testCaseStarting(Catch::TestCaseInfo const&) override {
|
||||
CATCH_ENFORCE( m_testRunCounter.hasActiveEvent(),
|
||||
"Test case can only be started if the test run has already started" );
|
||||
CATCH_ENFORCE( m_testCaseCounter.allEventsEnded(),
|
||||
"Test case cannot start if there is an unfinished one" );
|
||||
|
||||
++m_testCaseCounter.starting;
|
||||
|
||||
// Reset the part tracking for partial test case events
|
||||
m_lastSeenPartNumber = uint64_t(-1);
|
||||
}
|
||||
|
||||
void testCasePartialStarting(Catch::TestCaseInfo const&,
|
||||
uint64_t partNumber) override {
|
||||
CATCH_ENFORCE( m_testCaseCounter.hasSingleActiveEvent(),
|
||||
"Test case can only be partially started if the test case has fully started already" );
|
||||
CATCH_ENFORCE( m_lastSeenPartNumber + 1 == partNumber,
|
||||
"Partial test case started out of order" );
|
||||
|
||||
++m_testCasePartialCounter.starting;
|
||||
m_lastSeenPartNumber = partNumber;
|
||||
}
|
||||
|
||||
void sectionStarting(Catch::SectionInfo const&) override {
|
||||
CATCH_ENFORCE( m_testCaseCounter.hasSingleActiveEvent(),
|
||||
"Section can only start in a test case" );
|
||||
CATCH_ENFORCE( m_testCasePartialCounter.hasSingleActiveEvent(),
|
||||
"Section can only start in a test case" );
|
||||
|
||||
++m_sectionCounter.starting;
|
||||
}
|
||||
|
||||
void assertionStarting(Catch::AssertionInfo const&) override {
|
||||
CATCH_ENFORCE( m_testCaseCounter.hasSingleActiveEvent(),
|
||||
"Assertion can only start if test case is started" );
|
||||
|
||||
++m_assertionCounter.starting;
|
||||
}
|
||||
void assertionEnded(Catch::AssertionStats const&) override {
|
||||
// todo:
|
||||
// * Check that assertions are balanced
|
||||
// * Check that assertions has started
|
||||
++m_assertionCounter.ended;
|
||||
}
|
||||
|
||||
void sectionEnded(Catch::SectionStats const&) override {
|
||||
CATCH_ENFORCE( m_sectionCounter.hasActiveEvent(),
|
||||
"Section ended without corresponding start" );
|
||||
// TODO: Check that all assertions ended
|
||||
|
||||
++m_sectionCounter.ended;
|
||||
}
|
||||
|
||||
|
||||
void testCasePartialEnded(Catch::TestCaseStats const&,
|
||||
uint64_t partNumber) override {
|
||||
CATCH_ENFORCE( m_lastSeenPartNumber == partNumber,
|
||||
"Partial test case ended out of order" );
|
||||
CATCH_ENFORCE( m_testCasePartialCounter.hasSingleActiveEvent(),
|
||||
"Partial test case ended without corresponding start" );
|
||||
CATCH_ENFORCE( m_sectionCounter.allEventsEnded(),
|
||||
"Partial test case ended with unbalanced sections" );
|
||||
// TODO: Check that all assertions ended
|
||||
|
||||
++m_testCasePartialCounter.ended;
|
||||
}
|
||||
|
||||
|
||||
void testCaseEnded(Catch::TestCaseStats const&) override {
|
||||
CATCH_ENFORCE( m_testCaseCounter.hasSingleActiveEvent(),
|
||||
"Test case end is not matched with test case start" );
|
||||
CATCH_ENFORCE( m_testCasePartialCounter.allEventsEnded(),
|
||||
"A partial test case has not ended" );
|
||||
CATCH_ENFORCE( m_sectionCounter.allEventsEnded(),
|
||||
"Test case ended with unbalanced sections" );
|
||||
|
||||
// TODO: Check that all assertions ended
|
||||
|
||||
++m_testCaseCounter.ended;
|
||||
}
|
||||
void testRunEnded( Catch::TestRunStats const& ) override {
|
||||
CATCH_ENFORCE( m_testRunCounter.hasSingleActiveEvent(),
|
||||
"Test run end is not matched with test run start" );
|
||||
CATCH_ENFORCE( m_testRunCounter.ended == 0,
|
||||
"Test run can only end once" );
|
||||
|
||||
++m_testRunCounter.ended;
|
||||
}
|
||||
|
||||
~ValidatingTestListener() override;
|
||||
|
||||
private:
|
||||
EventCounter m_testRunCounter;
|
||||
EventCounter m_testCaseCounter;
|
||||
EventCounter m_testCasePartialCounter;
|
||||
uint64_t m_lastSeenPartNumber = 0;
|
||||
EventCounter m_sectionCounter;
|
||||
EventCounter m_assertionCounter;
|
||||
};
|
||||
|
||||
|
||||
ValidatingTestListener::~ValidatingTestListener() {
|
||||
// Throwing from noexcept destructor terminates, but we don't mind
|
||||
// because this is test-only check and we don't need to try and recover
|
||||
// from assumption violation here.
|
||||
|
||||
CATCH_ENFORCE( m_testRunCounter.ended < 2,
|
||||
"Test run should be started at most once" );
|
||||
CATCH_ENFORCE( m_testRunCounter.allEventsEnded(),
|
||||
"The test run has not finished" );
|
||||
CATCH_ENFORCE( m_testCaseCounter.allEventsEnded(),
|
||||
"A test case did not finish" );
|
||||
|
||||
// TODO: other counters being balanced?
|
||||
}
|
||||
|
||||
CATCH_REGISTER_LISTENER( ValidatingTestListener )
|
@ -0,0 +1,24 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
TEST_CASE( "sleep_for_100ms", "[.min_duration_test][approvals]" )
|
||||
{
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
|
||||
CHECK( true );
|
||||
}
|
||||
|
||||
TEST_CASE( "sleep_for_1000ms", "[.min_duration_test][approvals]" )
|
||||
{
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds( 1'000 ) );
|
||||
CHECK( true );
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using Catch::Approx;
|
||||
|
||||
namespace {
|
||||
static double divide(double a, double b) {
|
||||
return a / b;
|
||||
}
|
||||
|
||||
class StrongDoubleTypedef {
|
||||
double d_ = 0.0;
|
||||
|
||||
public:
|
||||
explicit StrongDoubleTypedef(double d) : d_(d) {}
|
||||
explicit operator double() const { return d_; }
|
||||
};
|
||||
|
||||
static std::ostream& operator<<(std::ostream& os, StrongDoubleTypedef td) {
|
||||
return os << "StrongDoubleTypedef(" << static_cast<double>(td) << ")";
|
||||
}
|
||||
} // end unnamed namespace
|
||||
|
||||
using namespace Catch::literals;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "A comparison that uses literals instead of the normal constructor", "[Approx]" ) {
|
||||
double d = 1.23;
|
||||
|
||||
REQUIRE( d == 1.23_a );
|
||||
REQUIRE( d != 1.22_a );
|
||||
REQUIRE( -d == -1.23_a );
|
||||
|
||||
REQUIRE( d == 1.2_a .epsilon(.1) );
|
||||
REQUIRE( d != 1.2_a .epsilon(.001) );
|
||||
REQUIRE( d == 1_a .epsilon(.3) );
|
||||
}
|
||||
|
||||
TEST_CASE( "Some simple comparisons between doubles", "[Approx]" ) {
|
||||
double d = 1.23;
|
||||
|
||||
REQUIRE( d == Approx( 1.23 ) );
|
||||
REQUIRE( d != Approx( 1.22 ) );
|
||||
REQUIRE( d != Approx( 1.24 ) );
|
||||
|
||||
REQUIRE( d == 1.23_a );
|
||||
REQUIRE( d != 1.22_a );
|
||||
|
||||
REQUIRE( Approx( d ) == 1.23 );
|
||||
REQUIRE( Approx( d ) != 1.22 );
|
||||
REQUIRE( Approx( d ) != 1.24 );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Approximate comparisons with different epsilons", "[Approx]" ) {
|
||||
double d = 1.23;
|
||||
|
||||
REQUIRE( d != Approx( 1.231 ) );
|
||||
REQUIRE( d == Approx( 1.231 ).epsilon( 0.1 ) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Less-than inequalities with different epsilons", "[Approx]" ) {
|
||||
double d = 1.23;
|
||||
|
||||
REQUIRE( d <= Approx( 1.24 ) );
|
||||
REQUIRE( d <= Approx( 1.23 ) );
|
||||
REQUIRE_FALSE( d <= Approx( 1.22 ) );
|
||||
REQUIRE( d <= Approx( 1.22 ).epsilon(0.1) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Greater-than inequalities with different epsilons", "[Approx]" ) {
|
||||
double d = 1.23;
|
||||
|
||||
REQUIRE( d >= Approx( 1.22 ) );
|
||||
REQUIRE( d >= Approx( 1.23 ) );
|
||||
REQUIRE_FALSE( d >= Approx( 1.24 ) );
|
||||
REQUIRE( d >= Approx( 1.24 ).epsilon(0.1) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Approximate comparisons with floats", "[Approx]" ) {
|
||||
REQUIRE( 1.23f == Approx( 1.23f ) );
|
||||
REQUIRE( 0.0f == Approx( 0.0f ) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Approximate comparisons with ints", "[Approx]" ) {
|
||||
REQUIRE( 1 == Approx( 1 ) );
|
||||
REQUIRE( 0 == Approx( 0 ) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Approximate comparisons with mixed numeric types", "[Approx]" ) {
|
||||
const double dZero = 0;
|
||||
const double dSmall = 0.00001;
|
||||
const double dMedium = 1.234;
|
||||
|
||||
REQUIRE( 1.0f == Approx( 1 ) );
|
||||
REQUIRE( 0 == Approx( dZero) );
|
||||
REQUIRE( 0 == Approx( dSmall ).margin( 0.001 ) );
|
||||
REQUIRE( 1.234f == Approx( dMedium ) );
|
||||
REQUIRE( dMedium == Approx( 1.234f ) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Use a custom approx", "[Approx][custom]" ) {
|
||||
double d = 1.23;
|
||||
|
||||
Approx approx = Approx::custom().epsilon( 0.01 );
|
||||
|
||||
REQUIRE( d == approx( 1.23 ) );
|
||||
REQUIRE( d == approx( 1.22 ) );
|
||||
REQUIRE( d == approx( 1.24 ) );
|
||||
REQUIRE( d != approx( 1.25 ) );
|
||||
|
||||
REQUIRE( approx( d ) == 1.23 );
|
||||
REQUIRE( approx( d ) == 1.22 );
|
||||
REQUIRE( approx( d ) == 1.24 );
|
||||
REQUIRE( approx( d ) != 1.25 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Approximate PI", "[Approx][PI]" ) {
|
||||
REQUIRE( divide( 22, 7 ) == Approx( 3.141 ).epsilon( 0.001 ) );
|
||||
REQUIRE( divide( 22, 7 ) != Approx( 3.141 ).epsilon( 0.0001 ) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TEST_CASE( "Absolute margin", "[Approx]" ) {
|
||||
REQUIRE( 104.0 != Approx(100.0) );
|
||||
REQUIRE( 104.0 == Approx(100.0).margin(5) );
|
||||
REQUIRE( 104.0 == Approx(100.0).margin(4) );
|
||||
REQUIRE( 104.0 != Approx(100.0).margin(3) );
|
||||
REQUIRE( 100.3 != Approx(100.0) );
|
||||
REQUIRE( 100.3 == Approx(100.0).margin(0.5) );
|
||||
}
|
||||
|
||||
TEST_CASE("Approx with exactly-representable margin", "[Approx]") {
|
||||
CHECK( 0.25f == Approx(0.0f).margin(0.25f) );
|
||||
|
||||
CHECK( 0.0f == Approx(0.25f).margin(0.25f) );
|
||||
CHECK( 0.5f == Approx(0.25f).margin(0.25f) );
|
||||
|
||||
CHECK( 245.0f == Approx(245.25f).margin(0.25f) );
|
||||
CHECK( 245.5f == Approx(245.25f).margin(0.25f) );
|
||||
}
|
||||
|
||||
TEST_CASE("Approx setters validate their arguments", "[Approx]") {
|
||||
REQUIRE_NOTHROW(Approx(0).margin(0));
|
||||
REQUIRE_NOTHROW(Approx(0).margin(1234656));
|
||||
|
||||
REQUIRE_THROWS_AS(Approx(0).margin(-2), std::domain_error);
|
||||
|
||||
REQUIRE_NOTHROW(Approx(0).epsilon(0));
|
||||
REQUIRE_NOTHROW(Approx(0).epsilon(1));
|
||||
|
||||
REQUIRE_THROWS_AS(Approx(0).epsilon(-0.001), std::domain_error);
|
||||
REQUIRE_THROWS_AS(Approx(0).epsilon(1.0001), std::domain_error);
|
||||
}
|
||||
|
||||
TEST_CASE("Default scale is invisible to comparison", "[Approx]") {
|
||||
REQUIRE(101.000001 != Approx(100).epsilon(0.01));
|
||||
REQUIRE(std::pow(10, -5) != Approx(std::pow(10, -7)));
|
||||
}
|
||||
|
||||
TEST_CASE("Epsilon only applies to Approx's value", "[Approx]") {
|
||||
REQUIRE(101.01 != Approx(100).epsilon(0.01));
|
||||
}
|
||||
|
||||
TEST_CASE("Assorted miscellaneous tests", "[Approx][approvals]") {
|
||||
REQUIRE(INFINITY == Approx(INFINITY));
|
||||
REQUIRE(-INFINITY != Approx(INFINITY));
|
||||
REQUIRE(1 != Approx(INFINITY));
|
||||
REQUIRE(INFINITY != Approx(1));
|
||||
REQUIRE(NAN != Approx(NAN));
|
||||
REQUIRE_FALSE(NAN == Approx(NAN));
|
||||
}
|
||||
|
||||
TEST_CASE( "Comparison with explicitly convertible types", "[Approx]" )
|
||||
{
|
||||
StrongDoubleTypedef td(10.0);
|
||||
|
||||
REQUIRE(td == Approx(10.0));
|
||||
REQUIRE(Approx(10.0) == td);
|
||||
|
||||
REQUIRE(td != Approx(11.0));
|
||||
REQUIRE(Approx(11.0) != td);
|
||||
|
||||
REQUIRE(td <= Approx(10.0));
|
||||
REQUIRE(td <= Approx(11.0));
|
||||
REQUIRE(Approx(10.0) <= td);
|
||||
REQUIRE(Approx(9.0) <= td);
|
||||
|
||||
REQUIRE(td >= Approx(9.0));
|
||||
REQUIRE(td >= Approx(td));
|
||||
REQUIRE(Approx(td) >= td);
|
||||
REQUIRE(Approx(11.0) >= td);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("Approx::operator() is const correct", "[Approx][.approvals]") {
|
||||
const Approx ap = Approx(0.0).margin(0.01);
|
||||
|
||||
// As long as this compiles, the test should be considered passing
|
||||
REQUIRE(1.0 == ap(1.0));
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
static bool itDoesThis() { return true; }
|
||||
|
||||
static bool itDoesThat() { return true; }
|
||||
|
||||
// a trivial fixture example to support SCENARIO_METHOD tests
|
||||
struct Fixture {
|
||||
Fixture(): d_counter( 0 ) {}
|
||||
|
||||
int counter() { return d_counter++; }
|
||||
|
||||
int d_counter;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
SCENARIO("Do that thing with the thing", "[Tags]") {
|
||||
GIVEN("This stuff exists") {
|
||||
// make stuff exist
|
||||
AND_GIVEN("And some assumption") {
|
||||
// Validate assumption
|
||||
WHEN("I do this") {
|
||||
// do this
|
||||
THEN("it should do this") {
|
||||
REQUIRE(itDoesThis());
|
||||
AND_THEN("do that") {
|
||||
REQUIRE(itDoesThat());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO( "Vector resizing affects size and capacity",
|
||||
"[vector][bdd][size][capacity]" ) {
|
||||
GIVEN( "an empty vector" ) {
|
||||
std::vector<int> v;
|
||||
REQUIRE( v.size() == 0 );
|
||||
|
||||
WHEN( "it is made larger" ) {
|
||||
v.resize( 10 );
|
||||
THEN( "the size and capacity go up" ) {
|
||||
REQUIRE( v.size() == 10 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
|
||||
AND_WHEN( "it is made smaller again" ) {
|
||||
v.resize( 5 );
|
||||
THEN(
|
||||
"the size goes down but the capacity stays the same" ) {
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WHEN( "we reserve more space" ) {
|
||||
v.reserve( 10 );
|
||||
THEN( "The capacity is increased but the size remains the same" ) {
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
REQUIRE( v.size() == 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("This is a really long scenario name to see how the list command deals with wrapping",
|
||||
"[very long tags][lots][long][tags][verbose]"
|
||||
"[one very long tag name that should cause line wrapping writing out using the list command]"
|
||||
"[anotherReallyLongTagNameButThisOneHasNoObviousWrapPointsSoShouldSplitWithinAWordUsingADashCharacter]") {
|
||||
GIVEN("A section name that is so long that it cannot fit in a single console width") {
|
||||
WHEN("The test headers are printed as part of the normal running of the scenario") {
|
||||
THEN("The, deliberately very long and overly verbose (you see what I did there?) section names must wrap, along with an indent") {
|
||||
SUCCEED("boo!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO_METHOD(Fixture,
|
||||
"BDD tests requiring Fixtures to provide commonly-accessed data or methods",
|
||||
"[bdd][fixtures]") {
|
||||
const int before(counter());
|
||||
GIVEN("No operations precede me") {
|
||||
REQUIRE(before == 0);
|
||||
WHEN("We get the count") {
|
||||
const int after(counter());
|
||||
THEN("Subsequently values are higher") {
|
||||
REQUIRE(after > before);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include <catch2/benchmark/catch_constructor.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace {
|
||||
std::uint64_t Fibonacci(std::uint64_t number) {
|
||||
return number < 2 ? number : Fibonacci(number - 1) + Fibonacci(number - 2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Benchmark Fibonacci", "[!benchmark]") {
|
||||
CHECK(Fibonacci(0) == 0);
|
||||
// some more asserts..
|
||||
CHECK(Fibonacci(5) == 5);
|
||||
// some more asserts..
|
||||
|
||||
REQUIRE( Fibonacci( 20 ) == 6'765 );
|
||||
BENCHMARK( "Fibonacci 20" ) {
|
||||
return Fibonacci(20);
|
||||
};
|
||||
|
||||
REQUIRE( Fibonacci( 25 ) == 75'025 );
|
||||
BENCHMARK( "Fibonacci 25" ) {
|
||||
return Fibonacci(25);
|
||||
};
|
||||
|
||||
BENCHMARK("Fibonacci 30") {
|
||||
return Fibonacci(30);
|
||||
};
|
||||
|
||||
BENCHMARK("Fibonacci 35") {
|
||||
return Fibonacci(35);
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("Benchmark containers", "[!benchmark]") {
|
||||
static const int size = 100;
|
||||
|
||||
std::vector<int> v;
|
||||
std::map<int, int> m;
|
||||
|
||||
SECTION("without generator") {
|
||||
BENCHMARK("Load up a vector") {
|
||||
v = std::vector<int>();
|
||||
for (int i = 0; i < size; ++i)
|
||||
v.push_back(i);
|
||||
};
|
||||
REQUIRE(v.size() == size);
|
||||
|
||||
// test optimizer control
|
||||
BENCHMARK("Add up a vector's content") {
|
||||
uint64_t add = 0;
|
||||
for (int i = 0; i < size; ++i)
|
||||
add += v[i];
|
||||
return add;
|
||||
};
|
||||
|
||||
BENCHMARK("Load up a map") {
|
||||
m = std::map<int, int>();
|
||||
for (int i = 0; i < size; ++i)
|
||||
m.insert({ i, i + 1 });
|
||||
};
|
||||
REQUIRE(m.size() == size);
|
||||
|
||||
BENCHMARK("Reserved vector") {
|
||||
v = std::vector<int>();
|
||||
v.reserve(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
v.push_back(i);
|
||||
};
|
||||
REQUIRE(v.size() == size);
|
||||
|
||||
BENCHMARK("Resized vector") {
|
||||
v = std::vector<int>();
|
||||
v.resize(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
v[i] = i;
|
||||
};
|
||||
REQUIRE(v.size() == size);
|
||||
|
||||
int array[size] {};
|
||||
BENCHMARK("A fixed size array that should require no allocations") {
|
||||
for (int i = 0; i < size; ++i)
|
||||
array[i] = i;
|
||||
};
|
||||
int sum = 0;
|
||||
for (int val : array)
|
||||
sum += val;
|
||||
REQUIRE(sum > size);
|
||||
|
||||
SECTION("XYZ") {
|
||||
|
||||
BENCHMARK_ADVANCED("Load up vector with chronometer")(Catch::Benchmark::Chronometer meter) {
|
||||
std::vector<int> k;
|
||||
meter.measure([&](int idx) {
|
||||
k = std::vector<int>();
|
||||
for (int i = 0; i < size; ++i)
|
||||
k.push_back(idx);
|
||||
});
|
||||
REQUIRE(k.size() == size);
|
||||
};
|
||||
|
||||
int runs = 0;
|
||||
BENCHMARK("Fill vector indexed", benchmarkIndex) {
|
||||
v = std::vector<int>();
|
||||
v.resize(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
v[i] = benchmarkIndex;
|
||||
runs = benchmarkIndex;
|
||||
};
|
||||
|
||||
for (int val : v) {
|
||||
REQUIRE(val == runs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("with generator") {
|
||||
auto generated = GENERATE(range(0, 10));
|
||||
BENCHMARK("Fill vector generated") {
|
||||
v = std::vector<int>();
|
||||
v.resize(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
v[i] = generated;
|
||||
};
|
||||
for (int val : v) {
|
||||
REQUIRE(val == generated);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("construct and destroy example") {
|
||||
BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter) {
|
||||
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
|
||||
meter.measure([&](int i) { storage[i].construct("thing"); });
|
||||
};
|
||||
|
||||
BENCHMARK_ADVANCED("destroy")(Catch::Benchmark::Chronometer meter) {
|
||||
std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
|
||||
for(auto&& o : storage)
|
||||
o.construct("thing");
|
||||
meter.measure([&](int i) { storage[i].destruct(); });
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Skip benchmark macros", "[!benchmark]") {
|
||||
std::vector<int> v;
|
||||
BENCHMARK("fill vector") {
|
||||
v.emplace_back(1);
|
||||
v.emplace_back(2);
|
||||
v.emplace_back(3);
|
||||
};
|
||||
REQUIRE(v.size() == 0);
|
||||
|
||||
std::size_t counter{0};
|
||||
BENCHMARK_ADVANCED("construct vector")(Catch::Benchmark::Chronometer meter) {
|
||||
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
|
||||
meter.measure([&](int i) { storage[i].construct("thing"); counter++; });
|
||||
};
|
||||
REQUIRE(counter == 0);
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
|
||||
// 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
|
||||
|
||||
#if defined( __GNUC__ ) || defined( __clang__ )
|
||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace {
|
||||
|
||||
class TestClass {
|
||||
std::string s;
|
||||
|
||||
public:
|
||||
TestClass(): s( "hello" ) {}
|
||||
|
||||
void succeedingCase() { REQUIRE( s == "hello" ); }
|
||||
void failingCase() { REQUIRE( s == "world" ); }
|
||||
};
|
||||
|
||||
struct Fixture {
|
||||
Fixture(): m_a( 1 ) {}
|
||||
|
||||
int m_a;
|
||||
};
|
||||
|
||||
struct Persistent_Fixture {
|
||||
mutable int m_a = 0;
|
||||
};
|
||||
|
||||
template <typename T> struct Template_Fixture {
|
||||
Template_Fixture(): m_a( 1 ) {}
|
||||
|
||||
T m_a;
|
||||
};
|
||||
|
||||
template <typename T> struct Template_Fixture_2 {
|
||||
Template_Fixture_2() = default;
|
||||
|
||||
T m_a;
|
||||
};
|
||||
|
||||
template <typename T> struct Template_Foo {
|
||||
size_t size() { return 0; }
|
||||
};
|
||||
|
||||
template <typename T, size_t V> struct Template_Foo_2 {
|
||||
size_t size() { return V; }
|
||||
};
|
||||
|
||||
template <int V> struct Nttp_Fixture { int value = V; };
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
METHOD_AS_TEST_CASE( TestClass::succeedingCase, "A METHOD_AS_TEST_CASE based test run that succeeds", "[class]" )
|
||||
METHOD_AS_TEST_CASE( TestClass::failingCase, "A METHOD_AS_TEST_CASE based test run that fails", "[.][class][failing]" )
|
||||
|
||||
TEST_CASE_METHOD( Fixture, "A TEST_CASE_METHOD based test run that succeeds", "[class]" )
|
||||
{
|
||||
REQUIRE( m_a == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE_PERSISTENT_FIXTURE( Persistent_Fixture, "A TEST_CASE_PERSISTENT_FIXTURE based test run that succeeds", "[class]" )
|
||||
{
|
||||
SECTION( "First partial run" ) {
|
||||
REQUIRE( m_a++ == 0 );
|
||||
}
|
||||
|
||||
SECTION( "Second partial run" ) {
|
||||
REQUIRE( m_a == 1 );
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE_METHOD(Template_Fixture, "A TEMPLATE_TEST_CASE_METHOD based test run that succeeds", "[class][template]", int, float, double) {
|
||||
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE_METHOD_SIG(Nttp_Fixture, "A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds", "[class][template][nttp]",((int V), V), 1, 3, 6) {
|
||||
REQUIRE(Nttp_Fixture<V>::value > 0);
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds","[class][template][product]",(std::vector,Template_Foo),(int,float))
|
||||
{
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 0 );
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds", "[class][template][product][nttp]", ((typename T, size_t S), T, S),(std::array, Template_Foo_2), ((int,2), (float,6)))
|
||||
{
|
||||
REQUIRE(Template_Fixture_2<TestType>{}.m_a.size() >= 2);
|
||||
}
|
||||
|
||||
using MyTypes = std::tuple<int, char, double>;
|
||||
TEMPLATE_LIST_TEST_CASE_METHOD(Template_Fixture, "Template test case method with test types specified inside std::tuple", "[class][template][list]", MyTypes)
|
||||
{
|
||||
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
|
||||
}
|
||||
|
||||
// We should be able to write our tests within a different namespace
|
||||
namespace Inner
|
||||
{
|
||||
TEST_CASE_METHOD( Fixture, "A TEST_CASE_METHOD based test run that fails", "[.][class][failing]" )
|
||||
{
|
||||
REQUIRE( m_a == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE_PERSISTENT_FIXTURE( Persistent_Fixture, "A TEST_CASE_PERSISTENT_FIXTURE based test run that fails", "[.][class][failing]" )
|
||||
{
|
||||
SECTION( "First partial run" ) {
|
||||
REQUIRE( m_a++ == 0 );
|
||||
}
|
||||
|
||||
SECTION( "Second partial run" ) {
|
||||
REQUIRE( m_a == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE_METHOD(Template_Fixture,"A TEMPLATE_TEST_CASE_METHOD based test run that fails", "[.][class][template][failing]", int, float, double)
|
||||
{
|
||||
REQUIRE( Template_Fixture<TestType>::m_a == 2 );
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE_METHOD_SIG(Nttp_Fixture, "A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails", "[.][class][template][nttp][failing]", ((int V), V), 1, 3, 6) {
|
||||
REQUIRE(Nttp_Fixture<V>::value == 0);
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails","[.][class][template][product][failing]",(std::vector,Template_Foo),(int,float))
|
||||
{
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 );
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails", "[.][class][template][product][nttp][failing]", ((typename T, size_t S), T, S), (std::array, Template_Foo_2), ((int, 2), (float, 6)))
|
||||
{
|
||||
REQUIRE(Template_Fixture_2<TestType>{}.m_a.size() < 2);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
// We want a class in nested namespace so we can test JUnit's classname normalization.
|
||||
namespace {
|
||||
namespace A {
|
||||
namespace B {
|
||||
class TestClass {};
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE_METHOD( A::B::TestClass,
|
||||
"A TEST_CASE_METHOD testing junit classname normalization",
|
||||
"[class][approvals]" ) {
|
||||
SUCCEED();
|
||||
}
|
@ -0,0 +1,469 @@
|
||||
|
||||
// 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 <helpers/type_with_lit_0_comparisons.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// Setup for #1403 -- look for global overloads of operator << for classes
|
||||
// in a different namespace.
|
||||
#include <ostream>
|
||||
|
||||
namespace foo {
|
||||
struct helper_1403 {
|
||||
bool operator==(helper_1403) const { return true; }
|
||||
};
|
||||
}
|
||||
|
||||
namespace bar {
|
||||
template <typename... Ts>
|
||||
struct TypeList {};
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic ignored "-Wmissing-declarations"
|
||||
#endif
|
||||
static std::ostream& operator<<(std::ostream& out, foo::helper_1403 const&) {
|
||||
return out << "[1403 helper]";
|
||||
}
|
||||
///////////////////////////////
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
// Comparison operators can return non-booleans.
|
||||
// This is unusual, but should be supported.
|
||||
struct logic_t {
|
||||
logic_t operator< (logic_t) const { return {}; }
|
||||
logic_t operator<=(logic_t) const { return {}; }
|
||||
logic_t operator> (logic_t) const { return {}; }
|
||||
logic_t operator>=(logic_t) const { return {}; }
|
||||
logic_t operator==(logic_t) const { return {}; }
|
||||
logic_t operator!=(logic_t) const { return {}; }
|
||||
explicit operator bool() const { return true; }
|
||||
};
|
||||
|
||||
|
||||
static void throws_int(bool b) {
|
||||
if (b) {
|
||||
throw 1;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool templated_tests(T t) {
|
||||
int a = 3;
|
||||
REQUIRE(a == t);
|
||||
CHECK(a == t);
|
||||
REQUIRE_THROWS(throws_int(true));
|
||||
CHECK_THROWS_AS(throws_int(true), int);
|
||||
REQUIRE_NOTHROW(throws_int(false));
|
||||
REQUIRE_THAT("aaa", Catch::Matchers::EndsWith("aaa"));
|
||||
return true;
|
||||
}
|
||||
|
||||
struct A {};
|
||||
|
||||
static std::ostream &operator<<(std::ostream &o, const A &) { return o << 0; }
|
||||
|
||||
struct B : private A {
|
||||
bool operator==(int) const { return true; }
|
||||
};
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
// Note that because -~GCC~-, this warning cannot be silenced temporarily, by pushing diagnostic stack...
|
||||
// Luckily it is firing in test files and thus can be silenced for the whole file, without losing much.
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
B f();
|
||||
|
||||
std::ostream g();
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
template <typename, typename>
|
||||
struct Fixture_1245 {};
|
||||
|
||||
// This is a minimal example for an issue we have found in 1.7.0
|
||||
struct dummy_809 {
|
||||
int i;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool operator==(const T& val, dummy_809 f) {
|
||||
return val == f.i;
|
||||
}
|
||||
|
||||
TEST_CASE("#809") {
|
||||
dummy_809 f;
|
||||
f.i = 42;
|
||||
REQUIRE(42 == f);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Changes to REQUIRE_THROWS_AS made it stop working in a template in
|
||||
// an unfixable way (as long as C++03 compatibility is being kept).
|
||||
// To prevent these from happening in the future, this needs to compile
|
||||
|
||||
TEST_CASE("#833") {
|
||||
REQUIRE(templated_tests<int>(3));
|
||||
}
|
||||
|
||||
|
||||
// Test containing example where original stream insertable check breaks compilation
|
||||
TEST_CASE("#872") {
|
||||
A dummy;
|
||||
CAPTURE(dummy);
|
||||
B x;
|
||||
REQUIRE (x == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("#1027: Bitfields can be captured") {
|
||||
struct Y {
|
||||
uint32_t v : 1;
|
||||
};
|
||||
Y y{ 0 };
|
||||
REQUIRE(y.v == 0);
|
||||
REQUIRE(0 == y.v);
|
||||
}
|
||||
|
||||
// Comparison operators can return non-booleans.
|
||||
// This is unusual, but should be supported.
|
||||
TEST_CASE("#1147") {
|
||||
logic_t t1, t2;
|
||||
REQUIRE(t1 == t2);
|
||||
REQUIRE(t1 != t2);
|
||||
REQUIRE(t1 < t2);
|
||||
REQUIRE(t1 > t2);
|
||||
REQUIRE(t1 <= t2);
|
||||
REQUIRE(t1 >= t2);
|
||||
}
|
||||
|
||||
// unsigned array
|
||||
TEST_CASE("#1238") {
|
||||
unsigned char uarr[] = "123";
|
||||
CAPTURE(uarr);
|
||||
signed char sarr[] = "456";
|
||||
CAPTURE(sarr);
|
||||
|
||||
REQUIRE(std::memcmp(uarr, "123", sizeof(uarr)) == 0);
|
||||
REQUIRE(std::memcmp(sarr, "456", sizeof(sarr)) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD((Fixture_1245<int, int>), "#1245", "[compilation]") {
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE("#1403", "[compilation]") {
|
||||
::foo::helper_1403 h1, h2;
|
||||
REQUIRE(h1 == h2);
|
||||
}
|
||||
|
||||
TEST_CASE("Optionally static assertions", "[compilation]") {
|
||||
STATIC_REQUIRE( std::is_void<void>::value );
|
||||
STATIC_REQUIRE_FALSE( std::is_void<int>::value );
|
||||
STATIC_CHECK( std::is_void<void>::value );
|
||||
STATIC_CHECK_FALSE( std::is_void<int>::value );
|
||||
}
|
||||
|
||||
TEST_CASE("#1548", "[compilation]") {
|
||||
using namespace bar;
|
||||
REQUIRE(std::is_same<TypeList<int>, TypeList<int>>::value);
|
||||
}
|
||||
|
||||
// #925
|
||||
using signal_t = void (*) (void*);
|
||||
|
||||
struct TestClass {
|
||||
signal_t testMethod_uponComplete_arg = nullptr;
|
||||
};
|
||||
|
||||
namespace utility {
|
||||
inline static void synchronizing_callback( void * ) { }
|
||||
}
|
||||
|
||||
#if defined (_MSC_VER)
|
||||
#pragma warning(push)
|
||||
// The function pointer comparison below triggers warning because of
|
||||
// calling conventions
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
TEST_CASE("#925: comparing function pointer to function address failed to compile", "[!nonportable]" ) {
|
||||
TestClass test;
|
||||
REQUIRE(utility::synchronizing_callback != test.testMethod_uponComplete_arg);
|
||||
}
|
||||
#if defined (_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
TEST_CASE( "#1319: Sections can have description (even if it is not saved",
|
||||
"[compilation]" ) {
|
||||
SECTION( "SectionName", "This is a long form section description" ) {
|
||||
SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Lambdas in assertions") {
|
||||
REQUIRE([]() { return true; }());
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct HasBitOperators {
|
||||
int value;
|
||||
|
||||
friend HasBitOperators operator| (HasBitOperators lhs, HasBitOperators rhs) {
|
||||
return { lhs.value | rhs.value };
|
||||
}
|
||||
friend HasBitOperators operator& (HasBitOperators lhs, HasBitOperators rhs) {
|
||||
return { lhs.value & rhs.value };
|
||||
}
|
||||
friend HasBitOperators operator^ (HasBitOperators lhs, HasBitOperators rhs) {
|
||||
return { lhs.value ^ rhs.value };
|
||||
}
|
||||
explicit operator bool() const {
|
||||
return !!value;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, HasBitOperators val) {
|
||||
out << "Val: " << val.value;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("Assertion macros support bit operators and bool conversions", "[compilation][bitops]") {
|
||||
HasBitOperators lhs{ 1 }, rhs{ 2 };
|
||||
REQUIRE(lhs | rhs);
|
||||
REQUIRE_FALSE(lhs & rhs);
|
||||
REQUIRE(HasBitOperators{ 1 } & HasBitOperators{ 1 });
|
||||
REQUIRE(lhs ^ rhs);
|
||||
REQUIRE_FALSE(lhs ^ lhs);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct ImmovableType {
|
||||
ImmovableType() = default;
|
||||
|
||||
ImmovableType(ImmovableType const&) = delete;
|
||||
ImmovableType& operator=(ImmovableType const&) = delete;
|
||||
ImmovableType(ImmovableType&&) = delete;
|
||||
ImmovableType& operator=(ImmovableType&&) = delete;
|
||||
|
||||
friend bool operator==(ImmovableType const&, ImmovableType const&) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("Immovable types are supported in basic assertions", "[compilation][.approvals]") {
|
||||
REQUIRE(ImmovableType{} == ImmovableType{});
|
||||
}
|
||||
|
||||
namespace adl {
|
||||
|
||||
struct always_true {
|
||||
explicit operator bool() const { return true; }
|
||||
};
|
||||
|
||||
#define COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(op) \
|
||||
template <class T, class U> \
|
||||
auto operator op (T&&, U&&) { \
|
||||
return always_true{}; \
|
||||
}
|
||||
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(==)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(!=)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(<)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(>)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(<=)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(>=)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(|)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(&)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(^)
|
||||
|
||||
#undef COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("ADL universal operators don't hijack expression deconstruction", "[compilation][.approvals]") {
|
||||
REQUIRE(adl::always_true{});
|
||||
REQUIRE(0 == adl::always_true{});
|
||||
REQUIRE(0 != adl::always_true{});
|
||||
REQUIRE(0 < adl::always_true{});
|
||||
REQUIRE(0 > adl::always_true{});
|
||||
REQUIRE(0 <= adl::always_true{});
|
||||
REQUIRE(0 >= adl::always_true{});
|
||||
REQUIRE(0 | adl::always_true{});
|
||||
REQUIRE(0 & adl::always_true{});
|
||||
REQUIRE(0 ^ adl::always_true{});
|
||||
}
|
||||
|
||||
TEST_CASE( "#2555 - types that can only be compared with 0 literal implemented as pointer conversion are supported",
|
||||
"[compilation][approvals]" ) {
|
||||
REQUIRE( TypeWithLit0Comparisons{} < 0 );
|
||||
REQUIRE_FALSE( 0 < TypeWithLit0Comparisons{} );
|
||||
REQUIRE( TypeWithLit0Comparisons{} <= 0 );
|
||||
REQUIRE_FALSE( 0 <= TypeWithLit0Comparisons{} );
|
||||
|
||||
REQUIRE( TypeWithLit0Comparisons{} > 0 );
|
||||
REQUIRE_FALSE( 0 > TypeWithLit0Comparisons{} );
|
||||
REQUIRE( TypeWithLit0Comparisons{} >= 0 );
|
||||
REQUIRE_FALSE( 0 >= TypeWithLit0Comparisons{} );
|
||||
|
||||
REQUIRE( TypeWithLit0Comparisons{} == 0 );
|
||||
REQUIRE_FALSE( 0 == TypeWithLit0Comparisons{} );
|
||||
REQUIRE( TypeWithLit0Comparisons{} != 0 );
|
||||
REQUIRE_FALSE( 0 != TypeWithLit0Comparisons{} );
|
||||
}
|
||||
|
||||
// These tests require `consteval` to propagate through `constexpr` calls
|
||||
// which is a late DR against C++20.
|
||||
#if defined( CATCH_CPP20_OR_GREATER ) && defined( __cpp_consteval ) && \
|
||||
__cpp_consteval >= 202211L
|
||||
// Can't have internal linkage to avoid warnings
|
||||
void ZeroLiteralErrorFunc();
|
||||
namespace {
|
||||
struct ZeroLiteralConsteval {
|
||||
template <class T, std::enable_if_t<std::is_same_v<T, int>, int> = 0>
|
||||
consteval ZeroLiteralConsteval( T zero ) noexcept {
|
||||
if ( zero != 0 ) { ZeroLiteralErrorFunc(); }
|
||||
}
|
||||
};
|
||||
|
||||
// Should only be constructible from literal 0. Uses the propagating
|
||||
// consteval constructor trick (currently used by MSVC, might be used
|
||||
// by libc++ in the future as well).
|
||||
struct TypeWithConstevalLit0Comparison {
|
||||
# define DEFINE_COMP_OP( op ) \
|
||||
constexpr friend bool operator op( TypeWithConstevalLit0Comparison, \
|
||||
ZeroLiteralConsteval ) { \
|
||||
return true; \
|
||||
} \
|
||||
constexpr friend bool operator op( ZeroLiteralConsteval, \
|
||||
TypeWithConstevalLit0Comparison ) { \
|
||||
return false; \
|
||||
} \
|
||||
/* std::orderings only have these for ==, but we add them for all \
|
||||
operators so we can test all overloads for decomposer */ \
|
||||
constexpr friend bool operator op( TypeWithConstevalLit0Comparison, \
|
||||
TypeWithConstevalLit0Comparison ) { \
|
||||
return true; \
|
||||
}
|
||||
|
||||
DEFINE_COMP_OP( < )
|
||||
DEFINE_COMP_OP( <= )
|
||||
DEFINE_COMP_OP( > )
|
||||
DEFINE_COMP_OP( >= )
|
||||
DEFINE_COMP_OP( == )
|
||||
DEFINE_COMP_OP( != )
|
||||
|
||||
#undef DEFINE_COMP_OP
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Catch {
|
||||
template <>
|
||||
struct capture_by_value<TypeWithConstevalLit0Comparison> : std::true_type {};
|
||||
}
|
||||
|
||||
TEST_CASE( "#2555 - types that can only be compared with 0 literal implemented as consteval check are supported",
|
||||
"[compilation][approvals]" ) {
|
||||
REQUIRE( TypeWithConstevalLit0Comparison{} < 0 );
|
||||
REQUIRE_FALSE( 0 < TypeWithConstevalLit0Comparison{} );
|
||||
REQUIRE( TypeWithConstevalLit0Comparison{} <= 0 );
|
||||
REQUIRE_FALSE( 0 <= TypeWithConstevalLit0Comparison{} );
|
||||
|
||||
REQUIRE( TypeWithConstevalLit0Comparison{} > 0 );
|
||||
REQUIRE_FALSE( 0 > TypeWithConstevalLit0Comparison{} );
|
||||
REQUIRE( TypeWithConstevalLit0Comparison{} >= 0 );
|
||||
REQUIRE_FALSE( 0 >= TypeWithConstevalLit0Comparison{} );
|
||||
|
||||
REQUIRE( TypeWithConstevalLit0Comparison{} == 0 );
|
||||
REQUIRE_FALSE( 0 == TypeWithConstevalLit0Comparison{} );
|
||||
REQUIRE( TypeWithConstevalLit0Comparison{} != 0 );
|
||||
REQUIRE_FALSE( 0 != TypeWithConstevalLit0Comparison{} );
|
||||
}
|
||||
|
||||
// We check all comparison ops to test, even though orderings, the primary
|
||||
// motivation for this functionality, only have self-comparison (and thus
|
||||
// have the ambiguity issue) for `==` and `!=`.
|
||||
TEST_CASE( "Comparing const instances of type registered with capture_by_value",
|
||||
"[regression][approvals][compilation]" ) {
|
||||
SECTION("Type with consteval-int constructor") {
|
||||
auto const const_Lit0Type_1 = TypeWithConstevalLit0Comparison{};
|
||||
auto const const_Lit0Type_2 = TypeWithConstevalLit0Comparison{};
|
||||
REQUIRE( const_Lit0Type_1 == const_Lit0Type_2 );
|
||||
REQUIRE( const_Lit0Type_1 <= const_Lit0Type_2 );
|
||||
REQUIRE( const_Lit0Type_1 < const_Lit0Type_2 );
|
||||
REQUIRE( const_Lit0Type_1 >= const_Lit0Type_2 );
|
||||
REQUIRE( const_Lit0Type_1 > const_Lit0Type_2 );
|
||||
REQUIRE( const_Lit0Type_1 != const_Lit0Type_2 );
|
||||
}
|
||||
SECTION("Type with constexpr-int constructor") {
|
||||
auto const const_Lit0Type_1 = TypeWithLit0Comparisons{};
|
||||
auto const const_Lit0Type_2 = TypeWithLit0Comparisons{};
|
||||
REQUIRE( const_Lit0Type_1 == const_Lit0Type_2 );
|
||||
REQUIRE( const_Lit0Type_1 <= const_Lit0Type_2 );
|
||||
REQUIRE( const_Lit0Type_1 < const_Lit0Type_2 );
|
||||
REQUIRE( const_Lit0Type_1 >= const_Lit0Type_2 );
|
||||
REQUIRE( const_Lit0Type_1 > const_Lit0Type_2 );
|
||||
REQUIRE( const_Lit0Type_1 != const_Lit0Type_2 );
|
||||
}
|
||||
}
|
||||
|
||||
#endif // C++20 consteval
|
||||
|
||||
|
||||
namespace {
|
||||
struct MultipleImplicitConstructors {
|
||||
MultipleImplicitConstructors( double ) {}
|
||||
MultipleImplicitConstructors( int64_t ) {}
|
||||
bool operator==( MultipleImplicitConstructors ) const { return true; }
|
||||
bool operator!=( MultipleImplicitConstructors ) const { return true; }
|
||||
bool operator<( MultipleImplicitConstructors ) const { return true; }
|
||||
bool operator<=( MultipleImplicitConstructors ) const { return true; }
|
||||
bool operator>( MultipleImplicitConstructors ) const { return true; }
|
||||
bool operator>=( MultipleImplicitConstructors ) const { return true; }
|
||||
};
|
||||
}
|
||||
TEST_CASE("#2571 - tests compile types that have multiple implicit constructors from lit 0",
|
||||
"[compilation][approvals]") {
|
||||
MultipleImplicitConstructors mic1( 0.0 );
|
||||
MultipleImplicitConstructors mic2( 0.0 );
|
||||
REQUIRE( mic1 == mic2 );
|
||||
REQUIRE( mic1 != mic2 );
|
||||
REQUIRE( mic1 < mic2 );
|
||||
REQUIRE( mic1 <= mic2 );
|
||||
REQUIRE( mic1 > mic2 );
|
||||
REQUIRE( mic1 >= mic2 );
|
||||
}
|
||||
|
||||
#if defined( CATCH_CONFIG_CPP20_COMPARE_OVERLOADS )
|
||||
// This test does not test all the related codepaths, but it is the original
|
||||
// reproducer
|
||||
TEST_CASE( "Comparing const std::weak_ordering instances must compile",
|
||||
"[compilation][approvals][regression]" ) {
|
||||
auto const const_ordering_1 = std::weak_ordering::less;
|
||||
auto const const_ordering_2 = std::weak_ordering::less;
|
||||
auto plain_ordering_1 = std::weak_ordering::less;
|
||||
REQUIRE( const_ordering_1 == plain_ordering_1 );
|
||||
REQUIRE( const_ordering_1 == const_ordering_2 );
|
||||
REQUIRE( plain_ordering_1 == const_ordering_1 );
|
||||
}
|
||||
#endif
|
@ -0,0 +1,334 @@
|
||||
|
||||
// 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
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wpadded"
|
||||
// Wdouble-promotion is not supported until 3.8
|
||||
# if (__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ > 7)
|
||||
# pragma clang diagnostic ignored "-Wdouble-promotion"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
using Catch::Approx;
|
||||
|
||||
#include <string>
|
||||
#include <limits>
|
||||
#include <cstdint>
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestData {
|
||||
int int_seven = 7;
|
||||
std::string str_hello = "hello";
|
||||
float float_nine_point_one = 9.1f;
|
||||
double double_pi = 3.1415926535;
|
||||
};
|
||||
|
||||
static const char* returnsConstNull() { return nullptr; }
|
||||
static char* returnsNull() { return nullptr; }
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
// The "failing" tests all use the CHECK macro, which continues if the specific test fails.
|
||||
// This allows us to see all results, even if an earlier check fails
|
||||
|
||||
// Equality tests
|
||||
TEST_CASE( "Equality checks that should succeed" )
|
||||
{
|
||||
TestData data;
|
||||
|
||||
REQUIRE( data.int_seven == 7 );
|
||||
REQUIRE( data.float_nine_point_one == Approx( 9.1f ) );
|
||||
REQUIRE( data.double_pi == Approx( 3.1415926535 ) );
|
||||
REQUIRE( data.str_hello == "hello" );
|
||||
REQUIRE( "hello" == data.str_hello );
|
||||
REQUIRE( data.str_hello.size() == 5 );
|
||||
|
||||
double x = 1.1 + 0.1 + 0.1;
|
||||
REQUIRE( x == Approx( 1.3 ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "Equality checks that should fail", "[.][failing][!mayfail]" )
|
||||
{
|
||||
TestData data;
|
||||
|
||||
CHECK( data.int_seven == 6 );
|
||||
CHECK( data.int_seven == 8 );
|
||||
CHECK( data.int_seven == 0 );
|
||||
CHECK( data.float_nine_point_one == Approx( 9.11f ) );
|
||||
CHECK( data.float_nine_point_one == Approx( 9.0f ) );
|
||||
CHECK( data.float_nine_point_one == Approx( 1 ) );
|
||||
CHECK( data.float_nine_point_one == Approx( 0 ) );
|
||||
CHECK( data.double_pi == Approx( 3.1415 ) );
|
||||
CHECK( data.str_hello == "goodbye" );
|
||||
CHECK( data.str_hello == "hell" );
|
||||
CHECK( data.str_hello == "hello1" );
|
||||
CHECK( data.str_hello.size() == 6 );
|
||||
|
||||
double x = 1.1 + 0.1 + 0.1;
|
||||
CHECK( x == Approx( 1.301 ) );
|
||||
}
|
||||
|
||||
// Needed to test junit reporter's handling of mayfail test cases and sections
|
||||
TEST_CASE("Mayfail test case with nested sections", "[!mayfail]") {
|
||||
SECTION("A") {
|
||||
SECTION("1") { FAIL(); }
|
||||
SECTION("2") { FAIL(); }
|
||||
}
|
||||
SECTION("B") {
|
||||
SECTION("1") { FAIL(); }
|
||||
SECTION("2") { FAIL(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "Inequality checks that should succeed" )
|
||||
{
|
||||
TestData data;
|
||||
|
||||
REQUIRE( data.int_seven != 6 );
|
||||
REQUIRE( data.int_seven != 8 );
|
||||
REQUIRE( data.float_nine_point_one != Approx( 9.11f ) );
|
||||
REQUIRE( data.float_nine_point_one != Approx( 9.0f ) );
|
||||
REQUIRE( data.float_nine_point_one != Approx( 1 ) );
|
||||
REQUIRE( data.float_nine_point_one != Approx( 0 ) );
|
||||
REQUIRE( data.double_pi != Approx( 3.1415 ) );
|
||||
REQUIRE( data.str_hello != "goodbye" );
|
||||
REQUIRE( data.str_hello != "hell" );
|
||||
REQUIRE( data.str_hello != "hello1" );
|
||||
REQUIRE( data.str_hello.size() != 6 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Inequality checks that should fail", "[.][failing][!shouldfail]" )
|
||||
{
|
||||
TestData data;
|
||||
|
||||
CHECK( data.int_seven != 7 );
|
||||
CHECK( data.float_nine_point_one != Approx( 9.1f ) );
|
||||
CHECK( data.double_pi != Approx( 3.1415926535 ) );
|
||||
CHECK( data.str_hello != "hello" );
|
||||
CHECK( data.str_hello.size() != 5 );
|
||||
}
|
||||
|
||||
// Ordering comparison tests
|
||||
TEST_CASE( "Ordering comparison checks that should succeed" )
|
||||
{
|
||||
TestData data;
|
||||
|
||||
REQUIRE( data.int_seven < 8 );
|
||||
REQUIRE( data.int_seven > 6 );
|
||||
REQUIRE( data.int_seven > 0 );
|
||||
REQUIRE( data.int_seven > -1 );
|
||||
|
||||
REQUIRE( data.int_seven >= 7 );
|
||||
REQUIRE( data.int_seven >= 6 );
|
||||
REQUIRE( data.int_seven <= 7 );
|
||||
REQUIRE( data.int_seven <= 8 );
|
||||
|
||||
REQUIRE( data.float_nine_point_one > 9 );
|
||||
REQUIRE( data.float_nine_point_one < 10 );
|
||||
REQUIRE( data.float_nine_point_one < 9.2 );
|
||||
|
||||
REQUIRE( data.str_hello <= "hello" );
|
||||
REQUIRE( data.str_hello >= "hello" );
|
||||
|
||||
REQUIRE( data.str_hello < "hellp" );
|
||||
REQUIRE( data.str_hello < "zebra" );
|
||||
REQUIRE( data.str_hello > "hellm" );
|
||||
REQUIRE( data.str_hello > "a" );
|
||||
}
|
||||
|
||||
TEST_CASE( "Ordering comparison checks that should fail", "[.][failing]" )
|
||||
{
|
||||
TestData data;
|
||||
|
||||
CHECK( data.int_seven > 7 );
|
||||
CHECK( data.int_seven < 7 );
|
||||
CHECK( data.int_seven > 8 );
|
||||
CHECK( data.int_seven < 6 );
|
||||
CHECK( data.int_seven < 0 );
|
||||
CHECK( data.int_seven < -1 );
|
||||
|
||||
CHECK( data.int_seven >= 8 );
|
||||
CHECK( data.int_seven <= 6 );
|
||||
|
||||
CHECK( data.float_nine_point_one < 9 );
|
||||
CHECK( data.float_nine_point_one > 10 );
|
||||
CHECK( data.float_nine_point_one > 9.2 );
|
||||
|
||||
CHECK( data.str_hello > "hello" );
|
||||
CHECK( data.str_hello < "hello" );
|
||||
CHECK( data.str_hello > "hellp" );
|
||||
CHECK( data.str_hello > "z" );
|
||||
CHECK( data.str_hello < "hellm" );
|
||||
CHECK( data.str_hello < "a" );
|
||||
|
||||
CHECK( data.str_hello >= "z" );
|
||||
CHECK( data.str_hello <= "a" );
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
// Comparisons with int literals
|
||||
TEST_CASE( "Comparisons with int literals don't warn when mixing signed/ unsigned" )
|
||||
{
|
||||
int i = 1;
|
||||
unsigned int ui = 2;
|
||||
long l = 3;
|
||||
unsigned long ul = 4;
|
||||
char c = 5;
|
||||
unsigned char uc = 6;
|
||||
|
||||
REQUIRE( i == 1 );
|
||||
REQUIRE( ui == 2 );
|
||||
REQUIRE( l == 3 );
|
||||
REQUIRE( ul == 4 );
|
||||
REQUIRE( c == 5 );
|
||||
REQUIRE( uc == 6 );
|
||||
|
||||
REQUIRE( 1 == i );
|
||||
REQUIRE( 2 == ui );
|
||||
REQUIRE( 3 == l );
|
||||
REQUIRE( 4 == ul );
|
||||
REQUIRE( 5 == c );
|
||||
REQUIRE( 6 == uc );
|
||||
|
||||
REQUIRE( (std::numeric_limits<uint32_t>::max)() > ul );
|
||||
}
|
||||
|
||||
// Disable warnings about sign conversions for the next two tests
|
||||
// (as we are deliberately invoking them)
|
||||
// - Currently only disabled for GCC/ LLVM. Should add VC++ too
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
|
||||
#endif
|
||||
|
||||
TEST_CASE( "comparisons between int variables" )
|
||||
{
|
||||
long long_var = 1L;
|
||||
unsigned char unsigned_char_var = 1;
|
||||
unsigned short unsigned_short_var = 1;
|
||||
unsigned int unsigned_int_var = 1;
|
||||
unsigned long unsigned_long_var = 1L;
|
||||
|
||||
REQUIRE( long_var == unsigned_char_var );
|
||||
REQUIRE( long_var == unsigned_short_var );
|
||||
REQUIRE( long_var == unsigned_int_var );
|
||||
REQUIRE( long_var == unsigned_long_var );
|
||||
}
|
||||
|
||||
TEST_CASE( "comparisons between const int variables" )
|
||||
{
|
||||
const unsigned char unsigned_char_var = 1;
|
||||
const unsigned short unsigned_short_var = 1;
|
||||
const unsigned int unsigned_int_var = 1;
|
||||
const unsigned long unsigned_long_var = 1L;
|
||||
|
||||
REQUIRE( unsigned_char_var == 1 );
|
||||
REQUIRE( unsigned_short_var == 1 );
|
||||
REQUIRE( unsigned_int_var == 1 );
|
||||
REQUIRE( unsigned_long_var == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Comparisons between unsigned ints and negative signed ints match c++ standard behaviour" )
|
||||
{
|
||||
CHECK( ( -1 > 2u ) );
|
||||
CHECK( -1 > 2u );
|
||||
|
||||
CHECK( ( 2u < -1 ) );
|
||||
CHECK( 2u < -1 );
|
||||
|
||||
const int minInt = (std::numeric_limits<int>::min)();
|
||||
CHECK( ( minInt > 2u ) );
|
||||
CHECK( minInt > 2u );
|
||||
}
|
||||
|
||||
TEST_CASE( "Comparisons between ints where one side is computed" )
|
||||
{
|
||||
CHECK( 54 == 6*9 );
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
TEST_CASE( "Pointers can be compared to null" )
|
||||
{
|
||||
TestData* p = nullptr;
|
||||
TestData* pNULL = nullptr;
|
||||
|
||||
REQUIRE( p == nullptr );
|
||||
REQUIRE( p == pNULL );
|
||||
|
||||
TestData data;
|
||||
p = &data;
|
||||
|
||||
REQUIRE( p != nullptr );
|
||||
|
||||
const TestData* cp = p;
|
||||
REQUIRE( cp != nullptr );
|
||||
|
||||
const TestData* const cpc = p;
|
||||
REQUIRE( cpc != nullptr );
|
||||
|
||||
REQUIRE( returnsNull() == nullptr );
|
||||
REQUIRE( returnsConstNull() == nullptr );
|
||||
|
||||
REQUIRE( nullptr != p );
|
||||
}
|
||||
|
||||
// Not (!) tests
|
||||
// The problem with the ! operator is that it has right-to-left associativity.
|
||||
// This means we can't isolate it when we decompose. The simple REQUIRE( !false ) form, therefore,
|
||||
// cannot have the operand value extracted. The test will work correctly, and the situation
|
||||
// is detected and a warning issued.
|
||||
// An alternative form of the macros (CHECK_FALSE and REQUIRE_FALSE) can be used instead to capture
|
||||
// the operand value.
|
||||
TEST_CASE( "'Not' checks that should succeed" )
|
||||
{
|
||||
bool falseValue = false;
|
||||
|
||||
REQUIRE( false == false );
|
||||
REQUIRE( true == true );
|
||||
REQUIRE( !false );
|
||||
REQUIRE_FALSE( false );
|
||||
|
||||
REQUIRE( !falseValue );
|
||||
REQUIRE_FALSE( falseValue );
|
||||
|
||||
REQUIRE( !(1 == 2) );
|
||||
REQUIRE_FALSE( 1 == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE( "'Not' checks that should fail", "[.][failing]" )
|
||||
{
|
||||
bool trueValue = true;
|
||||
|
||||
CHECK( false != false );
|
||||
CHECK( true != true );
|
||||
CHECK( !true );
|
||||
CHECK_FALSE( true );
|
||||
|
||||
CHECK( !trueValue );
|
||||
CHECK_FALSE( trueValue );
|
||||
|
||||
CHECK( !(1 == 1) );
|
||||
CHECK_FALSE( 1 == 1 );
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
|
||||
namespace {
|
||||
|
||||
struct truthy {
|
||||
truthy(bool b):m_value(b){}
|
||||
operator bool() const {
|
||||
return false;
|
||||
}
|
||||
bool m_value;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, truthy) {
|
||||
o << "Hey, its truthy!";
|
||||
return o;
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
TEST_CASE( "Reconstruction should be based on stringification: #914" , "[Decomposition][failing][.]") {
|
||||
CHECK(truthy(false));
|
||||
}
|
||||
|
||||
TEST_CASE("#1005: Comparing pointer to int and long (NULL can be either on various systems)", "[Decomposition][approvals]") {
|
||||
FILE* fptr = nullptr;
|
||||
REQUIRE( fptr == 0 );
|
||||
REQUIRE_FALSE( fptr != 0 );
|
||||
REQUIRE( fptr == 0l );
|
||||
REQUIRE_FALSE( fptr != 0l );
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_enum_values_registry.hpp>
|
||||
|
||||
|
||||
namespace {
|
||||
// Enum without user-provided stream operator
|
||||
enum Enum1 { Enum1Value0, Enum1Value1 };
|
||||
|
||||
// Enum with user-provided stream operator
|
||||
enum Enum2 { Enum2Value0, Enum2Value1 };
|
||||
|
||||
std::ostream& operator<<( std::ostream& os, Enum2 v ) {
|
||||
return os << "E2{" << static_cast<int>(v) << "}";
|
||||
}
|
||||
} // end anonymous namespace
|
||||
|
||||
TEST_CASE( "toString(enum)", "[toString][enum]" ) {
|
||||
Enum1 e0 = Enum1Value0;
|
||||
CHECK( ::Catch::Detail::stringify(e0) == "0" );
|
||||
Enum1 e1 = Enum1Value1;
|
||||
CHECK( ::Catch::Detail::stringify(e1) == "1" );
|
||||
}
|
||||
|
||||
TEST_CASE( "toString(enum w/operator<<)", "[toString][enum]" ) {
|
||||
Enum2 e0 = Enum2Value0;
|
||||
CHECK( ::Catch::Detail::stringify(e0) == "E2{0}" );
|
||||
Enum2 e1 = Enum2Value1;
|
||||
CHECK( ::Catch::Detail::stringify(e1) == "E2{1}" );
|
||||
}
|
||||
|
||||
// Enum class without user-provided stream operator
|
||||
namespace {
|
||||
enum class EnumClass1 { EnumClass1Value0, EnumClass1Value1 };
|
||||
|
||||
// Enum class with user-provided stream operator
|
||||
enum class EnumClass2 { EnumClass2Value0, EnumClass2Value1 };
|
||||
|
||||
std::ostream& operator<<( std::ostream& os, EnumClass2 e2 ) {
|
||||
switch( static_cast<int>( e2 ) ) {
|
||||
case static_cast<int>( EnumClass2::EnumClass2Value0 ):
|
||||
return os << "E2/V0";
|
||||
case static_cast<int>( EnumClass2::EnumClass2Value1 ):
|
||||
return os << "E2/V1";
|
||||
default:
|
||||
return os << "Unknown enum value " << static_cast<int>( e2 );
|
||||
}
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
TEST_CASE( "toString(enum class)", "[toString][enum][enumClass]" ) {
|
||||
EnumClass1 e0 = EnumClass1::EnumClass1Value0;
|
||||
CHECK( ::Catch::Detail::stringify(e0) == "0" );
|
||||
EnumClass1 e1 = EnumClass1::EnumClass1Value1;
|
||||
CHECK( ::Catch::Detail::stringify(e1) == "1" );
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "toString(enum class w/operator<<)", "[toString][enum][enumClass]" ) {
|
||||
EnumClass2 e0 = EnumClass2::EnumClass2Value0;
|
||||
CHECK( ::Catch::Detail::stringify(e0) == "E2/V0" );
|
||||
EnumClass2 e1 = EnumClass2::EnumClass2Value1;
|
||||
CHECK( ::Catch::Detail::stringify(e1) == "E2/V1" );
|
||||
|
||||
auto e3 = static_cast<EnumClass2>(10);
|
||||
CHECK( ::Catch::Detail::stringify(e3) == "Unknown enum value 10" );
|
||||
}
|
||||
|
||||
enum class EnumClass3 { Value1, Value2, Value3, Value4 };
|
||||
|
||||
CATCH_REGISTER_ENUM( EnumClass3, EnumClass3::Value1, EnumClass3::Value2, EnumClass3::Value3 )
|
||||
|
||||
|
||||
TEST_CASE( "Enums can quickly have stringification enabled using REGISTER_ENUM" ) {
|
||||
using Catch::Detail::stringify;
|
||||
REQUIRE( stringify( EnumClass3::Value1 ) == "Value1" );
|
||||
REQUIRE( stringify( EnumClass3::Value2 ) == "Value2" );
|
||||
REQUIRE( stringify( EnumClass3::Value3 ) == "Value3" );
|
||||
REQUIRE( stringify( EnumClass3::Value4 ) == "{** unexpected enum value **}" );
|
||||
|
||||
EnumClass3 ec3 = EnumClass3::Value2;
|
||||
REQUIRE( stringify( ec3 ) == "Value2" );
|
||||
}
|
||||
|
||||
namespace Bikeshed {
|
||||
enum class Colours { Red, Green, Blue };
|
||||
}
|
||||
|
||||
// Important!: This macro must appear at top level scope - not inside a namespace
|
||||
// You can fully qualify the names, or use a using if you prefer
|
||||
CATCH_REGISTER_ENUM( Bikeshed::Colours,
|
||||
Bikeshed::Colours::Red,
|
||||
Bikeshed::Colours::Green,
|
||||
Bikeshed::Colours::Blue )
|
||||
|
||||
TEST_CASE( "Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM" ) {
|
||||
using Catch::Detail::stringify;
|
||||
REQUIRE( stringify( Bikeshed::Colours::Red ) == "Red" );
|
||||
REQUIRE( stringify( Bikeshed::Colours::Blue ) == "Blue" );
|
||||
}
|
@ -0,0 +1,204 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_translate_exception.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4702) // Unreachable code -- unconditional throws and so on
|
||||
#endif
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
#pragma clang diagnostic ignored "-Wmissing-noreturn"
|
||||
#pragma clang diagnostic ignored "-Wunreachable-code-return"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
int thisThrows() {
|
||||
throw std::domain_error("expected exception");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int thisDoesntThrow() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
class CustomException {
|
||||
public:
|
||||
explicit CustomException(const std::string& msg)
|
||||
: m_msg(msg) {}
|
||||
|
||||
std::string const& getMessage() const {
|
||||
return m_msg;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_msg;
|
||||
};
|
||||
|
||||
class CustomStdException : public std::exception {
|
||||
public:
|
||||
explicit CustomStdException(const std::string& msg)
|
||||
: m_msg(msg) {}
|
||||
~CustomStdException() noexcept override = default;
|
||||
|
||||
CustomStdException( CustomStdException const& ) = default;
|
||||
CustomStdException& operator=( CustomStdException const& ) = default;
|
||||
|
||||
std::string const& getMessage() const {
|
||||
return m_msg;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_msg;
|
||||
};
|
||||
|
||||
[[noreturn]] void throwCustom() {
|
||||
throw CustomException("custom exception - not std");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE( "When checked exceptions are thrown they can be expected or unexpected", "[!throws]" ) {
|
||||
REQUIRE_THROWS_AS( thisThrows(), std::domain_error );
|
||||
REQUIRE_NOTHROW( thisDoesntThrow() );
|
||||
REQUIRE_THROWS( thisThrows() );
|
||||
}
|
||||
|
||||
TEST_CASE( "Expected exceptions that don't throw or unexpected exceptions fail the test", "[.][failing][!throws]" ) {
|
||||
CHECK_THROWS_AS( thisThrows(), std::string );
|
||||
CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error );
|
||||
CHECK_NOTHROW( thisThrows() );
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown directly they are always failures", "[.][failing][!throws]" ) {
|
||||
throw std::domain_error( "unexpected exception" );
|
||||
}
|
||||
|
||||
TEST_CASE( "An unchecked exception reports the line of the last assertion", "[.][failing][!throws]" ) {
|
||||
CHECK( 1 == 1 );
|
||||
throw std::domain_error( "unexpected exception" );
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown from sections they are always failures", "[.][failing][!throws]" ) {
|
||||
SECTION( "section name" ) {
|
||||
throw std::domain_error("unexpected exception");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown from functions they are always failures", "[.][failing][!throws]" ) {
|
||||
CHECK( thisThrows() == 0 );
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown during a REQUIRE the test should abort fail", "[.][failing][!throws]" ) {
|
||||
REQUIRE( thisThrows() == 0 );
|
||||
FAIL( "This should never happen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown during a CHECK the test should continue", "[.][failing][!throws]" ) {
|
||||
try {
|
||||
CHECK(thisThrows() == 0);
|
||||
}
|
||||
catch(...) {
|
||||
FAIL( "This should never happen" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown, but caught, they do not affect the test", "[!throws]" ) {
|
||||
try {
|
||||
throw std::domain_error( "unexpected exception" );
|
||||
}
|
||||
catch(...) {} // NOLINT(bugprone-empty-catch)
|
||||
}
|
||||
|
||||
|
||||
CATCH_TRANSLATE_EXCEPTION( CustomException const& ex ) {
|
||||
return ex.getMessage();
|
||||
}
|
||||
|
||||
CATCH_TRANSLATE_EXCEPTION( CustomStdException const& ex ) {
|
||||
return ex.getMessage();
|
||||
}
|
||||
|
||||
CATCH_TRANSLATE_EXCEPTION( double const& ex ) {
|
||||
return Catch::Detail::stringify( ex );
|
||||
}
|
||||
|
||||
TEST_CASE("Non-std exceptions can be translated", "[.][failing][!throws]" ) {
|
||||
throw CustomException( "custom exception" );
|
||||
}
|
||||
|
||||
TEST_CASE("Custom std-exceptions can be custom translated", "[.][failing][!throws]" ) {
|
||||
throw CustomStdException( "custom std exception" );
|
||||
}
|
||||
|
||||
TEST_CASE( "Custom exceptions can be translated when testing for nothrow", "[.][failing][!throws]" ) {
|
||||
REQUIRE_NOTHROW( throwCustom() );
|
||||
}
|
||||
|
||||
TEST_CASE( "Custom exceptions can be translated when testing for throwing as something else", "[.][failing][!throws]" ) {
|
||||
REQUIRE_THROWS_AS( throwCustom(), std::exception );
|
||||
}
|
||||
|
||||
TEST_CASE( "Unexpected exceptions can be translated", "[.][failing][!throws]" ) {
|
||||
throw double( 3.14 ); // NOLINT(readability-redundant-casting): the type is important here, so we want to be explicit
|
||||
}
|
||||
|
||||
TEST_CASE("Thrown string literals are translated", "[.][failing][!throws]") {
|
||||
throw "For some reason someone is throwing a string literal!";
|
||||
}
|
||||
|
||||
TEST_CASE("thrown std::strings are translated", "[.][failing][!throws]") {
|
||||
throw std::string{ "Why would you throw a std::string?" };
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "Exception messages can be tested for", "[!throws]" ) {
|
||||
using namespace Catch::Matchers;
|
||||
SECTION( "exact match" )
|
||||
REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
|
||||
SECTION( "different case" )
|
||||
REQUIRE_THROWS_WITH( thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) );
|
||||
SECTION( "wildcarded" ) {
|
||||
REQUIRE_THROWS_WITH( thisThrows(), StartsWith( "expected" ) );
|
||||
REQUIRE_THROWS_WITH( thisThrows(), EndsWith( "exception" ) );
|
||||
REQUIRE_THROWS_WITH( thisThrows(), ContainsSubstring( "except" ) );
|
||||
REQUIRE_THROWS_WITH( thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Mismatching exception messages failing the test", "[.][failing][!throws]" ) {
|
||||
REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
|
||||
REQUIRE_THROWS_WITH( thisThrows(), "should fail" );
|
||||
REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
|
||||
}
|
||||
|
||||
TEST_CASE( "#748 - captures with unexpected exceptions", "[.][failing][!throws][!shouldfail]" ) {
|
||||
int answer = 42;
|
||||
CAPTURE( answer );
|
||||
// the message should be printed on the first two sections but not on the third
|
||||
SECTION( "outside assertions" ) {
|
||||
thisThrows();
|
||||
}
|
||||
SECTION( "inside REQUIRE_NOTHROW" ) {
|
||||
REQUIRE_NOTHROW( thisThrows() );
|
||||
}
|
||||
SECTION( "inside REQUIRE_THROWS" ) {
|
||||
REQUIRE_THROWS( thisThrows() );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
@ -0,0 +1,323 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generator_exception.hpp>
|
||||
#include <catch2/generators/catch_generators_adapters.hpp>
|
||||
#include <catch2/generators/catch_generators_random.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
// Generators and sections can be nested freely
|
||||
TEST_CASE("Generators -- simple", "[generators]") {
|
||||
auto i = GENERATE(1, 2, 3);
|
||||
SECTION("one") {
|
||||
auto j = GENERATE(values({ -3, -2, -1 }));
|
||||
REQUIRE(j < i);
|
||||
}
|
||||
|
||||
SECTION("two") {
|
||||
// You can also explicitly set type for generators via Catch::Generators::as
|
||||
auto str = GENERATE(as<std::string>{}, "a", "bb", "ccc");
|
||||
REQUIRE(4u * i > str.size());
|
||||
}
|
||||
}
|
||||
|
||||
// You can create a cartesian-product of generators by creating multiple ones
|
||||
TEST_CASE("3x3x3 ints", "[generators]") {
|
||||
auto x = GENERATE(1, 2, 3);
|
||||
auto y = GENERATE(4, 5, 6);
|
||||
auto z = GENERATE(7, 8, 9);
|
||||
// These assertions will be run 27 times (3x3x3)
|
||||
CHECK(x < y);
|
||||
CHECK(y < z);
|
||||
REQUIRE(x < z);
|
||||
}
|
||||
|
||||
// You can also create data tuples
|
||||
TEST_CASE("tables", "[generators]") {
|
||||
// Note that this will not compile with libstdc++ older than libstdc++6
|
||||
// See https://stackoverflow.com/questions/12436586/tuple-vector-and-initializer-list
|
||||
// for possible workarounds
|
||||
// auto data = GENERATE(table<char const*, int>({
|
||||
// {"first", 5},
|
||||
// {"second", 6},
|
||||
// {"third", 5},
|
||||
// {"etc...", 6}
|
||||
// }));
|
||||
|
||||
// Workaround for the libstdc++ bug mentioned above
|
||||
using tuple_type = std::tuple<char const*, int>;
|
||||
auto data = GENERATE(table<char const*, int>({
|
||||
tuple_type{"first", 5},
|
||||
tuple_type{"second", 6},
|
||||
tuple_type{"third", 5},
|
||||
tuple_type{"etc...", 6}
|
||||
}));
|
||||
|
||||
REQUIRE(strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)));
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cpp_structured_bindings
|
||||
|
||||
// Structured bindings make the table utility much nicer to use
|
||||
TEST_CASE( "strlen2", "[approvals][generators]" ) {
|
||||
using tuple_type = std::tuple<std::string, int>; // see above workaround
|
||||
auto [test_input, expected] =
|
||||
GENERATE( table<std::string, size_t>( { tuple_type{ "one", 3 },
|
||||
tuple_type{ "two", 3 },
|
||||
tuple_type{ "three", 5 },
|
||||
tuple_type{ "four", 4 } } ) );
|
||||
|
||||
REQUIRE( test_input.size() == expected );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// An alternate way of doing data tables without structured bindings
|
||||
struct Data { std::string str; size_t len; };
|
||||
|
||||
TEST_CASE( "strlen3", "[generators]" ) {
|
||||
auto data = GENERATE( values<Data>({
|
||||
{"one", 3},
|
||||
{"two", 3},
|
||||
{"three", 5},
|
||||
{"four", 4}
|
||||
}));
|
||||
|
||||
REQUIRE( data.str.size() == data.len );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef __cpp_structured_bindings
|
||||
|
||||
// Based on example from https://docs.cucumber.io/gherkin/reference/#scenario-outline
|
||||
// (thanks to https://github.com/catchorg/Catch2/issues/850#issuecomment-399504851)
|
||||
|
||||
// Note that GIVEN, WHEN, and THEN now forward onto DYNAMIC_SECTION instead of SECTION.
|
||||
// DYNAMIC_SECTION takes its name as a stringstream-style expression, so can be formatted using
|
||||
// variables in scope - such as the generated variables here. This reads quite nicely in the
|
||||
// test name output (the full scenario description).
|
||||
|
||||
static auto eatCucumbers( int start, int eat ) -> int { return start-eat; }
|
||||
|
||||
SCENARIO("Eating cucumbers", "[generators][approvals]") {
|
||||
using tuple_type = std::tuple<int, int, int>;
|
||||
auto [start, eat, left] = GENERATE( table<int, int, int>(
|
||||
{ tuple_type{ 12, 5, 7 }, tuple_type{ 20, 5, 15 } } ) );
|
||||
|
||||
GIVEN( "there are " << start << " cucumbers" )
|
||||
WHEN( "I eat " << eat << " cucumbers" )
|
||||
THEN( "I should have " << left << " cucumbers" ) {
|
||||
REQUIRE( eatCucumbers( start, eat ) == left );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// There are also some generic generator manipulators
|
||||
TEST_CASE("Generators -- adapters", "[generators][generic]") {
|
||||
// TODO: This won't work yet, introduce GENERATE_VAR?
|
||||
//auto numbers = Catch::Generators::values({ 1, 2, 3, 4, 5, 6 });
|
||||
SECTION("Filtering by predicate") {
|
||||
SECTION("Basic usage") {
|
||||
// This filters out all odd (false) numbers, giving [2, 4, 6]
|
||||
auto i = GENERATE(filter([] (int val) { return val % 2 == 0; }, values({ 1, 2, 3, 4, 5, 6 })));
|
||||
REQUIRE(i % 2 == 0);
|
||||
}
|
||||
SECTION("Throws if there are no matching values") {
|
||||
using namespace Catch::Generators;
|
||||
REQUIRE_THROWS_AS(filter([] (int) {return false; }, value(1)), Catch::GeneratorException);
|
||||
}
|
||||
}
|
||||
SECTION("Shortening a range") {
|
||||
// This takes the first 3 elements from the values, giving back [1, 2, 3]
|
||||
auto i = GENERATE(take(3, values({ 1, 2, 3, 4, 5, 6 })));
|
||||
REQUIRE(i < 4);
|
||||
}
|
||||
SECTION("Transforming elements") {
|
||||
SECTION("Same type") {
|
||||
// This doubles values [1, 2, 3] into [2, 4, 6]
|
||||
auto i = GENERATE(map([] (int val) { return val * 2; }, values({ 1, 2, 3 })));
|
||||
REQUIRE(i % 2 == 0);
|
||||
}
|
||||
SECTION("Different type") {
|
||||
// This takes a generator that returns ints and maps them into strings
|
||||
auto i = GENERATE(map<std::string>([] (int val) { return std::to_string(val); }, values({ 1, 2, 3 })));
|
||||
REQUIRE(i.size() == 1);
|
||||
}
|
||||
SECTION("Different deduced type") {
|
||||
// This takes a generator that returns ints and maps them into strings
|
||||
auto i = GENERATE(map([] (int val) { return std::to_string(val); }, values({ 1, 2, 3 })));
|
||||
REQUIRE(i.size() == 1);
|
||||
}
|
||||
}
|
||||
SECTION("Repeating a generator") {
|
||||
// This will return values [1, 2, 3, 1, 2, 3]
|
||||
auto j = GENERATE(repeat(2, values({ 1, 2, 3 })));
|
||||
REQUIRE(j > 0);
|
||||
}
|
||||
SECTION("Chunking a generator into sized pieces") {
|
||||
SECTION("Number of elements in source is divisible by chunk size") {
|
||||
auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3, 3 })));
|
||||
REQUIRE(chunk2.size() == 2);
|
||||
REQUIRE(chunk2.front() == chunk2.back());
|
||||
}
|
||||
SECTION("Number of elements in source is not divisible by chunk size") {
|
||||
auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3 })));
|
||||
REQUIRE(chunk2.size() == 2);
|
||||
REQUIRE(chunk2.front() == chunk2.back());
|
||||
REQUIRE(chunk2.front() < 3);
|
||||
}
|
||||
SECTION("Chunk size of zero") {
|
||||
auto chunk2 = GENERATE(take(3, chunk(0, value(1))));
|
||||
REQUIRE(chunk2.size() == 0);
|
||||
}
|
||||
SECTION("Throws on too small generators") {
|
||||
using namespace Catch::Generators;
|
||||
REQUIRE_THROWS_AS(chunk(2, value(1)), Catch::GeneratorException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note that because of the non-reproducibility of distributions,
|
||||
// anything involving the random generators cannot be part of approvals
|
||||
TEST_CASE("Random generator", "[generators][approvals]") {
|
||||
SECTION("Infer int from integral arguments") {
|
||||
auto val = GENERATE(take(4, random(0, 1)));
|
||||
STATIC_REQUIRE(std::is_same<decltype(val), int>::value);
|
||||
REQUIRE(0 <= val);
|
||||
REQUIRE(val <= 1);
|
||||
}
|
||||
SECTION("Infer double from double arguments") {
|
||||
auto val = GENERATE(take(4, random(0., 1.)));
|
||||
STATIC_REQUIRE(std::is_same<decltype(val), double>::value);
|
||||
REQUIRE(0. <= val);
|
||||
REQUIRE(val < 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Nested generators and captured variables", "[generators]") {
|
||||
// Workaround for old libstdc++
|
||||
using record = std::tuple<int, int>;
|
||||
// Set up 3 ranges to generate numbers from
|
||||
auto extent = GENERATE(table<int, int>({
|
||||
record{3, 7},
|
||||
record{-5, -3},
|
||||
record{90, 100}
|
||||
}));
|
||||
|
||||
auto from = std::get<0>(extent);
|
||||
auto to = std::get<1>(extent);
|
||||
|
||||
auto values = GENERATE_COPY(range(from, to));
|
||||
REQUIRE(values > -6);
|
||||
}
|
||||
|
||||
namespace {
|
||||
size_t call_count = 0;
|
||||
size_t test_count = 0;
|
||||
std::vector<int> make_data() {
|
||||
return { 1, 3, 5, 7, 9, 11 };
|
||||
}
|
||||
std::vector<int> make_data_counted() {
|
||||
++call_count;
|
||||
return make_data();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#endif
|
||||
|
||||
TEST_CASE("Copy and then generate a range", "[generators]") {
|
||||
SECTION("from var and iterators") {
|
||||
static auto data = make_data();
|
||||
|
||||
// It is important to notice that a generator is only initialized
|
||||
// **once** per run. What this means is that modifying data will not
|
||||
// modify the underlying generator.
|
||||
auto elem = GENERATE_REF(from_range(data.begin(), data.end()));
|
||||
REQUIRE(elem % 2 == 1);
|
||||
}
|
||||
SECTION("From a temporary container") {
|
||||
auto elem = GENERATE(from_range(make_data_counted()));
|
||||
++test_count;
|
||||
REQUIRE(elem % 2 == 1);
|
||||
}
|
||||
SECTION("Final validation") {
|
||||
REQUIRE(call_count == 1);
|
||||
REQUIRE(make_data().size() == test_count);
|
||||
}
|
||||
}
|
||||
|
||||
#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) {
|
||||
int _ = GENERATE(1, 2);
|
||||
(void)_;
|
||||
++counter;
|
||||
}
|
||||
// There should be at most 6 (3 * 2) counter increments
|
||||
REQUIRE(counter < 7);
|
||||
}
|
||||
|
||||
TEST_CASE("#1913 - GENERATEs can share a line", "[regression][generators]") {
|
||||
int i = GENERATE(1, 2); int j = GENERATE(3, 4);
|
||||
REQUIRE(i != j);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class test_generator : public Catch::Generators::IGenerator<int> {
|
||||
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<int> {
|
||||
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 );
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,917 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_container_properties.hpp>
|
||||
#include <catch2/matchers/catch_matchers_contains.hpp>
|
||||
#include <catch2/matchers/catch_matchers_range_equals.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/matchers/catch_matchers_quantifiers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_predicate.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <helpers/range_test_helpers.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
struct MoveOnlyTestElement {
|
||||
int num = 0;
|
||||
MoveOnlyTestElement(int n) :num(n) {}
|
||||
|
||||
MoveOnlyTestElement(MoveOnlyTestElement&& rhs) = default;
|
||||
MoveOnlyTestElement& operator=(MoveOnlyTestElement&& rhs) = default;
|
||||
|
||||
friend bool operator==(MoveOnlyTestElement const& lhs, MoveOnlyTestElement const& rhs) {
|
||||
return lhs.num == rhs.num;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, MoveOnlyTestElement const& elem) {
|
||||
out << elem.num;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Basic use of the Contains range matcher", "[matchers][templated][contains]") {
|
||||
using Catch::Matchers::Contains;
|
||||
|
||||
SECTION("Different argument ranges, same element type, default comparison") {
|
||||
std::array<int, 3> a{ { 1,2,3 } };
|
||||
std::vector<int> b{ 0,1,2 };
|
||||
std::list<int> c{ 4,5,6 };
|
||||
|
||||
// A contains 1
|
||||
REQUIRE_THAT(a, Contains(1));
|
||||
// B contains 1
|
||||
REQUIRE_THAT(b, Contains(1));
|
||||
// C does not contain 1
|
||||
REQUIRE_THAT(c, !Contains(1));
|
||||
}
|
||||
|
||||
SECTION("Different argument ranges, same element type, custom comparison") {
|
||||
std::array<int, 3> a{ { 1,2,3 } };
|
||||
std::vector<int> b{ 0,1,2 };
|
||||
std::list<int> c{ 4,5,6 };
|
||||
|
||||
auto close_enough = [](int lhs, int rhs) { return std::abs(lhs - rhs) <= 1; };
|
||||
|
||||
// A contains 1, which is "close enough" to 0
|
||||
REQUIRE_THAT(a, Contains(0, close_enough));
|
||||
// B contains 0 directly
|
||||
REQUIRE_THAT(b, Contains(0, close_enough));
|
||||
// C does not contain anything "close enough" to 0
|
||||
REQUIRE_THAT(c, !Contains(0, close_enough));
|
||||
}
|
||||
|
||||
SECTION("Different element type, custom comparisons") {
|
||||
std::array<std::string, 3> a{ { "abc", "abcd" , "abcde" } };
|
||||
|
||||
REQUIRE_THAT(a, Contains(4, [](auto&& lhs, size_t sz) {
|
||||
return lhs.size() == sz;
|
||||
}));
|
||||
}
|
||||
|
||||
SECTION("Can handle type that requires ADL-found free function begin and end") {
|
||||
unrelated::needs_ADL_begin<int> in{1, 2, 3, 4, 5};
|
||||
|
||||
REQUIRE_THAT(in, Contains(1));
|
||||
REQUIRE_THAT(in, !Contains(8));
|
||||
}
|
||||
|
||||
SECTION("Initialization with move only types") {
|
||||
std::array<MoveOnlyTestElement, 3> in{ { MoveOnlyTestElement{ 1 }, MoveOnlyTestElement{ 2 }, MoveOnlyTestElement{ 3 } } };
|
||||
|
||||
REQUIRE_THAT(in, Contains(MoveOnlyTestElement{ 2 }));
|
||||
REQUIRE_THAT(in, !Contains(MoveOnlyTestElement{ 9 }));
|
||||
}
|
||||
|
||||
SECTION("Matching using matcher") {
|
||||
std::array<double, 4> in{ {1, 2, 3} };
|
||||
|
||||
REQUIRE_THAT(in, Contains(Catch::Matchers::WithinAbs(0.5, 0.5)));
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct has_empty {
|
||||
bool empty() const { return false; }
|
||||
};
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
TEST_CASE("Basic use of the Empty range matcher", "[matchers][templated][empty]") {
|
||||
using Catch::Matchers::IsEmpty;
|
||||
SECTION("Simple, std-provided containers") {
|
||||
std::array<int, 0> empty_array{};
|
||||
std::array<double, 1> non_empty_array{};
|
||||
REQUIRE_THAT(empty_array, IsEmpty());
|
||||
REQUIRE_THAT(non_empty_array, !IsEmpty());
|
||||
|
||||
std::vector<std::string> empty_vec;
|
||||
std::vector<char> non_empty_vec{ 'a', 'b', 'c' };
|
||||
REQUIRE_THAT(empty_vec, IsEmpty());
|
||||
REQUIRE_THAT(non_empty_vec, !IsEmpty());
|
||||
|
||||
std::list<std::list<std::list<int>>> inner_lists_are_empty;
|
||||
inner_lists_are_empty.push_back({});
|
||||
REQUIRE_THAT(inner_lists_are_empty, !IsEmpty());
|
||||
REQUIRE_THAT(inner_lists_are_empty.front(), IsEmpty());
|
||||
}
|
||||
SECTION("Type with empty") {
|
||||
REQUIRE_THAT(has_empty{}, !IsEmpty());
|
||||
}
|
||||
SECTION("Type requires ADL found empty free function") {
|
||||
REQUIRE_THAT(unrelated::ADL_empty{}, IsEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
class LessThanMatcher final : public Catch::Matchers::MatcherBase<size_t> {
|
||||
size_t m_target;
|
||||
public:
|
||||
explicit LessThanMatcher(size_t target):
|
||||
m_target(target)
|
||||
{}
|
||||
|
||||
bool match(size_t const& size) const override {
|
||||
return size < m_target;
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return "is less than " + std::to_string(m_target);
|
||||
}
|
||||
};
|
||||
|
||||
LessThanMatcher Lt(size_t sz) {
|
||||
return LessThanMatcher{ sz };
|
||||
}
|
||||
|
||||
struct has_size {
|
||||
size_t size() const {
|
||||
return 13;
|
||||
}
|
||||
};
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
TEST_CASE("Usage of the SizeIs range matcher", "[matchers][templated][size]") {
|
||||
using Catch::Matchers::SizeIs;
|
||||
SECTION("Some with stdlib containers") {
|
||||
std::vector<int> empty_vec;
|
||||
REQUIRE_THAT(empty_vec, SizeIs(0));
|
||||
REQUIRE_THAT(empty_vec, !SizeIs(2));
|
||||
REQUIRE_THAT(empty_vec, SizeIs(Lt(2)));
|
||||
|
||||
std::array<int, 2> arr{};
|
||||
REQUIRE_THAT(arr, SizeIs(2));
|
||||
REQUIRE_THAT(arr, SizeIs( Lt(3)));
|
||||
REQUIRE_THAT(arr, !SizeIs(!Lt(3)));
|
||||
|
||||
std::map<int, int> map{ {1, 1}, {2, 2}, {3, 3} };
|
||||
REQUIRE_THAT(map, SizeIs(3));
|
||||
}
|
||||
SECTION("Type requires ADL found size free function") {
|
||||
REQUIRE_THAT(unrelated::ADL_size{}, SizeIs(12));
|
||||
}
|
||||
SECTION("Type has size member") {
|
||||
REQUIRE_THAT(has_size{}, SizeIs(13));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Usage of AllMatch range matcher", "[matchers][templated][quantifiers]") {
|
||||
using Catch::Matchers::AllMatch;
|
||||
using Catch::Matchers::Predicate;
|
||||
|
||||
SECTION("Basic usage") {
|
||||
using Catch::Matchers::Contains;
|
||||
using Catch::Matchers::SizeIs;
|
||||
|
||||
std::array<std::array<int, 5>, 5> data{{
|
||||
{{ 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 }}
|
||||
}};
|
||||
|
||||
REQUIRE_THAT(data, AllMatch(SizeIs(5)));
|
||||
REQUIRE_THAT(data, !AllMatch(Contains(0) && Contains(1)));
|
||||
}
|
||||
|
||||
SECTION("Type requires ADL found begin and end") {
|
||||
unrelated::needs_ADL_begin<int> needs_adl{ 1, 2, 3, 4, 5 };
|
||||
REQUIRE_THAT( needs_adl, AllMatch( Predicate<int>( []( int elem ) {
|
||||
return elem < 6;
|
||||
} ) ) );
|
||||
}
|
||||
|
||||
SECTION("Shortcircuiting") {
|
||||
with_mocked_iterator_access<int> mocked{ 1, 2, 3, 4, 5 };
|
||||
SECTION("All are read") {
|
||||
auto allMatch = AllMatch(Predicate<int>([](int elem) {
|
||||
return elem < 10;
|
||||
}));
|
||||
REQUIRE_THAT(mocked, allMatch);
|
||||
REQUIRE(mocked.m_derefed[0]);
|
||||
REQUIRE(mocked.m_derefed[1]);
|
||||
REQUIRE(mocked.m_derefed[2]);
|
||||
REQUIRE(mocked.m_derefed[3]);
|
||||
REQUIRE(mocked.m_derefed[4]);
|
||||
}
|
||||
SECTION("Short-circuited") {
|
||||
auto allMatch = AllMatch(Predicate<int>([](int elem) {
|
||||
return elem < 3;
|
||||
}));
|
||||
REQUIRE_THAT(mocked, !allMatch);
|
||||
REQUIRE(mocked.m_derefed[0]);
|
||||
REQUIRE(mocked.m_derefed[1]);
|
||||
REQUIRE(mocked.m_derefed[2]);
|
||||
REQUIRE_FALSE(mocked.m_derefed[3]);
|
||||
REQUIRE_FALSE(mocked.m_derefed[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Usage of AnyMatch range matcher", "[matchers][templated][quantifiers]") {
|
||||
using Catch::Matchers::AnyMatch;
|
||||
using Catch::Matchers::Predicate;
|
||||
|
||||
SECTION("Basic usage") {
|
||||
using Catch::Matchers::Contains;
|
||||
using Catch::Matchers::SizeIs;
|
||||
|
||||
std::array<std::array<int, 5>, 5> data{ {
|
||||
{{ 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 }}
|
||||
} };
|
||||
|
||||
REQUIRE_THAT(data, AnyMatch(SizeIs(5)));
|
||||
REQUIRE_THAT(data, !AnyMatch(Contains(0) && Contains(10)));
|
||||
}
|
||||
|
||||
SECTION( "Type requires ADL found begin and end" ) {
|
||||
unrelated::needs_ADL_begin<int> needs_adl{ 1, 2, 3, 4, 5 };
|
||||
REQUIRE_THAT( needs_adl, AnyMatch( Predicate<int>( []( int elem ) {
|
||||
return elem < 3;
|
||||
} ) ) );
|
||||
}
|
||||
|
||||
SECTION("Shortcircuiting") {
|
||||
with_mocked_iterator_access<int> mocked{ 1, 2, 3, 4, 5 };
|
||||
SECTION("All are read") {
|
||||
auto anyMatch = AnyMatch(
|
||||
Predicate<int>( []( int elem ) { return elem > 10; } ) );
|
||||
REQUIRE_THAT( mocked, !anyMatch );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE( mocked.m_derefed[3] );
|
||||
REQUIRE( mocked.m_derefed[4] );
|
||||
}
|
||||
SECTION("Short-circuited") {
|
||||
auto anyMatch = AnyMatch(
|
||||
Predicate<int>( []( int elem ) { return elem < 3; } ) );
|
||||
REQUIRE_THAT( mocked, anyMatch );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[1] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[2] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[3] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[4] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Usage of NoneMatch range matcher", "[matchers][templated][quantifiers]") {
|
||||
using Catch::Matchers::NoneMatch;
|
||||
using Catch::Matchers::Predicate;
|
||||
|
||||
SECTION("Basic usage") {
|
||||
using Catch::Matchers::Contains;
|
||||
using Catch::Matchers::SizeIs;
|
||||
|
||||
std::array<std::array<int, 5>, 5> data{ {
|
||||
{{ 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 }}
|
||||
} };
|
||||
|
||||
REQUIRE_THAT(data, NoneMatch(SizeIs(6)));
|
||||
REQUIRE_THAT(data, !NoneMatch(Contains(0) && Contains(1)));
|
||||
}
|
||||
|
||||
SECTION( "Type requires ADL found begin and end" ) {
|
||||
unrelated::needs_ADL_begin<int> needs_adl{ 1, 2, 3, 4, 5 };
|
||||
REQUIRE_THAT( needs_adl, NoneMatch( Predicate<int>( []( int elem ) {
|
||||
return elem > 6;
|
||||
} ) ) );
|
||||
}
|
||||
|
||||
SECTION("Shortcircuiting") {
|
||||
with_mocked_iterator_access<int> mocked{ 1, 2, 3, 4, 5 };
|
||||
SECTION("All are read") {
|
||||
auto noneMatch = NoneMatch(
|
||||
Predicate<int>([](int elem) { return elem > 10; }));
|
||||
REQUIRE_THAT(mocked, noneMatch);
|
||||
REQUIRE(mocked.m_derefed[0]);
|
||||
REQUIRE(mocked.m_derefed[1]);
|
||||
REQUIRE(mocked.m_derefed[2]);
|
||||
REQUIRE(mocked.m_derefed[3]);
|
||||
REQUIRE(mocked.m_derefed[4]);
|
||||
}
|
||||
SECTION("Short-circuited") {
|
||||
auto noneMatch = NoneMatch(
|
||||
Predicate<int>([](int elem) { return elem < 3; }));
|
||||
REQUIRE_THAT(mocked, !noneMatch);
|
||||
REQUIRE(mocked.m_derefed[0]);
|
||||
REQUIRE_FALSE(mocked.m_derefed[1]);
|
||||
REQUIRE_FALSE(mocked.m_derefed[2]);
|
||||
REQUIRE_FALSE(mocked.m_derefed[3]);
|
||||
REQUIRE_FALSE(mocked.m_derefed[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct ConvertibleToBool
|
||||
{
|
||||
bool v;
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return v;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace Catch {
|
||||
template <>
|
||||
struct StringMaker<ConvertibleToBool> {
|
||||
static std::string
|
||||
convert( ConvertibleToBool const& convertible_to_bool ) {
|
||||
return ::Catch::Detail::stringify( convertible_to_bool.v );
|
||||
}
|
||||
};
|
||||
} // namespace Catch
|
||||
|
||||
TEST_CASE("Usage of AllTrue range matcher", "[matchers][templated][quantifiers]") {
|
||||
using Catch::Matchers::AllTrue;
|
||||
|
||||
SECTION( "Basic usage" ) {
|
||||
SECTION( "All true evaluates to true" ) {
|
||||
std::array<bool, 5> const data{ { true, true, true, true, true } };
|
||||
REQUIRE_THAT( data, AllTrue() );
|
||||
}
|
||||
SECTION( "Empty evaluates to true" ) {
|
||||
std::array<bool, 0> const data{};
|
||||
REQUIRE_THAT( data, AllTrue() );
|
||||
}
|
||||
SECTION( "One false evaluates to false" ) {
|
||||
std::array<bool, 5> const data{ { true, true, false, true, true } };
|
||||
REQUIRE_THAT( data, !AllTrue() );
|
||||
}
|
||||
SECTION( "All false evaluates to false" ) {
|
||||
std::array<bool, 5> const data{
|
||||
{ false, false, false, false, false } };
|
||||
REQUIRE_THAT( data, !AllTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Contained type is convertible to bool" ) {
|
||||
SECTION( "All true evaluates to true" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { true }, { true }, { true }, { true }, { true } } };
|
||||
REQUIRE_THAT( data, AllTrue() );
|
||||
}
|
||||
SECTION( "One false evaluates to false" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { true }, { true }, { false }, { true }, { true } } };
|
||||
REQUIRE_THAT( data, !AllTrue() );
|
||||
}
|
||||
SECTION( "All false evaluates to false" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { false }, { false }, { false }, { false }, { false } } };
|
||||
REQUIRE_THAT( data, !AllTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Shortcircuiting" ) {
|
||||
SECTION( "All are read" ) {
|
||||
with_mocked_iterator_access<bool> const mocked{
|
||||
true, true, true, true, true };
|
||||
REQUIRE_THAT( mocked, AllTrue() );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE( mocked.m_derefed[3] );
|
||||
REQUIRE( mocked.m_derefed[4] );
|
||||
}
|
||||
SECTION( "Short-circuited" ) {
|
||||
with_mocked_iterator_access<bool> const mocked{
|
||||
true, true, false, true, true };
|
||||
REQUIRE_THAT( mocked, !AllTrue() );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[3] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[4] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Usage of NoneTrue range matcher", "[matchers][templated][quantifiers]" ) {
|
||||
using Catch::Matchers::NoneTrue;
|
||||
|
||||
SECTION( "Basic usage" ) {
|
||||
SECTION( "All true evaluates to false" ) {
|
||||
std::array<bool, 5> const data{ { true, true, true, true, true } };
|
||||
REQUIRE_THAT( data, !NoneTrue() );
|
||||
}
|
||||
SECTION( "Empty evaluates to true" ) {
|
||||
std::array<bool, 0> const data{};
|
||||
REQUIRE_THAT( data, NoneTrue() );
|
||||
}
|
||||
SECTION( "One true evaluates to false" ) {
|
||||
std::array<bool, 5> const data{
|
||||
{ false, false, true, false, false } };
|
||||
REQUIRE_THAT( data, !NoneTrue() );
|
||||
}
|
||||
SECTION( "All false evaluates to true" ) {
|
||||
std::array<bool, 5> const data{
|
||||
{ false, false, false, false, false } };
|
||||
REQUIRE_THAT( data, NoneTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Contained type is convertible to bool" ) {
|
||||
SECTION( "All true evaluates to false" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { true }, { true }, { true }, { true }, { true } } };
|
||||
REQUIRE_THAT( data, !NoneTrue() );
|
||||
}
|
||||
SECTION( "One true evaluates to false" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { false }, { false }, { true }, { false }, { false } } };
|
||||
REQUIRE_THAT( data, !NoneTrue() );
|
||||
}
|
||||
SECTION( "All false evaluates to true" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { false }, { false }, { false }, { false }, { false } } };
|
||||
REQUIRE_THAT( data, NoneTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Shortcircuiting" ) {
|
||||
SECTION( "All are read" ) {
|
||||
with_mocked_iterator_access<bool> const mocked{
|
||||
false, false, false, false, false };
|
||||
REQUIRE_THAT( mocked, NoneTrue() );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE( mocked.m_derefed[3] );
|
||||
REQUIRE( mocked.m_derefed[4] );
|
||||
}
|
||||
SECTION( "Short-circuited" ) {
|
||||
with_mocked_iterator_access<bool> const mocked{
|
||||
false, false, true, true, true };
|
||||
REQUIRE_THAT( mocked, !NoneTrue() );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[3] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[4] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Usage of AnyTrue range matcher", "[matchers][templated][quantifiers]" ) {
|
||||
using Catch::Matchers::AnyTrue;
|
||||
|
||||
SECTION( "Basic usage" ) {
|
||||
SECTION( "All true evaluates to true" ) {
|
||||
std::array<bool, 5> const data{ { true, true, true, true, true } };
|
||||
REQUIRE_THAT( data, AnyTrue() );
|
||||
}
|
||||
SECTION( "Empty evaluates to false" ) {
|
||||
std::array<bool, 0> const data{};
|
||||
REQUIRE_THAT( data, !AnyTrue() );
|
||||
}
|
||||
SECTION( "One true evaluates to true" ) {
|
||||
std::array<bool, 5> const data{
|
||||
{ false, false, true, false, false } };
|
||||
REQUIRE_THAT( data, AnyTrue() );
|
||||
}
|
||||
SECTION( "All false evaluates to false" ) {
|
||||
std::array<bool, 5> const data{
|
||||
{ false, false, false, false, false } };
|
||||
REQUIRE_THAT( data, !AnyTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Contained type is convertible to bool" ) {
|
||||
SECTION( "All true evaluates to true" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { true }, { true }, { true }, { true }, { true } } };
|
||||
REQUIRE_THAT( data, AnyTrue() );
|
||||
}
|
||||
SECTION( "One true evaluates to true" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { false }, { false }, { true }, { false }, { false } } };
|
||||
REQUIRE_THAT( data, AnyTrue() );
|
||||
}
|
||||
SECTION( "All false evaluates to false" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { false }, { false }, { false }, { false }, { false } } };
|
||||
REQUIRE_THAT( data, !AnyTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Shortcircuiting" ) {
|
||||
SECTION( "All are read" ) {
|
||||
with_mocked_iterator_access<bool> const mocked{
|
||||
false, false, false, false, true };
|
||||
REQUIRE_THAT( mocked, AnyTrue() );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE( mocked.m_derefed[3] );
|
||||
REQUIRE( mocked.m_derefed[4] );
|
||||
}
|
||||
SECTION( "Short-circuited" ) {
|
||||
with_mocked_iterator_access<bool> const mocked{
|
||||
false, false, true, true, true };
|
||||
REQUIRE_THAT( mocked, AnyTrue() );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[3] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[4] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("All/Any/None True matchers support types with ADL begin",
|
||||
"[approvals][matchers][quantifiers][templated]") {
|
||||
using Catch::Matchers::AllTrue;
|
||||
using Catch::Matchers::NoneTrue;
|
||||
using Catch::Matchers::AnyTrue;
|
||||
|
||||
|
||||
SECTION( "Type requires ADL found begin and end" ) {
|
||||
unrelated::needs_ADL_begin<bool> const needs_adl{
|
||||
true, true, true, true, true };
|
||||
REQUIRE_THAT( needs_adl, AllTrue() );
|
||||
}
|
||||
|
||||
SECTION( "Type requires ADL found begin and end" ) {
|
||||
unrelated::needs_ADL_begin<bool> const needs_adl{
|
||||
false, false, false, false, false };
|
||||
REQUIRE_THAT( needs_adl, NoneTrue() );
|
||||
}
|
||||
|
||||
SECTION( "Type requires ADL found begin and end" ) {
|
||||
unrelated::needs_ADL_begin<bool> const needs_adl{
|
||||
false, false, true, false, false };
|
||||
REQUIRE_THAT( needs_adl, AnyTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
// Range loop iterating over range with different types for begin and end is a
|
||||
// C++17 feature, and GCC refuses to compile such code unless the lang mode is
|
||||
// set to C++17 or later.
|
||||
#if defined(CATCH_CPP17_OR_GREATER)
|
||||
|
||||
TEST_CASE( "The quantifier range matchers support types with different types returned from begin and end",
|
||||
"[matchers][templated][quantifiers][approvals]" ) {
|
||||
using Catch::Matchers::AllMatch;
|
||||
using Catch::Matchers::AllTrue;
|
||||
using Catch::Matchers::AnyMatch;
|
||||
using Catch::Matchers::AnyTrue;
|
||||
using Catch::Matchers::NoneMatch;
|
||||
using Catch::Matchers::NoneTrue;
|
||||
|
||||
using Catch::Matchers::Predicate;
|
||||
|
||||
SECTION( "AllAnyNoneMatch" ) {
|
||||
has_different_begin_end_types<int> diff_types{ 1, 2, 3, 4, 5 };
|
||||
REQUIRE_THAT( diff_types, !AllMatch( Predicate<int>( []( int elem ) {
|
||||
return elem < 3;
|
||||
} ) ) );
|
||||
|
||||
REQUIRE_THAT( diff_types, AnyMatch( Predicate<int>( []( int elem ) {
|
||||
return elem < 2;
|
||||
} ) ) );
|
||||
|
||||
REQUIRE_THAT( diff_types, !NoneMatch( Predicate<int>( []( int elem ) {
|
||||
return elem < 3;
|
||||
} ) ) );
|
||||
}
|
||||
SECTION( "AllAnyNoneTrue" ) {
|
||||
has_different_begin_end_types<bool> diff_types{ false, false, true, false, false };
|
||||
|
||||
REQUIRE_THAT( diff_types, !AllTrue() );
|
||||
REQUIRE_THAT( diff_types, AnyTrue() );
|
||||
REQUIRE_THAT( diff_types, !NoneTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
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<int> diff_types{ 1, 2, 3, 4, 5 };
|
||||
std::array<int, 5> 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<size_t> 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<int> empty_vector;
|
||||
CHECK_THAT( empty_vector, RangeEquals( empty_vector ) );
|
||||
}
|
||||
SECTION( "Empty container does not match non-empty container" ) {
|
||||
const std::vector<int> empty_vector;
|
||||
const std::vector<int> 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<int, 1> non_empty_array{ { 1 } };
|
||||
CHECK_THAT( non_empty_array, RangeEquals( non_empty_array ) );
|
||||
}
|
||||
SECTION( "Two equal-sized, equal, non-empty containers" ) {
|
||||
const std::array<int, 3> array_a{ { 1, 2, 3 } };
|
||||
CHECK_THAT( array_a, RangeEquals( array_a ) );
|
||||
}
|
||||
SECTION( "Two equal-sized, non-equal, non-empty containers" ) {
|
||||
const std::array<int, 3> array_a{ { 1, 2, 3 } };
|
||||
const std::array<int, 3> array_b{ { 2, 2, 3 } };
|
||||
const std::array<int, 3> 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<int> vector_a{ 1, 2, 3 };
|
||||
const std::vector<int> 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<int> vector_a{ { 1, 2, 3 } };
|
||||
const std::vector<int> 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<int> vector_a{ { 1, 2, 3 } };
|
||||
const std::vector<int> 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<int> 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<int> const mocked1{ 1, 2, 3, 4 };
|
||||
|
||||
SECTION( "Check short-circuits on failure" ) {
|
||||
std::array<int, 4> 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<int, 4> 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<int> empty_vector;
|
||||
CHECK_THAT( empty_vector, UnorderedRangeEquals( empty_vector ) );
|
||||
}
|
||||
SECTION( "Empty container does not match non-empty container" ) {
|
||||
const std::vector<int> empty_vector;
|
||||
const std::vector<int> 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<int, 1> non_empty_array{ { 1 } };
|
||||
CHECK_THAT( non_empty_array,
|
||||
UnorderedRangeEquals( non_empty_array ) );
|
||||
}
|
||||
SECTION( "Two equal-sized, equal, non-empty containers" ) {
|
||||
const std::array<int, 3> array_a{ { 1, 2, 3 } };
|
||||
CHECK_THAT( array_a, UnorderedRangeEquals( array_a ) );
|
||||
}
|
||||
SECTION( "Two equal-sized, non-equal, non-empty containers" ) {
|
||||
const std::array<int, 3> array_a{ { 1, 2, 3 } };
|
||||
const std::array<int, 3> array_b{ { 2, 2, 3 } };
|
||||
CHECK_THAT( array_a, !UnorderedRangeEquals( array_b ) );
|
||||
}
|
||||
SECTION( "Two non-equal-sized, non-empty containers" ) {
|
||||
const std::vector<int> vector_a{ 1, 2, 3 };
|
||||
const std::vector<int> 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<int> vector_a{ { 1, 10, 20 } };
|
||||
const std::vector<int> 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<int> vector_a{ { 1, 10, 21 } };
|
||||
const std::vector<int> 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<int> 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 <typename Container>
|
||||
static constexpr bool ContainerIsRandomAccess( const Container& ) {
|
||||
using array_iter_category = typename std::iterator_traits<
|
||||
typename Container::iterator>::iterator_category;
|
||||
|
||||
return std::is_base_of<std::random_access_iterator_tag,
|
||||
array_iter_category>::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<int, 3> 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<int, 3> array_int_3{ { 1, 2, 3 } };
|
||||
const std::array<int, 4> 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<int, 3> array_int_a{ { 1, 2, 3 } };
|
||||
const std::vector<int> 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<int, 3> array_int_a{ { 1, 2, 3 } };
|
||||
const std::list<int> 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<int> vector_int_a{ 1, 2, 3 };
|
||||
const std::vector<char> 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<int> vector_int_a{ 1, 2, 3 };
|
||||
const std::vector<char> 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<int> 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<int> vector_a{ { 1, 2, 3 } };
|
||||
const std::array<char, 3> 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 ) );
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,312 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE( "INFO and WARN do not abort tests", "[messages][.]" ) {
|
||||
INFO( "this is a " << "message" ); // This should output the message if a failure occurs
|
||||
WARN( "this is a " << "warning" ); // This should always output the message but then continue
|
||||
}
|
||||
|
||||
TEST_CASE( "#1455 - INFO and WARN can start with a linebreak", "[messages][.]" ) {
|
||||
// Previously these would be hidden from the console reporter output,
|
||||
// because it would fail at properly reflowing the text
|
||||
INFO( "\nThis info message starts with a linebreak" );
|
||||
WARN( "\nThis warning message starts with a linebreak" );
|
||||
}
|
||||
|
||||
TEST_CASE( "SUCCEED counts as a test pass", "[messages]" ) {
|
||||
SUCCEED( "this is a " << "success" );
|
||||
}
|
||||
|
||||
TEST_CASE( "INFO gets logged on failure", "[failing][messages][.]" ) {
|
||||
INFO( "this message should be logged" );
|
||||
INFO( "so should this" );
|
||||
int a = 2;
|
||||
REQUIRE( a == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE( "INFO gets logged on failure, even if captured before successful assertions", "[failing][messages][.]" ) {
|
||||
INFO( "this message may be logged later" );
|
||||
int a = 2;
|
||||
CHECK( a == 2 );
|
||||
|
||||
INFO( "this message should be logged" );
|
||||
|
||||
CHECK( a == 1 );
|
||||
|
||||
INFO( "and this, but later" );
|
||||
|
||||
CHECK( a == 0 );
|
||||
|
||||
INFO( "but not this" );
|
||||
|
||||
CHECK( a == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE( "FAIL aborts the test", "[failing][messages][.]" ) {
|
||||
FAIL( "This is a " << "failure" ); // This should output the message and abort
|
||||
WARN( "We should never see this");
|
||||
}
|
||||
|
||||
TEST_CASE( "FAIL_CHECK does not abort the test", "[failing][messages][.]" ) {
|
||||
FAIL_CHECK( "This is a " << "failure" ); // This should output the message then continue
|
||||
WARN( "This message appears in the output");
|
||||
}
|
||||
|
||||
TEST_CASE( "FAIL does not require an argument", "[failing][messages][.]" ) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
TEST_CASE( "SUCCEED does not require an argument", "[messages][.]" ) {
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE( "Output from all sections is reported", "[failing][messages][.]" ) {
|
||||
SECTION( "one" ) {
|
||||
FAIL( "Message from section one" );
|
||||
}
|
||||
|
||||
SECTION( "two" ) {
|
||||
FAIL( "Message from section two" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Standard output from all sections is reported", "[messages][.]" ) {
|
||||
SECTION( "one" ) {
|
||||
std::cout << "Message from section one\n";
|
||||
}
|
||||
|
||||
SECTION( "two" ) {
|
||||
std::cout << "Message from section two\n";
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Standard error is reported and redirected", "[messages][.][approvals]" ) {
|
||||
SECTION( "std::cerr" ) {
|
||||
std::cerr << "Write to std::cerr\n";
|
||||
}
|
||||
SECTION( "std::clog" ) {
|
||||
std::clog << "Write to std::clog\n";
|
||||
}
|
||||
SECTION( "Interleaved writes to cerr and clog" ) {
|
||||
std::cerr << "Inter";
|
||||
std::clog << "leaved";
|
||||
std::cerr << ' ';
|
||||
std::clog << "writes";
|
||||
std::cerr << " to error";
|
||||
std::clog << " streams\n" << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "INFO is reset for each loop", "[messages][failing][.]" ) {
|
||||
for( int i=0; i<100; i++ )
|
||||
{
|
||||
INFO( "current counter " << i );
|
||||
CAPTURE( i );
|
||||
REQUIRE( i < 10 );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "The NO_FAIL macro reports a failure but does not fail the test", "[messages]" ) {
|
||||
CHECK_NOFAIL( 1 == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE( "just info", "[info][isolated info][messages]" ) {
|
||||
INFO( "this should never be seen" );
|
||||
}
|
||||
TEST_CASE( "just failure", "[fail][isolated info][.][messages]" ) {
|
||||
FAIL( "Previous info should not be seen" );
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "sends information to INFO", "[.][failing]" ) {
|
||||
INFO( "hi" );
|
||||
int i = 7;
|
||||
CAPTURE( i );
|
||||
REQUIRE( false );
|
||||
}
|
||||
|
||||
TEST_CASE( "Pointers can be converted to strings", "[messages][.][approvals]" ) {
|
||||
int p;
|
||||
WARN( "actual address of p: " << &p );
|
||||
WARN( "toString(p): " << ::Catch::Detail::stringify( &p ) );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void unscoped_info( T msg ) {
|
||||
UNSCOPED_INFO( msg );
|
||||
}
|
||||
|
||||
TEST_CASE( "just unscoped info", "[unscoped][info]" ) {
|
||||
unscoped_info( "this should NOT be seen" );
|
||||
unscoped_info( "this also should NOT be seen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "just failure after unscoped info", "[failing][.][unscoped][info]" ) {
|
||||
FAIL( "previous unscoped info SHOULD not be seen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "print unscoped info if passing unscoped info is printed", "[unscoped][info]" ) {
|
||||
unscoped_info( "this MAY be seen IF info is printed for passing assertions" );
|
||||
REQUIRE( true );
|
||||
}
|
||||
|
||||
TEST_CASE( "prints unscoped info on failure", "[failing][.][unscoped][info]" ) {
|
||||
unscoped_info( "this SHOULD be seen" );
|
||||
unscoped_info( "this SHOULD also be seen" );
|
||||
REQUIRE( false );
|
||||
unscoped_info( "but this should NOT be seen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "not prints unscoped info from previous failures", "[failing][.][unscoped][info]" ) {
|
||||
unscoped_info( "this MAY be seen only for the FIRST assertion IF info is printed for passing assertions" );
|
||||
REQUIRE( true );
|
||||
unscoped_info( "this MAY be seen only for the SECOND assertion IF info is printed for passing assertions" );
|
||||
REQUIRE( true );
|
||||
unscoped_info( "this SHOULD be seen" );
|
||||
REQUIRE( false );
|
||||
}
|
||||
|
||||
TEST_CASE( "prints unscoped info only for the first assertion", "[failing][.][unscoped][info]" ) {
|
||||
unscoped_info( "this SHOULD be seen only ONCE" );
|
||||
CHECK( false );
|
||||
CHECK( true );
|
||||
unscoped_info( "this MAY also be seen only ONCE IF info is printed for passing assertions" );
|
||||
CHECK( true );
|
||||
CHECK( true );
|
||||
}
|
||||
|
||||
TEST_CASE( "stacks unscoped info in loops", "[failing][.][unscoped][info]" ) {
|
||||
UNSCOPED_INFO("Count 1 to 3...");
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
unscoped_info(i);
|
||||
}
|
||||
CHECK( false );
|
||||
|
||||
UNSCOPED_INFO("Count 4 to 6...");
|
||||
for (int i = 4; i <= 6; i++) {
|
||||
unscoped_info(i);
|
||||
}
|
||||
CHECK( false );
|
||||
}
|
||||
|
||||
TEST_CASE( "mix info, unscoped info and warning", "[unscoped][info]" ) {
|
||||
INFO("info");
|
||||
unscoped_info("unscoped info");
|
||||
WARN("and warn may mix");
|
||||
WARN("they are not cleared after warnings");
|
||||
}
|
||||
|
||||
TEST_CASE( "CAPTURE can deal with complex expressions", "[messages][capture]" ) {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
int c = 3;
|
||||
CAPTURE( a, b, c, a + b, a+b, c > b, a == 1 );
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-value" // In (1, 2), the "1" is unused ...
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-value" // All the comma operators are side-effect free
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4709) // comma in indexing operator
|
||||
#endif
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct helper_1436 {
|
||||
helper_1436(T1 t1_, T2 t2_):
|
||||
t1{ t1_ },
|
||||
t2{ t2_ }
|
||||
{}
|
||||
T1 t1;
|
||||
T2 t2;
|
||||
};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
std::ostream& operator<<(std::ostream& out, helper_1436<T1, T2> const& helper) {
|
||||
out << "{ " << helper.t1 << ", " << helper.t2 << " }";
|
||||
return out;
|
||||
}
|
||||
|
||||
// Clang and gcc have different names for this warning, and clang also
|
||||
// warns about an unused value. This warning must be disabled for C++20.
|
||||
#if defined(__GNUG__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpragmas"
|
||||
#pragma GCC diagnostic ignored "-Wcomma-subscript"
|
||||
#elif defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma clang diagnostic ignored "-Wunknown-warning-option"
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-comma-subscript"
|
||||
#pragma clang diagnostic ignored "-Wunused-value"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
struct custom_index_op {
|
||||
constexpr custom_index_op( std::initializer_list<T> ) {}
|
||||
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(custom_index_op<int>{1, 2, 3}[0, 1, 2],
|
||||
custom_index_op<int>{1, 2, 3}[(0, 1)],
|
||||
custom_index_op<int>{1, 2, 3}[0]);
|
||||
CAPTURE((helper_1436<int, int>{12, -12}),
|
||||
(helper_1436<int, int>(-12, 12)));
|
||||
CAPTURE( (1, 2), (2, 3) );
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
#ifdef __GNUG__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
TEST_CASE("CAPTURE parses string and character constants", "[messages][capture]") {
|
||||
CAPTURE(("comma, in string", "escaped, \", "), "single quote in string,',", "some escapes, \\,\\\\");
|
||||
CAPTURE("some, ), unmatched, } prenheses {[<");
|
||||
CAPTURE('"', '\'', ',', '}', ')', '(', '{');
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#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!" );
|
||||
}
|
@ -0,0 +1,560 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
#include <catch2/internal/catch_config_wchar.hpp>
|
||||
#include <catch2/internal/catch_windows_h_proxy.hpp>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <cerrno>
|
||||
#include <limits>
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
|
||||
namespace {
|
||||
|
||||
static const char* makeString(bool makeNull) {
|
||||
return makeNull ? nullptr : "valid string";
|
||||
}
|
||||
static bool testCheckedIf(bool flag) {
|
||||
CHECKED_IF(flag)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
static bool testCheckedElse(bool flag) {
|
||||
CHECKED_ELSE(flag)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned int Factorial(unsigned int number) {
|
||||
return number > 1 ? Factorial(number - 1) * number : 1;
|
||||
}
|
||||
|
||||
static int f() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void manuallyRegisteredTestFunction() {
|
||||
SUCCEED("was called");
|
||||
}
|
||||
|
||||
struct AutoTestReg {
|
||||
AutoTestReg() {
|
||||
REGISTER_TEST_CASE(manuallyRegisteredTestFunction, "ManuallyRegistered");
|
||||
}
|
||||
};
|
||||
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||
static AutoTestReg autoTestReg;
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
template<typename T>
|
||||
struct Foo {
|
||||
size_t size() { return 0; }
|
||||
};
|
||||
|
||||
template<typename T, size_t S>
|
||||
struct Bar {
|
||||
size_t size() { return S; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE( "random SECTION tests", "[.][sections][failing]" ) {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
|
||||
SECTION( "doesn't equal" ) {
|
||||
REQUIRE( a != b );
|
||||
REQUIRE( b != a );
|
||||
}
|
||||
|
||||
SECTION( "not equal" ) {
|
||||
REQUIRE( a != b);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "nested SECTION tests", "[.][sections][failing]" ) {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
|
||||
SECTION( "doesn't equal" ) {
|
||||
REQUIRE( a != b );
|
||||
REQUIRE( b != a );
|
||||
|
||||
SECTION( "not equal" ) {
|
||||
REQUIRE( a != b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "more nested SECTION tests", "[sections][failing][.]" ) {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
|
||||
SECTION( "doesn't equal" ) {
|
||||
SECTION( "equal" ) {
|
||||
REQUIRE( a == b );
|
||||
}
|
||||
|
||||
SECTION( "not equal" ) {
|
||||
REQUIRE( a != b );
|
||||
}
|
||||
SECTION( "less than" ) {
|
||||
REQUIRE( a < b );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "even more nested SECTION tests", "[sections]" ) {
|
||||
SECTION( "c" ) {
|
||||
SECTION( "d (leaf)" ) {
|
||||
SUCCEED(); // avoid failing due to no tests
|
||||
}
|
||||
|
||||
SECTION( "e (leaf)" ) {
|
||||
SUCCEED(); // avoid failing due to no tests
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "f (leaf)" ) {
|
||||
SUCCEED(); // avoid failing due to no tests
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "looped SECTION tests", "[.][failing][sections]" ) {
|
||||
int a = 1;
|
||||
|
||||
for( int b = 0; b < 10; ++b ) {
|
||||
DYNAMIC_SECTION( "b is currently: " << b ) {
|
||||
CHECK( b > a );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "looped tests", "[.][failing]" ) {
|
||||
static const int fib[] = { 1, 1, 2, 3, 5, 8, 13, 21 };
|
||||
|
||||
for( std::size_t i=0; i < sizeof(fib)/sizeof(int); ++i ) {
|
||||
INFO( "Testing if fib[" << i << "] (" << fib[i] << ") is even" );
|
||||
CHECK( ( fib[i] % 2 ) == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Sends stuff to stdout and stderr", "[.]" ) {
|
||||
std::cout << "A string sent directly to stdout\n" << std::flush;
|
||||
std::cerr << "A string sent directly to stderr\n" << std::flush;
|
||||
std::clog << "A string sent to stderr via clog\n" << std::flush;
|
||||
}
|
||||
|
||||
TEST_CASE( "null strings" ) {
|
||||
REQUIRE( makeString( false ) != static_cast<char*>(nullptr));
|
||||
REQUIRE( makeString( true ) == static_cast<char*>(nullptr));
|
||||
}
|
||||
|
||||
TEST_CASE( "checkedIf" ) {
|
||||
REQUIRE( testCheckedIf( true ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "checkedIf, failing", "[failing][.]" ) {
|
||||
REQUIRE( testCheckedIf( false ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "checkedElse" ) {
|
||||
REQUIRE( testCheckedElse( true ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "checkedElse, failing", "[failing][.]" ) {
|
||||
REQUIRE( testCheckedElse( false ) );
|
||||
}
|
||||
|
||||
TEST_CASE("Testing checked-if", "[checked-if]") {
|
||||
CHECKED_IF(true) {
|
||||
SUCCEED();
|
||||
}
|
||||
CHECKED_IF(false) {
|
||||
FAIL();
|
||||
}
|
||||
CHECKED_ELSE(true) {
|
||||
FAIL();
|
||||
}
|
||||
CHECKED_ELSE(false) {
|
||||
SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Testing checked-if 2", "[checked-if][!shouldfail]") {
|
||||
CHECKED_IF(true) {
|
||||
FAIL();
|
||||
}
|
||||
// If the checked if is not entered, this passes and the test
|
||||
// fails, because of the [!shouldfail] tag.
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE("Testing checked-if 3", "[checked-if][!shouldfail]") {
|
||||
CHECKED_ELSE(false) {
|
||||
FAIL();
|
||||
}
|
||||
// If the checked false is not entered, this passes and the test
|
||||
// fails, because of the [!shouldfail] tag.
|
||||
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: <test>it should be possible to embed xml characters, such as <, \" or &, or even whole <xml>documents</xml> within an attribute</test>" ) {
|
||||
SUCCEED(); // We need this here to stop it failing due to no tests
|
||||
}
|
||||
SECTION( "encoded chars: these should all be encoded: &&&\"\"\"<<<&\"<<&\"" ) {
|
||||
SUCCEED(); // We need this here to stop it failing due to no tests
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "send a single char to INFO", "[failing][.]" ) {
|
||||
INFO(3);
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
TEST_CASE( "Factorials are computed", "[factorial]" ) {
|
||||
REQUIRE( Factorial(0) == 1 );
|
||||
REQUIRE( Factorial(1) == 1 );
|
||||
REQUIRE( Factorial(2) == 2 );
|
||||
REQUIRE( Factorial(3) == 6 );
|
||||
REQUIRE( Factorial(10) == 3628800 );
|
||||
}
|
||||
|
||||
TEST_CASE( "An empty test with no assertions", "[empty]" ) {}
|
||||
|
||||
TEST_CASE( "Nice descriptive name", "[tag1][tag2][tag3][.]" ) {
|
||||
WARN( "This one ran" );
|
||||
}
|
||||
TEST_CASE( "first tag", "[tag1]" ) {}
|
||||
TEST_CASE( "second tag", "[tag2]" ) {}
|
||||
|
||||
TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
|
||||
|
||||
std::vector<int> v( 5 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
|
||||
SECTION( "resizing bigger changes size and capacity" ) {
|
||||
v.resize( 10 );
|
||||
|
||||
REQUIRE( v.size() == 10 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
SECTION( "resizing smaller changes size but not capacity" ) {
|
||||
v.resize( 0 );
|
||||
|
||||
REQUIRE( v.size() == 0 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
|
||||
SECTION( "We can use the 'swap trick' to reset the capacity" ) {
|
||||
std::vector<int> empty;
|
||||
empty.swap( v );
|
||||
|
||||
REQUIRE( v.capacity() == 0 );
|
||||
}
|
||||
}
|
||||
SECTION( "reserving bigger changes capacity but not size" ) {
|
||||
v.reserve( 10 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
SECTION( "reserving smaller does not change size or capacity" ) {
|
||||
v.reserve( 0 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE( "TemplateTest: vectors can be sized and resized", "[vector][template]", int, float, std::string, (std::tuple<int,float>) ) {
|
||||
|
||||
std::vector<TestType> v( 5 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
|
||||
SECTION( "resizing bigger changes size and capacity" ) {
|
||||
v.resize( 10 );
|
||||
|
||||
REQUIRE( v.size() == 10 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
SECTION( "resizing smaller changes size but not capacity" ) {
|
||||
v.resize( 0 );
|
||||
|
||||
REQUIRE( v.size() == 0 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
|
||||
SECTION( "We can use the 'swap trick' to reset the capacity" ) {
|
||||
std::vector<TestType> empty;
|
||||
empty.swap( v );
|
||||
|
||||
REQUIRE( v.capacity() == 0 );
|
||||
}
|
||||
}
|
||||
SECTION( "reserving bigger changes capacity but not size" ) {
|
||||
v.reserve( 10 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
SECTION( "reserving smaller does not change size or capacity" ) {
|
||||
v.reserve( 0 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE_SIG("TemplateTestSig: vectors can be sized and resized", "[vector][template][nttp]", ((typename TestType, int V), TestType, V), (int,5), (float,4), (std::string,15), ((std::tuple<int, float>), 6)) {
|
||||
|
||||
std::vector<TestType> v(V);
|
||||
|
||||
REQUIRE(v.size() == V);
|
||||
REQUIRE(v.capacity() >= V);
|
||||
|
||||
SECTION("resizing bigger changes size and capacity") {
|
||||
v.resize(2 * V);
|
||||
|
||||
REQUIRE(v.size() == 2 * V);
|
||||
REQUIRE(v.capacity() >= 2 * V);
|
||||
}
|
||||
SECTION("resizing smaller changes size but not capacity") {
|
||||
v.resize(0);
|
||||
|
||||
REQUIRE(v.size() == 0);
|
||||
REQUIRE(v.capacity() >= V);
|
||||
|
||||
SECTION("We can use the 'swap trick' to reset the capacity") {
|
||||
std::vector<TestType> empty;
|
||||
empty.swap(v);
|
||||
|
||||
REQUIRE(v.capacity() == 0);
|
||||
}
|
||||
}
|
||||
SECTION("reserving bigger changes capacity but not size") {
|
||||
v.reserve(2 * V);
|
||||
|
||||
REQUIRE(v.size() == V);
|
||||
REQUIRE(v.capacity() >= 2 * V);
|
||||
}
|
||||
SECTION("reserving smaller does not change size or capacity") {
|
||||
v.reserve(0);
|
||||
|
||||
REQUIRE(v.size() == V);
|
||||
REQUIRE(v.capacity() >= V);
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE("A Template product test case", "[template][product]", (std::vector, Foo), (int, float)) {
|
||||
TestType x;
|
||||
REQUIRE(x.size() == 0);
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_SIG("A Template product test case with array signature", "[template][product][nttp]", ((typename T, size_t S), T, S), (std::array, Bar), ((int, 9), (float, 42))) {
|
||||
TestType x;
|
||||
REQUIRE(x.size() > 0);
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE("Product with differing arities", "[template][product]", std::tuple, (int, (int, double), (int, double, float))) {
|
||||
REQUIRE(std::tuple_size<TestType>::value >= 1);
|
||||
}
|
||||
|
||||
using MyTypes = std::tuple<int, char, float>;
|
||||
TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside std::tuple", "[template][list]", MyTypes)
|
||||
{
|
||||
REQUIRE(std::is_arithmetic<TestType>::value);
|
||||
}
|
||||
|
||||
struct NonDefaultConstructibleType {
|
||||
NonDefaultConstructibleType() = delete;
|
||||
};
|
||||
|
||||
using MyNonDefaultConstructibleTypes = std::tuple<NonDefaultConstructibleType, float>;
|
||||
TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside non-default-constructible std::tuple", "[template][list]", MyNonDefaultConstructibleTypes)
|
||||
{
|
||||
REQUIRE(std::is_trivially_copyable<TestType>::value);
|
||||
}
|
||||
|
||||
struct NonCopyableAndNonMovableType {
|
||||
NonCopyableAndNonMovableType() = default;
|
||||
|
||||
NonCopyableAndNonMovableType(NonCopyableAndNonMovableType const &) = delete;
|
||||
NonCopyableAndNonMovableType(NonCopyableAndNonMovableType &&) = delete;
|
||||
auto operator=(NonCopyableAndNonMovableType const &) -> NonCopyableAndNonMovableType & = delete;
|
||||
auto operator=(NonCopyableAndNonMovableType &&) -> NonCopyableAndNonMovableType & = delete;
|
||||
};
|
||||
|
||||
using NonCopyableAndNonMovableTypes = std::tuple<NonCopyableAndNonMovableType, float>;
|
||||
TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside non-copyable and non-movable std::tuple", "[template][list]", NonCopyableAndNonMovableTypes)
|
||||
{
|
||||
REQUIRE(std::is_default_constructible<TestType>::value);
|
||||
}
|
||||
|
||||
// https://github.com/philsquared/Catch/issues/166
|
||||
TEST_CASE("A couple of nested sections followed by a failure", "[failing][.]") {
|
||||
SECTION("Outer")
|
||||
SECTION("Inner")
|
||||
SUCCEED("that's not flying - that's failing in style");
|
||||
|
||||
FAIL("to infinity and beyond");
|
||||
}
|
||||
|
||||
TEST_CASE("not allowed", "[!throws]") {
|
||||
// This test case should not be included if you run with -e on the command line
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE( "Tabs and newlines show in output", "[.][whitespace][failing]" ) {
|
||||
|
||||
// Based on issue #242
|
||||
std::string s1 = "if ($b == 10) {\n\t\t$a\t= 20;\n}";
|
||||
std::string s2 = "if ($b == 10) {\n\t$a = 20;\n}\n";
|
||||
CHECK( s1 == s2 );
|
||||
}
|
||||
|
||||
|
||||
#if defined(CATCH_CONFIG_WCHAR)
|
||||
TEST_CASE( "toString on const wchar_t const pointer returns the string contents", "[toString]" ) {
|
||||
const wchar_t * const s = L"wide load";
|
||||
std::string result = ::Catch::Detail::stringify( s );
|
||||
CHECK( result == "\"wide load\"" );
|
||||
}
|
||||
|
||||
TEST_CASE( "toString on const wchar_t pointer returns the string contents", "[toString]" ) {
|
||||
const wchar_t * s = L"wide load";
|
||||
std::string result = ::Catch::Detail::stringify( s );
|
||||
CHECK( result == "\"wide load\"" );
|
||||
}
|
||||
|
||||
TEST_CASE( "toString on wchar_t const pointer returns the string contents", "[toString]" ) {
|
||||
auto const s = const_cast<wchar_t*>( L"wide load" );
|
||||
std::string result = ::Catch::Detail::stringify( s );
|
||||
CHECK( result == "\"wide load\"" );
|
||||
}
|
||||
|
||||
TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) {
|
||||
auto s = const_cast<wchar_t*>( L"wide load" );
|
||||
std::string result = ::Catch::Detail::stringify( s );
|
||||
CHECK( result == "\"wide load\"" );
|
||||
}
|
||||
#endif // CATCH_CONFIG_WCHAR
|
||||
|
||||
TEST_CASE( "long long" ) {
|
||||
constexpr long long l = std::numeric_limits<long long>::max();
|
||||
|
||||
REQUIRE( l == std::numeric_limits<long long>::max() );
|
||||
}
|
||||
|
||||
TEST_CASE( "This test 'should' fail but doesn't", "[.][failing][!shouldfail]" ) {
|
||||
SUCCEED( "oops!" );
|
||||
}
|
||||
|
||||
TEST_CASE( "# A test name that starts with a #" ) {
|
||||
SUCCEED( "yay" );
|
||||
}
|
||||
|
||||
TEST_CASE( "#835 -- errno should not be touched by Catch2", "[.][failing][!shouldfail]" ) {
|
||||
errno = 1;
|
||||
// Check that reporting failed test doesn't change errno.
|
||||
CHECK(f() == 0);
|
||||
// We want to avoid expanding `errno` macro in assertion, because
|
||||
// we capture the expression after macro expansion, and would have
|
||||
// to normalize the ways different platforms spell `errno`.
|
||||
const auto errno_after = errno;
|
||||
REQUIRE(errno_after == 1);
|
||||
}
|
||||
|
||||
TEST_CASE( "#961 -- Dynamically created sections should all be reported", "[.]" ) {
|
||||
for (char i = '0'; i < '5'; ++i) {
|
||||
SECTION(std::string("Looped section ") + i) {
|
||||
SUCCEED( "Everything is OK" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "#1175 - Hidden Test", "[.]" ) {
|
||||
// Just for checking that hidden test is not listed by default
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE_SIG("#1954 - 7 arg template test case sig compiles", "[regression][.compilation]",
|
||||
((int Tnx, int Tnu, int Tny, int Tph, int Tch, int Tineq, int Teq), Tnx, Tnu, Tny, Tph, Tch, Tineq, Teq),
|
||||
(1, 1, 1, 1, 1, 0, 0), (5, 1, 1, 1, 1, 0, 0), (5, 3, 1, 1, 1, 0, 0)) {
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE("Same test name but with different tags is fine", "[.approvals][some-tag]") {}
|
||||
TEST_CASE("Same test name but with different tags is fine", "[.approvals][other-tag]") {}
|
||||
|
||||
// MinGW doesn't support __try, and Clang has only very partial support
|
||||
#if defined(_MSC_VER)
|
||||
void throw_and_catch()
|
||||
{
|
||||
__try {
|
||||
RaiseException(0xC0000005, 0, 0, NULL);
|
||||
}
|
||||
__except (1)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Validate SEH behavior - handled", "[approvals][FatalConditionHandler][CATCH_PLATFORM_WINDOWS]")
|
||||
{
|
||||
// Validate that Catch2 framework correctly handles tests raising and handling SEH exceptions.
|
||||
throw_and_catch();
|
||||
}
|
||||
|
||||
void throw_no_catch()
|
||||
{
|
||||
RaiseException(0xC0000005, 0, 0, NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Validate SEH behavior - unhandled", "[.approvals][FatalConditionHandler][CATCH_PLATFORM_WINDOWS]")
|
||||
{
|
||||
// Validate that Catch2 framework correctly handles tests raising and not handling SEH exceptions.
|
||||
throw_no_catch();
|
||||
}
|
||||
|
||||
static LONG CALLBACK dummyExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
TEST_CASE("Validate SEH behavior - no crash for stack unwinding", "[approvals][!throws][!shouldfail][FatalConditionHandler][CATCH_PLATFORM_WINDOWS]")
|
||||
{
|
||||
// Trigger stack unwinding with SEH top-level filter changed and validate the test fails expectedly with no application crash
|
||||
SetUnhandledExceptionFilter(dummyExceptionFilter);
|
||||
throw 1;
|
||||
}
|
||||
|
||||
#endif // _MSC_VER
|
@ -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 <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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<int> {
|
||||
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<int> {
|
||||
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 );
|
||||
}
|
@ -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
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#if defined(CATCH_CONFIG_CPP17_BYTE)
|
||||
|
||||
TEST_CASE( "std::byte -> toString", "[toString][byte][approvals]" ) {
|
||||
using type = std::byte;
|
||||
REQUIRE( "0" == ::Catch::Detail::stringify( type{ 0 } ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "std::vector<std::byte> -> toString", "[toString][byte][approvals]" ) {
|
||||
using type = std::vector<std::byte>;
|
||||
REQUIRE( "{ 0, 1, 2 }" == ::Catch::Detail::stringify( type{ std::byte{0}, std::byte{1}, std::byte{2} } ) );
|
||||
}
|
||||
|
||||
#endif // CATCH_INTERNAL_CONFIG_CPP17_BYTE
|
@ -0,0 +1,51 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
TEST_CASE("Stringifying std::chrono::duration helpers", "[toString][chrono]") {
|
||||
// No literals because we still support c++11
|
||||
auto hour = std::chrono::hours(1);
|
||||
auto minute = std::chrono::minutes(1);
|
||||
auto seconds = std::chrono::seconds(60);
|
||||
auto micro = std::chrono::microseconds(1);
|
||||
auto milli = std::chrono::milliseconds(1);
|
||||
auto nano = std::chrono::nanoseconds(1);
|
||||
REQUIRE(minute == seconds);
|
||||
REQUIRE(hour != seconds);
|
||||
REQUIRE(micro != milli);
|
||||
REQUIRE(nano != micro);
|
||||
}
|
||||
|
||||
TEST_CASE("Stringifying std::chrono::duration with weird ratios", "[toString][chrono]") {
|
||||
std::chrono::duration<int64_t, std::ratio<30>> half_minute(1);
|
||||
std::chrono::duration<int64_t, std::ratio<1, 1000000000000>> pico_second(1);
|
||||
std::chrono::duration<int64_t, std::ratio<1, 1000000000000000>> femto_second(1);
|
||||
std::chrono::duration<int64_t, std::ratio<1, 1000000000000000000>> atto_second(1);
|
||||
REQUIRE(half_minute != femto_second);
|
||||
REQUIRE(pico_second != atto_second);
|
||||
}
|
||||
|
||||
TEST_CASE("Stringifying std::chrono::time_point<system_clock>", "[toString][chrono]") {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto later = now + std::chrono::minutes(2);
|
||||
REQUIRE(now != later);
|
||||
}
|
||||
|
||||
TEST_CASE("Stringifying std::chrono::time_point<Clock>", "[toString][chrono][!nonportable]") {
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
auto later = now + std::chrono::minutes(2);
|
||||
REQUIRE(now != later);
|
||||
|
||||
auto now2 = std::chrono::steady_clock::now();
|
||||
auto later2 = now2 + std::chrono::minutes(2);
|
||||
REQUIRE(now2 != later2);
|
||||
}
|
@ -0,0 +1,200 @@
|
||||
|
||||
// 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
|
||||
|
||||
#define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
TEST_CASE( "Character pretty printing" ){
|
||||
SECTION("Specifically escaped"){
|
||||
CHECK(::Catch::Detail::stringify('\t') == "'\\t'");
|
||||
CHECK(::Catch::Detail::stringify('\n') == "'\\n'");
|
||||
CHECK(::Catch::Detail::stringify('\r') == "'\\r'");
|
||||
CHECK(::Catch::Detail::stringify('\f') == "'\\f'");
|
||||
}
|
||||
SECTION("General chars"){
|
||||
CHECK(::Catch::Detail::stringify( ' ' ) == "' '" );
|
||||
CHECK(::Catch::Detail::stringify( 'A' ) == "'A'" );
|
||||
CHECK(::Catch::Detail::stringify( 'z' ) == "'z'" );
|
||||
}
|
||||
SECTION("Low ASCII"){
|
||||
CHECK(::Catch::Detail::stringify( '\0' ) == "0" );
|
||||
CHECK(::Catch::Detail::stringify( static_cast<char>(2) ) == "2" );
|
||||
CHECK(::Catch::Detail::stringify( static_cast<char>(5) ) == "5" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "Capture and info messages" ) {
|
||||
SECTION("Capture should stringify like assertions") {
|
||||
int i = 2;
|
||||
CAPTURE(i);
|
||||
REQUIRE(true);
|
||||
}
|
||||
SECTION("Info should NOT stringify the way assertions do") {
|
||||
int i = 3;
|
||||
INFO(i);
|
||||
REQUIRE(true);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "std::map is convertible string", "[toString]" ) {
|
||||
|
||||
SECTION( "empty" ) {
|
||||
std::map<std::string, int> emptyMap;
|
||||
|
||||
REQUIRE( Catch::Detail::stringify( emptyMap ) == "{ }" );
|
||||
}
|
||||
|
||||
SECTION( "single item" ) {
|
||||
std::map<std::string, int> map = { { "one", 1 } };
|
||||
|
||||
REQUIRE( Catch::Detail::stringify( map ) == "{ { \"one\", 1 } }" );
|
||||
}
|
||||
|
||||
SECTION( "several items" ) {
|
||||
std::map<std::string, int> map = {
|
||||
{ "abc", 1 },
|
||||
{ "def", 2 },
|
||||
{ "ghi", 3 }
|
||||
};
|
||||
|
||||
REQUIRE( Catch::Detail::stringify( map ) == "{ { \"abc\", 1 }, { \"def\", 2 }, { \"ghi\", 3 } }" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "std::set is convertible string", "[toString]" ) {
|
||||
|
||||
SECTION( "empty" ) {
|
||||
std::set<std::string> emptySet;
|
||||
|
||||
REQUIRE( Catch::Detail::stringify( emptySet ) == "{ }" );
|
||||
}
|
||||
|
||||
SECTION( "single item" ) {
|
||||
std::set<std::string> set = { "one" };
|
||||
|
||||
REQUIRE( Catch::Detail::stringify( set ) == "{ \"one\" }" );
|
||||
}
|
||||
|
||||
SECTION( "several items" ) {
|
||||
std::set<std::string> set = { "abc", "def", "ghi" };
|
||||
|
||||
REQUIRE( Catch::Detail::stringify( set ) == "{ \"abc\", \"def\", \"ghi\" }" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Static arrays are convertible to string", "[toString]") {
|
||||
SECTION("Single item") {
|
||||
int singular[1] = { 1 };
|
||||
REQUIRE(Catch::Detail::stringify(singular) == "{ 1 }");
|
||||
}
|
||||
SECTION("Multiple") {
|
||||
int arr[3] = { 3, 2, 1 };
|
||||
REQUIRE(Catch::Detail::stringify(arr) == "{ 3, 2, 1 }");
|
||||
}
|
||||
SECTION("Non-trivial inner items") {
|
||||
std::vector<std::string> arr[2] = { {"1:1", "1:2", "1:3"}, {"2:1", "2:2"} };
|
||||
REQUIRE(Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
|
||||
|
||||
TEST_CASE("String views are stringified like other strings", "[toString][approvals]") {
|
||||
std::string_view view{"abc"};
|
||||
CHECK(Catch::Detail::stringify(view) == R"("abc")");
|
||||
|
||||
std::string_view arr[] { view };
|
||||
CHECK(Catch::Detail::stringify(arr) == R"({ "abc" })");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST_CASE("Precision of floating point stringification can be set", "[toString][floatingPoint]") {
|
||||
SECTION("Floats") {
|
||||
using sm = Catch::StringMaker<float>;
|
||||
const auto oldPrecision = sm::precision;
|
||||
|
||||
const float testFloat = 1.12345678901234567899f;
|
||||
sm::precision = 5;
|
||||
auto str1 = sm::convert( testFloat );
|
||||
// "1." prefix = 2 chars, f suffix is another char
|
||||
CHECK(str1.size() == 3 + 5);
|
||||
|
||||
sm::precision = 10;
|
||||
auto str2 = sm::convert(testFloat);
|
||||
REQUIRE(str2.size() == 3 + 10);
|
||||
sm::precision = oldPrecision;
|
||||
}
|
||||
SECTION("Double") {
|
||||
using sm = Catch::StringMaker<double>;
|
||||
const auto oldPrecision = sm::precision;
|
||||
|
||||
const double testDouble = 1.123456789012345678901234567899;
|
||||
sm::precision = 5;
|
||||
auto str1 = sm::convert(testDouble);
|
||||
// "1." prefix = 2 chars
|
||||
CHECK(str1.size() == 2 + 5);
|
||||
|
||||
sm::precision = 15;
|
||||
auto str2 = sm::convert(testDouble);
|
||||
REQUIRE(str2.size() == 2 + 15);
|
||||
|
||||
sm::precision = oldPrecision;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct WhatException : std::exception {
|
||||
char const* what() const noexcept override {
|
||||
return "This exception has overridden what() method";
|
||||
}
|
||||
~WhatException() override;
|
||||
};
|
||||
|
||||
struct OperatorException : std::exception {
|
||||
~OperatorException() override;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, OperatorException const&) {
|
||||
out << "OperatorException";
|
||||
return out;
|
||||
}
|
||||
|
||||
struct StringMakerException : std::exception {
|
||||
~StringMakerException() override;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace Catch {
|
||||
template <>
|
||||
struct StringMaker<StringMakerException> {
|
||||
static std::string convert(StringMakerException const&) {
|
||||
return "StringMakerException";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Avoid -Wweak-tables
|
||||
WhatException::~WhatException() = default;
|
||||
OperatorException::~OperatorException() = default;
|
||||
StringMakerException::~StringMakerException() = default;
|
||||
|
||||
|
||||
|
||||
|
||||
TEST_CASE("Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified", "[toString][exception]") {
|
||||
REQUIRE(::Catch::Detail::stringify(WhatException{}) == "This exception has overridden what() method");
|
||||
REQUIRE(::Catch::Detail::stringify(OperatorException{}) == "OperatorException");
|
||||
REQUIRE(::Catch::Detail::stringify(StringMakerException{}) == "StringMakerException");
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
|
||||
// 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
|
||||
|
||||
#define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#if defined(CATCH_CONFIG_CPP17_OPTIONAL)
|
||||
|
||||
TEST_CASE( "std::optional<int> -> toString", "[toString][optional][approvals]" ) {
|
||||
using type = std::optional<int>;
|
||||
REQUIRE( "{ }" == ::Catch::Detail::stringify( type{} ) );
|
||||
REQUIRE( "0" == ::Catch::Detail::stringify( type{ 0 } ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "std::optional<std::string> -> toString", "[toString][optional][approvals]" ) {
|
||||
using type = std::optional<std::string>;
|
||||
REQUIRE( "{ }" == ::Catch::Detail::stringify( type{} ) );
|
||||
REQUIRE( "\"abc\"" == ::Catch::Detail::stringify( type{ "abc" } ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "std::vector<std::optional<int> > -> toString", "[toString][optional][approvals]" ) {
|
||||
using type = std::vector<std::optional<int> >;
|
||||
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
|
@ -0,0 +1,38 @@
|
||||
|
||||
// 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
|
||||
|
||||
#define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
TEST_CASE( "std::pair<int,std::string> -> toString", "[toString][pair]" ) {
|
||||
std::pair<int,std::string> value( 34, "xyzzy" );
|
||||
REQUIRE( ::Catch::Detail::stringify( value ) == "{ 34, \"xyzzy\" }" );
|
||||
}
|
||||
|
||||
TEST_CASE( "std::pair<int,const std::string> -> toString", "[toString][pair]" ) {
|
||||
std::pair<int,const std::string> value( 34, "xyzzy" );
|
||||
REQUIRE( ::Catch::Detail::stringify(value) == "{ 34, \"xyzzy\" }" );
|
||||
}
|
||||
|
||||
TEST_CASE( "std::vector<std::pair<std::string,int> > -> toString", "[toString][pair]" ) {
|
||||
std::vector<std::pair<std::string,int> > pr;
|
||||
pr.push_back( std::make_pair("green", 55 ) );
|
||||
REQUIRE( ::Catch::Detail::stringify( pr ) == "{ { \"green\", 55 } }" );
|
||||
}
|
||||
|
||||
// This is pretty contrived - I figure if this works, anything will...
|
||||
TEST_CASE( "pair<pair<int,const char *,pair<std::string,int> > -> toString", "[toString][pair]" ) {
|
||||
typedef std::pair<int,const char *> left_t;
|
||||
typedef std::pair<std::string,int> right_t;
|
||||
|
||||
left_t left( 42, "Arthur" );
|
||||
right_t right( "Ford", 24 );
|
||||
|
||||
std::pair<left_t,right_t> pair( left, right );
|
||||
REQUIRE( ::Catch::Detail::stringify( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" );
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
|
||||
// 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
|
||||
|
||||
#define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
TEST_CASE( "tuple<>", "[toString][tuple]" )
|
||||
{
|
||||
typedef std::tuple<> type;
|
||||
CHECK( "{ }" == ::Catch::Detail::stringify(type{}) );
|
||||
type value {};
|
||||
CHECK( "{ }" == ::Catch::Detail::stringify(value) );
|
||||
}
|
||||
|
||||
TEST_CASE( "tuple<int>", "[toString][tuple]" )
|
||||
{
|
||||
typedef std::tuple<int> type;
|
||||
CHECK( "{ 0 }" == ::Catch::Detail::stringify(type{0}) );
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "tuple<float,int>", "[toString][tuple]" )
|
||||
{
|
||||
typedef std::tuple<float,int> type;
|
||||
CHECK( "1.5f" == ::Catch::Detail::stringify(float(1.5)) );
|
||||
CHECK( "{ 1.5f, 0 }" == ::Catch::Detail::stringify(type{1.5f,0}) );
|
||||
}
|
||||
|
||||
TEST_CASE( "tuple<string,string>", "[toString][tuple]" )
|
||||
{
|
||||
typedef std::tuple<std::string,std::string> type;
|
||||
CHECK( "{ \"hello\", \"world\" }" == ::Catch::Detail::stringify(type{"hello","world"}) );
|
||||
}
|
||||
|
||||
TEST_CASE( "tuple<tuple<int>,tuple<>,float>", "[toString][tuple]" )
|
||||
{
|
||||
typedef std::tuple<std::tuple<int>,std::tuple<>,float> type;
|
||||
type value { std::tuple<int>{42}, {}, 1.5f };
|
||||
CHECK( "{ { 42 }, { }, 1.5f }" == ::Catch::Detail::stringify(value) );
|
||||
}
|
||||
|
||||
TEST_CASE( "tuple<nullptr,int,const char *>", "[approvals][toString][tuple]" ) {
|
||||
typedef std::tuple<std::nullptr_t,int,const char *> type;
|
||||
type value { nullptr, 42, "Catch me" };
|
||||
CHECK( "{ nullptr, 42, \"Catch me\" }" == ::Catch::Detail::stringify(value) );
|
||||
}
|
||||
|
@ -0,0 +1,99 @@
|
||||
|
||||
// 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
|
||||
|
||||
#define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#if defined(CATCH_CONFIG_CPP17_VARIANT)
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
// We need 2 types with non-trivial copies/moves
|
||||
struct MyType1 {
|
||||
MyType1() = default;
|
||||
[[noreturn]] MyType1(MyType1 const&) { throw 1; }
|
||||
MyType1& operator=(MyType1 const&) { throw 3; }
|
||||
};
|
||||
struct MyType2 {
|
||||
MyType2() = default;
|
||||
[[noreturn]] MyType2(MyType2 const&) { throw 2; }
|
||||
MyType2& operator=(MyType2 const&) { throw 4; }
|
||||
};
|
||||
|
||||
TEST_CASE( "variant<std::monostate>", "[toString][variant][approvals]")
|
||||
{
|
||||
using type = std::variant<std::monostate>;
|
||||
CHECK( "{ }" == ::Catch::Detail::stringify(type{}) );
|
||||
type value {};
|
||||
CHECK( "{ }" == ::Catch::Detail::stringify(value) );
|
||||
CHECK( "{ }" == ::Catch::Detail::stringify(std::get<0>(value)) );
|
||||
}
|
||||
|
||||
TEST_CASE( "variant<int>", "[toString][variant][approvals]")
|
||||
{
|
||||
using type = std::variant<int>;
|
||||
CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
|
||||
}
|
||||
|
||||
TEST_CASE( "variant<float, int>", "[toString][variant][approvals]")
|
||||
{
|
||||
using type = std::variant<float, int>;
|
||||
CHECK( "0.5f" == ::Catch::Detail::stringify(type{0.5f}) );
|
||||
CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
|
||||
}
|
||||
|
||||
TEST_CASE( "variant -- valueless-by-exception", "[toString][variant][approvals]" ) {
|
||||
using type = std::variant<MyType1, MyType2>;
|
||||
|
||||
type value;
|
||||
REQUIRE_THROWS_AS(value.emplace<MyType2>(MyType2{}), int);
|
||||
REQUIRE(value.valueless_by_exception());
|
||||
CHECK("{valueless variant}" == ::Catch::Detail::stringify(value));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "variant<string, int>", "[toString][variant][approvals]")
|
||||
{
|
||||
using type = std::variant<std::string, int>;
|
||||
CHECK( "\"foo\"" == ::Catch::Detail::stringify(type{"foo"}) );
|
||||
CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
|
||||
}
|
||||
|
||||
TEST_CASE( "variant<variant<float, int>, string>", "[toString][variant][approvals]")
|
||||
{
|
||||
using inner = std::variant<MyType1, float, int>;
|
||||
using type = std::variant<inner, std::string>;
|
||||
CHECK( "0.5f" == ::Catch::Detail::stringify(type{0.5f}) );
|
||||
CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
|
||||
CHECK( "\"foo\"" == ::Catch::Detail::stringify(type{"foo"}) );
|
||||
|
||||
SECTION("valueless nested variant") {
|
||||
type value = inner{0.5f};
|
||||
REQUIRE( std::holds_alternative<inner>(value) );
|
||||
REQUIRE( std::holds_alternative<float>(std::get<inner>(value)) );
|
||||
|
||||
REQUIRE_THROWS_AS( std::get<0>(value).emplace<MyType1>(MyType1{}), int );
|
||||
|
||||
// outer variant is still valid and contains inner
|
||||
REQUIRE( std::holds_alternative<inner>(value) );
|
||||
// inner variant is valueless
|
||||
REQUIRE( std::get<inner>(value).valueless_by_exception() );
|
||||
CHECK( "{valueless variant}" == ::Catch::Detail::stringify(value) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "variant<nullptr,int,const char *>", "[toString][variant][approvals]" )
|
||||
{
|
||||
using type = std::variant<std::nullptr_t,int,const char *>;
|
||||
CHECK( "nullptr" == ::Catch::Detail::stringify(type{nullptr}) );
|
||||
CHECK( "42" == ::Catch::Detail::stringify(type{42}) );
|
||||
CHECK( "\"Catch me\"" == ::Catch::Detail::stringify(type{"Catch me"}) );
|
||||
}
|
||||
|
||||
#endif // CATCH_INTERNAL_CONFIG_CPP17_VARIANT
|
@ -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 <catch2/catch_test_macros.hpp>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
// vector
|
||||
TEST_CASE( "vector<int> -> toString", "[toString][vector]" )
|
||||
{
|
||||
std::vector<int> vv;
|
||||
REQUIRE( ::Catch::Detail::stringify(vv) == "{ }" );
|
||||
vv.push_back( 42 );
|
||||
REQUIRE( ::Catch::Detail::stringify(vv) == "{ 42 }" );
|
||||
vv.push_back( 250 );
|
||||
REQUIRE( ::Catch::Detail::stringify(vv) == "{ 42, 250 }" );
|
||||
}
|
||||
|
||||
TEST_CASE( "vector<string> -> toString", "[toString][vector]" )
|
||||
{
|
||||
std::vector<std::string> vv;
|
||||
REQUIRE( ::Catch::Detail::stringify(vv) == "{ }" );
|
||||
vv.emplace_back( "hello" );
|
||||
REQUIRE( ::Catch::Detail::stringify(vv) == "{ \"hello\" }" );
|
||||
vv.emplace_back( "world" );
|
||||
REQUIRE( ::Catch::Detail::stringify(vv) == "{ \"hello\", \"world\" }" );
|
||||
}
|
||||
|
||||
namespace {
|
||||
/* Minimal Allocator */
|
||||
template<typename T>
|
||||
struct minimal_allocator {
|
||||
using value_type = T;
|
||||
using size_type = std::size_t;
|
||||
|
||||
minimal_allocator() = default;
|
||||
template <typename U>
|
||||
minimal_allocator(const minimal_allocator<U>&) {}
|
||||
|
||||
|
||||
T *allocate( size_type n ) {
|
||||
return static_cast<T *>( ::operator new( n * sizeof(T) ) );
|
||||
}
|
||||
void deallocate( T *p, size_type /*n*/ ) {
|
||||
::operator delete( static_cast<void *>(p) );
|
||||
}
|
||||
template<typename U>
|
||||
bool operator==( const minimal_allocator<U>& ) const { return true; }
|
||||
template<typename U>
|
||||
bool operator!=( const minimal_allocator<U>& ) const { return false; }
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE( "vector<int,allocator> -> toString", "[toString][vector,allocator]" ) {
|
||||
std::vector<int,minimal_allocator<int> > vv;
|
||||
REQUIRE( ::Catch::Detail::stringify(vv) == "{ }" );
|
||||
vv.push_back( 42 );
|
||||
REQUIRE( ::Catch::Detail::stringify(vv) == "{ 42 }" );
|
||||
vv.push_back( 250 );
|
||||
REQUIRE( ::Catch::Detail::stringify(vv) == "{ 42, 250 }" );
|
||||
}
|
||||
|
||||
TEST_CASE( "vec<vec<string,alloc>> -> toString", "[toString][vector,allocator]" ) {
|
||||
using inner = std::vector<std::string, minimal_allocator<std::string>>;
|
||||
using vector = std::vector<inner>;
|
||||
vector v;
|
||||
REQUIRE( ::Catch::Detail::stringify(v) == "{ }" );
|
||||
v.push_back( inner { "hello" } );
|
||||
v.push_back( inner { "world" } );
|
||||
REQUIRE( ::Catch::Detail::stringify(v) == "{ { \"hello\" }, { \"world\" } }" );
|
||||
}
|
||||
|
||||
// Based on PR by mat-so: https://github.com/catchorg/Catch2/pull/606/files#diff-43562f40f8c6dcfe2c54557316e0f852
|
||||
TEST_CASE( "vector<bool> -> toString", "[toString][containers][vector]" ) {
|
||||
std::vector<bool> bools;
|
||||
REQUIRE( ::Catch::Detail::stringify(bools) == "{ }");
|
||||
bools.push_back(true);
|
||||
REQUIRE( ::Catch::Detail::stringify(bools) == "{ true }");
|
||||
bools.push_back(false);
|
||||
REQUIRE( ::Catch::Detail::stringify(bools) == "{ true, false }");
|
||||
}
|
||||
TEST_CASE( "array<int, N> -> toString", "[toString][containers][array]" ) {
|
||||
std::array<int, 0> empty;
|
||||
REQUIRE( Catch::Detail::stringify( empty ) == "{ }" );
|
||||
std::array<int, 1> oneValue = {{ 42 }};
|
||||
REQUIRE( Catch::Detail::stringify( oneValue ) == "{ 42 }" );
|
||||
std::array<int, 2> twoValues = {{ 42, 250 }};
|
||||
REQUIRE( Catch::Detail::stringify( twoValues ) == "{ 42, 250 }" );
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
// This has to be left enabled until end of the TU, because the GCC
|
||||
// frontend reports operator<<(std::ostream& os, const has_maker_and_operator&)
|
||||
// as unused anyway
|
||||
# pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
struct has_operator { };
|
||||
struct has_maker {};
|
||||
struct has_maker_and_operator {};
|
||||
struct has_neither {};
|
||||
struct has_template_operator {};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const has_operator&) {
|
||||
os << "operator<<( has_operator )";
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const has_maker_and_operator&) {
|
||||
os << "operator<<( has_maker_and_operator )";
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename StreamT>
|
||||
StreamT& operator<<(StreamT& os, const has_template_operator&) {
|
||||
os << "operator<<( has_template_operator )";
|
||||
return os;
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace Catch {
|
||||
template<>
|
||||
struct StringMaker<has_maker> {
|
||||
static std::string convert( const has_maker& ) {
|
||||
return "StringMaker<has_maker>";
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct StringMaker<has_maker_and_operator> {
|
||||
static std::string convert( const has_maker_and_operator& ) {
|
||||
return "StringMaker<has_maker_and_operator>";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Call the operator
|
||||
TEST_CASE( "stringify( has_operator )", "[toString]" ) {
|
||||
has_operator item;
|
||||
REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_operator )" );
|
||||
}
|
||||
|
||||
// Call the stringmaker
|
||||
TEST_CASE( "stringify( has_maker )", "[toString]" ) {
|
||||
has_maker item;
|
||||
REQUIRE( ::Catch::Detail::stringify( item ) == "StringMaker<has_maker>" );
|
||||
}
|
||||
|
||||
// Call the stringmaker
|
||||
TEST_CASE( "stringify( has_maker_and_operator )", "[toString]" ) {
|
||||
has_maker_and_operator item;
|
||||
REQUIRE( ::Catch::Detail::stringify( item ) == "StringMaker<has_maker_and_operator>" );
|
||||
}
|
||||
|
||||
TEST_CASE("stringify( has_neither )", "[toString]") {
|
||||
has_neither item;
|
||||
REQUIRE( ::Catch::Detail::stringify(item) == "{?}" );
|
||||
}
|
||||
|
||||
// Call the templated operator
|
||||
TEST_CASE( "stringify( has_template_operator )", "[toString]" ) {
|
||||
has_template_operator item;
|
||||
REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" );
|
||||
}
|
||||
|
||||
|
||||
// Vectors...
|
||||
|
||||
TEST_CASE( "stringify( vectors<has_operator> )", "[toString]" ) {
|
||||
std::vector<has_operator> v(1);
|
||||
REQUIRE( ::Catch::Detail::stringify( v ) == "{ operator<<( has_operator ) }" );
|
||||
}
|
||||
|
||||
TEST_CASE( "stringify( vectors<has_maker> )", "[toString]" ) {
|
||||
std::vector<has_maker> v(1);
|
||||
REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" );
|
||||
}
|
||||
|
||||
TEST_CASE( "stringify( vectors<has_maker_and_operator> )", "[toString]" ) {
|
||||
std::vector<has_maker_and_operator> v(1);
|
||||
REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker_and_operator> }" );
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Range-based conversion should only be used if other possibilities fail
|
||||
struct int_iterator {
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = int;
|
||||
using reference = int&;
|
||||
using pointer = int*;
|
||||
|
||||
int_iterator() = default;
|
||||
int_iterator(int i) :val(i) {}
|
||||
|
||||
value_type operator*() const { return val; }
|
||||
bool operator==(int_iterator rhs) const { return val == rhs.val; }
|
||||
bool operator!=(int_iterator rhs) const { return val != rhs.val; }
|
||||
int_iterator operator++() { ++val; return *this; }
|
||||
int_iterator operator++(int) {
|
||||
auto temp(*this);
|
||||
++val;
|
||||
return temp;
|
||||
}
|
||||
private:
|
||||
int val = 5;
|
||||
};
|
||||
|
||||
struct streamable_range {
|
||||
int_iterator begin() const { return int_iterator{ 1 }; }
|
||||
int_iterator end() const { return {}; }
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const streamable_range&) {
|
||||
os << "op<<(streamable_range)";
|
||||
return os;
|
||||
}
|
||||
|
||||
struct stringmaker_range {
|
||||
int_iterator begin() const { return int_iterator{ 1 }; }
|
||||
int_iterator end() const { return {}; }
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace Catch {
|
||||
template <>
|
||||
struct StringMaker<stringmaker_range> {
|
||||
static std::string convert(stringmaker_range const&) {
|
||||
return "stringmaker(streamable_range)";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct just_range {
|
||||
int_iterator begin() const { return int_iterator{ 1 }; }
|
||||
int_iterator end() const { return {}; }
|
||||
};
|
||||
|
||||
struct disabled_range {
|
||||
int_iterator begin() const { return int_iterator{ 1 }; }
|
||||
int_iterator end() const { return {}; }
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace Catch {
|
||||
template <>
|
||||
struct is_range<disabled_range> {
|
||||
static const bool value = false;
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("stringify ranges", "[toString]") {
|
||||
REQUIRE(::Catch::Detail::stringify(streamable_range{}) == "op<<(streamable_range)");
|
||||
REQUIRE(::Catch::Detail::stringify(stringmaker_range{}) == "stringmaker(streamable_range)");
|
||||
REQUIRE(::Catch::Detail::stringify(just_range{}) == "{ 1, 2, 3, 4 }");
|
||||
REQUIRE(::Catch::Detail::stringify(disabled_range{}) == "{?}");
|
||||
}
|
@ -0,0 +1,380 @@
|
||||
|
||||
// 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
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Wpadded"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable : 4702) // Disable unreachable code warning for the last test
|
||||
// that is triggered when compiling as Win32|Release
|
||||
#endif
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
struct Opaque
|
||||
{
|
||||
int val;
|
||||
bool operator ==( const Opaque& o ) const
|
||||
{
|
||||
return val == o.val;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE
|
||||
(
|
||||
"A failing expression with a non streamable type is still captured",
|
||||
"[Tricky][failing][.]"
|
||||
)
|
||||
{
|
||||
|
||||
Opaque o1, o2;
|
||||
o1.val = 7;
|
||||
o2.val = 8;
|
||||
|
||||
CHECK( &o1 == &o2 );
|
||||
CHECK( o1 == o2 );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE
|
||||
(
|
||||
"An expression with side-effects should only be evaluated once",
|
||||
"[Tricky]"
|
||||
)
|
||||
{
|
||||
int i = 7;
|
||||
|
||||
REQUIRE( i++ == 7 );
|
||||
REQUIRE( i++ == 8 );
|
||||
|
||||
}
|
||||
|
||||
namespace A {
|
||||
struct X
|
||||
{
|
||||
X() : a(4), b(2), c(7) {}
|
||||
X(int v) : a(v), b(2), c(7) {}
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
};
|
||||
}
|
||||
|
||||
namespace B {
|
||||
struct Y
|
||||
{
|
||||
Y() : a(4), b(2), c(7) {}
|
||||
Y(int v) : a(v), b(2), c(7) {}
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
};
|
||||
}
|
||||
|
||||
inline bool operator==(const A::X& lhs, const B::Y& rhs)
|
||||
{
|
||||
return (lhs.a == rhs.a);
|
||||
}
|
||||
|
||||
inline bool operator==(const B::Y& lhs, const A::X& rhs)
|
||||
{
|
||||
return (lhs.a == rhs.a);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/* This, currently, does not compile with LLVM
|
||||
TEST_CASE
|
||||
(
|
||||
"Operators at different namespace levels not hijacked by Koenig lookup"
|
||||
"[Tricky]"
|
||||
)
|
||||
{
|
||||
A::X x;
|
||||
B::Y y;
|
||||
REQUIRE( x == y );
|
||||
}
|
||||
*/
|
||||
|
||||
namespace ObjectWithConversions
|
||||
{
|
||||
struct Object
|
||||
{
|
||||
operator unsigned int() const {return 0xc0000000;}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE
|
||||
(
|
||||
"Implicit conversions are supported inside assertion macros",
|
||||
"[Tricky][approvals]"
|
||||
)
|
||||
{
|
||||
Object o;
|
||||
REQUIRE(0xc0000000 == o );
|
||||
}
|
||||
}
|
||||
|
||||
namespace EnumBitFieldTests
|
||||
{
|
||||
enum Bits : uint32_t {
|
||||
bit0 = 0x0001,
|
||||
bit1 = 0x0002,
|
||||
bit2 = 0x0004,
|
||||
bit3 = 0x0008,
|
||||
bit1and2 = bit1 | bit2,
|
||||
bit30 = 0x40000000,
|
||||
bit31 = 0x80000000,
|
||||
bit30and31 = bit30 | bit31
|
||||
};
|
||||
|
||||
TEST_CASE( "Test enum bit values", "[Tricky]" )
|
||||
{
|
||||
REQUIRE( 0xc0000000 == bit30and31 );
|
||||
}
|
||||
}
|
||||
|
||||
struct Obj
|
||||
{
|
||||
Obj():prop(&p){}
|
||||
|
||||
int p = 0;
|
||||
int* prop;
|
||||
};
|
||||
|
||||
TEST_CASE("boolean member", "[Tricky]")
|
||||
{
|
||||
Obj obj;
|
||||
REQUIRE( obj.prop != nullptr );
|
||||
}
|
||||
|
||||
// Tests for a problem submitted by Ralph McArdell
|
||||
//
|
||||
// The static bool value should not need to be defined outside the
|
||||
// struct it is declared in - but when evaluating it in a deduced
|
||||
// context it appears to require the extra definition.
|
||||
// The issue was fixed by adding bool overloads to bypass the
|
||||
// templates that were there to deduce it.
|
||||
template <bool B>
|
||||
struct is_true
|
||||
{
|
||||
static const bool value = B;
|
||||
};
|
||||
|
||||
TEST_CASE( "(unimplemented) static bools can be evaluated", "[Tricky]" )
|
||||
{
|
||||
SECTION("compare to true")
|
||||
{
|
||||
REQUIRE( is_true<true>::value == true );
|
||||
REQUIRE( true == is_true<true>::value );
|
||||
}
|
||||
SECTION("compare to false")
|
||||
{
|
||||
REQUIRE( is_true<false>::value == false );
|
||||
REQUIRE( false == is_true<false>::value );
|
||||
}
|
||||
|
||||
SECTION("negation")
|
||||
{
|
||||
REQUIRE( !is_true<false>::value );
|
||||
}
|
||||
|
||||
SECTION("double negation")
|
||||
{
|
||||
REQUIRE( !!is_true<true>::value );
|
||||
}
|
||||
|
||||
SECTION("direct")
|
||||
{
|
||||
REQUIRE( is_true<true>::value );
|
||||
REQUIRE_FALSE( is_true<false>::value );
|
||||
}
|
||||
}
|
||||
|
||||
struct Boolable
|
||||
{
|
||||
explicit Boolable( bool value ) : m_value( value ) {}
|
||||
|
||||
explicit operator bool() const {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool m_value;
|
||||
};
|
||||
|
||||
TEST_CASE( "Objects that evaluated in boolean contexts can be checked", "[Tricky][SafeBool]" )
|
||||
{
|
||||
Boolable True( true );
|
||||
Boolable False( false );
|
||||
|
||||
CHECK( True );
|
||||
CHECK( !False );
|
||||
CHECK_FALSE( False );
|
||||
}
|
||||
|
||||
TEST_CASE( "Assertions then sections", "[Tricky]" )
|
||||
{
|
||||
// This was causing a failure due to the way the console reporter was handling
|
||||
// the current section
|
||||
|
||||
REQUIRE( true );
|
||||
|
||||
SECTION( "A section" )
|
||||
{
|
||||
REQUIRE( true );
|
||||
|
||||
SECTION( "Another section" )
|
||||
{
|
||||
REQUIRE( true );
|
||||
}
|
||||
SECTION( "Another other section" )
|
||||
{
|
||||
REQUIRE( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Awkward
|
||||
{
|
||||
operator int() const { return 7; }
|
||||
};
|
||||
|
||||
TEST_CASE( "non streamable - with conv. op", "[Tricky]" )
|
||||
{
|
||||
Awkward awkward;
|
||||
std::string s = ::Catch::Detail::stringify( awkward );
|
||||
REQUIRE( s == "7" );
|
||||
}
|
||||
|
||||
inline void foo() {}
|
||||
|
||||
using fooptr_t = void (*)();
|
||||
|
||||
TEST_CASE( "Comparing function pointers", "[Tricky][function pointer]" )
|
||||
{
|
||||
// This was giving a warning in VS2010
|
||||
// #179
|
||||
fooptr_t a = foo;
|
||||
|
||||
REQUIRE( a );
|
||||
REQUIRE( a == &foo );
|
||||
}
|
||||
|
||||
struct S
|
||||
{
|
||||
void f() {}
|
||||
};
|
||||
|
||||
|
||||
TEST_CASE( "Comparing member function pointers", "[Tricky][member function pointer][approvals]" )
|
||||
{
|
||||
using MF = void (S::*)();
|
||||
MF m = &S::f;
|
||||
|
||||
CHECK( m == &S::f );
|
||||
}
|
||||
|
||||
class ClassName {};
|
||||
|
||||
TEST_CASE( "pointer to class", "[Tricky]" )
|
||||
{
|
||||
ClassName *p = 0;
|
||||
REQUIRE( p == 0 );
|
||||
}
|
||||
|
||||
#include <memory>
|
||||
|
||||
TEST_CASE( "null_ptr", "[Tricky]" )
|
||||
{
|
||||
std::unique_ptr<int> ptr;
|
||||
REQUIRE(ptr.get() == nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE( "X/level/0/a", "[Tricky]" ) { SUCCEED(""); }
|
||||
TEST_CASE( "X/level/0/b", "[Tricky][fizz]" ){ SUCCEED(""); }
|
||||
TEST_CASE( "X/level/1/a", "[Tricky]" ) { SUCCEED(""); }
|
||||
TEST_CASE( "X/level/1/b", "[Tricky]" ) { SUCCEED(""); }
|
||||
|
||||
TEST_CASE( "has printf" ) {
|
||||
|
||||
// This can cause problems as, currently, stdout itself is not redirected - only the cout (and cerr) buffer
|
||||
printf( "loose text artifact\n" );
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct constructor_throws {
|
||||
[[noreturn]] constructor_throws() {
|
||||
throw 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("Commas in various macros are allowed") {
|
||||
REQUIRE_THROWS( std::vector<constructor_throws>{constructor_throws{}, constructor_throws{}} );
|
||||
CHECK_THROWS( std::vector<constructor_throws>{constructor_throws{}, constructor_throws{}} );
|
||||
REQUIRE_NOTHROW( std::vector<int>{1, 2, 3} == std::vector<int>{1, 2, 3} );
|
||||
CHECK_NOTHROW( std::vector<int>{1, 2, 3} == std::vector<int>{1, 2, 3} );
|
||||
|
||||
REQUIRE(std::vector<int>{1, 2} == std::vector<int>{1, 2});
|
||||
CHECK( std::vector<int>{1, 2} == std::vector<int>{1, 2} );
|
||||
REQUIRE_FALSE(std::vector<int>{1, 2} == std::vector<int>{1, 2, 3});
|
||||
CHECK_FALSE( std::vector<int>{1, 2} == std::vector<int>{1, 2, 3} );
|
||||
|
||||
CHECK_NOFAIL( std::vector<int>{1, 2} == std::vector<int>{1, 2} );
|
||||
CHECKED_IF( std::vector<int>{1, 2} == std::vector<int>{1, 2} ) {
|
||||
REQUIRE(true);
|
||||
} CHECKED_ELSE( std::vector<int>{1, 2} == std::vector<int>{1, 2} ) {
|
||||
CHECK(true);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "non-copyable objects", "[.][failing]" ) {
|
||||
// Thanks to Agustin Bergé (@k-ballo on the cpplang Slack) for raising this
|
||||
std::type_info const& ti = typeid(int);
|
||||
CHECK( ti == typeid(int) );
|
||||
}
|
||||
|
||||
TEST_CASE("#1514: stderr/stdout is not captured in tests aborted by an exception", "[output-capture][regression][.]") {
|
||||
std::cout << "This would not be caught previously\n" << std::flush;
|
||||
std::clog << "Nor would this\n" << std::flush;
|
||||
// FAIL aborts the test by throwing a Catch exception
|
||||
FAIL("1514");
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "#2025: -c shouldn't cause infinite loop", "[sections][generators][regression][.approvals]" ) {
|
||||
SECTION( "Check cursor from buffer offset" ) {
|
||||
auto bufPos = GENERATE_REF( range( 0, 44 ) );
|
||||
WHEN( "Buffer position is " << bufPos ) { REQUIRE( 1 == 1 ); }
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("#2025: original repro", "[sections][generators][regression][.approvals]") {
|
||||
auto fov = GENERATE(true, false);
|
||||
DYNAMIC_SECTION("fov_" << fov) {
|
||||
std::cout << "inside with fov: " << fov << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("#2025: same-level sections", "[sections][generators][regression][.approvals]") {
|
||||
SECTION("A") {
|
||||
SUCCEED();
|
||||
}
|
||||
auto i = GENERATE(1, 2, 3);
|
||||
SECTION("B") {
|
||||
REQUIRE(i < 4);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
|
||||
TEST_CASE()
|
||||
{
|
||||
SUCCEED( "anonymous test case" );
|
||||
}
|
||||
|
||||
TEST_CASE( "Test case with one argument" )
|
||||
{
|
||||
SUCCEED( "no assertions" );
|
||||
}
|
||||
|
||||
TEST_CASE( "Variadic macros", "[variadic][sections]" )
|
||||
{
|
||||
SECTION( "Section with one argument" )
|
||||
{
|
||||
SUCCEED( "no assertions" );
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
#include <helpers/parse_test_spec.hpp>
|
||||
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_tag_alias_registry.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
TestSpec parseTestSpec( std::string const& arg ) {
|
||||
return TestSpecParser( ITagAliasRegistry::get() )
|
||||
.parse( arg )
|
||||
.testSpec();
|
||||
}
|
||||
|
||||
} // namespace Catch
|
@ -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
|
||||
|
||||
#ifndef CATCH_TEST_HELPERS_PARSE_TEST_SPEC_HPP_INCLUDED
|
||||
#define CATCH_TEST_HELPERS_PARSE_TEST_SPEC_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_test_spec.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
TestSpec parseTestSpec( std::string const& arg );
|
||||
}
|
||||
|
||||
#endif // CATCH_TEST_HELPERS_PARSE_TEST_SPEC_HPP_INCLUDED
|
@ -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 <catch2/catch_tostring.hpp>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace unrelated {
|
||||
template <typename T>
|
||||
class needs_ADL_begin {
|
||||
std::vector<T> m_elements;
|
||||
|
||||
public:
|
||||
using iterator = typename std::vector<T>::iterator;
|
||||
using const_iterator = typename std::vector<T>::const_iterator;
|
||||
|
||||
needs_ADL_begin( std::initializer_list<T> 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 <typename T>
|
||||
class has_different_begin_end_types {
|
||||
// Using std::vector<T> leads to annoying issues when T is bool
|
||||
// so we just use list because the perf is not critical and ugh.
|
||||
std::list<T> 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<T>::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<T> 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 <typename T>
|
||||
struct with_mocked_iterator_access {
|
||||
std::vector<T> m_elements;
|
||||
|
||||
// use plain arrays to have nicer printouts with CHECK(...)
|
||||
mutable std::unique_ptr<bool[]> m_derefed;
|
||||
|
||||
// We want to check which elements were dereferenced when iterating, so
|
||||
// we can check whether iterator-using code traverses range correctly
|
||||
template <bool is_const>
|
||||
class basic_iterator {
|
||||
template <typename U>
|
||||
using constify_t = std::conditional_t<is_const, std::add_const_t<U>, U>;
|
||||
|
||||
constify_t<with_mocked_iterator_access>* 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<T>;
|
||||
using const_reference = typename std::vector<T>::const_reference;
|
||||
using reference = typename std::vector<T>::reference;
|
||||
using pointer = typename std::vector<T>::pointer;
|
||||
|
||||
basic_iterator( constify_t<with_mocked_iterator_access>* 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<false>;
|
||||
using const_iterator = basic_iterator<true>;
|
||||
|
||||
with_mocked_iterator_access( std::initializer_list<T> init ):
|
||||
m_elements( init ),
|
||||
m_derefed( std::make_unique<bool[]>( 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 <typename T>
|
||||
struct is_range<with_mocked_iterator_access<T>> : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct StringMaker<with_mocked_iterator_access<T>> {
|
||||
static std::string
|
||||
convert( with_mocked_iterator_access<T> 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
|
@ -0,0 +1,55 @@
|
||||
|
||||
// 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_TYPE_WITH_LIT_0_COMPARISONS_HPP_INCLUDED
|
||||
#define CATCH_TEST_HELPERS_TYPE_WITH_LIT_0_COMPARISONS_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// Should only be constructible from literal 0.
|
||||
// Based on the constructor from pointer trick, used by libstdc++ and libc++
|
||||
// (formerly also MSVC, but they've moved to consteval int constructor).
|
||||
// Used by `TypeWithLit0Comparisons` for testing comparison
|
||||
// ops that only work with literal zero, the way std::*orderings do
|
||||
struct ZeroLiteralAsPointer {
|
||||
constexpr ZeroLiteralAsPointer( ZeroLiteralAsPointer* ) noexcept {}
|
||||
|
||||
template <typename T,
|
||||
typename = std::enable_if_t<!std::is_same<T, int>::value>>
|
||||
constexpr ZeroLiteralAsPointer( T ) = delete;
|
||||
};
|
||||
|
||||
|
||||
struct TypeWithLit0Comparisons {
|
||||
#define DEFINE_COMP_OP( op ) \
|
||||
constexpr friend bool operator op( TypeWithLit0Comparisons, \
|
||||
ZeroLiteralAsPointer ) { \
|
||||
return true; \
|
||||
} \
|
||||
constexpr friend bool operator op( ZeroLiteralAsPointer, \
|
||||
TypeWithLit0Comparisons ) { \
|
||||
return false; \
|
||||
} \
|
||||
/* std::orderings only have these for ==, but we add them for all \
|
||||
operators so we can test all overloads for decomposer */ \
|
||||
constexpr friend bool operator op( TypeWithLit0Comparisons, \
|
||||
TypeWithLit0Comparisons ) { \
|
||||
return true; \
|
||||
}
|
||||
|
||||
DEFINE_COMP_OP( < )
|
||||
DEFINE_COMP_OP( <= )
|
||||
DEFINE_COMP_OP( > )
|
||||
DEFINE_COMP_OP( >= )
|
||||
DEFINE_COMP_OP( == )
|
||||
DEFINE_COMP_OP( != )
|
||||
|
||||
#undef DEFINE_COMP_OP
|
||||
};
|
||||
|
||||
#endif // CATCH_TEST_HELPERS_TYPE_WITH_LIT_0_COMPARISONS_HPP_INCLUDED
|
Reference in New Issue
Block a user