// ----------------------------------------------------------- // Copyright (c) 2001 Jeremy Siek // Copyright (c) 2003-2006, 2025 Gennaro Prota // // 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) // // ----------------------------------------------------------- #include "bitset_test.hpp" #include "boost/config.hpp" #include "boost/dynamic_bitset/dynamic_bitset.hpp" #include #include #include #include #include #if ! defined( BOOST_NO_STRINGSTREAM ) # include #endif #if defined BOOST_NO_STD_WSTRING # define BOOST_DYNAMIC_BITSET_NO_WCHAR_T_TESTS #endif #if ! defined BOOST_DYNAMIC_BITSET_NO_WCHAR_T_TESTS std::wstring widen_string( const std::string & str, const std::locale & loc = std::locale() ) { std::wstring result; const std::string::size_type len = str.length(); if ( len != 0 ) { typedef std::ctype< wchar_t > ct_type; typedef std::wstring::traits_type tr_type; const ct_type & ct = std::use_facet< ct_type >( loc ); result.resize( len ); for ( std::size_t i = 0; i < len; ++i ) tr_type::assign( result[ i ], ct.widen( str[ i ] ) ); } return result; } #endif template< typename Block, typename AllocatorOrContainer = std::allocator< Block > > void run_test_cases() { typedef boost::dynamic_bitset< Block, AllocatorOrContainer > bitset_type; typedef bitset_test< bitset_type > Tests; //===================================================================== // Test stream operator<< { // The test "variables" are: the stream type and its state, the // exception mask, the width, the fill char and the padding side (left/right) std::ios::iostate masks[] = { std::ios::goodbit, std::ios::eofbit, std::ios::failbit, std::ios::eofbit | std::ios::failbit }; static std::string strings[] = { std::string( "" ), std::string( "0" ), std::string( "1" ), std::string( "11100" ), get_long_string() }; char fill_chars[] = { '*', 'x', ' ' }; std::size_t num_masks = sizeof( masks ) / sizeof( masks[ 0 ] ); std::size_t num_strings = sizeof( strings ) / sizeof( strings[ 0 ] ); std::size_t num_chars = sizeof( fill_chars ) / sizeof( fill_chars[ 0 ] ); std::fstream not_good_stream( "dynamic_bitset_tests - this file shouldn't exist", std::ios::in ); for ( std::size_t mi = 0; mi < num_masks; ++mi ) { for ( std::size_t si = 0; si < num_strings; ++si ) { std::streamsize slen = (std::streamsize)( strings[ si ].length() ); assert( ( std::numeric_limits< std::streamsize >::max )() >= (std::streamsize)( 1 + slen * 2 ) ); for ( std::size_t ci = 0; ci < num_chars; ++ci ) { // note how "negative widths" are tested too const std::streamsize widths[] = { -1 - slen / 2, 0, slen / 2, 1 + slen * 2 }; std::size_t num_widths = sizeof( widths ) / sizeof( widths[ 0 ] ); for ( std::size_t wi = 0; wi < num_widths; ++wi ) { std::streamsize w = widths[ wi ]; { // test 0 - stream !good() if ( not_good_stream.good() ) throw std::logic_error( "Error in operator << tests" " - please, double check" ); bitset_type b( strings[ si ] ); not_good_stream.width( w ); not_good_stream.fill( fill_chars[ ci ] ); try { not_good_stream.exceptions( masks[ mi ] ); } catch ( ... ) { } Tests::stream_inserter( b, not_good_stream, "" ); } { // test 1a - file stream scoped_temp_file stf; bitset_type b( strings[ si ] ); std::ofstream file( stf.path().string().c_str(), std::ios::trunc ); file.width( w ); file.fill( fill_chars[ ci ] ); file.exceptions( masks[ mi ] ); Tests::stream_inserter( b, file, stf.path().string().c_str() ); } { // NOTE: there are NO string stream tests } #if ! defined( BOOST_DYNAMIC_BITSET_NO_WCHAR_T_TESTS ) { // test 1b - wide file stream scoped_temp_file stf; bitset_type b( strings[ si ] ); std::wofstream file( stf.path().string().c_str() ); file.width( w ); file.fill( fill_chars[ ci ] ); file.exceptions( masks[ mi ] ); Tests::stream_inserter( b, file, stf.path().string().c_str() ); } #endif } } } } // for (; mi..) } //===================================================================== // Test stream operator>> { // The test "variables" are: the stream type, the exception mask, // the actual contents (and/or state) of the stream, and width. // // With few exceptions, each test case consists of writing a different // assortment of digits and "whitespaces" to a text stream and then checking // that what was written gets read back unchanged. That's NOT guaranteed by // the standard, unless the assortment always ends with a '\n' and satisfies // other conditions (see C99, 7.19.2/2), however it works in practice and is // a good "real life" test. Some characters, such as '\v' and '\f', are not // used exactly because they are the ones which will most likely give problems // on some systems (for instance '\f' could actually be written as a sequence // of new-lines, and we could never be able to read it back) // // Note how the bitset object is not initially empty. That helps checking // that it isn't erroneously clear()ed by operator>>. std::ios::iostate masks[] = { std::ios::goodbit, std::ios::eofbit, std::ios::failbit, std::ios::eofbit | std::ios::failbit }; const std::string spaces = "\t\n "; //"\t\n\v\f "; const std::string long_string = get_long_string(); const static std::string strings[] = { // empty string std::string( "" ), // no bitset spaces, // no bitset std::string( "x" ), std::string( "\t xyz" ), // bitset of size 1 std::string( "0" ), std::string( "1" ), std::string( " 0 " ), std::string( " 1 " ), spaces + "1", "1" + spaces, spaces + "1" + spaces, std::string( " x1x " ), std::string( " 1x " ), // long bitset long_string, " " + long_string + " xyz", spaces + long_string, spaces + long_string + spaces }; //----------------------------------------------------- std::stringstream not_good_stream; not_good_stream << "test"; std::string sink; not_good_stream >> sink; // now the stream should be in eof state const std::size_t num_masks = sizeof( masks ) / sizeof( masks[ 0 ] ); const std::size_t num_strings = sizeof( strings ) / sizeof( strings[ 0 ] ); for ( std::size_t mi = 0; mi < num_masks; ++mi ) { for ( std::size_t si = 0; si < num_strings; ++si ) { const std::streamsize slen = (std::streamsize)( strings[ si ].length() ); assert( ( std::numeric_limits< std::streamsize >::max )() >= (std::streamsize)( 1 + slen * 2 ) ); std::streamsize widths[] = { -1, 0, slen / 2, slen, 1 + slen * 2 }; std::size_t num_widths = sizeof( widths ) / sizeof( widths[ 0 ] ); for ( std::size_t wi = 0; wi < num_widths; ++wi ) { const std::streamsize w = widths[ wi ]; // test 0 - !good() stream { if ( not_good_stream.good() ) throw std::logic_error( "Error in operator >> tests" " - please, double check" ); bitset_type b( 1, 15ul ); // note: b is not empty not_good_stream.width( w ); try { not_good_stream.exceptions( masks[ mi ] ); } catch ( ... ) { } std::string irrelevant; Tests::stream_extractor( b, not_good_stream, irrelevant ); } // test 1a - (narrow) file stream { scoped_temp_file stf; bitset_type b( 1, 255ul ); { std::ofstream f( stf.path().string().c_str() ); f << strings[ si ]; } std::ifstream f( stf.path().string().c_str() ); f.width( w ); f.exceptions( masks[ mi ] ); Tests::stream_extractor( b, f, strings[ si ] ); } #if ! defined( BOOST_NO_STRINGSTREAM ) // test 2a - stringstream { bitset_type b( 1, 255ul ); std::istringstream stream( strings[ si ] ); stream.width( w ); stream.exceptions( masks[ mi ] ); Tests::stream_extractor( b, stream, strings[ si ] ); } #endif #if ! defined( BOOST_DYNAMIC_BITSET_NO_WCHAR_T_TESTS ) // test 1b - wchar_t file stream { scoped_temp_file stf; std::wstring wstr = widen_string( strings[ si ] ); bitset_type b( 1, 255ul ); { std::basic_ofstream< wchar_t > of( stf.path().string().c_str() ); of << wstr; } std::basic_ifstream< wchar_t > f( stf.path().string().c_str() ); f.width( w ); f.exceptions( masks[ mi ] ); Tests::stream_extractor( b, f, wstr ); } // test 2b - wstringstream { bitset_type b( 1, 255ul ); std::wstring wstr = widen_string( strings[ si ] ); std::wistringstream wstream( wstr ); wstream.width( w ); wstream.exceptions( masks[ mi ] ); Tests::stream_extractor( b, wstream, wstr ); } #endif // BOOST_DYNAMIC_BITSET_NO_WCHAR_T_TESTS } } } // for ( mi = 0; ...) } //===================================================================== // << Any other tests go here >> // ..... } int main() { run_test_cases< unsigned char >(); run_test_cases< unsigned char, small_vector< unsigned char > >(); run_test_cases< unsigned short >(); run_test_cases< unsigned short, small_vector< unsigned short > >(); run_test_cases< unsigned int >(); run_test_cases< unsigned int, small_vector< unsigned int > >(); run_test_cases< unsigned long >(); run_test_cases< unsigned long, small_vector< unsigned long > >(); run_test_cases< unsigned long long >(); run_test_cases< unsigned long long, small_vector< unsigned long long > >(); return boost::report_errors(); }