forked from Alepha/Alepha
Improved table test output and fixed bugs in word wrap and its test.
This commit is contained in:
@ -10,8 +10,8 @@ static_assert( __cplusplus > 2020'00 );
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
using Alepha::exports::types::argcnt_t;
|
using Alepha::Hydrogen::exports::types::argcnt_t;
|
||||||
using Alepha::exports::types::argvec_t;
|
using Alepha::Hydrogen::exports::types::argvec_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
@ -4,8 +4,8 @@ static_assert( __cplusplus > 2020'00 );
|
|||||||
|
|
||||||
#include <Alepha/Alepha.h>
|
#include <Alepha/Alepha.h>
|
||||||
|
|
||||||
#include <Alepha/meta/is_pair.h>
|
#include <Alepha/Meta/is_pair.h>
|
||||||
#include <Alepha/meta/is_tuple.h>
|
#include <Alepha/Meta/is_tuple.h>
|
||||||
|
|
||||||
namespace Alepha::Hydrogen::Meta
|
namespace Alepha::Hydrogen::Meta
|
||||||
{
|
{
|
||||||
|
|||||||
47
Meta/sequence_kind.h
Normal file
47
Meta/sequence_kind.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
static_assert( __cplusplus > 2020'00 );
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Alepha/Alepha.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include <Alepha/Meta/is_sequence.h>
|
||||||
|
|
||||||
|
namespace Alepha::Hydrogen::Meta ::detail:: type_traits::sequence_kind
|
||||||
|
{
|
||||||
|
inline namespace exports {}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
constexpr bool is_std_array_v= false;
|
||||||
|
|
||||||
|
template< typename T, std::size_t sz >
|
||||||
|
constexpr bool is_std_array_v< std::array< T, sz > >{ true };
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
concept SequenceOfKnownKind= is_sequence_v< T > or is_std_array_v< T >;
|
||||||
|
|
||||||
|
template< SequenceOfKnownKind Seq >
|
||||||
|
constexpr const char *
|
||||||
|
sequence_kind_f() noexcept
|
||||||
|
{
|
||||||
|
if constexpr( is_std_array_v< Seq > ) return "array";
|
||||||
|
if constexpr( is_vector_v< Seq > ) return "vector";
|
||||||
|
if constexpr( is_deque_v< Seq > ) return "deque";
|
||||||
|
if constexpr( is_list_v< Seq > ) return "list";
|
||||||
|
if constexpr( is_string_v< Seq > ) return "string";
|
||||||
|
if constexpr( is_forward_list_v< Seq > ) return "forward_list";
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace exports
|
||||||
|
{
|
||||||
|
template< SequenceOfKnownKind Seq >
|
||||||
|
constexpr const char *const sequence_kind_v= sequence_kind_f< Seq >();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Alepha::Hydrogen::Meta::inline exports::inline type_traits::inline sequence_kind
|
||||||
|
{
|
||||||
|
using namespace detail::type_traits::sequence_kind::exports;
|
||||||
|
}
|
||||||
|
|
||||||
@ -9,19 +9,47 @@ static_assert( __cplusplus > 2020'00 );
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
#include <numeric>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#include <boost/core/demangle.hpp>
|
#include <boost/core/demangle.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
#include <Alepha/Meta/is_vector.h>
|
#include <Alepha/Meta/is_vector.h>
|
||||||
|
#include <Alepha/Meta/is_optional.h>
|
||||||
|
#include <Alepha/Meta/is_streamable.h>
|
||||||
|
#include <Alepha/Meta/is_sequence.h>
|
||||||
|
#include <Alepha/Meta/is_product_type.h>
|
||||||
|
|
||||||
#include <Alepha/Meta/product_type_decay.h>
|
#include <Alepha/Meta/product_type_decay.h>
|
||||||
|
#include <Alepha/Meta/sequence_kind.h>
|
||||||
|
|
||||||
|
#include <Alepha/function_traits.h>
|
||||||
|
#include <Alepha/template_for_each.h>
|
||||||
|
|
||||||
#include <Alepha/Utility/evaluation.h>
|
#include <Alepha/Utility/evaluation.h>
|
||||||
|
|
||||||
|
#include <Alepha/TotalOrder.h>
|
||||||
#include <Alepha/console.h>
|
#include <Alepha/console.h>
|
||||||
|
|
||||||
namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||||
{
|
{
|
||||||
inline namespace exports
|
inline namespace exports
|
||||||
{
|
{
|
||||||
template< auto > struct TableTest;
|
enum class OutputMode { All, Relaxed };
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename F >
|
||||||
|
concept FunctionVariable=
|
||||||
|
requires( const F &f )
|
||||||
|
{
|
||||||
|
{ std::function{ f } };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
namespace exports
|
||||||
|
{
|
||||||
|
template< FunctionVariable auto, OutputMode outputMode= OutputMode::All > struct TableTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void breakpoint() {}
|
inline void breakpoint() {}
|
||||||
@ -33,16 +61,184 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
using namespace Alepha::console::C;
|
using namespace Alepha::console::C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using std::begin, std::end;
|
||||||
using namespace Utility::exports::evaluation;
|
using namespace Utility::exports::evaluation;
|
||||||
|
using namespace std::literals::string_literals;
|
||||||
|
|
||||||
template< typename RetVal, typename ... Args, RetVal (*function)( Args... ) >
|
template< template< typename, typename... > class Sequence, typename ... TupleArgs >
|
||||||
struct exports::TableTest< function >
|
auto
|
||||||
|
withIndex( const Sequence< std::tuple< TupleArgs... > > &original )
|
||||||
{
|
{
|
||||||
using args_type= Meta::product_type_decay_t< std::tuple< Args... > >;
|
auto indices= evaluate <=[&]
|
||||||
|
{
|
||||||
|
std::vector< int > v{ std::distance( begin( original ), end( original ) ) };
|
||||||
|
std::iota( begin( v ), end( v ), 0 );
|
||||||
|
return v;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto bindIndex= []( const auto i, const auto e ) { return std::tuple_cat( i, e ); };
|
||||||
|
using indexed_table_entry= decltype( bindIndex( indices.front(), original.front() ) );
|
||||||
|
std::vector< indexed_table_entry > rv;
|
||||||
|
std::transform( begin( indices ), end( indices ), begin( original ), std::back_inserter( rv ), bindIndex );
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< OutputMode outputMode, typename T >
|
||||||
|
std::string
|
||||||
|
stringifyValue( const T &v )
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
if constexpr( false ) ; // To keep the rest of the clauses regular
|
||||||
|
else if constexpr( std::is_same_v< std::uint8_t, std::decay_t< T > > )
|
||||||
|
{
|
||||||
|
oss << std::hex << std::setw( 2 ) << std::setfill( '0' ) << int( v );
|
||||||
|
}
|
||||||
|
else if constexpr( std::is_same_v< bool, std::decay_t< T > > )
|
||||||
|
{
|
||||||
|
oss << std::boolalpha << v;
|
||||||
|
}
|
||||||
|
else if constexpr( std::is_same_v< std::string, std::decay_t< T > > )
|
||||||
|
{
|
||||||
|
oss << "(String with " << v.size() << " chars)";
|
||||||
|
oss << '\n' << R"(""")" << '\n';
|
||||||
|
for( const char ch: v )
|
||||||
|
{
|
||||||
|
if( ch == '\n' ) oss << "<EOL>\n";
|
||||||
|
else if( std::isalnum( ch ) or std::ispunct( ch ) or ( ch == ' ' ) ) oss << ch;
|
||||||
|
else oss << "<\\0x" << std::hex << std::setw( 2 ) << std::setfill( '0' ) << unsigned( ch ) << '>';
|
||||||
|
}
|
||||||
|
oss << '\n' << R"(""")";
|
||||||
|
}
|
||||||
|
else if constexpr( Meta::is_ostreamable_v< T > )
|
||||||
|
{
|
||||||
|
return boost::lexical_cast< std::string >( v );
|
||||||
|
}
|
||||||
|
else if constexpr( Meta::is_optional_v< T > )
|
||||||
|
{
|
||||||
|
return v.has_value() ? stringifyValue< outputMode >( v.value() ) : "<noopt>"s;
|
||||||
|
}
|
||||||
|
else if constexpr( Meta::is_sequence_v< T > )
|
||||||
|
{
|
||||||
|
if constexpr( outputMode == OutputMode::Relaxed and not Meta::is_ostreamable_v< typename T::value_type > )
|
||||||
|
{
|
||||||
|
oss << "<Unstreamable sequence of " << v.size() << " elements.>";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oss << Meta::sequence_kind_v< T > << "(" << v.size() << " elements):\n{" << std::endl;
|
||||||
|
|
||||||
|
int index= 0;
|
||||||
|
for( const auto &elem: v ) oss << "\t" << index++ << ": " << stringifyValue< outputMode >( elem ) << "," << std::endl;
|
||||||
|
oss << "}" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if constexpr( Meta::is_pair_v< T > )
|
||||||
|
{
|
||||||
|
const auto &[ first, second ]= v;
|
||||||
|
return stringifyValue< outputMode >( std::tie( first, second ) );
|
||||||
|
}
|
||||||
|
else if constexpr( Meta::is_tuple_v< T > )
|
||||||
|
{
|
||||||
|
oss << '[';
|
||||||
|
tuple_for_each( v ) <=[&oss, first= true]( const auto &elem ) mutable
|
||||||
|
{
|
||||||
|
if( not first ) oss << ", ";
|
||||||
|
first= false;
|
||||||
|
oss << std::endl << stringifyValue< outputMode >( elem );
|
||||||
|
};
|
||||||
|
oss << std::endl << ']' << std::endl;
|
||||||
|
}
|
||||||
|
else if constexpr( std::is_same_v< T, TotalOrder > )
|
||||||
|
{
|
||||||
|
if( false ) ; // For alignment
|
||||||
|
else if( v == TotalOrder::less ) oss << "less";
|
||||||
|
else if ( v == TotalOrder::equal ) oss << "equal";
|
||||||
|
else if( v == TotalOrder::greater ) oss << "greater";
|
||||||
|
else throw std::logic_error( "Impossible `TotalOrder` condition." );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static_assert( dependent_value< false, T >, "One of the types used in the testing table does not support stringification." );
|
||||||
|
}
|
||||||
|
return std::move( oss ).str();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
printDebuggingForStrings( const std::string &witness, const std::string &expected )
|
||||||
|
{
|
||||||
|
const std::size_t amount= std::min( witness.size(), expected.size() );
|
||||||
|
if( witness.size() != expected.size() )
|
||||||
|
{
|
||||||
|
std::cout << "Witness string size did not match the expected string size. Only mismatches found in the first "
|
||||||
|
<< amount << " characters will be printed." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( int i= 0; i < amount; ++i )
|
||||||
|
{
|
||||||
|
if( witness.at( i ) == expected.at( i ) ) continue;
|
||||||
|
std::cout << "Mismatch at index: " << i << std::endl;
|
||||||
|
std::cout << "witness: " << witness.at( i ) << std::endl;
|
||||||
|
std::cout << "expected: " << expected.at( i ) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< OutputMode outputMode, typename T >
|
||||||
|
void
|
||||||
|
printDebugging( const T &witness, const T &expected )
|
||||||
|
{
|
||||||
|
if constexpr( std::is_same_v< std::string, std::decay_t< T > > )
|
||||||
|
{
|
||||||
|
printDebuggingForStrings( witness, expected );
|
||||||
|
}
|
||||||
|
else if constexpr( Meta::is_sequence_v< T > )
|
||||||
|
{
|
||||||
|
if constexpr( std::is_same_v< std::string, typename T::value_type > )
|
||||||
|
{
|
||||||
|
if( witness.size() == expected.size() ) for( std::size_t i= 0; i < witness.size(); ++i )
|
||||||
|
{
|
||||||
|
if( witness.at( i ) != expected.at( i ) ) printDebuggingForStrings( witness.at( i ), expected.at( i ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( witness.size() != expected.size() )
|
||||||
|
{
|
||||||
|
std::cout << "Witness sequence size of " << witness.size() << " did not match the expected sequence size of "
|
||||||
|
<< expected.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto next= std::make_pair( begin( witness ), begin( expected ) );
|
||||||
|
bool first= true;
|
||||||
|
while( next.first != end( witness ) and next.second != end( expected ) )
|
||||||
|
{
|
||||||
|
if( not first )
|
||||||
|
{
|
||||||
|
std::cout << "Mismatch at witness index " << std::distance( begin( witness ), next.first ) << " and "
|
||||||
|
<< "expected index " << std::distance( begin( expected ), next.second ) << std::endl;
|
||||||
|
++next.first; ++next.second;
|
||||||
|
}
|
||||||
|
first= false;
|
||||||
|
next= std::mismatch( next.first, end( witness ), next.second, end( expected ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl
|
||||||
|
<< "computed: " << stringifyValue< outputMode >( witness ) << std::endl
|
||||||
|
<< "expected: " << stringifyValue< outputMode >( expected ) << std::endl << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< FunctionVariable auto function, OutputMode outputMode >
|
||||||
|
struct exports::TableTest
|
||||||
|
{
|
||||||
|
using function_traits_type= function_traits< decltype( function ) >;
|
||||||
|
|
||||||
|
using args_type= Meta::product_type_decay_t< typename function_traits_type::args_type >;
|
||||||
|
using return_type= typename function_traits_type::return_type;
|
||||||
|
|
||||||
struct Cases
|
struct Cases
|
||||||
{
|
{
|
||||||
using TestDescription= std::tuple< std::string, args_type, RetVal >;
|
using TestDescription= std::tuple< std::string, args_type, return_type >;
|
||||||
|
|
||||||
std::vector< TestDescription > tests;
|
std::vector< TestDescription > tests;
|
||||||
|
|
||||||
@ -58,10 +254,13 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
{
|
{
|
||||||
if( C::debugCaseTypes ) std::cerr << boost::core::demangle( typeid( params ).name() ) << std::endl;
|
if( C::debugCaseTypes ) std::cerr << boost::core::demangle( typeid( params ).name() ) << std::endl;
|
||||||
breakpoint();
|
breakpoint();
|
||||||
if( std::apply( function, params ) != expected )
|
const auto witness= std::apply( function, params );
|
||||||
|
const auto result= witness == expected;
|
||||||
|
if( not result )
|
||||||
{
|
{
|
||||||
std::cout << C::red << " FAILURE" << C::normal << ": " << comment << std::endl;
|
std::cout << C::red << " FAILURE" << C::normal << ": " << comment << std::endl;
|
||||||
++failureCount;
|
++failureCount;
|
||||||
|
printDebugging< outputMode >( witness, expected );
|
||||||
}
|
}
|
||||||
else std::cout << C::green << " SUCCESS" << C::normal << ": " << comment << std::endl;
|
else std::cout << C::green << " SUCCESS" << C::normal << ": " << comment << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,8 +8,8 @@ static_assert( __cplusplus > 2020'00 );
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
using Alepha::exports::types::argcnt_t;
|
using Alepha::Hydrogen::exports::types::argcnt_t;
|
||||||
using Alepha::exports::types::argvec_t;
|
using Alepha::Hydrogen::exports::types::argvec_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -21,8 +21,8 @@ main( const argcnt_t argcnt, const argvec_t argvec )
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
using namespace Alepha::Testing::exports;
|
using namespace Alepha::Testing::exports;
|
||||||
using namespace Alepha::exports::comparisons;
|
using namespace Alepha::Hydrogen::exports::comparisons;
|
||||||
using namespace Alepha::exports::capabilities;
|
using namespace Alepha::Hydrogen::exports::capabilities;
|
||||||
|
|
||||||
template
|
template
|
||||||
<
|
<
|
||||||
@ -41,7 +41,7 @@ namespace
|
|||||||
};
|
};
|
||||||
|
|
||||||
using Date= Date_core<>;
|
using Date= Date_core<>;
|
||||||
namespace detail= Alepha::detail::capabilities;
|
namespace detail= Alepha::Hydrogen::detail::capabilities;
|
||||||
|
|
||||||
namespace Meta= Alepha::Meta;
|
namespace Meta= Alepha::Meta;
|
||||||
|
|
||||||
|
|||||||
86
template_for_each.h
Normal file
86
template_for_each.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
static_assert( __cplusplus > 2020'00 );
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "Concepts.h"
|
||||||
|
|
||||||
|
namespace Alepha::inline Cavorite ::detail:: template_for_each_module
|
||||||
|
{
|
||||||
|
inline namespace exports
|
||||||
|
{
|
||||||
|
constexpr void tuple_for_each( const std::tuple<> &, const Functional auto ) noexcept {}
|
||||||
|
|
||||||
|
template< typename ... Args, typename Function >
|
||||||
|
constexpr void
|
||||||
|
tuple_for_each( const std::tuple< Args... > &tuple, Function body )
|
||||||
|
noexcept
|
||||||
|
(
|
||||||
|
( ... and noexcept( body( std::declval< const Args & >() ) ) )
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const auto callWrapper= [&body]( auto &&element ) { body( element ); return nullptr; };
|
||||||
|
|
||||||
|
auto loop_body_handler= [&]( auto &&... tuple_elements )
|
||||||
|
{
|
||||||
|
std::nullptr_t expansion[]= { callWrapper( tuple_elements )... };
|
||||||
|
|
||||||
|
std::ignore= expansion;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::apply( loop_body_handler, tuple );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply type_identity to all tuple elements
|
||||||
|
template< typename > struct type_identify_tuple;
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
using type_identify_tuple_t= typename type_identify_tuple< T >::type;
|
||||||
|
|
||||||
|
template<> struct type_identify_tuple< std::tuple<> > { using type= std::tuple<>; };
|
||||||
|
|
||||||
|
template< typename ... Args >
|
||||||
|
struct type_identify_tuple< std::tuple< Args... > >
|
||||||
|
{
|
||||||
|
using type= std::tuple< std::type_identity< Args >... >;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Nicer for-each syntax helper:
|
||||||
|
template< typename Tuple >
|
||||||
|
struct for_each_syntax_adaptor
|
||||||
|
{
|
||||||
|
Tuple &tuple;
|
||||||
|
|
||||||
|
template< typename Function >
|
||||||
|
constexpr void
|
||||||
|
operator <= ( Function &&func ) noexcept( noexcept( tuple_for_each( tuple, std::forward< Function >( func ) ) ) )
|
||||||
|
{
|
||||||
|
return tuple_for_each( tuple, std::forward< Function >( func ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr operator decltype( std::ignore ) () const= delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename Tuple >
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr auto
|
||||||
|
tuple_for_each( Tuple &tuple ) noexcept
|
||||||
|
{
|
||||||
|
return for_each_syntax_adaptor< Tuple >{ tuple };
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename Tuple >
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr auto
|
||||||
|
tuple_for_each( const Tuple &tuple ) noexcept
|
||||||
|
{
|
||||||
|
return for_each_syntax_adaptor< const Tuple >{ tuple };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Alepha::Cavorite::inline exports::inline template_for_each_module
|
||||||
|
{
|
||||||
|
using namespace detail::template_for_each_module::exports;
|
||||||
|
}
|
||||||
@ -23,14 +23,8 @@ namespace Alepha::Cavorite ::detail:: word_wrap
|
|||||||
{
|
{
|
||||||
if( currentLineWidth + word.size() > maximumWidth )
|
if( currentLineWidth + word.size() > maximumWidth )
|
||||||
{
|
{
|
||||||
//std::cerr << "Going to newline on word: " << word << "(currentLineWidth= " << currentLineWidth << ")" << std::endl;
|
|
||||||
result+= '\n';
|
result+= '\n';
|
||||||
//const auto orig= result.size();
|
|
||||||
std::fill_n( back_inserter( result ), nextLineOffset, ' ' );
|
std::fill_n( back_inserter( result ), nextLineOffset, ' ' );
|
||||||
//assert( orig + nextLineOffset == result.size() );
|
|
||||||
//std::cerr << "orig: " << orig << " nextLineOffset: " << nextLineOffset << " result: " << result.size() << std::endl;
|
|
||||||
|
|
||||||
//result+= '%';
|
|
||||||
return nextLineOffset;
|
return nextLineOffset;
|
||||||
}
|
}
|
||||||
else return currentLineWidth;
|
else return currentLineWidth;
|
||||||
@ -58,9 +52,17 @@ namespace Alepha::Cavorite ::detail:: word_wrap
|
|||||||
{
|
{
|
||||||
if( ch == '\n' )
|
if( ch == '\n' )
|
||||||
{
|
{
|
||||||
std::ignore= putWord( std::move( word ), result, lineLength );
|
const auto prev= lineLength;
|
||||||
|
const auto size= word.size();
|
||||||
|
lineLength= putWord( std::move( word ), result, lineLength );
|
||||||
word.clear();
|
word.clear();
|
||||||
lineLength= 0;
|
result+= '\n';
|
||||||
|
if( lineLength == prev + size )
|
||||||
|
{
|
||||||
|
std::fill_n( back_inserter( result ), nextLineOffset, ' ' );
|
||||||
|
lineLength= nextLineOffset;
|
||||||
|
}
|
||||||
|
else lineLength= 0;
|
||||||
}
|
}
|
||||||
else if( ch == ' ' )
|
else if( ch == ' ' )
|
||||||
{
|
{
|
||||||
|
|||||||
@ -24,21 +24,21 @@ static auto init= Alepha::Utility::enroll <=[]
|
|||||||
{ "Simple", { "Hello", 100, 0 }, "Hello" },
|
{ "Simple", { "Hello", 100, 0 }, "Hello" },
|
||||||
{ "space should be kept", { "Hello ", 10, 0 }, "Hello " },
|
{ "space should be kept", { "Hello ", 10, 0 }, "Hello " },
|
||||||
{ "space should be dropped", { "Hello ", 5, 0 }, "Hello" },
|
{ "space should be dropped", { "Hello ", 5, 0 }, "Hello" },
|
||||||
{ "all spaces should be dropped", { "Hello ", 5, 0 }, "Hello" },
|
{ "all spaces should be dropped", { "Hello ", 5, 0 }, "Hello" },
|
||||||
{ "two spaces should be kept", { "Hello ", 7, 0 }, "Hello " },
|
{ "two spaces should be kept", { "Hello ", 7, 0 }, "Hello " },
|
||||||
{ "too narrow, forces wrap anyway", { "Hello", 4, 0 }, "\nHello" },
|
{ "too narrow, forces wrap anyway", { "Hello", 4, 0 }, "\nHello" },
|
||||||
{ "too narrow, forces wrap anyway, drops space", { "Hello ", 4, 0 }, "\nHello" },
|
{ "too narrow, forces wrap anyway, drops space", { "Hello ", 4, 0 }, "\nHello" },
|
||||||
{ "too narrow, forces wrap anyway, drops spaces", { "Hello ", 4, 0 }, "\nHello" },
|
{ "too narrow, forces wrap anyway, drops spaces", { "Hello ", 4, 0 }, "\nHello" },
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string helloWorld= "Hello World";
|
const std::string helloWorld= "Hello World";
|
||||||
"word_wrap.noindent.two_words"_test <=TableTest< Alepha::wordWrap >::Cases
|
"word_wrap.noindent.two_words"_test <=TableTest< Alepha::wordWrap >::Cases
|
||||||
{
|
{
|
||||||
{ "Simple", { helloWorld, 100, 0 }, helloWorld },
|
{ "Simple", { helloWorld, 100, 0 }, helloWorld },
|
||||||
{ "Trailing space should be kept", { helloWorld +" ", 100, 0 }, helloWorld + " " },
|
{ "Trailing space should be kept", { helloWorld + " ", 100, 0 }, helloWorld + " " },
|
||||||
{ "Trailing spaces should be kept", { helloWorld + " ", 100, 0 }, helloWorld + " " },
|
{ "Trailing spaces should be kept", { helloWorld + " ", 100, 0 }, helloWorld + " " },
|
||||||
{ "Trailing spaces should be dropped", { helloWorld + " ", helloWorld.size(), 0 }, helloWorld },
|
{ "Trailing spaces should be dropped", { helloWorld + " ", helloWorld.size(), 0 }, helloWorld },
|
||||||
{ "All but 2 trailing spaces dropped", { helloWorld + " ", helloWorld.size() + 2, 0 },
|
{ "All but 2 trailing spaces dropped", { helloWorld + " ", helloWorld.size() + 2, 0 },
|
||||||
helloWorld + " "},
|
helloWorld + " "},
|
||||||
|
|
||||||
{ "Split line", { helloWorld, 8, 0 }, "Hello \nWorld" }, // TODO: Should we swallow trailing spaces?
|
{ "Split line", { helloWorld, 8, 0 }, "Hello \nWorld" }, // TODO: Should we swallow trailing spaces?
|
||||||
@ -117,8 +117,8 @@ static auto init= Alepha::Utility::enroll <=[]
|
|||||||
"word_wrap.indent"_test <=TableTest< Alepha::wordWrap >::Cases
|
"word_wrap.indent"_test <=TableTest< Alepha::wordWrap >::Cases
|
||||||
{
|
{
|
||||||
{ "Two word indent, simple", { "Hello World!", 8, 2 }, "Hello \n World!" },
|
{ "Two word indent, simple", { "Hello World!", 8, 2 }, "Hello \n World!" },
|
||||||
{ "Three word indent, simple", { "Hello Wonderful World!", 16, 4 }, "Hello Wonderful \n World!" },
|
{ "Three word indent, simple", { "Hello Wonderful World!", 16, 4 }, "Hello Wonderful \n World!" },
|
||||||
{ "Three word indent, corner case", { "Hello Wonderful World!", 15, 4 }, "Hello Wonderful\n World!" },
|
{ "Three word indent, corner case", { "Hello Wonderful World!", 15, 4 }, "Hello Wonderful\n World!" },
|
||||||
{ "Two word indent, extra newline", { "Hello\n\nWorld!", 8, 2 }, "Hello\n \n World!" },
|
{ "Two word indent, extra newline", { "Hello\n\nWorld!", 8, 2 }, "Hello\n \n World!" },
|
||||||
{ "Two word indent, one newline", { "Hello\nWorld!", 8, 2 }, "Hello\n World!" },
|
{ "Two word indent, one newline", { "Hello\nWorld!", 8, 2 }, "Hello\n World!" },
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user