diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 47e151df..5165d37d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -119,7 +119,7 @@ set(INTERNAL_HEADERS ${SOURCES_DIR}/internal/catch_test_registry.hpp ${SOURCES_DIR}/catch_test_spec.hpp ${SOURCES_DIR}/internal/catch_test_spec_parser.hpp - ${SOURCES_DIR}/internal/catch_text.hpp + ${SOURCES_DIR}/internal/catch_textflow.hpp ${SOURCES_DIR}/catch_timer.hpp ${SOURCES_DIR}/internal/catch_to_string.hpp ${SOURCES_DIR}/catch_tostring.hpp @@ -175,6 +175,7 @@ set(IMPL_SOURCES ${SOURCES_DIR}/internal/catch_test_case_registry_impl.cpp ${SOURCES_DIR}/internal/catch_test_case_tracker.cpp ${SOURCES_DIR}/internal/catch_test_registry.cpp + ${SOURCES_DIR}/internal/catch_textflow.cpp ${SOURCES_DIR}/catch_test_spec.cpp ${SOURCES_DIR}/internal/catch_test_spec_parser.cpp ${SOURCES_DIR}/catch_timer.cpp diff --git a/src/catch2/catch_all.hpp b/src/catch2/catch_all.hpp index 5f8d32dc..508f38db 100644 --- a/src/catch2/catch_all.hpp +++ b/src/catch2/catch_all.hpp @@ -83,7 +83,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/catch2/catch_session.cpp b/src/catch2/catch_session.cpp index 80767184..05cf6bd1 100644 --- a/src/catch2/catch_session.cpp +++ b/src/catch2/catch_session.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include @@ -144,7 +144,7 @@ namespace Catch { try { std::rethrow_exception(ex_ptr); } catch ( std::exception const& ex ) { - Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; + Catch::cerr() << TextFlow::Column( ex.what() ).indent(2) << '\n'; } } } @@ -182,7 +182,7 @@ namespace Catch { Catch::cerr() << Colour( Colour::Red ) << "\nError(s) in input:\n" - << Column( result.errorMessage() ).indent( 2 ) + << TextFlow::Column( result.errorMessage() ).indent( 2 ) << "\n\n"; Catch::cerr() << "Run with -? for usage\n" << std::endl; return MaxExitCode; diff --git a/src/catch2/interfaces/catch_interfaces_reporter.cpp b/src/catch2/interfaces/catch_interfaces_reporter.cpp index 3d1a01c5..7e4dd9ef 100644 --- a/src/catch2/interfaces/catch_interfaces_reporter.cpp +++ b/src/catch2/interfaces/catch_interfaces_reporter.cpp @@ -9,11 +9,13 @@ #include #include #include +#include #include #include -#include +#include #include #include +#include #include #include @@ -117,15 +119,15 @@ namespace Catch { for (auto const& desc : descriptions) { if (config.verbosity() == Verbosity::Quiet) { Catch::cout() - << Column(desc.name) + << TextFlow::Column(desc.name) .indent(2) .width(5 + maxNameLen) << '\n'; } else { Catch::cout() - << Column(desc.name + ":") + << TextFlow::Column(desc.name + ":") .indent(2) .width(5 + maxNameLen) - + Column(desc.description) + + TextFlow::Column(desc.description) .initialIndent(0) .indent(2) .width(CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8) @@ -149,12 +151,12 @@ namespace Catch { : Colour::None; Colour colourGuard(colour); - Catch::cout() << Column(testCaseInfo.name).initialIndent(2).indent(4) << '\n'; + Catch::cout() << TextFlow::Column(testCaseInfo.name).initialIndent(2).indent(4) << '\n'; if (config.verbosity() >= Verbosity::High) { - Catch::cout() << Column(Catch::Detail::stringify(testCaseInfo.lineInfo)).indent(4) << std::endl; + Catch::cout() << TextFlow::Column(Catch::Detail::stringify(testCaseInfo.lineInfo)).indent(4) << std::endl; } if (!testCaseInfo.tags.empty() && config.verbosity() > Verbosity::Quiet) { - Catch::cout() << Column(testCaseInfo.tagsAsString()).indent(6) << '\n'; + Catch::cout() << TextFlow::Column(testCaseInfo.tagsAsString()).indent(6) << '\n'; } } @@ -176,7 +178,7 @@ namespace Catch { ReusableStringStream rss; rss << " " << std::setw(2) << tagCount.count << " "; auto str = rss.str(); - auto wrapper = Column(tagCount.all()) + auto wrapper = TextFlow::Column(tagCount.all()) .initialIndent(0) .indent(str.size()) .width(CATCH_CONFIG_CONSOLE_WIDTH - 10); diff --git a/src/catch2/internal/catch_clara.hpp b/src/catch2/internal/catch_clara.hpp index 19db5492..927813b6 100644 --- a/src/catch2/internal/catch_clara.hpp +++ b/src/catch2/internal/catch_clara.hpp @@ -22,7 +22,6 @@ #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wweak-vtables" - #pragma clang diagnostic ignored "-Wexit-time-destructors" #pragma clang diagnostic ignored "-Wshadow" #pragma clang diagnostic ignored "-Wdeprecated" #endif diff --git a/src/catch2/internal/catch_clara_upstream.hpp b/src/catch2/internal/catch_clara_upstream.hpp index 64b762d0..76263b53 100644 --- a/src/catch2/internal/catch_clara_upstream.hpp +++ b/src/catch2/internal/catch_clara_upstream.hpp @@ -14,10 +14,6 @@ #define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 #endif -#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH -#endif - #ifndef CLARA_CONFIG_OPTIONAL_TYPE #ifdef __has_include #if __has_include() && __cplusplus >= 201703L @@ -28,356 +24,16 @@ #endif -// ----------- #included from clara_textflow.hpp ----------- +#include -// TextFlowCpp -// -// A single-header library for wrapping and laying out basic text, by Phil Nash -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// This project is hosted at https://github.com/philsquared/textflowcpp - -#ifndef CATCH_CLARA_TEXTFLOW_HPP_INCLUDED -#define CATCH_CLARA_TEXTFLOW_HPP_INCLUDED - -#include -#include -#include -#include - -#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 -#endif - - -namespace Catch { -namespace clara { -namespace TextFlow { - -inline auto isWhitespace(char c) -> bool { - static std::string chars = " \t\n\r"; - return chars.find(c) != std::string::npos; -} -inline auto isBreakableBefore(char c) -> bool { - static std::string chars = "[({<|"; - return chars.find(c) != std::string::npos; -} -inline auto isBreakableAfter(char c) -> bool { - static std::string chars = "])}>.,:;*+-=&/\\"; - return chars.find(c) != std::string::npos; -} - -class Columns; - -class Column { - std::vector m_strings; - size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; - size_t m_indent = 0; - size_t m_initialIndent = std::string::npos; - -public: - class iterator { - friend Column; - - Column const& m_column; - size_t m_stringIndex = 0; - size_t m_pos = 0; - - size_t m_len = 0; - size_t m_end = 0; - bool m_suffix = false; - - iterator(Column const& column, size_t stringIndex) - : m_column(column), - m_stringIndex(stringIndex) {} - - auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } - - auto isBoundary(size_t at) const -> bool { - assert(at > 0); - assert(at <= line().size()); - - return at == line().size() || - (isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) || - isBreakableBefore(line()[at]) || - isBreakableAfter(line()[at - 1]); - } - - void calcLength() { - assert(m_stringIndex < m_column.m_strings.size()); - - m_suffix = false; - auto width = m_column.m_width - indent(); - m_end = m_pos; - if (line()[m_pos] == '\n') { - ++m_end; - } - while (m_end < line().size() && line()[m_end] != '\n') - ++m_end; - - if (m_end < m_pos + width) { - m_len = m_end - m_pos; - } else { - size_t len = width; - while (len > 0 && !isBoundary(m_pos + len)) - --len; - while (len > 0 && isWhitespace(line()[m_pos + len - 1])) - --len; - - if (len > 0) { - m_len = len; - } else { - m_suffix = true; - m_len = width - 1; - } - } - } - - auto indent() const -> size_t { - auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; - return initial == std::string::npos ? m_column.m_indent : initial; - } - - auto addIndentAndSuffix(std::string const &plain) const -> std::string { - return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain); - } - - public: - using difference_type = std::ptrdiff_t; - using value_type = std::string; - using pointer = value_type * ; - using reference = value_type & ; - using iterator_category = std::forward_iterator_tag; - - explicit iterator(Column const& column) : m_column(column) { - assert(m_column.m_width > m_column.m_indent); - assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent); - calcLength(); - if (m_len == 0) - m_stringIndex++; // Empty string - } - - auto operator *() const -> std::string { - assert(m_stringIndex < m_column.m_strings.size()); - assert(m_pos <= m_end); - return addIndentAndSuffix(line().substr(m_pos, m_len)); - } - - auto operator ++() -> iterator& { - m_pos += m_len; - if (m_pos < line().size() && line()[m_pos] == '\n') - m_pos += 1; - else - while (m_pos < line().size() && isWhitespace(line()[m_pos])) - ++m_pos; - - if (m_pos == line().size()) { - m_pos = 0; - ++m_stringIndex; - } - if (m_stringIndex < m_column.m_strings.size()) - calcLength(); - return *this; - } - auto operator ++(int) -> iterator { - iterator prev(*this); - operator++(); - return prev; - } - - auto operator ==(iterator const& other) const -> bool { - return - m_pos == other.m_pos && - m_stringIndex == other.m_stringIndex && - &m_column == &other.m_column; - } - auto operator !=(iterator const& other) const -> bool { - return !operator==(other); - } - }; - using const_iterator = iterator; - - explicit Column(std::string const& text) { m_strings.push_back(text); } - - auto width(size_t newWidth) -> Column& { - assert(newWidth > 0); - m_width = newWidth; - return *this; - } - auto indent(size_t newIndent) -> Column& { - m_indent = newIndent; - return *this; - } - auto initialIndent(size_t newIndent) -> Column& { - m_initialIndent = newIndent; - return *this; - } - - auto width() const -> size_t { return m_width; } - auto begin() const -> iterator { return iterator(*this); } - auto end() const -> iterator { return { *this, m_strings.size() }; } - - inline friend std::ostream& operator << (std::ostream& os, Column const& col) { - bool first = true; - for (auto line : col) { - if (first) - first = false; - else - os << "\n"; - os << line; - } - return os; - } - - auto operator + (Column const& other)->Columns; - - auto toString() const -> std::string { - std::ostringstream oss; - oss << *this; - return oss.str(); - } -}; - -class Spacer : public Column { - -public: - explicit Spacer(size_t spaceWidth) : Column("") { - width(spaceWidth); - } -}; - -class Columns { - std::vector m_columns; - -public: - - class iterator { - friend Columns; - struct EndTag {}; - - std::vector const& m_columns; - std::vector m_iterators; - size_t m_activeIterators; - - iterator(Columns const& columns, EndTag) - : m_columns(columns.m_columns), - m_activeIterators(0) { - m_iterators.reserve(m_columns.size()); - - for (auto const& col : m_columns) - m_iterators.push_back(col.end()); - } - - public: - using difference_type = std::ptrdiff_t; - using value_type = std::string; - using pointer = value_type * ; - using reference = value_type & ; - using iterator_category = std::forward_iterator_tag; - - explicit iterator(Columns const& columns) - : m_columns(columns.m_columns), - m_activeIterators(m_columns.size()) { - m_iterators.reserve(m_columns.size()); - - for (auto const& col : m_columns) - m_iterators.push_back(col.begin()); - } - - auto operator ==(iterator const& other) const -> bool { - return m_iterators == other.m_iterators; - } - auto operator !=(iterator const& other) const -> bool { - return m_iterators != other.m_iterators; - } - auto operator *() const -> std::string { - std::string row, padding; - - for (size_t i = 0; i < m_columns.size(); ++i) { - auto width = m_columns[i].width(); - if (m_iterators[i] != m_columns[i].end()) { - std::string col = *m_iterators[i]; - row += padding + col; - if (col.size() < width) - padding = std::string(width - col.size(), ' '); - else - padding = ""; - } else { - padding += std::string(width, ' '); - } - } - return row; - } - auto operator ++() -> iterator& { - for (size_t i = 0; i < m_columns.size(); ++i) { - if (m_iterators[i] != m_columns[i].end()) - ++m_iterators[i]; - } - return *this; - } - auto operator ++(int) -> iterator { - iterator prev(*this); - operator++(); - return prev; - } - }; - using const_iterator = iterator; - - auto begin() const -> iterator { return iterator(*this); } - auto end() const -> iterator { return { *this, iterator::EndTag() }; } - - auto operator += (Column const& col) -> Columns& { - m_columns.push_back(col); - return *this; - } - auto operator + (Column const& col) -> Columns { - Columns combined = *this; - combined += col; - return combined; - } - - inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) { - - bool first = true; - for (auto line : cols) { - if (first) - first = false; - else - os << "\n"; - os << line; - } - return os; - } - - auto toString() const -> std::string { - std::ostringstream oss; - oss << *this; - return oss.str(); - } -}; - -inline auto Column::operator + (Column const& other) -> Columns { - Columns cols; - cols += *this; - cols += other; - return cols; -} -} - -} -} -#endif // CATCH_CLARA_TEXTFLOW_HPP_INCLUDED - -// ----------- end of #include from clara_textflow.hpp ----------- // ........... back in clara.hpp #include #include #include -#include #include +#include +#include #if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) #define CATCH_PLATFORM_WINDOWS @@ -989,7 +645,7 @@ namespace detail { oss << opt; } if( !m_hint.empty() ) - oss << " <" << m_hint << ">"; + oss << " <" << m_hint << '>'; return { { oss.str(), m_description } }; } @@ -1122,26 +778,26 @@ namespace detail { void writeToStream( std::ostream &os ) const { if (!m_exeName.name().empty()) { - os << "usage:\n" << " " << m_exeName.name() << " "; + os << "usage:\n" << " " << m_exeName.name() << ' '; bool required = true, first = true; for( auto const &arg : m_args ) { if (first) first = false; else - os << " "; + os << ' '; if( arg.isOptional() && required ) { - os << "["; + os << '['; required = false; } - os << "<" << arg.hint() << ">"; + os << '<' << arg.hint() << '>'; if( arg.cardinality() == 0 ) os << " ... "; } if( !required ) - os << "]"; + os << ']'; if( !m_options.empty() ) os << " options"; - os << "\n\nwhere options are:" << std::endl; + os << "\n\nwhere options are:\n"; } auto rows = getHelpColumns(); @@ -1157,7 +813,7 @@ namespace detail { TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + TextFlow::Spacer(4) + TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); - os << row << std::endl; + os << row << '\n'; } } diff --git a/src/catch2/internal/catch_text.hpp b/src/catch2/internal/catch_text.hpp deleted file mode 100644 index 7a2c2923..00000000 --- a/src/catch2/internal/catch_text.hpp +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Created by Phil on 10/2/2014. - * Copyright 2014 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_CATCH_TEXT_H_INCLUDED -#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED - -#include - -namespace Catch { - using namespace clara::TextFlow; -} - -#endif // TWOBLUECUBES_CATCH_TEXT_H_INCLUDED diff --git a/src/catch2/internal/catch_textflow.cpp b/src/catch2/internal/catch_textflow.cpp new file mode 100644 index 00000000..c65a6eb9 --- /dev/null +++ b/src/catch2/internal/catch_textflow.cpp @@ -0,0 +1,235 @@ +#include +#include +#include + +namespace { + bool isWhitespace( char c ) { + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; + } + + bool isBreakableBefore( char c ) { + static const char chars[] = "[({<|"; + return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr; + } + + bool isBreakableAfter( char c ) { + static const char chars[] = "])}>.,:;*+-=&/\\"; + return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr; + } + + bool isBoundary( std::string const& line, size_t at ) { + assert( at > 0 ); + assert( at <= line.size() ); + + return at == line.size() || + ( isWhitespace( line[at] ) && !isWhitespace( line[at - 1] ) ) || + isBreakableBefore( line[at] ) || + isBreakableAfter( line[at - 1] ); + } + +} // namespace + +namespace Catch { + namespace TextFlow { + + void Column::iterator::calcLength() { + m_suffix = false; + auto width = m_column.m_width - indent(); + m_end = m_pos; + std::string const& current_line = m_column.m_string; + if ( current_line[m_pos] == '\n' ) { + ++m_end; + } + while ( m_end < current_line.size() && + current_line[m_end] != '\n' ) { + ++m_end; + } + + if ( m_end < m_pos + width ) { + m_len = m_end - m_pos; + } else { + size_t len = width; + while ( len > 0 && !isBoundary( current_line, m_pos + len ) ) { + --len; + } + while ( len > 0 && + isWhitespace( current_line[m_pos + len - 1] ) ) { + --len; + } + + if ( len > 0 ) { + m_len = len; + } else { + m_suffix = true; + m_len = width - 1; + } + } + } + + size_t Column::iterator::indent() const { + auto initial = + m_pos == 0 ? m_column.m_initialIndent : std::string::npos; + return initial == std::string::npos ? m_column.m_indent : initial; + } + + std::string + Column::iterator::addIndentAndSuffix( size_t position, + size_t length ) const { + std::string ret; + const auto desired_indent = indent(); + ret.reserve( desired_indent + length + m_suffix ); + ret.append( desired_indent, ' ' ); + ret.append( m_column.m_string, position, length ); + if ( m_suffix ) { + ret.push_back( '-' ); + } + + return ret; + } + + Column::iterator::iterator( Column const& column ): m_column( column ) { + assert( m_column.m_width > m_column.m_indent ); + assert( m_column.m_initialIndent == std::string::npos || + m_column.m_width > m_column.m_initialIndent ); + calcLength(); + if ( m_len == 0 ) { + m_pos = m_column.m_string.size(); + } + } + + std::string Column::iterator::operator*() const { + assert( m_pos <= m_end ); + return addIndentAndSuffix( m_pos, m_len ); + } + + Column::iterator& Column::iterator::operator++() { + m_pos += m_len; + std::string const& current_line = m_column.m_string; + if ( m_pos < current_line.size() && current_line[m_pos] == '\n' ) { + m_pos += 1; + } else { + while ( m_pos < current_line.size() && + isWhitespace( current_line[m_pos] ) ) { + ++m_pos; + } + } + + if ( m_pos != current_line.size() ) { + calcLength(); + } + return *this; + } + + Column::iterator Column::iterator::operator++( int ) { + iterator prev( *this ); + operator++(); + return prev; + } + + std::ostream& operator<<( std::ostream& os, Column const& col ) { + bool first = true; + for ( auto line : col ) { + if ( first ) { + first = false; + } else { + os << '\n'; + } + os << line; + } + return os; + } + + Column Spacer( size_t spaceWidth ) { + Column ret{ "" }; + ret.width( spaceWidth ); + return ret; + } + + Columns::iterator::iterator( Columns const& columns, EndTag ): + m_columns( columns.m_columns ), m_activeIterators( 0 ) { + + m_iterators.reserve( m_columns.size() ); + for ( auto const& col : m_columns ) { + m_iterators.push_back( col.end() ); + } + } + + Columns::iterator::iterator( Columns const& columns ): + m_columns( columns.m_columns ), + m_activeIterators( m_columns.size() ) { + + m_iterators.reserve( m_columns.size() ); + for ( auto const& col : m_columns ) { + m_iterators.push_back( col.begin() ); + } + } + + std::string Columns::iterator::operator*() const { + std::string row, padding; + + for ( size_t i = 0; i < m_columns.size(); ++i ) { + const auto width = m_columns[i].width(); + if ( m_iterators[i] != m_columns[i].end() ) { + std::string col = *m_iterators[i]; + row += padding; + row += col; + + padding.clear(); + if ( col.size() < width ) { + padding.append( width - col.size(), ' ' ); + } + } else { + padding.append( width, ' ' ); + } + } + return row; + } + + Columns::iterator& Columns::iterator::operator++() { + for ( size_t i = 0; i < m_columns.size(); ++i ) { + if ( m_iterators[i] != m_columns[i].end() ) { + ++m_iterators[i]; + } + } + return *this; + } + + Columns::iterator Columns::iterator::operator++( int ) { + iterator prev( *this ); + operator++(); + return prev; + } + + std::ostream& operator<<( std::ostream& os, Columns const& cols ) { + bool first = true; + for ( auto line : cols ) { + if ( first ) { + first = false; + } else { + os << '\n'; + } + os << line; + } + return os; + } + + Columns Column::operator+( Column const& other ) { + Columns cols; + cols += *this; + cols += other; + return cols; + } + + Columns& Columns::operator+=( Column const& col ) { + m_columns.push_back( col ); + return *this; + } + + Columns Columns::operator+( Column const& col ) { + Columns combined = *this; + combined += col; + return combined; + } + + } // namespace TextFlow +} // namespace Catch diff --git a/src/catch2/internal/catch_textflow.hpp b/src/catch2/internal/catch_textflow.hpp new file mode 100644 index 00000000..27f5184b --- /dev/null +++ b/src/catch2/internal/catch_textflow.hpp @@ -0,0 +1,144 @@ +#ifndef CATCH_CLARA_TEXTFLOW_HPP_INCLUDED +#define CATCH_CLARA_TEXTFLOW_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + namespace TextFlow { + + class Columns; + + class Column { + std::string m_string; + size_t m_width = CATCH_CONFIG_CONSOLE_WIDTH - 1; + size_t m_indent = 0; + size_t m_initialIndent = std::string::npos; + + public: + class iterator { + friend Column; + struct EndTag {}; + + Column const& m_column; + size_t m_pos = 0; + + size_t m_len = 0; + size_t m_end = 0; + bool m_suffix = false; + + iterator( Column const& column, EndTag ): + m_column( column ), m_pos( m_column.m_string.size() ) {} + + void calcLength(); + + // Returns current indention width + size_t indent() const; + + // Creates an indented and (optionally) suffixed string from + // current iterator position, indentation and length. + std::string addIndentAndSuffix( size_t position, + size_t length ) const; + + public: + using difference_type = std::ptrdiff_t; + using value_type = std::string; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::forward_iterator_tag; + + explicit iterator( Column const& column ); + + std::string operator*() const; + + iterator& operator++(); + iterator operator++( int ); + + bool operator==( iterator const& other ) const { + return m_pos == other.m_pos && &m_column == &other.m_column; + } + bool operator!=( iterator const& other ) const { + return !operator==( other ); + } + }; + using const_iterator = iterator; + + explicit Column( std::string const& text ): m_string( text ) {} + + Column& width( size_t newWidth ) { + assert( newWidth > 0 ); + m_width = newWidth; + return *this; + } + Column& indent( size_t newIndent ) { + m_indent = newIndent; + return *this; + } + Column& initialIndent( size_t newIndent ) { + m_initialIndent = newIndent; + return *this; + } + + size_t width() const { return m_width; } + iterator begin() const { return iterator( *this ); } + iterator end() const { return { *this, iterator::EndTag{} }; } + + friend std::ostream& operator<<( std::ostream& os, + Column const& col ); + + Columns operator+( Column const& other ); + }; + + //! Creates a column that serves as an empty space of specific width + Column Spacer( size_t spaceWidth ); + + class Columns { + std::vector m_columns; + + public: + class iterator { + friend Columns; + struct EndTag {}; + + std::vector const& m_columns; + std::vector m_iterators; + size_t m_activeIterators; + + iterator( Columns const& columns, EndTag ); + + public: + using difference_type = std::ptrdiff_t; + using value_type = std::string; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::forward_iterator_tag; + + explicit iterator( Columns const& columns ); + + auto operator==( iterator const& other ) const -> bool { + return m_iterators == other.m_iterators; + } + auto operator!=( iterator const& other ) const -> bool { + return m_iterators != other.m_iterators; + } + std::string operator*() const; + iterator& operator++(); + iterator operator++( int ); + }; + using const_iterator = iterator; + + iterator begin() const { return iterator( *this ); } + iterator end() const { return { *this, iterator::EndTag() }; } + + Columns& operator+=( Column const& col ); + Columns operator+( Column const& col ); + + friend std::ostream& operator<<( std::ostream& os, + Columns const& cols ); + }; + + } // namespace TextFlow +} // namespace Catch +#endif // CATCH_CLARA_TEXTFLOW_HPP_INCLUDED diff --git a/src/catch2/reporters/catch_reporter_console.cpp b/src/catch2/reporters/catch_reporter_console.cpp index afceede4..2924c920 100644 --- a/src/catch2/reporters/catch_reporter_console.cpp +++ b/src/catch2/reporters/catch_reporter_console.cpp @@ -14,12 +14,11 @@ #include #include #include -#include +#include #include #include #include #include -#include #include #include @@ -152,7 +151,7 @@ private: if (result.hasExpandedExpression()) { stream << "with expansion:\n"; Colour colourGuard(Colour::ReconstructedExpression); - stream << Column(result.getExpandedExpression()).indent(2) << '\n'; + stream << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n'; } } void printMessage() const { @@ -161,7 +160,7 @@ private: for (auto const& msg : messages) { // If this assertion is a warning ignore any INFO messages if (printInfoMessages || msg.type != ResultWas::Info) - stream << Column(msg.message).indent(2) << '\n'; + stream << TextFlow::Column(msg.message).indent(2) << '\n'; } } void printSourceInfo() const { @@ -297,10 +296,10 @@ public: m_isOpen = true; *this << RowBreak(); - Columns headerCols; - Spacer spacer(2); + TextFlow::Columns headerCols; + auto spacer = TextFlow::Spacer(2); for (auto const& info : m_columnInfos) { - headerCols += Column(info.name).width(static_cast(info.width - 2)); + headerCols += TextFlow::Column(info.name).width(static_cast(info.width - 2)); headerCols += spacer; } m_os << headerCols << '\n'; @@ -438,7 +437,7 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { void ConsoleReporter::benchmarkPreparing(std::string const& name) { lazyPrintWithoutClosingBenchmarkTable(); - auto nameCol = Column(name).width(static_cast(m_tablePrinter->columnInfos()[0].width - 2)); + auto nameCol = TextFlow::Column(name).width(static_cast(m_tablePrinter->columnInfos()[0].width - 2)); bool firstLine = true; for (auto line : nameCol) { @@ -585,7 +584,7 @@ void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t i += 2; else i = 0; - stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; + stream << TextFlow::Column(_string).indent(indent + i).initialIndent(indent) << '\n'; } struct SummaryColumn { diff --git a/src/catch2/reporters/catch_reporter_junit.cpp b/src/catch2/reporters/catch_reporter_junit.cpp index 0f171e05..3b8e2e9a 100644 --- a/src/catch2/reporters/catch_reporter_junit.cpp +++ b/src/catch2/reporters/catch_reporter_junit.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -266,7 +266,7 @@ namespace Catch { } if (result.hasExpandedExpression()) { rss << "with expansion:\n"; - rss << Column(result.getExpandedExpression()).indent(2) << '\n'; + rss << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n'; } } else { rss << '\n'; diff --git a/src/catch2/reporters/catch_reporter_teamcity.cpp b/src/catch2/reporters/catch_reporter_teamcity.cpp index 5634971d..dd60cf9e 100644 --- a/src/catch2/reporters/catch_reporter_teamcity.cpp +++ b/src/catch2/reporters/catch_reporter_teamcity.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include @@ -23,7 +23,7 @@ namespace Catch { i += 2; else i = 0; - os << Column(_string) + os << TextFlow::Column(_string) .indent(indent + i) .initialIndent(indent) << '\n'; }