mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 13:26:10 +01:00
Add support for retrieving generator's element as string
This commit is contained in:
parent
af8b54ecd5
commit
48f3226974
@ -184,6 +184,7 @@ set(IMPL_SOURCES
|
|||||||
${SOURCES_DIR}/internal/catch_istream.cpp
|
${SOURCES_DIR}/internal/catch_istream.cpp
|
||||||
${SOURCES_DIR}/generators/internal/catch_generators_combined_tu.cpp
|
${SOURCES_DIR}/generators/internal/catch_generators_combined_tu.cpp
|
||||||
${SOURCES_DIR}/interfaces/catch_interfaces_combined_tu.cpp
|
${SOURCES_DIR}/interfaces/catch_interfaces_combined_tu.cpp
|
||||||
|
${SOURCES_DIR}/interfaces/catch_interfaces_generatortracker.cpp
|
||||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter.cpp
|
${SOURCES_DIR}/interfaces/catch_interfaces_reporter.cpp
|
||||||
${SOURCES_DIR}/internal/catch_list.cpp
|
${SOURCES_DIR}/internal/catch_list.cpp
|
||||||
${SOURCES_DIR}/matchers/catch_matchers_floating_point.cpp
|
${SOURCES_DIR}/matchers/catch_matchers_floating_point.cpp
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#ifndef CATCH_GENERATORS_HPP_INCLUDED
|
#ifndef CATCH_GENERATORS_HPP_INCLUDED
|
||||||
#define CATCH_GENERATORS_HPP_INCLUDED
|
#define CATCH_GENERATORS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <catch2/catch_tostring.hpp>
|
||||||
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
||||||
#include <catch2/internal/catch_source_line_info.hpp>
|
#include <catch2/internal/catch_source_line_info.hpp>
|
||||||
#include <catch2/internal/catch_stringref.hpp>
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
@ -32,6 +33,10 @@ namespace Detail {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class IGenerator : public GeneratorUntypedBase {
|
class IGenerator : public GeneratorUntypedBase {
|
||||||
|
std::string stringifyImpl() const override {
|
||||||
|
return ::Catch::Detail::stringify( get() );
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~IGenerator() override = default;
|
~IGenerator() override = default;
|
||||||
IGenerator() = default;
|
IGenerator() = default;
|
||||||
|
32
src/catch2/interfaces/catch_interfaces_generatortracker.cpp
Normal file
32
src/catch2/interfaces/catch_interfaces_generatortracker.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Generators {
|
||||||
|
|
||||||
|
bool GeneratorUntypedBase::countedNext() {
|
||||||
|
auto ret = next();
|
||||||
|
if ( ret ) {
|
||||||
|
m_stringReprCache.clear();
|
||||||
|
++m_currentElementIndex;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringRef GeneratorUntypedBase::currentElementAsString() const {
|
||||||
|
if ( m_stringReprCache.empty() ) {
|
||||||
|
m_stringReprCache = stringifyImpl();
|
||||||
|
}
|
||||||
|
return m_stringReprCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
} // namespace Catch
|
@ -9,11 +9,18 @@
|
|||||||
#define CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
|
#define CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
|
||||||
|
|
||||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
namespace Generators {
|
namespace Generators {
|
||||||
class GeneratorUntypedBase {
|
class GeneratorUntypedBase {
|
||||||
|
// Caches result from `toStringImpl`, assume that when it is an
|
||||||
|
// empty string, the cache is invalidated.
|
||||||
|
mutable std::string m_stringReprCache;
|
||||||
|
|
||||||
// Counts based on `next` returning true
|
// Counts based on `next` returning true
|
||||||
std::size_t m_currentElementIndex = 0;
|
std::size_t m_currentElementIndex = 0;
|
||||||
|
|
||||||
@ -25,6 +32,9 @@ namespace Catch {
|
|||||||
*/
|
*/
|
||||||
virtual bool next() = 0;
|
virtual bool next() = 0;
|
||||||
|
|
||||||
|
//! Customization point for `currentElementAsString`
|
||||||
|
virtual std::string stringifyImpl() const = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GeneratorUntypedBase() = default;
|
GeneratorUntypedBase() = default;
|
||||||
// Generation of copy ops is deprecated (and Clang will complain)
|
// Generation of copy ops is deprecated (and Clang will complain)
|
||||||
@ -44,15 +54,24 @@ namespace Catch {
|
|||||||
* As with `next`, returns true iff the move succeeded and
|
* As with `next`, returns true iff the move succeeded and
|
||||||
* the generator has new valid element to provide.
|
* the generator has new valid element to provide.
|
||||||
*/
|
*/
|
||||||
bool countedNext() {
|
bool countedNext();
|
||||||
auto ret = next();
|
|
||||||
if ( ret ) {
|
|
||||||
++m_currentElementIndex;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t currentElementIndex() const { return m_currentElementIndex; }
|
std::size_t currentElementIndex() const { return m_currentElementIndex; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns generator's current element as user-friendly string.
|
||||||
|
*
|
||||||
|
* By default returns string equivalent to calling
|
||||||
|
* `Catch::Detail::stringify` on the current element, but generators
|
||||||
|
* can customize their implementation as needed.
|
||||||
|
*
|
||||||
|
* Not thread-safe due to internal caching.
|
||||||
|
*
|
||||||
|
* The returned ref is valid only until the generator instance
|
||||||
|
* is destructed, or it moves onto the next element, whichever
|
||||||
|
* comes first.
|
||||||
|
*/
|
||||||
|
StringRef currentElementAsString() const;
|
||||||
};
|
};
|
||||||
using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
|
using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
|
||||||
|
|
||||||
|
@ -424,3 +424,92 @@ TEST_CASE("Generators count returned elements", "[generators][approvals]") {
|
|||||||
REQUIRE_FALSE( generator.countedNext() );
|
REQUIRE_FALSE( generator.countedNext() );
|
||||||
REQUIRE( generator.currentElementIndex() == 2 );
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// caching?
|
||||||
|
Loading…
Reference in New Issue
Block a user