From e03649dc1ac16f051397264584d20f045a993ee3 Mon Sep 17 00:00:00 2001 From: Daniel Frey Date: Sat, 16 Nov 2024 12:28:22 +0100 Subject: [PATCH] Cleanup clang-tidy issues --- include/tao/pq/parameter_traits.hpp | 2 +- src/lib/pq/connection.cpp | 76 +-- src/lib/pq/exception.cpp | 44 +- src/lib/pq/internal/poll.cpp | 6 +- src/lib/pq/internal/strtox.cpp | 4 +- src/lib/pq/large_object.cpp | 2 +- src/lib/pq/parameter_traits.cpp | 4 +- src/lib/pq/result.cpp | 2 +- src/lib/pq/result_traits.cpp | 6 +- src/lib/pq/table_writer.cpp | 2 +- src/lib/pq/transaction.cpp | 6 +- src/test/macros.hpp | 22 +- src/test/pq/aggregate.cpp | 38 +- src/test/pq/array.cpp | 194 ++++---- src/test/pq/basic_datatypes.cpp | 663 ++++++++++++++------------- src/test/pq/connection.cpp | 196 ++++---- src/test/pq/connection_pool.cpp | 206 +++++---- src/test/pq/example.cpp | 62 +-- src/test/pq/exception.cpp | 34 +- src/test/pq/getenv.cpp | 22 +- src/test/pq/large_object.cpp | 212 ++++----- src/test/pq/notifications.cpp | 92 ++-- src/test/pq/parameter.cpp | 124 ++--- src/test/pq/resize_uninitialized.cpp | 88 ++-- src/test/pq/result.cpp | 298 ++++++------ src/test/pq/row.cpp | 152 +++--- src/test/pq/strtox.cpp | 198 ++++---- src/test/pq/table_reader.cpp | 170 +++---- src/test/pq/table_writer.cpp | 150 +++--- src/test/pq/traits.cpp | 140 +++--- src/test/pq/transaction.cpp | 168 +++---- 31 files changed, 1748 insertions(+), 1635 deletions(-) diff --git a/include/tao/pq/parameter_traits.hpp b/include/tao/pq/parameter_traits.hpp index c2d2b3a..94ea085 100644 --- a/include/tao/pq/parameter_traits.hpp +++ b/include/tao/pq/parameter_traits.hpp @@ -436,7 +436,7 @@ namespace tao::pq // generate bytea hex format constexpr char hex[] = "0123456789abcdef"; auto pos = data.size(); - internal::resize_uninitialized( data, pos + 3 + 2 * m_v.size() ); + internal::resize_uninitialized( data, pos + 3 + ( 2 * m_v.size() ) ); data[ pos++ ] = '\\'; data[ pos++ ] = '\\'; data[ pos++ ] = 'x'; diff --git a/src/lib/pq/connection.cpp b/src/lib/pq/connection.cpp index 96f6a26..8183a0a 100644 --- a/src/lib/pq/connection.cpp +++ b/src/lib/pq/connection.cpp @@ -4,6 +4,7 @@ #include +#include #include #include #include @@ -76,35 +77,39 @@ namespace tao::pq {} }; - [[nodiscard]] inline auto isolation_level_extension( const isolation_level il ) -> const char* + namespace { - switch( il ) { - case isolation_level::default_isolation_level: - return ""; - case isolation_level::serializable: - return " ISOLATION LEVEL SERIALIZABLE"; - case isolation_level::repeatable_read: - return " ISOLATION LEVEL REPEATABLE READ"; - case isolation_level::read_committed: - return " ISOLATION LEVEL READ COMMITTED"; - case isolation_level::read_uncommitted: - return " ISOLATION LEVEL READ UNCOMMITTED"; + [[nodiscard]] inline auto isolation_level_extension( const isolation_level il ) -> const char* + { + switch( il ) { + case isolation_level::default_isolation_level: + return ""; + case isolation_level::serializable: + return " ISOLATION LEVEL SERIALIZABLE"; + case isolation_level::repeatable_read: + return " ISOLATION LEVEL REPEATABLE READ"; + case isolation_level::read_committed: + return " ISOLATION LEVEL READ COMMITTED"; + case isolation_level::read_uncommitted: + return " ISOLATION LEVEL READ UNCOMMITTED"; + } + TAO_PQ_UNREACHABLE; // LCOV_EXCL_LINE } - TAO_PQ_UNREACHABLE; // LCOV_EXCL_LINE - } - [[nodiscard]] inline auto access_mode_extension( const access_mode am ) -> const char* - { - switch( am ) { - case access_mode::default_access_mode: - return ""; - case access_mode::read_write: - return " READ WRITE"; - case access_mode::read_only: - return " READ ONLY"; + [[nodiscard]] inline auto access_mode_extension( const access_mode am ) -> const char* + { + switch( am ) { + case access_mode::default_access_mode: + return ""; + case access_mode::read_write: + return " READ WRITE"; + case access_mode::read_only: + return " READ ONLY"; + } + TAO_PQ_UNREACHABLE; // LCOV_EXCL_LINE } - TAO_PQ_UNREACHABLE; // LCOV_EXCL_LINE - } + + } // namespace class top_level_transaction final : public transaction_base @@ -113,7 +118,7 @@ namespace tao::pq top_level_transaction( const std::shared_ptr< pq::connection >& connection, const isolation_level il, const access_mode am ) : transaction_base( connection ) { - this->execute( std::string( "START TRANSACTION" ) + isolation_level_extension( il ) + access_mode_extension( am ) ); + this->execute( std::format( "START TRANSACTION{}{}", isolation_level_extension( il ), access_mode_extension( am ) ) ); } ~top_level_transaction() override @@ -123,10 +128,10 @@ namespace tao::pq rollback(); } // LCOV_EXCL_START - catch( const std::exception& ) { + catch( const std::exception& ) { // NOLINT(bugprone-empty-catch) // TAO_LOG( WARNING, "unable to rollback transaction, swallowing exception: " + std::string( e.what() ) ); } - catch( ... ) { + catch( ... ) { // NOLINT(bugprone-empty-catch) // TAO_LOG( WARNING, "unable to rollback transaction, swallowing unknown exception" ); } // LCOV_EXCL_STOP @@ -155,10 +160,14 @@ namespace tao::pq } }; - [[nodiscard]] constexpr auto is_identifier( const std::string_view value ) noexcept -> bool + namespace { - return !value.empty() && ( value.find_first_not_of( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" ) == std::string_view::npos ) && ( std::isdigit( value[ 0 ] ) == 0 ); - } + [[nodiscard]] constexpr auto is_identifier( const std::string_view value ) noexcept -> bool + { + return !value.empty() && ( value.find_first_not_of( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" ) == std::string_view::npos ) && ( std::isdigit( value[ 0 ] ) == 0 ); + } + + } // namespace } // namespace internal @@ -225,10 +234,7 @@ namespace tao::pq while( true ) { int timeout_ms = -1; if( m_timeout ) { - timeout_ms = static_cast< int >( std::chrono::duration_cast< std::chrono::milliseconds >( end - std::chrono::steady_clock::now() ).count() ); - if( timeout_ms < 0 ) { - timeout_ms = 0; // LCOV_EXCL_LINE - } + timeout_ms = std::max( static_cast< int >( std::chrono::duration_cast< std::chrono::milliseconds >( end - std::chrono::steady_clock::now() ).count() ), 0 ); } switch( m_poll( socket(), wait_for_write, timeout_ms ) ) { diff --git a/src/lib/pq/exception.cpp b/src/lib/pq/exception.cpp index c439659..b25a138 100644 --- a/src/lib/pq/exception.cpp +++ b/src/lib/pq/exception.cpp @@ -119,8 +119,10 @@ namespace tao::pq throw stacked_diagnostics_accessed_without_active_handler( error_message, sql_state ); } throw diagnostics_exception( error_message, sql_state ); + + default: + throw sql_error( error_message, sql_state ); } - break; case '2': switch( sql_state[ 1 ] ) { @@ -426,8 +428,10 @@ namespace tao::pq throw function_executed_no_return_statement( error_message, sql_state ); } throw sql_routine_exception( error_message, sql_state ); + + default: + throw sql_error( error_message, sql_state ); } - break; case '3': switch( sql_state[ 1 ] ) { @@ -478,8 +482,10 @@ namespace tao::pq case 'F': throw invalid_schema_name( error_message, sql_state ); + + default: + throw sql_error( error_message, sql_state ); } - break; case '4': switch( sql_state[ 1 ] ) { @@ -632,8 +638,10 @@ namespace tao::pq case '4': throw with_check_option_violation( error_message, sql_state ); + + default: + throw sql_error( error_message, sql_state ); } - break; case '5': switch( sql_state[ 1 ] ) { @@ -708,15 +716,19 @@ namespace tao::pq throw duplicate_file( error_message, sql_state ); } throw system_error( error_message, sql_state ); + + default: + throw sql_error( error_message, sql_state ); } - break; case '7': switch( sql_state[ 1 ] ) { case '2': throw snapshot_too_old( error_message, sql_state ); + + default: + throw sql_error( error_message, sql_state ); } - break; case 'F': switch( sql_state[ 1 ] ) { @@ -725,8 +737,10 @@ namespace tao::pq throw lock_file_exists( error_message, sql_state ); } throw config_file_error( error_message, sql_state ); + + default: + throw sql_error( error_message, sql_state ); } - break; case 'H': switch( sql_state[ 1 ] ) { @@ -810,8 +824,10 @@ namespace tao::pq throw fdw_invalid_descriptor_field_identifier( error_message, sql_state ); } throw fdw_error( error_message, sql_state ); + + default: + throw sql_error( error_message, sql_state ); } - break; case 'P': switch( sql_state[ 1 ] ) { @@ -829,8 +845,10 @@ namespace tao::pq throw assert_failure( error_message, sql_state ); } throw plpgsql_error( error_message, sql_state ); + + default: + throw sql_error( error_message, sql_state ); } - break; case 'X': switch( sql_state[ 1 ] ) { @@ -842,10 +860,14 @@ namespace tao::pq throw index_corrupted( error_message, sql_state ); } throw internal_error( error_message, sql_state ); + + default: + throw sql_error( error_message, sql_state ); } - break; + + default: + throw sql_error( error_message, sql_state ); } - throw sql_error( error_message, sql_state ); // LCOV_EXCL_STOP } diff --git a/src/lib/pq/internal/poll.cpp b/src/lib/pq/internal/poll.cpp index 1ae98e0..d0ac32a 100644 --- a/src/lib/pq/internal/poll.cpp +++ b/src/lib/pq/internal/poll.cpp @@ -83,7 +83,11 @@ namespace tao::pq::internal #else const short events = POLLIN | ( wait_for_write ? POLLOUT : 0 ); - pollfd pfd = { socket, events, 0 }; + pollfd pfd = { + .fd = socket, + .events = events, + .revents = 0 + }; errno = 0; const auto result = ::poll( &pfd, 1, timeout_ms ); switch( result ) { diff --git a/src/lib/pq/internal/strtox.cpp b/src/lib/pq/internal/strtox.cpp index 4a02832..b16f870 100644 --- a/src/lib/pq/internal/strtox.cpp +++ b/src/lib/pq/internal/strtox.cpp @@ -76,8 +76,10 @@ namespace tao::pq::internal else { throw std::overflow_error( failure_message< T >( input ) ); } + + default: + throw std::runtime_error( std::format( "code should be unreachable, errno: {}, input: \"{}\"", errno, input ) ); // LCOV_EXCL_LINE } - throw std::runtime_error( std::format( "code should be unreachable, errno: {}, input: \"{}\"", errno, input ) ); // LCOV_EXCL_LINE } } // namespace diff --git a/src/lib/pq/large_object.cpp b/src/lib/pq/large_object.cpp index f5857e2..1ad676b 100644 --- a/src/lib/pq/large_object.cpp +++ b/src/lib/pq/large_object.cpp @@ -76,7 +76,7 @@ namespace tao::pq close(); } // LCOV_EXCL_START - catch( ... ) { + catch( ... ) { // NOLINT(bugprone-empty-catch) // TODO: How to handle this case properly? } // LCOV_EXCL_STOP diff --git a/src/lib/pq/parameter_traits.cpp b/src/lib/pq/parameter_traits.cpp index da2ae2e..c679db1 100644 --- a/src/lib/pq/parameter_traits.cpp +++ b/src/lib/pq/parameter_traits.cpp @@ -22,7 +22,7 @@ namespace tao::pq::internal buffer += data; break; } - buffer.append( data.data(), n ); + buffer.append( data.data(), n ); // NOLINT(bugprone-suspicious-stringview-data-usage) buffer += '\\'; buffer += data[ n ]; data.remove_prefix( n + 1 ); @@ -42,7 +42,7 @@ namespace tao::pq::internal buffer += data; return; } - buffer.append( data.data(), n ); + buffer.append( data.data(), n ); // NOLINT(bugprone-suspicious-stringview-data-usage) buffer += '\\'; buffer += data[ n ]; data.remove_prefix( n + 1 ); diff --git a/src/lib/pq/result.cpp b/src/lib/pq/result.cpp index dc0c60d..75f00db 100644 --- a/src/lib/pq/result.cpp +++ b/src/lib/pq/result.cpp @@ -122,7 +122,7 @@ namespace tao::pq auto result::get( const std::size_t row, const std::size_t column ) const -> const char* { if( is_null( row, column ) ) { - throw std::runtime_error( std::format( "unexpected NULL value in row {} column {}/'{}'", row, column, name( column ).c_str() ) ); + throw std::runtime_error( std::format( "unexpected NULL value in row {} column {}/'{}'", row, column, name( column ) ) ); } return PQgetvalue( m_pgresult.get(), static_cast< int >( row ), static_cast< int >( column ) ); } diff --git a/src/lib/pq/result_traits.cpp b/src/lib/pq/result_traits.cpp index f5cc277..4a25333 100644 --- a/src/lib/pq/result_traits.cpp +++ b/src/lib/pq/result_traits.cpp @@ -38,14 +38,14 @@ namespace tao::pq throw std::invalid_argument( "unescape BYTEA failed: " + std::string( value ) ); } - const auto size = input / 2 - 1; + const auto size = ( input / 2 ) - 1; binary nrv; internal::resize_uninitialized( nrv, size ); for( std::size_t pos = 0; pos < size; ++pos ) { - const auto high = unhex( value[ 2 + 2 * pos ] ); - const auto low = unhex( value[ 2 + 2 * pos + 1 ] ); + const auto high = unhex( value[ 2 + ( 2 * pos ) ] ); + const auto low = unhex( value[ 2 + ( 2 * pos ) + 1 ] ); nrv[ pos ] = static_cast< std::byte >( ( high << 4 ) | low ); } return nrv; diff --git a/src/lib/pq/table_writer.cpp b/src/lib/pq/table_writer.cpp index d9d1aab..2663ae5 100644 --- a/src/lib/pq/table_writer.cpp +++ b/src/lib/pq/table_writer.cpp @@ -21,7 +21,7 @@ namespace tao::pq try { std::ignore = m_transaction->get_result(); } - catch( ... ) { + catch( ... ) { // NOLINT(bugprone-empty-catch) } } } diff --git a/src/lib/pq/transaction.cpp b/src/lib/pq/transaction.cpp index ab1af03..b9ca162 100644 --- a/src/lib/pq/transaction.cpp +++ b/src/lib/pq/transaction.cpp @@ -29,10 +29,10 @@ namespace tao::pq rollback(); } // LCOV_EXCL_START - catch( const std::exception& ) { + catch( const std::exception& ) { // NOLINT(bugprone-empty-catch) // TAO_LOG( WARNING, "unable to rollback transaction, swallowing exception: " + std::string( e.what() ) ); } - catch( ... ) { + catch( ... ) { // NOLINT(bugprone-empty-catch) // TAO_LOG( WARNING, "unable to rollback transaction, swallowing unknown exception" ); } // LCOV_EXCL_STOP @@ -75,7 +75,7 @@ namespace tao::pq rollback(); } // LCOV_EXCL_START - catch( ... ) { + catch( ... ) { // NOLINT(bugprone-empty-catch) // TODO: How to handle this case properly? } // LCOV_EXCL_STOP diff --git a/src/test/macros.hpp b/src/test/macros.hpp index ea5a31a..19aabf5 100644 --- a/src/test/macros.hpp +++ b/src/test/macros.hpp @@ -17,16 +17,16 @@ #define STRINGIFY( ... ) STRINGIFY_INTERNAL( __VA_ARGS__ ) #define FILE_AND_LINE __FILE__ ":" STRINGIFY( __LINE__ ) -#define TEST_EXECUTE_MESSAGE( MeSSaGe, ... ) \ - do { \ - std::cout << "TEST [ " MeSSaGe << " ] in [ " FILE_AND_LINE " ]" << std::endl; \ - __VA_ARGS__; \ +#define TEST_EXECUTE_MESSAGE( MeSSaGe, ... ) \ + do { \ + std::cout << "TEST [ " MeSSaGe << " ] in [ " FILE_AND_LINE " ]\n"; \ + __VA_ARGS__; \ } while( false ) -#define TEST_FAILED \ - do { \ - std::cerr << "TEST FAILED in [ " FILE_AND_LINE " ]" << std::endl; \ - std::exit( 1 ); \ +#define TEST_FAILED \ + do { \ + std::cerr << "TEST FAILED in [ " FILE_AND_LINE " ]\n"; \ + std::exit( 1 ); \ } while( false ) #define TEST_ASSERT_MESSAGE( MeSSaGe, ... ) \ @@ -45,12 +45,12 @@ } catch( const tao::pq::sql_error& e ) { \ std::cout << "TEST caught [ " << tao::pq::internal::demangle( typeid( e ) ) << " ] " \ << "with SQLSTATE [ " << e.sqlstate << " ] " \ - << "and [ " << e.what() << " ] in [ " FILE_AND_LINE " ]" << std::endl; \ + << "and [ " << e.what() << " ] in [ " FILE_AND_LINE " ]\n"; \ } catch( const std::exception& e ) { \ std::cout << "TEST caught [ " << tao::pq::internal::demangle( typeid( e ) ) << " ] " \ - << "with [ " << e.what() << " ] in [ " FILE_AND_LINE " ]" << std::endl; \ + << "with [ " << e.what() << " ] in [ " FILE_AND_LINE " ]\n"; \ } catch( ... ) { \ - std::cout << "TEST caught unknown exception in [ " FILE_AND_LINE " ]" << std::endl; \ + std::cout << "TEST caught unknown exception in [ " FILE_AND_LINE " ]\n"; \ } ) #define TEST_EXECUTE( ... ) TEST_EXECUTE_MESSAGE( "EXECUTE " #__VA_ARGS__, __VA_ARGS__ ) diff --git a/src/test/pq/aggregate.cpp b/src/test/pq/aggregate.cpp index a2ee511..b9cf49a 100644 --- a/src/test/pq/aggregate.cpp +++ b/src/test/pq/aggregate.cpp @@ -21,24 +21,32 @@ namespace example template<> inline constexpr bool tao::pq::is_aggregate< example::user > = true; -void run() +namespace { - const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); + void run() + { + const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); - connection->execute( "DROP TABLE IF EXISTS tao_aggregate_test" ); - connection->execute( "CREATE TABLE tao_aggregate_test ( name TEXT PRIMARY KEY, age INTEGER, planet TEXT )" ); + connection->execute( "DROP TABLE IF EXISTS tao_aggregate_test" ); + connection->execute( "CREATE TABLE tao_aggregate_test ( name TEXT PRIMARY KEY, age INTEGER, planet TEXT )" ); - { - const example::user u{ "R. Giskard Reventlov", 42, "Aurora" }; - TEST_EXECUTE( connection->execute( "INSERT INTO tao_aggregate_test VALUES ( $1, $2, $3 )", u ) ); - } + { + const example::user u{ + .name = "R. Giskard Reventlov", + .age = 42, + .planet = "Aurora" + }; + TEST_EXECUTE( connection->execute( "INSERT INTO tao_aggregate_test VALUES ( $1, $2, $3 )", u ) ); + } - for( const example::user u : connection->execute( "SELECT name, age, planet FROM tao_aggregate_test" ) ) { // NOLINT(performance-for-range-copy) - TEST_ASSERT( u.name == "R. Giskard Reventlov" ); - TEST_ASSERT( u.age == 42 ); - TEST_ASSERT( u.planet == "Aurora" ); + for( const example::user u : connection->execute( "SELECT name, age, planet FROM tao_aggregate_test" ) ) { // NOLINT(performance-for-range-copy) + TEST_ASSERT( u.name == "R. Giskard Reventlov" ); + TEST_ASSERT( u.age == 42 ); + TEST_ASSERT( u.planet == "Aurora" ); + } } -} + +} // namespace auto main() -> int // NOLINT(bugprone-exception-escape) { @@ -47,11 +55,11 @@ auto main() -> int // NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/array.cpp b/src/test/pq/array.cpp index 81b395e..b74c3e8 100644 --- a/src/test/pq/array.cpp +++ b/src/test/pq/array.cpp @@ -7,103 +7,107 @@ #include -void run() +namespace { - // overwrite the default with an environment variable if needed - const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); - const auto connection = tao::pq::connection::create( connection_string ); - - { - connection->execute( "DROP TABLE IF EXISTS tao_array_test" ); - connection->execute( "CREATE TABLE tao_array_test ( a INTEGER[] )" ); - - std::array< int, 4 > v{ 1, 0, 2, 4 }; - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v ); - - std::vector< int > v2 = { 42, 1701 }; - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v2 ); - - v2.clear(); - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v2 ); - - const auto r = connection->execute( "SELECT * FROM tao_array_test" ).vector< std::vector< int > >(); - TEST_ASSERT( r.size() == 3 ); - TEST_ASSERT( r[ 0 ].size() == 4 ); - TEST_ASSERT( r[ 0 ][ 0 ] == 1 ); - TEST_ASSERT( r[ 0 ][ 1 ] == 0 ); - TEST_ASSERT( r[ 0 ][ 2 ] == 2 ); - TEST_ASSERT( r[ 0 ][ 3 ] == 4 ); - TEST_ASSERT( r[ 1 ].size() == 2 ); - TEST_ASSERT( r[ 1 ][ 0 ] == 42 ); - TEST_ASSERT( r[ 1 ][ 1 ] == 1701 ); - TEST_ASSERT( r[ 2 ].empty() ); - } - - { - connection->execute( "DROP TABLE IF EXISTS tao_array_test" ); - connection->execute( "CREATE TABLE tao_array_test ( a TEXT[] )" ); - - std::vector< std::optional< std::string > > v = { "FOO", "", "{BAR\\BAZ\"B,L;A}", "NULL", std::nullopt }; - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v ); - - const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< std::vector< std::optional< std::string > > >(); - TEST_ASSERT( r.size() == 5 ); - TEST_ASSERT( *r[ 0 ] == "FOO" ); - TEST_ASSERT( r[ 1 ]->empty() ); - TEST_ASSERT( *r[ 2 ] == "{BAR\\BAZ\"B,L;A}" ); - TEST_ASSERT( *r[ 3 ] == "NULL" ); - TEST_ASSERT( !r[ 4 ] ); - } - - { - connection->execute( "DROP TABLE IF EXISTS tao_array_test" ); - connection->execute( "CREATE TABLE tao_array_test ( a TEXT[][] NOT NULL )" ); - - std::vector< std::vector< std::string > > v = { { "1", "F\"O\\O", "NULL" }, { "4", " XYZ ", "6" } }; - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v ); - - const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< std::vector< std::vector< std::string > > >(); - TEST_ASSERT( r == v ); - } - + void run() { - connection->execute( "DROP TABLE IF EXISTS tao_array_test" ); - connection->execute( "CREATE TABLE tao_array_test ( a BYTEA[][] NOT NULL )" ); - - std::vector< tao::pq::binary > v = { tao::pq::to_binary( "1" ), - tao::pq::binary(), - tao::pq::to_binary( "F\"O\\O" ), - tao::pq::to_binary( "NU\0LL" ) }; - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v ); - - const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< std::vector< tao::pq::binary > >(); - // TEST_ASSERT( r == v ); + // overwrite the default with an environment variable if needed + const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); + const auto connection = tao::pq::connection::create( connection_string ); + + { + connection->execute( "DROP TABLE IF EXISTS tao_array_test" ); + connection->execute( "CREATE TABLE tao_array_test ( a INTEGER[] )" ); + + const std::array v{ 1, 0, 2, 4 }; + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v ); + + std::vector v2 = { 42, 1701 }; + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v2 ); + + v2.clear(); + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v2 ); + + const auto r = connection->execute( "SELECT * FROM tao_array_test" ).vector< std::vector< int > >(); + TEST_ASSERT( r.size() == 3 ); + TEST_ASSERT( r[ 0 ].size() == 4 ); + TEST_ASSERT( r[ 0 ][ 0 ] == 1 ); + TEST_ASSERT( r[ 0 ][ 1 ] == 0 ); + TEST_ASSERT( r[ 0 ][ 2 ] == 2 ); + TEST_ASSERT( r[ 0 ][ 3 ] == 4 ); + TEST_ASSERT( r[ 1 ].size() == 2 ); + TEST_ASSERT( r[ 1 ][ 0 ] == 42 ); + TEST_ASSERT( r[ 1 ][ 1 ] == 1701 ); + TEST_ASSERT( r[ 2 ].empty() ); + } + + { + connection->execute( "DROP TABLE IF EXISTS tao_array_test" ); + connection->execute( "CREATE TABLE tao_array_test ( a TEXT[] )" ); + + const std::vector< std::optional< std::string > > v = { "FOO", "", "{BAR\\BAZ\"B,L;A}", "NULL", std::nullopt }; + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v ); + + const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< std::vector< std::optional< std::string > > >(); + TEST_ASSERT( r.size() == 5 ); + TEST_ASSERT( r[ 0 ] == "FOO" ); + TEST_ASSERT( r[ 1 ]->empty() ); // NOLINT(bugprone-unchecked-optional-access) + TEST_ASSERT( r[ 2 ] == "{BAR\\BAZ\"B,L;A}" ); + TEST_ASSERT( r[ 3 ] == "NULL" ); + TEST_ASSERT( !r[ 4 ] ); + } + + { + connection->execute( "DROP TABLE IF EXISTS tao_array_test" ); + connection->execute( "CREATE TABLE tao_array_test ( a TEXT[][] NOT NULL )" ); + + const std::vector< std::vector< std::string > > v = { { "1", "F\"O\\O", "NULL" }, { "4", " XYZ ", "6" } }; + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v ); + + const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< std::vector< std::vector< std::string > > >(); + TEST_ASSERT( r == v ); + } + + { + connection->execute( "DROP TABLE IF EXISTS tao_array_test" ); + connection->execute( "CREATE TABLE tao_array_test ( a BYTEA[][] NOT NULL )" ); + + const std::vector< tao::pq::binary > v = { tao::pq::to_binary( "1" ), + tao::pq::binary(), + tao::pq::to_binary( "F\"O\\O" ), + tao::pq::to_binary( "NU\0LL" ) }; + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v ); + + const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< std::vector< tao::pq::binary > >(); + // TEST_ASSERT( r == v ); + } + + TEST_THROWS( connection->execute( "SELECT $1", "" ).as< std::vector< std::string > >() ); + TEST_THROWS( connection->execute( "SELECT $1", "{" ).as< std::vector< std::string > >() ); + TEST_THROWS( connection->execute( "SELECT $1", "{FOO" ).as< std::vector< std::string > >() ); + TEST_THROWS( connection->execute( "SELECT $1", "{NULL}" ).as< std::vector< std::string > >() ); + TEST_THROWS( connection->execute( "SELECT $1", "{\"FOO}" ).as< std::vector< std::string > >() ); + TEST_THROWS( connection->execute( "SELECT $1", "{FOO}BAR" ).as< std::vector< std::string > >() ); + + { + connection->execute( "DROP TABLE IF EXISTS tao_array_test" ); + connection->execute( "CREATE TABLE tao_array_test ( a INTEGER NOT NULL )" ); + + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 1 ); + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 2 ); + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 3 ); + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 4 ); + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 5 ); + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 6 ); + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 7 ); + connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 8 ); + + const auto result = connection->execute( "SELECT * FROM tao_array_test WHERE a = ANY( $1 )", std::array{ 2, 3, 5, 6, 9 } ); + TEST_ASSERT( result.vector< int >() == std::vector< int >{ 2, 3, 5, 6 } ); + } } - TEST_THROWS( connection->execute( "SELECT $1", "" ).as< std::vector< std::string > >() ); - TEST_THROWS( connection->execute( "SELECT $1", "{" ).as< std::vector< std::string > >() ); - TEST_THROWS( connection->execute( "SELECT $1", "{FOO" ).as< std::vector< std::string > >() ); - TEST_THROWS( connection->execute( "SELECT $1", "{NULL}" ).as< std::vector< std::string > >() ); - TEST_THROWS( connection->execute( "SELECT $1", "{\"FOO}" ).as< std::vector< std::string > >() ); - TEST_THROWS( connection->execute( "SELECT $1", "{FOO}BAR" ).as< std::vector< std::string > >() ); - - { - connection->execute( "DROP TABLE IF EXISTS tao_array_test" ); - connection->execute( "CREATE TABLE tao_array_test ( a INTEGER NOT NULL )" ); - - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 1 ); - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 2 ); - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 3 ); - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 4 ); - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 5 ); - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 6 ); - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 7 ); - connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", 8 ); - - const auto result = connection->execute( "SELECT * FROM tao_array_test WHERE a = ANY( $1 )", std::array{ 2, 3, 5, 6, 9 } ); - TEST_ASSERT( result.vector< int >() == std::vector< int >{ 2, 3, 5, 6 } ); - } -} +} // namespace auto main() -> int // NOLINT(bugprone-exception-escape) { @@ -112,11 +116,11 @@ auto main() -> int // NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/basic_datatypes.cpp b/src/test/pq/basic_datatypes.cpp index 44ed48a..b3cb0f7 100644 --- a/src/test/pq/basic_datatypes.cpp +++ b/src/test/pq/basic_datatypes.cpp @@ -15,372 +15,375 @@ #include #include -std::shared_ptr< tao::pq::connection > my_connection; - -auto prepare_datatype( const std::string& datatype ) -> bool +namespace { - static std::string last; - if( datatype == last ) { - return false; - } - last = datatype; - my_connection->execute( "DROP TABLE IF EXISTS tao_basic_datatypes_test" ); - my_connection->execute( "CREATE TABLE tao_basic_datatypes_test ( a " + datatype + " )" ); - return true; -} + std::shared_ptr< tao::pq::connection > my_connection; -void check_null( const std::string& datatype ) -{ - std::cout << "check null: " << datatype << std::endl; - if( prepare_datatype( datatype ) ) { - TEST_ASSERT( my_connection->execute( "INSERT INTO tao_basic_datatypes_test VALUES ( $1 )", tao::pq::null ).rows_affected() == 1 ); + auto prepare_datatype( const std::string& datatype ) -> bool + { + static std::string last; + if( datatype == last ) { + return false; + } + last = datatype; + my_connection->execute( "DROP TABLE IF EXISTS tao_basic_datatypes_test" ); + my_connection->execute( "CREATE TABLE tao_basic_datatypes_test ( a " + datatype + " )" ); + return true; } - else { - TEST_ASSERT( my_connection->execute( "UPDATE tao_basic_datatypes_test SET a=$1", tao::pq::null ).rows_affected() == 1 ); + + void check_null( const std::string& datatype ) + { + std::cout << "check null: " << datatype << '\n'; + if( prepare_datatype( datatype ) ) { + TEST_ASSERT( my_connection->execute( "INSERT INTO tao_basic_datatypes_test VALUES ( $1 )", tao::pq::null ).rows_affected() == 1 ); + } + else { + TEST_ASSERT( my_connection->execute( "UPDATE tao_basic_datatypes_test SET a=$1", tao::pq::null ).rows_affected() == 1 ); + } + const auto result = my_connection->execute( "SELECT * FROM tao_basic_datatypes_test" ); + TEST_ASSERT( result[ 0 ][ 0 ].is_null() ); } - const auto result = my_connection->execute( "SELECT * FROM tao_basic_datatypes_test" ); - TEST_ASSERT( result[ 0 ][ 0 ].is_null() ); -} -template< typename T > -void check( const std::string& datatype, const T& value ) -{ - std::cout << "check: " << datatype << " value: " << value << std::endl; - TEST_ASSERT( !prepare_datatype( datatype ) ); - TEST_ASSERT( my_connection->execute( "UPDATE tao_basic_datatypes_test SET a=$1", value ).rows_affected() == 1 ); + template< typename T > + void check( const std::string& datatype, const T& value ) + { + std::cout << "check: " << datatype << " value: " << value << '\n'; + TEST_ASSERT( !prepare_datatype( datatype ) ); + TEST_ASSERT( my_connection->execute( "UPDATE tao_basic_datatypes_test SET a=$1", value ).rows_affected() == 1 ); - const auto result = my_connection->execute( "SELECT * FROM tao_basic_datatypes_test" ); - if( value == value ) { // NOLINT(misc-redundant-expression) - if( result[ 0 ][ 0 ].as< T >() != value ) { - // LCOV_EXCL_START - std::cout << "check: " << datatype << " value: " << value << " result: " << result.get( 0, 0 ) << " FAILED!" << std::endl; - TEST_ASSERT( false ); - // LCOV_EXCL_STOP + const auto result = my_connection->execute( "SELECT * FROM tao_basic_datatypes_test" ); + if( value == value ) { // NOLINT(misc-redundant-expression) + if( result[ 0 ][ 0 ].as< T >() != value ) { + // LCOV_EXCL_START + std::cout << "check: " << datatype << " value: " << value << " result: " << result.get( 0, 0 ) << " FAILED!\n"; + TEST_ASSERT( false ); + // LCOV_EXCL_STOP + } } - } - else { - const auto v = result[ 0 ][ 0 ].as< T >(); - if( v == v ) { // NOLINT(misc-redundant-expression) - // LCOV_EXCL_START - std::cout << "check: " << datatype << " value: NaN result: " << result.get( 0, 0 ) << " FAILED!" << std::endl; - TEST_ASSERT( false ); - // LCOV_EXCL_STOP + else { + const auto v = result[ 0 ][ 0 ].as< T >(); + if( v == v ) { // NOLINT(misc-redundant-expression) + // LCOV_EXCL_START + std::cout << "check: " << datatype << " value: NaN result: " << result.get( 0, 0 ) << " FAILED!\n"; + TEST_ASSERT( false ); + // LCOV_EXCL_STOP + } } } -} -template< typename T > -auto check( const std::string& datatype ) - -> std::enable_if_t< std::is_signed_v< T > > -{ - check_null( datatype ); - check< T >( datatype, std::numeric_limits< T >::min() ); - check_null( datatype ); - check< T >( datatype, -42 ); - check< T >( datatype, -1 ); - check< T >( datatype, 0 ); - check< T >( datatype, 1 ); - check< T >( datatype, 42 ); - check< T >( datatype, std::numeric_limits< T >::max() ); -} + template< typename T > + requires std::is_signed_v< T > + auto check( const std::string& datatype ) + { + check_null( datatype ); + check< T >( datatype, std::numeric_limits< T >::min() ); + check_null( datatype ); + check< T >( datatype, -42 ); + check< T >( datatype, -1 ); + check< T >( datatype, 0 ); + check< T >( datatype, 1 ); + check< T >( datatype, 42 ); + check< T >( datatype, std::numeric_limits< T >::max() ); + } -template< typename T > -auto check( const std::string& datatype ) - -> std::enable_if_t< std::is_unsigned_v< T > > -{ - check_null( datatype ); - check< T >( datatype, 0 ); - check_null( datatype ); - check< T >( datatype, 1 ); - check< T >( datatype, 42 ); - check< T >( datatype, std::numeric_limits< T >::max() ); -} + template< typename T > + requires std::is_unsigned_v< T > + auto check( const std::string& datatype ) + { + check_null( datatype ); + check< T >( datatype, 0 ); + check_null( datatype ); + check< T >( datatype, 1 ); + check< T >( datatype, 42 ); + check< T >( datatype, std::numeric_limits< T >::max() ); + } -template< typename T > -void check_bytea( const T& t ) -{ - TEST_ASSERT( my_connection->execute( "UPDATE tao_basic_datatypes_test SET a=$1", t ).rows_affected() == 1 ); + void check_bytea( const auto& t ) + { + TEST_ASSERT( my_connection->execute( "UPDATE tao_basic_datatypes_test SET a=$1", t ).rows_affected() == 1 ); - const auto result = my_connection->execute( "SELECT * FROM tao_basic_datatypes_test" )[ 0 ][ 0 ].as< tao::pq::binary >(); - TEST_ASSERT( tao::pq::internal::compare( result, t ) ); -} + const auto result = my_connection->execute( "SELECT * FROM tao_basic_datatypes_test" )[ 0 ][ 0 ].as< tao::pq::binary >(); + TEST_ASSERT( tao::pq::internal::compare( result, t ) ); + } -void run() -{ - my_connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); - my_connection->set_timeout( std::chrono::seconds( 1 ) ); + void run() + { + my_connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); + my_connection->set_timeout( std::chrono::seconds( 1 ) ); - check_null( "BOOLEAN" ); - check< bool >( "BOOLEAN", true ); - check_null( "BOOLEAN" ); - check< bool >( "BOOLEAN", false ); + check_null( "BOOLEAN" ); + check< bool >( "BOOLEAN", true ); + check_null( "BOOLEAN" ); + check< bool >( "BOOLEAN", false ); - // single characters in PostgreSQL are stored in a column of type "char", note the quotes are part of the type's name! - check_null( "\"char\"" ); - check< char >( "\"char\"", 'a' ); - check_null( "\"char\"" ); - check< char >( "\"char\"", 'z' ); - check< char >( "\"char\"", 'A' ); - check< char >( "\"char\"", 'Z' ); - check< char >( "\"char\"", '0' ); - check< char >( "\"char\"", '9' ); - check< char >( "\"char\"", '$' ); - check< char >( "\"char\"", '%' ); - check< char >( "\"char\"", ' ' ); - check< char >( "\"char\"", '"' ); - check< char >( "\"char\"", '\'' ); - check< char >( "\"char\"", '\\' ); - check< char >( "\"char\"", '\n' ); - check< char >( "\"char\"", '\t' ); + // single characters in PostgreSQL are stored in a column of type "char", note the quotes are part of the type's name! + check_null( "\"char\"" ); + check< char >( "\"char\"", 'a' ); + check_null( "\"char\"" ); + check< char >( "\"char\"", 'z' ); + check< char >( "\"char\"", 'A' ); + check< char >( "\"char\"", 'Z' ); + check< char >( "\"char\"", '0' ); + check< char >( "\"char\"", '9' ); + check< char >( "\"char\"", '$' ); + check< char >( "\"char\"", '%' ); + check< char >( "\"char\"", ' ' ); + check< char >( "\"char\"", '"' ); + check< char >( "\"char\"", '\'' ); + check< char >( "\"char\"", '\\' ); + check< char >( "\"char\"", '\n' ); + check< char >( "\"char\"", '\t' ); - check< signed char >( "NUMERIC" ); - check< unsigned char >( "NUMERIC" ); - check< short >( "NUMERIC" ); - check< unsigned short >( "NUMERIC" ); - check< int >( "NUMERIC" ); - check< unsigned >( "NUMERIC" ); - check< long >( "NUMERIC" ); - check< unsigned long >( "NUMERIC" ); - check< long long >( "NUMERIC" ); - check< unsigned long long >( "NUMERIC" ); + check< signed char >( "NUMERIC" ); + check< unsigned char >( "NUMERIC" ); + check< short >( "NUMERIC" ); + check< unsigned short >( "NUMERIC" ); + check< int >( "NUMERIC" ); + check< unsigned >( "NUMERIC" ); + check< long >( "NUMERIC" ); + check< unsigned long >( "NUMERIC" ); + check< long long >( "NUMERIC" ); + check< unsigned long long >( "NUMERIC" ); - // this allows precise floating point values - my_connection->execute( "SET extra_float_digits=3" ); + // this allows precise floating point values + my_connection->execute( "SET extra_float_digits=3" ); - check_null( "REAL" ); - check< float >( "REAL", std::numeric_limits< float >::lowest() ); - check_null( "REAL" ); - check< float >( "REAL", -1e37F ); - check< float >( "REAL", -1.25F ); - check< float >( "REAL", -1.F ); - check< float >( "REAL", -0.25F ); - check< float >( "REAL", -1e-37F ); - check< float >( "REAL", 0.F ); - check< float >( "REAL", std::numeric_limits< float >::min() ); - check< float >( "REAL", 1e-37F ); - { - float value = 0.123456F; - for( int i = 0; i < 32; ++i ) { - check< float >( "REAL", value ); - value = std::nextafterf( value, 1 ); + check_null( "REAL" ); + check< float >( "REAL", std::numeric_limits< float >::lowest() ); + check_null( "REAL" ); + check< float >( "REAL", -1e37F ); + check< float >( "REAL", -1.25F ); + check< float >( "REAL", -1.F ); + check< float >( "REAL", -0.25F ); + check< float >( "REAL", -1e-37F ); + check< float >( "REAL", 0.F ); + check< float >( "REAL", std::numeric_limits< float >::min() ); + check< float >( "REAL", 1e-37F ); + { + float value = 0.123456F; + for( int i = 0; i < 32; ++i ) { + check< float >( "REAL", value ); + value = std::nextafterf( value, 1 ); + } } - } - check< float >( "REAL", 0.25F ); - check< float >( "REAL", 1.F ); - check< float >( "REAL", 1.F + std::numeric_limits< float >::epsilon() ); - check< float >( "REAL", 1.25F ); - check< float >( "REAL", 1e37F ); - check< float >( "REAL", std::numeric_limits< float >::max() ); - check< float >( "REAL", INFINITY ); - check< float >( "REAL", -INFINITY ); - check< float >( "REAL", NAN ); + check< float >( "REAL", 0.25F ); + check< float >( "REAL", 1.F ); + check< float >( "REAL", 1.F + std::numeric_limits< float >::epsilon() ); + check< float >( "REAL", 1.25F ); + check< float >( "REAL", 1e37F ); + check< float >( "REAL", std::numeric_limits< float >::max() ); + check< float >( "REAL", INFINITY ); + check< float >( "REAL", -INFINITY ); + check< float >( "REAL", NAN ); - check_null( "DOUBLE PRECISION" ); - check< double >( "DOUBLE PRECISION", std::numeric_limits< double >::lowest() ); - check_null( "DOUBLE PRECISION" ); - check< double >( "DOUBLE PRECISION", -1e308 ); - check< double >( "DOUBLE PRECISION", -1.25 ); - check< double >( "DOUBLE PRECISION", -1 ); - check< double >( "DOUBLE PRECISION", -0.25 ); - check< double >( "DOUBLE PRECISION", -1e-307 ); - check< double >( "DOUBLE PRECISION", 0 ); - check< double >( "DOUBLE PRECISION", std::numeric_limits< double >::min() ); - check< double >( "DOUBLE PRECISION", 1e-307 ); - { - double value = 0.123456789012345; - for( int i = 0; i < 32; ++i ) { - check< double >( "DOUBLE PRECISION", value ); - value = std::nextafter( value, 1 ); + check_null( "DOUBLE PRECISION" ); + check< double >( "DOUBLE PRECISION", std::numeric_limits< double >::lowest() ); + check_null( "DOUBLE PRECISION" ); + check< double >( "DOUBLE PRECISION", -1e308 ); + check< double >( "DOUBLE PRECISION", -1.25 ); + check< double >( "DOUBLE PRECISION", -1 ); + check< double >( "DOUBLE PRECISION", -0.25 ); + check< double >( "DOUBLE PRECISION", -1e-307 ); + check< double >( "DOUBLE PRECISION", 0 ); + check< double >( "DOUBLE PRECISION", std::numeric_limits< double >::min() ); + check< double >( "DOUBLE PRECISION", 1e-307 ); + { + double value = 0.123456789012345; + for( int i = 0; i < 32; ++i ) { + check< double >( "DOUBLE PRECISION", value ); + value = std::nextafter( value, 1 ); + } } - } - check< double >( "DOUBLE PRECISION", 0.25 ); - check< double >( "DOUBLE PRECISION", 1 ); - check< double >( "DOUBLE PRECISION", 1 + std::numeric_limits< double >::epsilon() ); - check< double >( "DOUBLE PRECISION", 1.25 ); - check< double >( "DOUBLE PRECISION", 1e308 ); - check< double >( "DOUBLE PRECISION", std::numeric_limits< double >::max() ); - check< double >( "DOUBLE PRECISION", INFINITY ); - check< double >( "DOUBLE PRECISION", -INFINITY ); // NOLINT(bugprone-narrowing-conversions) - check< double >( "DOUBLE PRECISION", NAN ); + check< double >( "DOUBLE PRECISION", 0.25 ); + check< double >( "DOUBLE PRECISION", 1 ); + check< double >( "DOUBLE PRECISION", 1 + std::numeric_limits< double >::epsilon() ); + check< double >( "DOUBLE PRECISION", 1.25 ); + check< double >( "DOUBLE PRECISION", 1e308 ); + check< double >( "DOUBLE PRECISION", std::numeric_limits< double >::max() ); + check< double >( "DOUBLE PRECISION", INFINITY ); + check< double >( "DOUBLE PRECISION", -INFINITY ); // NOLINT(bugprone-narrowing-conversions) + check< double >( "DOUBLE PRECISION", NAN ); - check_null( "NUMERIC" ); - check< float >( "NUMERIC", std::numeric_limits< float >::lowest() ); - check< float >( "NUMERIC", -1e37F ); - check< float >( "NUMERIC", -1.25F ); - check< float >( "NUMERIC", -1.F ); - check< float >( "NUMERIC", -0.25F ); - check< float >( "NUMERIC", -1e-37F ); - check< float >( "NUMERIC", 0.F ); - check< float >( "NUMERIC", std::numeric_limits< float >::min() ); - check< float >( "NUMERIC", 1e-37F ); - { - float value = 0.123456F; - for( int i = 0; i < 32; ++i ) { - check< float >( "NUMERIC", value ); - value = std::nextafterf( value, 1 ); + check_null( "NUMERIC" ); + check< float >( "NUMERIC", std::numeric_limits< float >::lowest() ); + check< float >( "NUMERIC", -1e37F ); + check< float >( "NUMERIC", -1.25F ); + check< float >( "NUMERIC", -1.F ); + check< float >( "NUMERIC", -0.25F ); + check< float >( "NUMERIC", -1e-37F ); + check< float >( "NUMERIC", 0.F ); + check< float >( "NUMERIC", std::numeric_limits< float >::min() ); + check< float >( "NUMERIC", 1e-37F ); + { + float value = 0.123456F; + for( int i = 0; i < 32; ++i ) { + check< float >( "NUMERIC", value ); + value = std::nextafterf( value, 1 ); + } } - } - check< float >( "NUMERIC", 0.25F ); - check< float >( "NUMERIC", 1.F ); - check< float >( "NUMERIC", 1.F + std::numeric_limits< float >::epsilon() ); - check< float >( "NUMERIC", 1.25F ); - check< float >( "NUMERIC", 1e37F ); - check< float >( "NUMERIC", std::numeric_limits< float >::max() ); - check< float >( "NUMERIC", NAN ); + check< float >( "NUMERIC", 0.25F ); + check< float >( "NUMERIC", 1.F ); + check< float >( "NUMERIC", 1.F + std::numeric_limits< float >::epsilon() ); + check< float >( "NUMERIC", 1.25F ); + check< float >( "NUMERIC", 1e37F ); + check< float >( "NUMERIC", std::numeric_limits< float >::max() ); + check< float >( "NUMERIC", NAN ); - check< double >( "NUMERIC", std::numeric_limits< double >::lowest() ); - check< double >( "NUMERIC", -1e308 ); - check< double >( "NUMERIC", -1.25 ); - check< double >( "NUMERIC", -1 ); - check< double >( "NUMERIC", -0.25 ); - check< double >( "NUMERIC", -1e-307 ); - check< double >( "NUMERIC", 0 ); - check< double >( "NUMERIC", std::numeric_limits< double >::min() ); - check< double >( "NUMERIC", 1e-307 ); - { - double value = 0.123456789012345; - for( int i = 0; i < 32; ++i ) { - check< double >( "NUMERIC", value ); - value = std::nextafter( value, 1 ); + check< double >( "NUMERIC", std::numeric_limits< double >::lowest() ); + check< double >( "NUMERIC", -1e308 ); + check< double >( "NUMERIC", -1.25 ); + check< double >( "NUMERIC", -1 ); + check< double >( "NUMERIC", -0.25 ); + check< double >( "NUMERIC", -1e-307 ); + check< double >( "NUMERIC", 0 ); + check< double >( "NUMERIC", std::numeric_limits< double >::min() ); + check< double >( "NUMERIC", 1e-307 ); + { + double value = 0.123456789012345; + for( int i = 0; i < 32; ++i ) { + check< double >( "NUMERIC", value ); + value = std::nextafter( value, 1 ); + } } - } - check< double >( "NUMERIC", 0.25 ); - check< double >( "NUMERIC", 1 ); - check< double >( "NUMERIC", 1 + std::numeric_limits< double >::epsilon() ); - check< double >( "NUMERIC", 1.25 ); - check< double >( "NUMERIC", 1e308 ); - check< double >( "NUMERIC", std::numeric_limits< double >::max() ); - check< double >( "NUMERIC", NAN ); + check< double >( "NUMERIC", 0.25 ); + check< double >( "NUMERIC", 1 ); + check< double >( "NUMERIC", 1 + std::numeric_limits< double >::epsilon() ); + check< double >( "NUMERIC", 1.25 ); + check< double >( "NUMERIC", 1e308 ); + check< double >( "NUMERIC", std::numeric_limits< double >::max() ); + check< double >( "NUMERIC", NAN ); - check< long double >( "NUMERIC", std::numeric_limits< long double >::lowest() ); - check< long double >( "NUMERIC", -1e308 ); - check< long double >( "NUMERIC", -1.25 ); - check< long double >( "NUMERIC", -1 ); - check< long double >( "NUMERIC", -0.25 ); - check< long double >( "NUMERIC", -1e-307 ); - check< long double >( "NUMERIC", 0 ); - check< long double >( "NUMERIC", std::numeric_limits< long double >::min() ); - check< long double >( "NUMERIC", 1e-307 ); - { - long double value = 0.123456789012345; - for( int i = 0; i < 32; ++i ) { - check< long double >( "NUMERIC", value ); - value = std::nextafterl( value, 1 ); + check< long double >( "NUMERIC", std::numeric_limits< long double >::lowest() ); + check< long double >( "NUMERIC", -1e308 ); + check< long double >( "NUMERIC", -1.25 ); + check< long double >( "NUMERIC", -1 ); + check< long double >( "NUMERIC", -0.25 ); + check< long double >( "NUMERIC", -1e-307 ); + check< long double >( "NUMERIC", 0 ); + check< long double >( "NUMERIC", std::numeric_limits< long double >::min() ); + check< long double >( "NUMERIC", 1e-307 ); + { + long double value = 0.123456789012345; + for( int i = 0; i < 32; ++i ) { + check< long double >( "NUMERIC", value ); + value = std::nextafterl( value, 1 ); + } } - } - check< long double >( "NUMERIC", 0.25 ); - check< long double >( "NUMERIC", 1 ); - check< long double >( "NUMERIC", 1e-307 ); - check< long double >( "NUMERIC", 1 + std::numeric_limits< long double >::epsilon() ); - check< long double >( "NUMERIC", 1.25 ); - check< long double >( "NUMERIC", 1e308 ); - check< long double >( "NUMERIC", std::numeric_limits< long double >::max() ); - check< long double >( "NUMERIC", NAN ); + check< long double >( "NUMERIC", 0.25 ); + check< long double >( "NUMERIC", 1 ); + check< long double >( "NUMERIC", 1e-307 ); + check< long double >( "NUMERIC", 1 + std::numeric_limits< long double >::epsilon() ); + check< long double >( "NUMERIC", 1.25 ); + check< long double >( "NUMERIC", 1e308 ); + check< long double >( "NUMERIC", std::numeric_limits< long double >::max() ); + check< long double >( "NUMERIC", NAN ); - check_null( "TEXT" ); - check< float >( "TEXT", std::numeric_limits< float >::lowest() ); - check_null( "TEXT" ); - check< float >( "TEXT", -1e37F ); - check< float >( "TEXT", -1.25F ); - check< float >( "TEXT", -1.F ); - check< float >( "TEXT", -0.25F ); - check< float >( "TEXT", -1e-37F ); - check< float >( "TEXT", 0.F ); - check< float >( "TEXT", std::numeric_limits< float >::min() ); - check< float >( "TEXT", 1e-37F ); - { - float value = 0.123456F; - for( int i = 0; i < 32; ++i ) { - check< float >( "TEXT", value ); - value = std::nextafterf( value, 1 ); + check_null( "TEXT" ); + check< float >( "TEXT", std::numeric_limits< float >::lowest() ); + check_null( "TEXT" ); + check< float >( "TEXT", -1e37F ); + check< float >( "TEXT", -1.25F ); + check< float >( "TEXT", -1.F ); + check< float >( "TEXT", -0.25F ); + check< float >( "TEXT", -1e-37F ); + check< float >( "TEXT", 0.F ); + check< float >( "TEXT", std::numeric_limits< float >::min() ); + check< float >( "TEXT", 1e-37F ); + { + float value = 0.123456F; + for( int i = 0; i < 32; ++i ) { + check< float >( "TEXT", value ); + value = std::nextafterf( value, 1 ); + } } - } - check< float >( "TEXT", 0.25F ); - check< float >( "TEXT", 1.F ); - check< float >( "TEXT", 1.F + std::numeric_limits< float >::epsilon() ); - check< float >( "TEXT", 1.25F ); - check< float >( "TEXT", 1e37F ); - check< float >( "TEXT", std::numeric_limits< float >::max() ); - check< float >( "TEXT", INFINITY ); - check< float >( "TEXT", -INFINITY ); - check< float >( "TEXT", NAN ); + check< float >( "TEXT", 0.25F ); + check< float >( "TEXT", 1.F ); + check< float >( "TEXT", 1.F + std::numeric_limits< float >::epsilon() ); + check< float >( "TEXT", 1.25F ); + check< float >( "TEXT", 1e37F ); + check< float >( "TEXT", std::numeric_limits< float >::max() ); + check< float >( "TEXT", INFINITY ); + check< float >( "TEXT", -INFINITY ); + check< float >( "TEXT", NAN ); - check< double >( "TEXT", std::numeric_limits< double >::lowest() ); - check< double >( "TEXT", -1e308 ); - check< double >( "TEXT", -1.25 ); - check< double >( "TEXT", -1 ); - check< double >( "TEXT", -0.25 ); - check< double >( "TEXT", -1e-307 ); - check< double >( "TEXT", 0 ); - check< double >( "TEXT", std::numeric_limits< double >::min() ); - check< double >( "TEXT", 1e-307 ); - { - double value = 0.123456789012345; - for( int i = 0; i < 32; ++i ) { - check< double >( "TEXT", value ); - value = std::nextafter( value, 1 ); + check< double >( "TEXT", std::numeric_limits< double >::lowest() ); + check< double >( "TEXT", -1e308 ); + check< double >( "TEXT", -1.25 ); + check< double >( "TEXT", -1 ); + check< double >( "TEXT", -0.25 ); + check< double >( "TEXT", -1e-307 ); + check< double >( "TEXT", 0 ); + check< double >( "TEXT", std::numeric_limits< double >::min() ); + check< double >( "TEXT", 1e-307 ); + { + double value = 0.123456789012345; + for( int i = 0; i < 32; ++i ) { + check< double >( "TEXT", value ); + value = std::nextafter( value, 1 ); + } } - } - check< double >( "TEXT", 0.25 ); - check< double >( "TEXT", 1 ); - check< double >( "TEXT", 1 + std::numeric_limits< double >::epsilon() ); - check< double >( "TEXT", 1.25 ); - check< double >( "TEXT", 1e308 ); - check< double >( "TEXT", std::numeric_limits< double >::max() ); - check< double >( "TEXT", INFINITY ); - check< double >( "TEXT", -INFINITY ); // NOLINT(bugprone-narrowing-conversions) - check< double >( "TEXT", NAN ); + check< double >( "TEXT", 0.25 ); + check< double >( "TEXT", 1 ); + check< double >( "TEXT", 1 + std::numeric_limits< double >::epsilon() ); + check< double >( "TEXT", 1.25 ); + check< double >( "TEXT", 1e308 ); + check< double >( "TEXT", std::numeric_limits< double >::max() ); + check< double >( "TEXT", INFINITY ); + check< double >( "TEXT", -INFINITY ); // NOLINT(bugprone-narrowing-conversions) + check< double >( "TEXT", NAN ); - // there is no data type to store 'long double' to PostgreSQL - but TEXT should do just fine... - check< long double >( "TEXT", std::numeric_limits< long double >::lowest() ); - check< long double >( "TEXT", -1e308 ); - check< long double >( "TEXT", -1.25 ); - check< long double >( "TEXT", -1 ); - check< long double >( "TEXT", -0.25 ); - check< long double >( "TEXT", -1e-307 ); - check< long double >( "TEXT", 0 ); - check< long double >( "TEXT", std::numeric_limits< long double >::min() ); - check< long double >( "TEXT", 1e-307 ); - { - long double value = 0.123456789012345; - for( int i = 0; i < 32; ++i ) { - check< long double >( "TEXT", value ); - value = std::nextafterl( value, 1 ); + // there is no data type to store 'long double' to PostgreSQL - but TEXT should do just fine... + check< long double >( "TEXT", std::numeric_limits< long double >::lowest() ); + check< long double >( "TEXT", -1e308 ); + check< long double >( "TEXT", -1.25 ); + check< long double >( "TEXT", -1 ); + check< long double >( "TEXT", -0.25 ); + check< long double >( "TEXT", -1e-307 ); + check< long double >( "TEXT", 0 ); + check< long double >( "TEXT", std::numeric_limits< long double >::min() ); + check< long double >( "TEXT", 1e-307 ); + { + long double value = 0.123456789012345; + for( int i = 0; i < 32; ++i ) { + check< long double >( "TEXT", value ); + value = std::nextafterl( value, 1 ); + } } - } - check< long double >( "TEXT", 0.25 ); - check< long double >( "TEXT", 1 ); - check< long double >( "TEXT", 1e-307 ); - check< long double >( "TEXT", 1 + std::numeric_limits< long double >::epsilon() ); - check< long double >( "TEXT", 1.25 ); - check< long double >( "TEXT", 1e308 ); - check< long double >( "TEXT", std::numeric_limits< long double >::max() ); - check< long double >( "TEXT", INFINITY ); - check< long double >( "TEXT", -INFINITY ); // NOLINT(bugprone-narrowing-conversions) - check< long double >( "TEXT", NAN ); + check< long double >( "TEXT", 0.25 ); + check< long double >( "TEXT", 1 ); + check< long double >( "TEXT", 1e-307 ); + check< long double >( "TEXT", 1 + std::numeric_limits< long double >::epsilon() ); + check< long double >( "TEXT", 1.25 ); + check< long double >( "TEXT", 1e308 ); + check< long double >( "TEXT", std::numeric_limits< long double >::max() ); + check< long double >( "TEXT", INFINITY ); + check< long double >( "TEXT", -INFINITY ); // NOLINT(bugprone-narrowing-conversions) + check< long double >( "TEXT", NAN ); - check< std::string >( "TEXT", "" ); - check< std::string >( "TEXT", " " ); - check< std::string >( "TEXT", "abc" ); - check< std::string >( "TEXT", "Hello, world!" ); - check< std::string >( "TEXT", ";" ); - check< std::string >( "TEXT", "\\" ); - check< std::string >( "TEXT", "\"" ); - check< std::string >( "TEXT", "'" ); - check< std::string >( "TEXT", "'; DROP TABLE users; --" ); - check< std::string >( "TEXT", "ä" ); - check< std::string >( "TEXT", "€" ); - check< std::string >( "TEXT", "𝄞" ); - check< std::string >( "TEXT", "äöüÄÖÜ߀𝄞" ); - check< std::string >( "TEXT", "ä\tö\nü\1Ä\"Ö;Ü'ß#€𝄞" ); + check< std::string >( "TEXT", "" ); + check< std::string >( "TEXT", " " ); + check< std::string >( "TEXT", "abc" ); + check< std::string >( "TEXT", "Hello, world!" ); + check< std::string >( "TEXT", ";" ); + check< std::string >( "TEXT", "\\" ); + check< std::string >( "TEXT", "\"" ); + check< std::string >( "TEXT", "'" ); + check< std::string >( "TEXT", "'; DROP TABLE users; --" ); + check< std::string >( "TEXT", "ä" ); + check< std::string >( "TEXT", "€" ); + check< std::string >( "TEXT", "𝄞" ); + check< std::string >( "TEXT", "äöüÄÖÜ߀𝄞" ); + check< std::string >( "TEXT", "ä\tö\nü\1Ä\"Ö;Ü'ß#€𝄞" ); - check_null( "BYTEA" ); + check_null( "BYTEA" ); - const unsigned char bdata[] = { 'v', 255, 0, 'a', 1, 'b', 0 }; + const unsigned char bdata[] = { 'v', 255, 0, 'a', 1, 'b', 0 }; - check_bytea( tao::pq::to_binary( bdata ) ); - check_bytea( tao::pq::to_binary_view( bdata ) ); -} + check_bytea( tao::pq::to_binary( bdata ) ); + check_bytea( tao::pq::to_binary_view( bdata ) ); + } + +} // namespace auto main() -> int { @@ -389,11 +392,11 @@ auto main() -> int } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/connection.cpp b/src/test/pq/connection.cpp index 5f98ceb..2af6531 100644 --- a/src/test/pq/connection.cpp +++ b/src/test/pq/connection.cpp @@ -9,139 +9,143 @@ #include -// LCOV_EXCL_START -auto my_poll( const int /*unused*/, const bool /*unused*/, const int /*unused*/ ) -> tao::pq::poll::status +namespace { - TAO_PQ_UNREACHABLE; -} -// LCOV_EXCL_STOP + // LCOV_EXCL_START + auto my_poll( const int /*unused*/, const bool /*unused*/, const int /*unused*/ ) -> tao::pq::poll::status + { + TAO_PQ_UNREACHABLE; + } + // LCOV_EXCL_STOP -void run() -{ - using namespace std::chrono_literals; + void run() + { + using namespace std::chrono_literals; - // overwrite the default with an environment variable if needed - const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); // NOLINT(clang-analyzer-deadcode.DeadStores) + // overwrite the default with an environment variable if needed + const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); // NOLINT(clang-analyzer-deadcode.DeadStores) - // connection_string must be valid - TEST_THROWS( tao::pq::connection::create( "=" ) ); + // connection_string must be valid + TEST_THROWS( tao::pq::connection::create( "=" ) ); - // connection_string must reference an existing and accessible database - TEST_THROWS( tao::pq::connection::create( "dbname=DOES_NOT_EXIST" ) ); + // connection_string must reference an existing and accessible database + TEST_THROWS( tao::pq::connection::create( "dbname=DOES_NOT_EXIST" ) ); - // open a connection - const auto connection = tao::pq::connection::create( connection_string ); - connection->set_timeout( 1s ); + // open a connection + const auto connection = tao::pq::connection::create( connection_string ); + connection->set_timeout( 1s ); - // open a second, independent connection (and discard it immediately) - std::ignore = tao::pq::connection::create( connection_string ); + // open a second, independent connection (and discard it immediately) + std::ignore = tao::pq::connection::create( connection_string ); - // execute an SQL statement - connection->execute( "DROP TABLE IF EXISTS tao_connection_test" ); + // execute an SQL statement + connection->execute( "DROP TABLE IF EXISTS tao_connection_test" ); - // execution of empty statements fails - TEST_THROWS( connection->execute( "" ) ); + // execution of empty statements fails + TEST_THROWS( connection->execute( "" ) ); - // execution of invalid statements fails - TEST_THROWS( connection->execute( "FOO BAR BAZ" ) ); + // execution of invalid statements fails + TEST_THROWS( connection->execute( "FOO BAR BAZ" ) ); - // a prepared statement's name must be a valid C++ identifier - TEST_THROWS( connection->prepare( "", "DROP TABLE IF EXISTS tao_connection_test" ) ); - TEST_THROWS( connection->prepare( "0drop_table", "DROP TABLE IF EXISTS tao_connection_test" ) ); - TEST_THROWS( connection->prepare( "drop table", "DROP TABLE IF EXISTS tao_connection_test" ) ); + // a prepared statement's name must be a valid C++ identifier + TEST_THROWS( connection->prepare( "", "DROP TABLE IF EXISTS tao_connection_test" ) ); + TEST_THROWS( connection->prepare( "0drop_table", "DROP TABLE IF EXISTS tao_connection_test" ) ); + TEST_THROWS( connection->prepare( "drop table", "DROP TABLE IF EXISTS tao_connection_test" ) ); - // prepare a statement - connection->prepare( "drop_table", "DROP TABLE IF EXISTS tao_connection_test" ); + // prepare a statement + connection->prepare( "drop_table", "DROP TABLE IF EXISTS tao_connection_test" ); - // execute a prepared statement - // - // note: the name of a prepared statement must be a valid identifier, all - // actual SQL statements can be writen in a form which does not match a valid - // identifier, so you can always make sure that they can not be confused. - connection->execute( "drop_table" ); + // execute a prepared statement + // + // note: the name of a prepared statement must be a valid identifier, all + // actual SQL statements can be writen in a form which does not match a valid + // identifier, so you can always make sure that they can not be confused. + connection->execute( "drop_table" ); - // a statement which is not a query does not return "affected rows" - TEST_THROWS( connection->execute( "drop_table" ).rows_affected() ); + // a statement which is not a query does not return "affected rows" + TEST_THROWS( connection->execute( "drop_table" ).rows_affected() ); - // deallocate a prepared statement - connection->deallocate( "drop_table" ); + // deallocate a prepared statement + connection->deallocate( "drop_table" ); - // no longer possible - TEST_THROWS( connection->execute( "drop_table" ) ); + // no longer possible + TEST_THROWS( connection->execute( "drop_table" ) ); - // deallocate must refer to a prepared statement - TEST_THROWS( connection->deallocate( "drop_table" ) ); + // deallocate must refer to a prepared statement + TEST_THROWS( connection->deallocate( "drop_table" ) ); - // deallocate must get a valid name - TEST_THROWS( connection->deallocate( "FOO BAR" ) ); + // deallocate must get a valid name + TEST_THROWS( connection->deallocate( "FOO BAR" ) ); - // test that prepared statement names are case sensitive - connection->prepare( "a", "SELECT 1" ); - connection->prepare( "A", "SELECT 2" ); + // test that prepared statement names are case sensitive + connection->prepare( "a", "SELECT 1" ); + connection->prepare( "A", "SELECT 2" ); - TEST_THROWS( connection->prepare( "a", "SELECT 2" ) ); + TEST_THROWS( connection->prepare( "a", "SELECT 2" ) ); - TEST_ASSERT_MESSAGE( "checking prepared statement 'a'", connection->execute( "a" ).as< int >() == 1 ); + TEST_ASSERT_MESSAGE( "checking prepared statement 'a'", connection->execute( "a" ).as< int >() == 1 ); - connection->deallocate( "a" ); + connection->deallocate( "a" ); - TEST_ASSERT_MESSAGE( "checking prepared statement 'A'", connection->execute( "A" ).as< int >() == 2 ); + TEST_ASSERT_MESSAGE( "checking prepared statement 'A'", connection->execute( "A" ).as< int >() == 2 ); - connection->prepare( "a", "SELECT 3" ); + connection->prepare( "a", "SELECT 3" ); - TEST_ASSERT_MESSAGE( "checking prepared statement 'a'", connection->execute( "a" ).as< int >() == 3 ); - TEST_ASSERT_MESSAGE( "checking prepared statement 'A'", connection->execute( "A" ).as< int >() == 2 ); + TEST_ASSERT_MESSAGE( "checking prepared statement 'a'", connection->execute( "a" ).as< int >() == 3 ); + TEST_ASSERT_MESSAGE( "checking prepared statement 'A'", connection->execute( "A" ).as< int >() == 2 ); - connection->deallocate( "A" ); + connection->deallocate( "A" ); - TEST_ASSERT_MESSAGE( "checking prepared statement 'a'", connection->execute( "a" ).as< int >() == 3 ); + TEST_ASSERT_MESSAGE( "checking prepared statement 'a'", connection->execute( "a" ).as< int >() == 3 ); - connection->prepare( "A", "SELECT 4" ); + connection->prepare( "A", "SELECT 4" ); - TEST_ASSERT_MESSAGE( "checking prepared statement 'a'", connection->execute( "a" ).as< int >() == 3 ); - TEST_ASSERT_MESSAGE( "checking prepared statement 'A'", connection->execute( "A" ).as< int >() == 4 ); + TEST_ASSERT_MESSAGE( "checking prepared statement 'a'", connection->execute( "a" ).as< int >() == 3 ); + TEST_ASSERT_MESSAGE( "checking prepared statement 'A'", connection->execute( "A" ).as< int >() == 4 ); - // create a test table - connection->execute( "CREATE TABLE tao_connection_test ( a INTEGER PRIMARY KEY, b INTEGER )" ); + // create a test table + connection->execute( "CREATE TABLE tao_connection_test ( a INTEGER PRIMARY KEY, b INTEGER )" ); - // a DELETE statement does not yield a result set - TEST_THROWS( connection->execute( "DELETE FROM tao_connection_test" ).empty() ); + // a DELETE statement does not yield a result set + TEST_THROWS( connection->execute( "DELETE FROM tao_connection_test" ).empty() ); - // out of range access throws - TEST_THROWS( connection->execute( "SELECT * FROM tao_connection_test" ).at( 0 ) ); + // out of range access throws + TEST_THROWS( connection->execute( "SELECT * FROM tao_connection_test" ).at( 0 ) ); - // insert some data - connection->execute( "INSERT INTO tao_connection_test VALUES ( 1, 42 )" ); + // insert some data + connection->execute( "INSERT INTO tao_connection_test VALUES ( 1, 42 )" ); - TEST_THROWS( connection->execute( "COPY tao_connection_test ( a, b ) TO STDOUT" ) ); - TEST_THROWS( connection->execute( "COPY tao_connection_test ( a, b ) FROM STDIN" ) ); + TEST_THROWS( connection->execute( "COPY tao_connection_test ( a, b ) TO STDOUT" ) ); + TEST_THROWS( connection->execute( "COPY tao_connection_test ( a, b ) FROM STDIN" ) ); - // read data - TEST_ASSERT( connection->execute( "SELECT b FROM tao_connection_test WHERE a = 1" )[ 0 ][ 0 ].get() == std::string( "42" ) ); + // read data + TEST_ASSERT( connection->execute( "SELECT b FROM tao_connection_test WHERE a = 1" )[ 0 ][ 0 ].get() == std::string( "42" ) ); - TEST_THROWS( connection->execute( "SELECT $1", "" ).as< tao::pq::binary >() ); - TEST_THROWS( connection->execute( "SELECT $1", "\\" ).as< tao::pq::binary >() ); - TEST_THROWS( connection->execute( "SELECT $1", "\\xa" ).as< tao::pq::binary >() ); - TEST_THROWS( connection->execute( "SELECT $1", "\\xa." ).as< tao::pq::binary >() ); + TEST_THROWS( connection->execute( "SELECT $1", "" ).as< tao::pq::binary >() ); + TEST_THROWS( connection->execute( "SELECT $1", "\\" ).as< tao::pq::binary >() ); + TEST_THROWS( connection->execute( "SELECT $1", "\\xa" ).as< tao::pq::binary >() ); + TEST_THROWS( connection->execute( "SELECT $1", "\\xa." ).as< tao::pq::binary >() ); - { - using callback_t = tao::pq::poll::status ( * )( int, bool, int ); - - const auto old_cb = *connection->poll_callback().target< callback_t >(); - TEST_ASSERT( old_cb != nullptr ); - TEST_ASSERT( *connection->poll_callback().target< callback_t >() != &my_poll ); - connection->set_poll_callback( my_poll ); - TEST_ASSERT( *connection->poll_callback().target< callback_t >() == &my_poll ); - connection->reset_poll_callback(); - TEST_ASSERT( *connection->poll_callback().target< callback_t >() == old_cb ); - } + { + using callback_t = tao::pq::poll::status ( * )( int, bool, int ); - connection->reset_timeout(); - TEST_EXECUTE( connection->execute( "SELECT pg_sleep( 0.2 )" ) ); + const auto old_cb = *connection->poll_callback().target< callback_t >(); + TEST_ASSERT( old_cb != nullptr ); + TEST_ASSERT( *connection->poll_callback().target< callback_t >() != &my_poll ); + connection->set_poll_callback( my_poll ); + TEST_ASSERT( *connection->poll_callback().target< callback_t >() == &my_poll ); + connection->reset_poll_callback(); + TEST_ASSERT( *connection->poll_callback().target< callback_t >() == old_cb ); + } - connection->set_timeout( 100ms ); - TEST_THROWS( connection->execute( "SELECT pg_sleep( .2 )" ) ); -} + connection->reset_timeout(); + TEST_EXECUTE( connection->execute( "SELECT pg_sleep( 0.2 )" ) ); + + connection->set_timeout( 100ms ); + TEST_THROWS( connection->execute( "SELECT pg_sleep( .2 )" ) ); + } + +} // namespace auto main() -> int // NOLINT(bugprone-exception-escape) { @@ -150,11 +154,11 @@ auto main() -> int // NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/connection_pool.cpp b/src/test/pq/connection_pool.cpp index eb05ed3..f89a76c 100644 --- a/src/test/pq/connection_pool.cpp +++ b/src/test/pq/connection_pool.cpp @@ -7,133 +7,137 @@ #include -class limited_connection_pool - : public tao::pq::connection_pool +namespace { - struct guard + class limited_connection_pool + : public tao::pq::connection_pool { - std::atomic< std::size_t >& m_counter; - - explicit guard( std::atomic< std::size_t >& counter ) noexcept - : m_counter( counter ) + struct guard { - ++m_counter; - } + std::atomic< std::size_t >& m_counter; + + explicit guard( std::atomic< std::size_t >& counter ) noexcept + : m_counter( counter ) + { + ++m_counter; + } + + guard( const guard& ) = delete; + guard( guard&& ) = delete; + void operator=( const guard& ) = delete; + void operator=( guard&& ) = delete; + + ~guard() + { + --m_counter; + } + }; - guard( const guard& ) = delete; - guard( guard&& ) = delete; - void operator=( const guard& ) = delete; - void operator=( guard&& ) = delete; + mutable std::atomic< std::size_t > m_creating = 0; - ~guard() + using tao::pq::connection_pool::connection_pool; + + [[nodiscard]] auto v_create() const -> std::unique_ptr< tao::pq::connection > override { - --m_counter; + if( attached() >= 4 || ( m_creating.load() > 2 ) ) { + throw std::runtime_error( "connection limit reached" ); + } + const guard g( m_creating ); + return connection_pool::v_create(); } }; - mutable std::atomic< std::size_t > m_creating = 0; - - using tao::pq::connection_pool::connection_pool; - - [[nodiscard]] auto v_create() const -> std::unique_ptr< tao::pq::connection > override + // LCOV_EXCL_START + auto my_poll( const int /*unused*/, const bool /*unused*/, const int /*unused*/ ) -> tao::pq::poll::status { - if( attached() >= 4 || ( m_creating.load() > 2 ) ) { - throw std::runtime_error( "connection limit reached" ); - } - const guard g( m_creating ); - return connection_pool::v_create(); + TAO_PQ_UNREACHABLE; } -}; - -// LCOV_EXCL_START -auto my_poll( const int /*unused*/, const bool /*unused*/, const int /*unused*/ ) -> tao::pq::poll::status -{ - TAO_PQ_UNREACHABLE; -} -// LCOV_EXCL_STOP - -void run() -{ - // overwrite the default with an environment variable if needed - const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); - - const auto pool = tao::pq::connection_pool::create< limited_connection_pool >( connection_string ); + // LCOV_EXCL_STOP - TEST_ASSERT( pool->empty() ); - TEST_ASSERT( pool->attached() == 0 ); + void run() + { + // overwrite the default with an environment variable if needed + const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); - TEST_ASSERT( pool->connection() ); + const auto pool = tao::pq::connection_pool::create< limited_connection_pool >( connection_string ); - TEST_ASSERT( !pool->empty() ); - TEST_ASSERT( pool->size() == 1 ); - TEST_ASSERT( pool->attached() == 0 ); + TEST_ASSERT( pool->empty() ); + TEST_ASSERT( pool->attached() == 0 ); - TEST_ASSERT( pool->connection()->execute( "SELECT 1" ).as< int >() == 1 ); + TEST_ASSERT( pool->connection() ); - TEST_ASSERT( pool->size() == 1 ); - TEST_ASSERT( pool->attached() == 0 ); + TEST_ASSERT( !pool->empty() ); + TEST_ASSERT( pool->size() == 1 ); + TEST_ASSERT( pool->attached() == 0 ); - { - const auto conn = pool->connection(); - TEST_ASSERT( pool->connection() ); - TEST_ASSERT( conn->execute( "SELECT 2" ).as< int >() == 2 ); + TEST_ASSERT( pool->connection()->execute( "SELECT 1" ).as< int >() == 1 ); TEST_ASSERT( pool->size() == 1 ); - TEST_ASSERT( pool->attached() == 1 ); + TEST_ASSERT( pool->attached() == 0 ); - const auto pool2 = tao::pq::connection_pool::create( connection_string ); - TEST_ASSERT( pool->connection()->execute( "SELECT 3" ).as< int >() == 3 ); - TEST_ASSERT( pool2->connection()->execute( "SELECT 4" ).as< int >() == 4 ); - TEST_ASSERT( conn->execute( "SELECT 5" ).as< int >() == 5 ); - TEST_ASSERT( pool2->connection()->execute( "SELECT 6" ).as< int >() == 6 ); - } + { + const auto conn = pool->connection(); + TEST_ASSERT( pool->connection() ); + TEST_ASSERT( conn->execute( "SELECT 2" ).as< int >() == 2 ); + + TEST_ASSERT( pool->size() == 1 ); + TEST_ASSERT( pool->attached() == 1 ); + + const auto pool2 = tao::pq::connection_pool::create( connection_string ); + TEST_ASSERT( pool->connection()->execute( "SELECT 3" ).as< int >() == 3 ); + TEST_ASSERT( pool2->connection()->execute( "SELECT 4" ).as< int >() == 4 ); + TEST_ASSERT( conn->execute( "SELECT 5" ).as< int >() == 5 ); + TEST_ASSERT( pool2->connection()->execute( "SELECT 6" ).as< int >() == 6 ); + } - TEST_ASSERT( pool->size() == 2 ); - TEST_ASSERT( pool->attached() == 0 ); - { - [[maybe_unused]] const auto c0 = pool->connection(); - [[maybe_unused]] const auto c1 = pool->connection(); - TEST_ASSERT( pool->empty() ); - TEST_ASSERT( pool->attached() == 2 ); + TEST_ASSERT( pool->size() == 2 ); + TEST_ASSERT( pool->attached() == 0 ); { - [[maybe_unused]] const auto c2 = pool->connection(); - [[maybe_unused]] const auto c3 = pool->connection(); + [[maybe_unused]] const auto c0 = pool->connection(); + [[maybe_unused]] const auto c1 = pool->connection(); TEST_ASSERT( pool->empty() ); - TEST_ASSERT( pool->attached() == 4 ); - - TEST_THROWS( pool->connection() ); + TEST_ASSERT( pool->attached() == 2 ); + { + [[maybe_unused]] const auto c2 = pool->connection(); + [[maybe_unused]] const auto c3 = pool->connection(); + TEST_ASSERT( pool->empty() ); + TEST_ASSERT( pool->attached() == 4 ); + + TEST_THROWS( pool->connection() ); + + TEST_ASSERT( pool->empty() ); + TEST_ASSERT( pool->attached() == 4 ); + } + TEST_ASSERT( pool->size() == 2 ); + TEST_ASSERT( pool->attached() == 2 ); + } + TEST_ASSERT( pool->size() == 4 ); + TEST_ASSERT( pool->attached() == 0 ); - TEST_ASSERT( pool->empty() ); - TEST_ASSERT( pool->attached() == 4 ); + { + using callback_t = tao::pq::poll::status ( * )( int, bool, int ); + + const auto old_cb = *pool->poll_callback().target< callback_t >(); + TEST_ASSERT( old_cb != nullptr ); + TEST_ASSERT( *pool->poll_callback().target< callback_t >() != &my_poll ); + TEST_ASSERT( *pool->connection()->poll_callback().target< callback_t >() != &my_poll ); + pool->set_poll_callback( my_poll ); + TEST_ASSERT( *pool->poll_callback().target< callback_t >() == &my_poll ); + TEST_ASSERT( *pool->connection()->poll_callback().target< callback_t >() == &my_poll ); + pool->reset_poll_callback(); + TEST_ASSERT( *pool->poll_callback().target< callback_t >() == old_cb ); + TEST_ASSERT( *pool->connection()->poll_callback().target< callback_t >() == old_cb ); } - TEST_ASSERT( pool->size() == 2 ); - TEST_ASSERT( pool->attached() == 2 ); - } - TEST_ASSERT( pool->size() == 4 ); - TEST_ASSERT( pool->attached() == 0 ); - { - using callback_t = tao::pq::poll::status ( * )( int, bool, int ); - - const auto old_cb = *pool->poll_callback().target< callback_t >(); - TEST_ASSERT( old_cb != nullptr ); - TEST_ASSERT( *pool->poll_callback().target< callback_t >() != &my_poll ); - TEST_ASSERT( *pool->connection()->poll_callback().target< callback_t >() != &my_poll ); - pool->set_poll_callback( my_poll ); - TEST_ASSERT( *pool->poll_callback().target< callback_t >() == &my_poll ); - TEST_ASSERT( *pool->connection()->poll_callback().target< callback_t >() == &my_poll ); - pool->reset_poll_callback(); - TEST_ASSERT( *pool->poll_callback().target< callback_t >() == old_cb ); - TEST_ASSERT( *pool->connection()->poll_callback().target< callback_t >() == old_cb ); - } + using namespace std::chrono_literals; + pool->set_timeout( 100ms ); + TEST_THROWS( pool->execute( "SELECT pg_sleep( .5 )" ) ); - using namespace std::chrono_literals; - pool->set_timeout( 100ms ); - TEST_THROWS( pool->execute( "SELECT pg_sleep( .5 )" ) ); + pool->reset_timeout(); + TEST_EXECUTE( pool->execute( "SELECT pg_sleep( .5 )" ) ); + } - pool->reset_timeout(); - TEST_EXECUTE( pool->execute( "SELECT pg_sleep( .5 )" ) ); -} +} // namespace auto main() -> int // NOLINT(bugprone-exception-escape) { @@ -142,11 +146,11 @@ auto main() -> int // NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/example.cpp b/src/test/pq/example.cpp index 0729ad1..426d7e2 100644 --- a/src/test/pq/example.cpp +++ b/src/test/pq/example.cpp @@ -8,43 +8,47 @@ #include #include -void run() +namespace { - // overwrite the default with an environment variable if needed - const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); + void run() + { + // overwrite the default with an environment variable if needed + const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); - // open a connection to the database - const auto conn = tao::pq::connection::create( connection_string ); + // open a connection to the database + const auto conn = tao::pq::connection::create( connection_string ); - // execute statements - conn->execute( "DROP TABLE IF EXISTS tao_example" ); - conn->execute( "CREATE TABLE tao_example ( name TEXT PRIMARY KEY, age INTEGER NOT NULL )" ); + // execute statements + conn->execute( "DROP TABLE IF EXISTS tao_example" ); + conn->execute( "CREATE TABLE tao_example ( name TEXT PRIMARY KEY, age INTEGER NOT NULL )" ); - // prepare statements - conn->prepare( "insert_user", "INSERT INTO tao_example ( name, age ) VALUES ( $1, $2 )" ); + // prepare statements + conn->prepare( "insert_user", "INSERT INTO tao_example ( name, age ) VALUES ( $1, $2 )" ); - { - // begin transaction - const auto tr = conn->transaction(); + { + // begin transaction + const auto tr = conn->transaction(); - // execute previously prepared statements - tr->execute( "insert_user", "Daniel", 42 ); - tr->execute( "insert_user", "Tom", 41 ); - tr->execute( "insert_user", "Jerry", 29 ); + // execute previously prepared statements + tr->execute( "insert_user", "Daniel", 42 ); + tr->execute( "insert_user", "Tom", 41 ); + tr->execute( "insert_user", "Jerry", 29 ); - // commit transaction - tr->commit(); - } + // commit transaction + tr->commit(); + } - // query data - const auto users = conn->execute( "SELECT name, age FROM tao_example WHERE age >= $1", 40 ); + // query data + const auto users = conn->execute( "SELECT name, age FROM tao_example WHERE age >= $1", 40 ); - // iterate and convert results - for( const auto& row : users ) { - std::cout << row[ "name" ].as< std::string >() << " is " - << row[ "age" ].as< unsigned >() << " years old.\n"; + // iterate and convert results + for( const auto& row : users ) { + std::cout << row[ "name" ].as< std::string >() << " is " + << row[ "age" ].as< unsigned >() << " years old.\n"; + } } -} + +} // namespace auto main() -> int { @@ -53,11 +57,11 @@ auto main() -> int } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/exception.cpp b/src/test/pq/exception.cpp index a2e7bb9..cbf103f 100644 --- a/src/test/pq/exception.cpp +++ b/src/test/pq/exception.cpp @@ -7,24 +7,28 @@ #include -void run() +namespace { - // overwrite the default with an environment variable if needed - const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); - const auto connection = tao::pq::connection::create( connection_string ); - connection->execute( "DROP TABLE IF EXISTS tao_exception_test" ); + void run() + { + // overwrite the default with an environment variable if needed + const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); + const auto connection = tao::pq::connection::create( connection_string ); + connection->execute( "DROP TABLE IF EXISTS tao_exception_test" ); - TEST_THROWS( connection->execute( "SELECT a FROM tao_exception_test" ) ); + TEST_THROWS( connection->execute( "SELECT a FROM tao_exception_test" ) ); - connection->execute( "CREATE TABLE tao_exception_test ( a TEXT PRIMARY KEY, b TEXT NOT NULL )" ); + connection->execute( "CREATE TABLE tao_exception_test ( a TEXT PRIMARY KEY, b TEXT NOT NULL )" ); - TEST_THROWS( connection->execute( "SELECT c FROM tao_exception_test" ) ); + TEST_THROWS( connection->execute( "SELECT c FROM tao_exception_test" ) ); - TEST_THROWS( connection->execute( "FOO BAR BAZ" ) ); - TEST_THROWS( connection->execute( "SELECT 1/0" ) ); - TEST_THROWS( connection->execute( "SELECT * FROM tao_exception_test WHERE a = 42" ) ); - TEST_THROWS( connection->execute( "SELECT * FROM tao_exception_test WHERE a[0] = 'FOO'" ) ); -} + TEST_THROWS( connection->execute( "FOO BAR BAZ" ) ); + TEST_THROWS( connection->execute( "SELECT 1/0" ) ); + TEST_THROWS( connection->execute( "SELECT * FROM tao_exception_test WHERE a = 42" ) ); + TEST_THROWS( connection->execute( "SELECT * FROM tao_exception_test WHERE a[0] = 'FOO'" ) ); + } + +} // namespace auto main() -> int // NOLINT(bugprone-exception-escape) { @@ -33,11 +37,11 @@ auto main() -> int // NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/getenv.cpp b/src/test/pq/getenv.cpp index 9e3ed6e..bfc05d7 100644 --- a/src/test/pq/getenv.cpp +++ b/src/test/pq/getenv.cpp @@ -5,15 +5,19 @@ #include "../getenv.hpp" #include "../macros.hpp" -void run() +namespace { - TEST_ASSERT( !tao::pq::internal::getenv( "PATH" ).empty() ); - TEST_THROWS( tao::pq::internal::getenv( "TAOPQ_DOESNOTEXIST" ) ); + void run() + { + TEST_ASSERT( !tao::pq::internal::getenv( "PATH" ).empty() ); + TEST_THROWS( tao::pq::internal::getenv( "TAOPQ_DOESNOTEXIST" ) ); - TEST_ASSERT( !tao::pq::internal::getenv( "PATH", "" ).empty() ); - TEST_ASSERT( tao::pq::internal::getenv( "TAOPQ_DOESNOTEXIST", "" ).empty() ); - TEST_ASSERT( tao::pq::internal::getenv( "TAOPQ_DOESNOTEXIST", "DEFAULT VALUE" ) == "DEFAULT VALUE" ); -} + TEST_ASSERT( !tao::pq::internal::getenv( "PATH", "" ).empty() ); + TEST_ASSERT( tao::pq::internal::getenv( "TAOPQ_DOESNOTEXIST", "" ).empty() ); + TEST_ASSERT( tao::pq::internal::getenv( "TAOPQ_DOESNOTEXIST", "DEFAULT VALUE" ) == "DEFAULT VALUE" ); + } + +} // namespace auto main() -> int { @@ -22,11 +26,11 @@ auto main() -> int } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/large_object.cpp b/src/test/pq/large_object.cpp index 5065d73..656f203 100644 --- a/src/test/pq/large_object.cpp +++ b/src/test/pq/large_object.cpp @@ -12,121 +12,125 @@ #include #include -template< typename R, typename T > -void test( const std::shared_ptr< tao::pq::connection >& connection, const T& data ) +namespace { - const auto transaction = connection->transaction(); - - const auto oid = tao::pq::large_object::create( transaction ); - tao::pq::large_object lo( transaction, oid, std::ios_base::in | std::ios_base::out ); - lo.write( data ); - - lo.seek( 0, std::ios_base::beg ); - - const auto result = lo.read< R >( 10 ); - TEST_ASSERT( tao::pq::internal::compare( result, data ) ); -} - -void run() -{ - const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); - - { - const auto transaction = connection->transaction(); - const auto oid = tao::pq::large_object::create( transaction ); - tao::pq::large_object lo( transaction, oid, std::ios_base::in | std::ios_base::out ); - tao::pq::large_object lo2 = std::move( lo ); - lo = std::move( lo2 ); - TEST_ASSERT( lo.tell() == 0 ); - lo.resize( 42 ); - TEST_ASSERT( lo.seek( 20, std::ios_base::beg ) == 20 ); - TEST_ASSERT( lo.tell() == 20 ); - TEST_ASSERT( lo.seek( -20, std::ios_base::end ) == 22 ); - TEST_ASSERT( lo.tell() == 22 ); - TEST_ASSERT( lo.seek( 5, std::ios_base::cur ) == 27 ); - TEST_ASSERT( lo.tell() == 27 ); - TEST_ASSERT( lo.seek( -7, std::ios_base::cur ) == 20 ); - TEST_ASSERT( lo.tell() == 20 ); - TEST_THROWS( lo.seek( -60, std::ios_base::end ) ); - } - - test< std::string >( connection, std::string( "hello" ) ); - test< std::string >( connection, std::string_view( "hello" ) ); - - test< tao::pq::binary >( connection, tao::pq::to_binary( "nice!" ) ); - test< tao::pq::binary >( connection, tao::pq::to_binary_view( "nice!" ) ); - + template< typename R, typename T > + void test( const std::shared_ptr< tao::pq::connection >& connection, const T& data ) { const auto transaction = connection->transaction(); - const auto oid = tao::pq::large_object::create( transaction ); - tao::pq::large_object lo( transaction, oid, std::ios_base::in ); - TEST_THROWS( lo.write( "abc" ) ); - } - - { - const auto transaction = connection->transaction(); - const auto oid = tao::pq::large_object::create( transaction ); - tao::pq::large_object lo( transaction, oid, std::ios_base::out ); - TEST_THROWS( lo.read( std::numeric_limits< unsigned >::max() ) ); - } - { - const auto transaction = connection->transaction(); const auto oid = tao::pq::large_object::create( transaction ); tao::pq::large_object lo( transaction, oid, std::ios_base::in | std::ios_base::out ); - lo.close(); - } + lo.write( data ); - { - const auto transaction = connection->transaction(); - const auto oid = tao::pq::large_object::create( transaction ); - tao::pq::large_object lo( transaction, oid, std::ios_base::in | std::ios_base::out ); - TEST_THROWS( lo.resize( -5 ) ); - } - - { - const auto transaction = connection->transaction(); - const auto oid = tao::pq::large_object::create( transaction ); - tao::pq::large_object lo( transaction, oid, std::ios_base::in | std::ios_base::out ); - tao::pq::large_object::remove( transaction, oid ); - TEST_THROWS( lo.tell() ); - } + lo.seek( 0, std::ios_base::beg ); - { - const auto transaction = connection->transaction(); - const auto oid = tao::pq::large_object::create( transaction ); - TEST_THROWS( tao::pq::large_object::create( transaction, oid ) ); + const auto result = lo.read< R >( 10 ); + TEST_ASSERT( tao::pq::internal::compare( result, data ) ); } + void run() { - const auto transaction = connection->transaction(); - const auto oid = tao::pq::large_object::create( transaction ); - tao::pq::large_object::remove( transaction, oid ); - TEST_THROWS( tao::pq::large_object::remove( transaction, oid ) ); + const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); + + { + const auto transaction = connection->transaction(); + const auto oid = tao::pq::large_object::create( transaction ); + tao::pq::large_object lo( transaction, oid, std::ios_base::in | std::ios_base::out ); + tao::pq::large_object lo2 = std::move( lo ); + lo = std::move( lo2 ); + TEST_ASSERT( lo.tell() == 0 ); + lo.resize( 42 ); + TEST_ASSERT( lo.seek( 20, std::ios_base::beg ) == 20 ); + TEST_ASSERT( lo.tell() == 20 ); + TEST_ASSERT( lo.seek( -20, std::ios_base::end ) == 22 ); + TEST_ASSERT( lo.tell() == 22 ); + TEST_ASSERT( lo.seek( 5, std::ios_base::cur ) == 27 ); + TEST_ASSERT( lo.tell() == 27 ); + TEST_ASSERT( lo.seek( -7, std::ios_base::cur ) == 20 ); + TEST_ASSERT( lo.tell() == 20 ); + TEST_THROWS( lo.seek( -60, std::ios_base::end ) ); + } + + test< std::string >( connection, std::string( "hello" ) ); + test< std::string >( connection, std::string_view( "hello" ) ); + + test< tao::pq::binary >( connection, tao::pq::to_binary( "nice!" ) ); + test< tao::pq::binary >( connection, tao::pq::to_binary_view( "nice!" ) ); + + { + const auto transaction = connection->transaction(); + const auto oid = tao::pq::large_object::create( transaction ); + tao::pq::large_object lo( transaction, oid, std::ios_base::in ); + TEST_THROWS( lo.write( "abc" ) ); + } + + { + const auto transaction = connection->transaction(); + const auto oid = tao::pq::large_object::create( transaction ); + tao::pq::large_object lo( transaction, oid, std::ios_base::out ); + TEST_THROWS( lo.read( std::numeric_limits< unsigned >::max() ) ); + } + + { + const auto transaction = connection->transaction(); + const auto oid = tao::pq::large_object::create( transaction ); + tao::pq::large_object lo( transaction, oid, std::ios_base::in | std::ios_base::out ); + lo.close(); + } + + { + const auto transaction = connection->transaction(); + const auto oid = tao::pq::large_object::create( transaction ); + tao::pq::large_object lo( transaction, oid, std::ios_base::in | std::ios_base::out ); + TEST_THROWS( lo.resize( -5 ) ); + } + + { + const auto transaction = connection->transaction(); + const auto oid = tao::pq::large_object::create( transaction ); + const tao::pq::large_object lo( transaction, oid, std::ios_base::in | std::ios_base::out ); + tao::pq::large_object::remove( transaction, oid ); + TEST_THROWS( lo.tell() ); + } + + { + const auto transaction = connection->transaction(); + const auto oid = tao::pq::large_object::create( transaction ); + TEST_THROWS( tao::pq::large_object::create( transaction, oid ) ); + } + + { + const auto transaction = connection->transaction(); + const auto oid = tao::pq::large_object::create( transaction ); + tao::pq::large_object::remove( transaction, oid ); + TEST_THROWS( tao::pq::large_object::remove( transaction, oid ) ); + } + + { + const auto transaction = connection->transaction(); + const auto oid = tao::pq::large_object::create( transaction ); + tao::pq::large_object::remove( transaction, oid ); + TEST_THROWS( tao::pq::large_object( transaction, oid, std::ios_base::in | std::ios_base::out ) ); + } + + { + const auto transaction = connection->transaction(); + const auto oid = tao::pq::large_object::create( transaction ); + const char* filename = "dummy.txt"; + tao::pq::large_object::export_file( transaction, oid, filename ); + const auto oid2 = tao::pq::large_object::import_file( transaction, filename ); + TEST_ASSERT( oid != oid2 ); + TEST_THROWS( tao::pq::large_object::export_file( transaction, oid, "" ) ); + } + + { + const auto transaction = connection->transaction(); + TEST_THROWS( tao::pq::large_object::import_file( transaction, "" ) ); + } } - { - const auto transaction = connection->transaction(); - const auto oid = tao::pq::large_object::create( transaction ); - tao::pq::large_object::remove( transaction, oid ); - TEST_THROWS( tao::pq::large_object( transaction, oid, std::ios_base::in | std::ios_base::out ) ); - } - - { - const auto transaction = connection->transaction(); - const auto oid = tao::pq::large_object::create( transaction ); - const char* filename = "dummy.txt"; - tao::pq::large_object::export_file( transaction, oid, filename ); - const auto oid2 = tao::pq::large_object::import_file( transaction, filename ); - TEST_ASSERT( oid != oid2 ); - TEST_THROWS( tao::pq::large_object::export_file( transaction, oid, "" ) ); - } - - { - const auto transaction = connection->transaction(); - TEST_THROWS( tao::pq::large_object::import_file( transaction, "" ) ); - } -} +} // namespace auto main() -> int { @@ -135,11 +139,11 @@ auto main() -> int } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/notifications.cpp b/src/test/pq/notifications.cpp index 3363605..77031bc 100644 --- a/src/test/pq/notifications.cpp +++ b/src/test/pq/notifications.cpp @@ -13,63 +13,67 @@ #include #endif -std::size_t counter = 0; - -void handle_notification( const tao::pq::notification& n ) +namespace { - std::cout << "channel '" << n.channel() << "' received '" << n.payload() << "'\n"; - ++counter; -} + std::size_t counter = 0; -std::size_t foo_counter = 0; + void handle_notification( const tao::pq::notification& n ) + { + std::cout << "channel '" << n.channel() << "' received '" << n.payload() << "'\n"; + ++counter; + } -void handle_foo_notification( const char* payload ) -{ - std::cout << "foo handler received '" << payload << "'\n"; - ++foo_counter; -} + std::size_t foo_counter = 0; -void run() -{ - // overwrite the default with an environment variable if needed - const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); - const auto connection = tao::pq::connection::create( connection_string ); + void handle_foo_notification( const char* payload ) + { + std::cout << "foo handler received '" << payload << "'\n"; + ++foo_counter; + } + + void run() + { + // overwrite the default with an environment variable if needed + const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); + const auto connection = tao::pq::connection::create( connection_string ); - TEST_EXECUTE( connection->set_notification_handler( handle_notification ) ); - TEST_EXECUTE( connection->listen( "FOO", handle_foo_notification ) ); - TEST_ASSERT( counter == 0 ); - TEST_ASSERT( foo_counter == 0 ); + TEST_EXECUTE( connection->set_notification_handler( handle_notification ) ); + TEST_EXECUTE( connection->listen( "FOO", handle_foo_notification ) ); + TEST_ASSERT( counter == 0 ); + TEST_ASSERT( foo_counter == 0 ); - TEST_EXECUTE( connection->notify( "FOO" ) ); - TEST_ASSERT( counter == 1 ); - TEST_ASSERT( foo_counter == 1 ); + TEST_EXECUTE( connection->notify( "FOO" ) ); + TEST_ASSERT( counter == 1 ); + TEST_ASSERT( foo_counter == 1 ); - TEST_ASSERT( connection->notification_handler( "FOO" ) ); - TEST_ASSERT( !connection->notification_handler( "BAR" ) ); - TEST_EXECUTE( connection->reset_notification_handler( "FOO" ) ); - TEST_ASSERT( !connection->notification_handler( "FOO" ) ); + TEST_ASSERT( connection->notification_handler( "FOO" ) ); + TEST_ASSERT( !connection->notification_handler( "BAR" ) ); + TEST_EXECUTE( connection->reset_notification_handler( "FOO" ) ); + TEST_ASSERT( !connection->notification_handler( "FOO" ) ); - TEST_EXECUTE( connection->notify( "FOO", "with payload" ) ); - TEST_ASSERT( counter == 2 ); - TEST_ASSERT( foo_counter == 1 ); + TEST_EXECUTE( connection->notify( "FOO", "with payload" ) ); + TEST_ASSERT( counter == 2 ); + TEST_ASSERT( foo_counter == 1 ); - TEST_EXECUTE( connection->unlisten( "FOO" ) ); - TEST_EXECUTE( connection->notify( "FOO" ) ); - TEST_EXECUTE( connection->get_notifications() ); - TEST_ASSERT( counter == 2 ); + TEST_EXECUTE( connection->unlisten( "FOO" ) ); + TEST_EXECUTE( connection->notify( "FOO" ) ); + TEST_EXECUTE( connection->get_notifications() ); + TEST_ASSERT( counter == 2 ); - TEST_ASSERT( connection->notification_handler() ); - TEST_EXECUTE( connection->reset_notification_handler() ); - TEST_ASSERT( !connection->notification_handler() ); + TEST_ASSERT( connection->notification_handler() ); + TEST_EXECUTE( connection->reset_notification_handler() ); + TEST_ASSERT( !connection->notification_handler() ); #if defined( _WIN32 ) - closesocket( connection->socket() ); + closesocket( connection->socket() ); #else - close( connection->socket() ); + close( connection->socket() ); #endif - TEST_THROWS( connection->get_notifications() ); -} + TEST_THROWS( connection->get_notifications() ); + } + +} // namespace auto main() -> int // NOLINT(bugprone-exception-escape) { @@ -78,11 +82,11 @@ auto main() -> int // NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/parameter.cpp b/src/test/pq/parameter.cpp index 34cb5f9..d50b516 100644 --- a/src/test/pq/parameter.cpp +++ b/src/test/pq/parameter.cpp @@ -8,80 +8,84 @@ #include #include -void run() +namespace { - // overwrite the default with an environment variable if needed - const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); - - // open a connection to the database - const auto conn = tao::pq::connection::create( connection_string ); + void run() + { + // overwrite the default with an environment variable if needed + const auto connection_string = tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ); - // execute statements - conn->execute( "DROP TABLE IF EXISTS tao_parameter_test" ); - conn->execute( "CREATE TABLE tao_parameter_test ( name TEXT PRIMARY KEY, age INTEGER NOT NULL )" ); + // open a connection to the database + const auto conn = tao::pq::connection::create( connection_string ); - // prepare statements - conn->prepare( "insert_user", "INSERT INTO tao_parameter_test ( name, age ) VALUES ( $1, $2 )" ); + // execute statements + conn->execute( "DROP TABLE IF EXISTS tao_parameter_test" ); + conn->execute( "CREATE TABLE tao_parameter_test ( name TEXT PRIMARY KEY, age INTEGER NOT NULL )" ); - { - // begin transaction - const auto tr = conn->transaction(); + // prepare statements + conn->prepare( "insert_user", "INSERT INTO tao_parameter_test ( name, age ) VALUES ( $1, $2 )" ); - // execute previously prepared statements { - tao::pq::parameter p( "Daniel", 42 ); - tr->execute( "insert_user", p ); - p.reset(); - p.bind( "Tom" ); - tao::pq::parameter p2( 41 ); - tr->execute( "insert_user", tao::pq::parameter( p, p2 ) ); + // begin transaction + const auto tr = conn->transaction(); + + // execute previously prepared statements + { + tao::pq::parameter p( "Daniel", 42 ); + tr->execute( "insert_user", p ); + p.reset(); + p.bind( "Tom" ); + tao::pq::parameter p2( 41 ); + tr->execute( "insert_user", tao::pq::parameter( p, p2 ) ); + } + + { + tao::pq::parameter< 2 > p; + std::string s = "Alice"; + p.bind( s ); + p.bind( std::move( s ) ); + p.reset( std::string( "Jerry" ), 42 + 7 ); + p.bind(); + tao::pq::parameter<> p2( p ); + tr->execute( "insert_user", p2 ); + } + + { + tao::pq::parameter< 1 > p; + std::string s = "Alice"; + p.bind( std::move( s ) ); + tr->execute( "insert_user", p, 44 ); + } + + // commit transaction + tr->commit(); } - { - tao::pq::parameter< 2 > p; - std::string s = "Alice"; - p.bind( s ); - p.bind( std::move( s ) ); - p.reset( std::string( "Jerry" ), 42 + 7 ); - p.bind(); - tao::pq::parameter<> p2( p ); - tr->execute( "insert_user", p2 ); + // query data + const auto users = conn->execute( "SELECT name, age FROM tao_parameter_test WHERE age >= $1", 40 ); + + // iterate and convert results + for( const auto& row : users ) { + std::cout << row[ "name" ].as< std::string >() << " is " + << row[ "age" ].as< unsigned >() << " years old.\n"; } { tao::pq::parameter< 1 > p; - std::string s = "Alice"; - p.bind( std::move( s ) ); - tr->execute( "insert_user", p, 44 ); + p.bind( 1 ); + TEST_THROWS( p.bind( 2 ) ); } - // commit transaction - tr->commit(); - } - - // query data - const auto users = conn->execute( "SELECT name, age FROM tao_parameter_test WHERE age >= $1", 40 ); - - // iterate and convert results - for( const auto& row : users ) { - std::cout << row[ "name" ].as< std::string >() << " is " - << row[ "age" ].as< unsigned >() << " years old.\n"; - } - - { - tao::pq::parameter< 1 > p; - p.bind( 1 ); - TEST_THROWS( p.bind( 2 ) ); + { + tao::pq::parameter< 1 > p; + tao::pq::parameter< 1 > p2; + p.bind( 1 ); + p2.bind( 1 ); + TEST_THROWS( p.bind( p2 ) ); + } } - { - tao::pq::parameter< 1 > p; - tao::pq::parameter< 1 > p2; - p.bind( 1 ); - p2.bind( 1 ); - TEST_THROWS( p.bind( p2 ) ); - } -} +} // namespace auto main() -> int // NOLINT(bugprone-exception-escape) { @@ -90,11 +94,11 @@ auto main() -> int // NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/resize_uninitialized.cpp b/src/test/pq/resize_uninitialized.cpp index 4a083a7..a6de159 100644 --- a/src/test/pq/resize_uninitialized.cpp +++ b/src/test/pq/resize_uninitialized.cpp @@ -6,56 +6,60 @@ #include -void test( std::string& s, const std::size_t size ) +namespace { - tao::pq::internal::resize_uninitialized( s, size ); - TEST_ASSERT( s.size() == size ); - TEST_ASSERT( s[ size ] == '\0' ); -} + void test( std::string& s, const std::size_t size ) + { + tao::pq::internal::resize_uninitialized( s, size ); + TEST_ASSERT( s.size() == size ); + TEST_ASSERT( s[ size ] == '\0' ); + } -void run() -{ - std::string s = "hello"; - test( s, 2 ); - TEST_ASSERT( s[ 0 ] == 'h' ); - TEST_ASSERT( s[ 1 ] == 'e' ); + void run() + { + std::string s = "hello"; + test( s, 2 ); + TEST_ASSERT( s[ 0 ] == 'h' ); + TEST_ASSERT( s[ 1 ] == 'e' ); - test( s, 5 ); - TEST_ASSERT( s[ 0 ] == 'h' ); - TEST_ASSERT( s[ 1 ] == 'e' ); + test( s, 5 ); + TEST_ASSERT( s[ 0 ] == 'h' ); + TEST_ASSERT( s[ 1 ] == 'e' ); - test( s, 32 ); - TEST_ASSERT( s[ 0 ] == 'h' ); - TEST_ASSERT( s[ 1 ] == 'e' ); + test( s, 32 ); + TEST_ASSERT( s[ 0 ] == 'h' ); + TEST_ASSERT( s[ 1 ] == 'e' ); - test( s, 1000000000 ); - TEST_ASSERT( s[ 0 ] == 'h' ); - TEST_ASSERT( s[ 1 ] == 'e' ); + test( s, 1000000000 ); + TEST_ASSERT( s[ 0 ] == 'h' ); + TEST_ASSERT( s[ 1 ] == 'e' ); - test( s, 2 ); - TEST_ASSERT( s[ 0 ] == 'h' ); - TEST_ASSERT( s[ 1 ] == 'e' ); + test( s, 2 ); + TEST_ASSERT( s[ 0 ] == 'h' ); + TEST_ASSERT( s[ 1 ] == 'e' ); - std::vector< std::byte > v = { static_cast< std::byte >( 42 ), static_cast< std::byte >( 69 ) }; - TEST_ASSERT( v.size() == 2 ); - TEST_ASSERT( v[ 0 ] == static_cast< std::byte >( 42 ) ); - TEST_ASSERT( v[ 1 ] == static_cast< std::byte >( 69 ) ); + std::vector< std::byte > v = { static_cast< std::byte >( 42 ), static_cast< std::byte >( 69 ) }; + TEST_ASSERT( v.size() == 2 ); + TEST_ASSERT( v[ 0 ] == static_cast< std::byte >( 42 ) ); + TEST_ASSERT( v[ 1 ] == static_cast< std::byte >( 69 ) ); - tao::pq::internal::resize_uninitialized( v, 5 ); - TEST_ASSERT( v.size() == 5 ); - TEST_ASSERT( v[ 0 ] == static_cast< std::byte >( 42 ) ); - TEST_ASSERT( v[ 1 ] == static_cast< std::byte >( 69 ) ); + tao::pq::internal::resize_uninitialized( v, 5 ); + TEST_ASSERT( v.size() == 5 ); + TEST_ASSERT( v[ 0 ] == static_cast< std::byte >( 42 ) ); + TEST_ASSERT( v[ 1 ] == static_cast< std::byte >( 69 ) ); - tao::pq::internal::resize_uninitialized( v, 1000000000 ); - TEST_ASSERT( v.size() == 1000000000 ); - TEST_ASSERT( v[ 0 ] == static_cast< std::byte >( 42 ) ); - TEST_ASSERT( v[ 1 ] == static_cast< std::byte >( 69 ) ); + tao::pq::internal::resize_uninitialized( v, 1000000000 ); + TEST_ASSERT( v.size() == 1000000000 ); + TEST_ASSERT( v[ 0 ] == static_cast< std::byte >( 42 ) ); + TEST_ASSERT( v[ 1 ] == static_cast< std::byte >( 69 ) ); - tao::pq::internal::resize_uninitialized( v, 2 ); - TEST_ASSERT( v.size() == 2 ); - TEST_ASSERT( v[ 0 ] == static_cast< std::byte >( 42 ) ); - TEST_ASSERT( v[ 1 ] == static_cast< std::byte >( 69 ) ); -} + tao::pq::internal::resize_uninitialized( v, 2 ); + TEST_ASSERT( v.size() == 2 ); + TEST_ASSERT( v[ 0 ] == static_cast< std::byte >( 42 ) ); + TEST_ASSERT( v[ 1 ] == static_cast< std::byte >( 69 ) ); + } + +} // namespace auto main() -> int { @@ -64,11 +68,11 @@ auto main() -> int } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/result.cpp b/src/test/pq/result.cpp index 465347a..c4a09fb 100644 --- a/src/test/pq/result.cpp +++ b/src/test/pq/result.cpp @@ -10,154 +10,158 @@ #include #include -void run() // NOLINT(readability-function-size) +namespace { - const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); - - TEST_EXECUTE( connection->execute( "SELECT NULL" ) ); - TEST_ASSERT( connection->execute( "SELECT NULL" ).is_null( 0, 0 ) ); - TEST_THROWS( connection->execute( "SELECT NULL" ).is_null( 0, 1 ) ); - TEST_THROWS( connection->execute( "SELECT NULL" ).is_null( 1, 0 ) ); - TEST_THROWS( connection->execute( "SELECT NULL" ).get( 0, 0 ) ); - TEST_THROWS( connection->execute( "SELECT NULL" ).get( 0, 1 ) ); - TEST_THROWS( connection->execute( "SELECT NULL" ).get( 1, 0 ) ); - TEST_ASSERT( connection->execute( "SELECT NULL" )[ 0 ].is_null( 0 ) ); - TEST_THROWS( connection->execute( "SELECT NULL" )[ 0 ].is_null( 1 ) ); - TEST_ASSERT( connection->execute( "SELECT NULL" )[ 0 ][ 0 ].is_null() ); - TEST_ASSERT( connection->execute( "SELECT NULL" )[ 0 ][ 0 ] == tao::pq::null ); - TEST_ASSERT( !( connection->execute( "SELECT NULL" )[ 0 ][ 0 ] != tao::pq::null ) ); - TEST_THROWS( connection->execute( "SELECT NULL" )[ 0 ].at( 1 ) ); - TEST_THROWS( connection->execute( "SELECT NULL" ).at( 1 )[ 1 ] ); - - TEST_EXECUTE( connection->execute( "SELECT 42" ) ); - TEST_ASSERT( !connection->execute( "SELECT 42" ).is_null( 0, 0 ) ); - TEST_THROWS( connection->execute( "SELECT 42" ).is_null( 0, 1 ) ); - TEST_THROWS( connection->execute( "SELECT 42" ).is_null( 1, 0 ) ); - TEST_ASSERT( connection->execute( "SELECT 42" ).get( 0, 0 ) == std::string( "42" ) ); - TEST_THROWS( connection->execute( "SELECT 42" ).get( 0, 1 ) ); - TEST_THROWS( connection->execute( "SELECT 42" ).get( 1, 0 ) ); - TEST_ASSERT( !connection->execute( "SELECT 42" )[ 0 ].is_null( 0 ) ); - TEST_THROWS( connection->execute( "SELECT 42" )[ 0 ].is_null( 1 ) ); - TEST_ASSERT( !connection->execute( "SELECT 42" )[ 0 ][ 0 ].is_null() ); - TEST_ASSERT( connection->execute( "SELECT 42" )[ 0 ][ 0 ] != tao::pq::null ); - TEST_ASSERT( !( connection->execute( "SELECT 42" )[ 0 ][ 0 ] == tao::pq::null ) ); - TEST_THROWS( connection->execute( "SELECT 42" )[ 0 ].at( 1 ) ); - TEST_THROWS( connection->execute( "SELECT 42" ).at( 1 )[ 1 ] ); - - TEST_ASSERT( connection->execute( "SELECT 42" ).as< int >() == 42 ); - TEST_ASSERT( connection->execute( "SELECT 1764" ).optional< int >() == 1764 ); - TEST_ASSERT( !connection->execute( "SELECT 64 WHERE FALSE" ).optional< int >() ); - TEST_ASSERT( !connection->execute( "SELECT NULL" ).as< std::optional< int > >() ); - - TEST_ASSERT( connection->execute( "SELECT 42" ).tuple< int >() == std::tuple< int >( 42 ) ); - - TEST_ASSERT( connection->execute( "SELECT 1, 2" ).pair< int, int >() == std::pair< int, int >( 1, 2 ) ); - TEST_ASSERT( connection->execute( "SELECT 1, 2, 3, 4" ).tuple< int, int, int, int >() == std::tuple< int, int, int, int >( 1, 2, 3, 4 ) ); - - TEST_ASSERT( connection->execute( "SELECT 42" ).columns() == 1 ); - TEST_ASSERT( connection->execute( "SELECT 42" ).vector< int >().size() == 1 ); - TEST_ASSERT( connection->execute( "SELECT 42" ).list< int >().size() == 1 ); - TEST_ASSERT( connection->execute( "SELECT 42" ).set< int >().size() == 1 ); - TEST_ASSERT( connection->execute( "SELECT 42" ).multiset< int >().size() == 1 ); - TEST_ASSERT( connection->execute( "SELECT 42" ).unordered_set< int >().size() == 1 ); - TEST_ASSERT( connection->execute( "SELECT 42" ).unordered_multiset< int >().size() == 1 ); - - TEST_THROWS( connection->execute( "SELECT 42" ).as< bool >() ); - - TEST_ASSERT( connection->execute( "SELECT 1, 2" ).columns() == 2 ); - TEST_ASSERT( connection->execute( "SELECT 1, 2" ).map< int, int >().size() == 1 ); - TEST_ASSERT( connection->execute( "SELECT 1, 2" ).multimap< int, int >().size() == 1 ); - TEST_ASSERT( connection->execute( "SELECT 1, 2" ).unordered_map< int, int >().size() == 1 ); - TEST_ASSERT( connection->execute( "SELECT 1, 2" ).unordered_multimap< int, int >().size() == 1 ); - - TEST_ASSERT( connection->execute( "SELECT 1 UNION ALL SELECT 2" ).list< int >().size() == 2 ); - TEST_ASSERT( connection->execute( "SELECT 1, 2, 3, 4 UNION ALL SELECT 5, 6, 7, 8" ).list< std::tuple< int, int, int, int > >().size() == 2 ); - TEST_ASSERT( connection->execute( "SELECT 1, 2 UNION ALL SELECT 2, 5 UNION ALL SELECT 3, 42" ).map< int, int >().size() == 3 ); - - const auto result = connection->execute( "SELECT 1 AS a, 2 AS B, 3 AS \"C\"" ); - - TEST_ASSERT( result.has_rows_affected() ); - TEST_ASSERT( !result.empty() ); - TEST_ASSERT( result.size() == 1 ); - TEST_ASSERT( result.columns() == 3 ); - TEST_ASSERT( result.at( 0 ).columns() == 3 ); - TEST_THROWS( result.at( 1 ) ); - - TEST_ASSERT( result.name( 0 ) == "a" ); - TEST_ASSERT( result.name( 1 ) == "b" ); - TEST_ASSERT( result.name( 2 ) == "C" ); - - TEST_ASSERT( result.index( "a" ) == 0 ); - TEST_ASSERT( result.index( "A" ) == 0 ); - TEST_ASSERT( result.index( "\"a\"" ) == 0 ); - TEST_THROWS( result.index( "\"A\"" ) ); - - TEST_ASSERT( result.index( "b" ) == 1 ); - TEST_ASSERT( result.index( "B" ) == 1 ); - TEST_ASSERT( result.index( "\"b\"" ) == 1 ); - TEST_THROWS( result.index( "\"B\"" ) ); - - TEST_THROWS( result.index( "c" ) ); - TEST_THROWS( result.index( "C" ) ); - TEST_THROWS( result.index( "\"c\"" ) ); - TEST_ASSERT( result.index( "\"C\"" ) == 2 ); - - TEST_THROWS( connection->execute( "SELECT 42 WHERE FALSE" ).as< int >() ); - TEST_THROWS( connection->execute( "SELECT 1 UNION ALL SELECT 2" ).as< int >() ); - - TEST_THROWS( connection->execute( "SELECT 42" ).pair< int, int >() ); - TEST_THROWS( connection->execute( "SELECT 1, 2" ).as< int >() ); - - TEST_THROWS( connection->execute( "SELECT ''" ).as< char >() ); - TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< char >() ); - - TEST_THROWS( connection->execute( "SELECT ''" ).as< signed char >() ); - TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< signed char >() ); - TEST_THROWS( connection->execute( "SELECT -129" ).as< signed char >() ); - TEST_ASSERT( connection->execute( "SELECT -128" ).as< signed char >() == -128 ); - TEST_ASSERT( connection->execute( "SELECT 127" ).as< signed char >() == 127 ); - TEST_THROWS( connection->execute( "SELECT 128" ).as< signed char >() ); - - TEST_THROWS( connection->execute( "SELECT ''" ).as< unsigned char >() ); - TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< unsigned char >() ); - TEST_ASSERT( connection->execute( "SELECT 255" ).as< unsigned char >() == 255 ); - TEST_THROWS( connection->execute( "SELECT 256" ).as< unsigned char >() ); - - TEST_THROWS( connection->execute( "SELECT ''" ).as< short >() ); - TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< short >() ); - TEST_THROWS( connection->execute( "SELECT -32769" ).as< short >() ); - TEST_ASSERT( connection->execute( "SELECT -32768" ).as< short >() == -32768 ); - TEST_ASSERT( connection->execute( "SELECT 32767" ).as< short >() == 32767 ); - TEST_THROWS( connection->execute( "SELECT 32768" ).as< short >() ); - - TEST_THROWS( connection->execute( "SELECT ''" ).as< unsigned short >() ); - TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< unsigned short >() ); - TEST_ASSERT( connection->execute( "SELECT 65535" ).as< unsigned short >() == 65535 ); - TEST_THROWS( connection->execute( "SELECT 65536" ).as< unsigned short >() ); - - TEST_THROWS( connection->execute( "SELECT ''" ).as< int >() ); - TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< int >() ); - TEST_THROWS( connection->execute( "SELECT -2147483649" ).as< int >() ); - TEST_ASSERT( connection->execute( "SELECT -2147483648" ).as< int >() == -2147483648LL ); - TEST_ASSERT( connection->execute( "SELECT 2147483647" ).as< int >() == 2147483647 ); - TEST_THROWS( connection->execute( "SELECT 2147483648" ).as< int >() ); - - TEST_THROWS( connection->execute( "SELECT ''" ).as< unsigned >() ); - TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< unsigned >() ); - TEST_ASSERT( connection->execute( "SELECT 4294967295" ).as< unsigned >() == 4294967295 ); - TEST_THROWS( connection->execute( "SELECT 4294967296" ).as< unsigned >() ); - - TEST_THROWS( connection->execute( "SELECT '42 FOO'" ).as< unsigned >() ); - TEST_THROWS( connection->execute( "SELECT '42BAR'" ).as< unsigned >() ); - - int count = 0; - for( const auto& row : connection->execute( "SELECT 1 UNION ALL SELECT 2" ) ) { - for( const auto& field : row ) { - TEST_ASSERT( field.as< int >() == ++count ); + void run() // NOLINT(readability-function-size) + { + const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); + + TEST_EXECUTE( connection->execute( "SELECT NULL" ) ); + TEST_ASSERT( connection->execute( "SELECT NULL" ).is_null( 0, 0 ) ); + TEST_THROWS( connection->execute( "SELECT NULL" ).is_null( 0, 1 ) ); + TEST_THROWS( connection->execute( "SELECT NULL" ).is_null( 1, 0 ) ); + TEST_THROWS( connection->execute( "SELECT NULL" ).get( 0, 0 ) ); + TEST_THROWS( connection->execute( "SELECT NULL" ).get( 0, 1 ) ); + TEST_THROWS( connection->execute( "SELECT NULL" ).get( 1, 0 ) ); + TEST_ASSERT( connection->execute( "SELECT NULL" )[ 0 ].is_null( 0 ) ); + TEST_THROWS( connection->execute( "SELECT NULL" )[ 0 ].is_null( 1 ) ); + TEST_ASSERT( connection->execute( "SELECT NULL" )[ 0 ][ 0 ].is_null() ); + TEST_ASSERT( connection->execute( "SELECT NULL" )[ 0 ][ 0 ] == tao::pq::null ); + TEST_ASSERT( !( connection->execute( "SELECT NULL" )[ 0 ][ 0 ] != tao::pq::null ) ); + TEST_THROWS( connection->execute( "SELECT NULL" )[ 0 ].at( 1 ) ); + TEST_THROWS( connection->execute( "SELECT NULL" ).at( 1 )[ 1 ] ); + + TEST_EXECUTE( connection->execute( "SELECT 42" ) ); + TEST_ASSERT( !connection->execute( "SELECT 42" ).is_null( 0, 0 ) ); + TEST_THROWS( connection->execute( "SELECT 42" ).is_null( 0, 1 ) ); + TEST_THROWS( connection->execute( "SELECT 42" ).is_null( 1, 0 ) ); + TEST_ASSERT( connection->execute( "SELECT 42" ).get( 0, 0 ) == std::string( "42" ) ); + TEST_THROWS( connection->execute( "SELECT 42" ).get( 0, 1 ) ); + TEST_THROWS( connection->execute( "SELECT 42" ).get( 1, 0 ) ); + TEST_ASSERT( !connection->execute( "SELECT 42" )[ 0 ].is_null( 0 ) ); + TEST_THROWS( connection->execute( "SELECT 42" )[ 0 ].is_null( 1 ) ); + TEST_ASSERT( !connection->execute( "SELECT 42" )[ 0 ][ 0 ].is_null() ); + TEST_ASSERT( connection->execute( "SELECT 42" )[ 0 ][ 0 ] != tao::pq::null ); + TEST_ASSERT( !( connection->execute( "SELECT 42" )[ 0 ][ 0 ] == tao::pq::null ) ); + TEST_THROWS( connection->execute( "SELECT 42" )[ 0 ].at( 1 ) ); + TEST_THROWS( connection->execute( "SELECT 42" ).at( 1 )[ 1 ] ); + + TEST_ASSERT( connection->execute( "SELECT 42" ).as< int >() == 42 ); + TEST_ASSERT( connection->execute( "SELECT 1764" ).optional< int >() == 1764 ); + TEST_ASSERT( !connection->execute( "SELECT 64 WHERE FALSE" ).optional< int >() ); + TEST_ASSERT( !connection->execute( "SELECT NULL" ).as< std::optional< int > >() ); + + TEST_ASSERT( connection->execute( "SELECT 42" ).tuple< int >() == std::tuple< int >( 42 ) ); + + TEST_ASSERT( connection->execute( "SELECT 1, 2" ).pair< int, int >() == std::pair< int, int >( 1, 2 ) ); + TEST_ASSERT( connection->execute( "SELECT 1, 2, 3, 4" ).tuple< int, int, int, int >() == std::tuple< int, int, int, int >( 1, 2, 3, 4 ) ); + + TEST_ASSERT( connection->execute( "SELECT 42" ).columns() == 1 ); + TEST_ASSERT( connection->execute( "SELECT 42" ).vector< int >().size() == 1 ); + TEST_ASSERT( connection->execute( "SELECT 42" ).list< int >().size() == 1 ); + TEST_ASSERT( connection->execute( "SELECT 42" ).set< int >().size() == 1 ); + TEST_ASSERT( connection->execute( "SELECT 42" ).multiset< int >().size() == 1 ); + TEST_ASSERT( connection->execute( "SELECT 42" ).unordered_set< int >().size() == 1 ); + TEST_ASSERT( connection->execute( "SELECT 42" ).unordered_multiset< int >().size() == 1 ); + + TEST_THROWS( connection->execute( "SELECT 42" ).as< bool >() ); + + TEST_ASSERT( connection->execute( "SELECT 1, 2" ).columns() == 2 ); + TEST_ASSERT( connection->execute( "SELECT 1, 2" ).map< int, int >().size() == 1 ); + TEST_ASSERT( connection->execute( "SELECT 1, 2" ).multimap< int, int >().size() == 1 ); + TEST_ASSERT( connection->execute( "SELECT 1, 2" ).unordered_map< int, int >().size() == 1 ); + TEST_ASSERT( connection->execute( "SELECT 1, 2" ).unordered_multimap< int, int >().size() == 1 ); + + TEST_ASSERT( connection->execute( "SELECT 1 UNION ALL SELECT 2" ).list< int >().size() == 2 ); + TEST_ASSERT( connection->execute( "SELECT 1, 2, 3, 4 UNION ALL SELECT 5, 6, 7, 8" ).list< std::tuple< int, int, int, int > >().size() == 2 ); + TEST_ASSERT( connection->execute( "SELECT 1, 2 UNION ALL SELECT 2, 5 UNION ALL SELECT 3, 42" ).map< int, int >().size() == 3 ); + + const auto result = connection->execute( "SELECT 1 AS a, 2 AS B, 3 AS \"C\"" ); + + TEST_ASSERT( result.has_rows_affected() ); + TEST_ASSERT( !result.empty() ); + TEST_ASSERT( result.size() == 1 ); + TEST_ASSERT( result.columns() == 3 ); + TEST_ASSERT( result.at( 0 ).columns() == 3 ); + TEST_THROWS( result.at( 1 ) ); + + TEST_ASSERT( result.name( 0 ) == "a" ); + TEST_ASSERT( result.name( 1 ) == "b" ); + TEST_ASSERT( result.name( 2 ) == "C" ); + + TEST_ASSERT( result.index( "a" ) == 0 ); + TEST_ASSERT( result.index( "A" ) == 0 ); + TEST_ASSERT( result.index( "\"a\"" ) == 0 ); + TEST_THROWS( result.index( "\"A\"" ) ); + + TEST_ASSERT( result.index( "b" ) == 1 ); + TEST_ASSERT( result.index( "B" ) == 1 ); + TEST_ASSERT( result.index( "\"b\"" ) == 1 ); + TEST_THROWS( result.index( "\"B\"" ) ); + + TEST_THROWS( result.index( "c" ) ); + TEST_THROWS( result.index( "C" ) ); + TEST_THROWS( result.index( "\"c\"" ) ); + TEST_ASSERT( result.index( "\"C\"" ) == 2 ); + + TEST_THROWS( connection->execute( "SELECT 42 WHERE FALSE" ).as< int >() ); + TEST_THROWS( connection->execute( "SELECT 1 UNION ALL SELECT 2" ).as< int >() ); + + TEST_THROWS( connection->execute( "SELECT 42" ).pair< int, int >() ); + TEST_THROWS( connection->execute( "SELECT 1, 2" ).as< int >() ); + + TEST_THROWS( connection->execute( "SELECT ''" ).as< char >() ); + TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< char >() ); + + TEST_THROWS( connection->execute( "SELECT ''" ).as< signed char >() ); + TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< signed char >() ); + TEST_THROWS( connection->execute( "SELECT -129" ).as< signed char >() ); + TEST_ASSERT( connection->execute( "SELECT -128" ).as< signed char >() == -128 ); + TEST_ASSERT( connection->execute( "SELECT 127" ).as< signed char >() == 127 ); + TEST_THROWS( connection->execute( "SELECT 128" ).as< signed char >() ); + + TEST_THROWS( connection->execute( "SELECT ''" ).as< unsigned char >() ); + TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< unsigned char >() ); + TEST_ASSERT( connection->execute( "SELECT 255" ).as< unsigned char >() == 255 ); + TEST_THROWS( connection->execute( "SELECT 256" ).as< unsigned char >() ); + + TEST_THROWS( connection->execute( "SELECT ''" ).as< short >() ); + TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< short >() ); + TEST_THROWS( connection->execute( "SELECT -32769" ).as< short >() ); + TEST_ASSERT( connection->execute( "SELECT -32768" ).as< short >() == -32768 ); + TEST_ASSERT( connection->execute( "SELECT 32767" ).as< short >() == 32767 ); + TEST_THROWS( connection->execute( "SELECT 32768" ).as< short >() ); + + TEST_THROWS( connection->execute( "SELECT ''" ).as< unsigned short >() ); + TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< unsigned short >() ); + TEST_ASSERT( connection->execute( "SELECT 65535" ).as< unsigned short >() == 65535 ); + TEST_THROWS( connection->execute( "SELECT 65536" ).as< unsigned short >() ); + + TEST_THROWS( connection->execute( "SELECT ''" ).as< int >() ); + TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< int >() ); + TEST_THROWS( connection->execute( "SELECT -2147483649" ).as< int >() ); + TEST_ASSERT( connection->execute( "SELECT -2147483648" ).as< int >() == -2147483648LL ); + TEST_ASSERT( connection->execute( "SELECT 2147483647" ).as< int >() == 2147483647 ); + TEST_THROWS( connection->execute( "SELECT 2147483648" ).as< int >() ); + + TEST_THROWS( connection->execute( "SELECT ''" ).as< unsigned >() ); + TEST_THROWS( connection->execute( "SELECT 'Hallo'" ).as< unsigned >() ); + TEST_ASSERT( connection->execute( "SELECT 4294967295" ).as< unsigned >() == 4294967295 ); + TEST_THROWS( connection->execute( "SELECT 4294967296" ).as< unsigned >() ); + + TEST_THROWS( connection->execute( "SELECT '42 FOO'" ).as< unsigned >() ); + TEST_THROWS( connection->execute( "SELECT '42BAR'" ).as< unsigned >() ); + + int count = 0; + for( const auto& row : connection->execute( "SELECT 1 UNION ALL SELECT 2" ) ) { + for( const auto& field : row ) { + TEST_ASSERT( field.as< int >() == ++count ); + } } + TEST_ASSERT( count == 2 ); } - TEST_ASSERT( count == 2 ); -} + +} // namespace auto main() -> int // NOLINT(bugprone-exception-escape) { @@ -166,11 +170,11 @@ auto main() -> int // NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/row.cpp b/src/test/pq/row.cpp index c1b491f..dcd659c 100644 --- a/src/test/pq/row.cpp +++ b/src/test/pq/row.cpp @@ -10,80 +10,84 @@ #include #include -void run() +namespace { - const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); - - TEST_ASSERT( connection->execute( "SELECT 42" )[ 0 ].as< int >() == 42 ); - TEST_ASSERT( connection->execute( "SELECT 1764" ).at( 0 ).optional< int >() == 1764 ); - TEST_ASSERT( !connection->execute( "SELECT NULL" )[ 0 ].as< std::optional< int > >() ); - - TEST_ASSERT( connection->execute( "SELECT 42" )[ 0 ][ 0 ].get() == std::string( "42" ) ); - TEST_ASSERT( connection->execute( "SELECT 42" )[ 0 ][ 0 ].as< int >() == 42 ); - TEST_ASSERT( connection->execute( "SELECT 42" )[ 0 ][ 0 ].optional< int >() == 42 ); - - TEST_ASSERT( connection->execute( "SELECT 1, 2" )[ 0 ].pair< int, int >() == std::pair< int, int >( 1, 2 ) ); - TEST_ASSERT( connection->execute( "SELECT 1, 2, 3, 4" )[ 0 ].tuple< int, int, int, int >() == std::tuple< int, int, int, int >( 1, 2, 3, 4 ) ); - - TEST_THROWS( connection->execute( "SELECT 42" )[ 0 ].as< bool >() ); - - const auto result = connection->execute( "SELECT 1 AS a, 2 AS B, 3 AS \"C\", 4 as \"A\"" ); - const auto& row = result[ 0 ]; - - TEST_ASSERT( row.columns() == 4 ); - - TEST_ASSERT( row.name( 0 ) == "a" ); - TEST_ASSERT( row.name( 1 ) == "b" ); - TEST_ASSERT( row.name( 2 ) == "C" ); - TEST_ASSERT( row.name( 3 ) == "A" ); - TEST_THROWS( row.name( 4 ) ); - - TEST_ASSERT( row.at( 0 ).name() == "a" ); - TEST_ASSERT( row[ 1 ].name() == "b" ); - TEST_ASSERT( row.at( 2 ).name() == "C" ); - TEST_ASSERT( row[ 3 ].name() == "A" ); - TEST_THROWS( row.at( 4 ) ); - - TEST_ASSERT( row.index( "a" ) == 0 ); - TEST_ASSERT( row.index( "A" ) == 0 ); - TEST_ASSERT( row.index( "\"a\"" ) == 0 ); - TEST_ASSERT( row.index( "\"A\"" ) == 3 ); - - TEST_ASSERT( row.index( "b" ) == 1 ); - TEST_ASSERT( row.index( "B" ) == 1 ); - TEST_ASSERT( row.index( "\"b\"" ) == 1 ); - TEST_THROWS( row.index( "\"B\"" ) ); - - TEST_THROWS( row.index( "c" ) ); - TEST_THROWS( row.index( "C" ) ); - TEST_THROWS( row.index( "\"c\"" ) ); - TEST_ASSERT( row.index( "\"C\"" ) == 2 ); - - TEST_THROWS( row.get< std::string >( 4 ) ); - TEST_THROWS( row.get< std::optional< std::string > >( 4 ) ); - TEST_THROWS( row.get< std::pair< std::string, std::string > >( 3 ) ); - - const auto result2 = connection->execute( "SELECT 1 AS a, 2 AS b, 3 AS a" ); - const auto& row2 = result2[ 0 ]; - - TEST_ASSERT( row2.index( "a" ) == 0 ); - TEST_ASSERT( row2.index( "A" ) == 0 ); - TEST_ASSERT( row2.slice( 1, 2 ).index( "a" ) == 1 ); - TEST_ASSERT( row2.slice( 1, 2 ).index( "A" ) == 1 ); - - TEST_THROWS( row2.slice( 1, 1 ).index( "a" ) ); - TEST_THROWS( row2.slice( 1, 1 ).index( "A" ) ); - TEST_THROWS( row2.slice( 2, 1 ).index( "b" ) ); - TEST_THROWS( row2.slice( 2, 1 ).index( "B" ) ); - - TEST_THROWS( row2.slice( 0, 0 ) ); - TEST_THROWS( row2.slice( 1, 0 ) ); - TEST_THROWS( row2.slice( 2, 0 ) ); + void run() + { + const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); + + TEST_ASSERT( connection->execute( "SELECT 42" )[ 0 ].as< int >() == 42 ); + TEST_ASSERT( connection->execute( "SELECT 1764" ).at( 0 ).optional< int >() == 1764 ); + TEST_ASSERT( !connection->execute( "SELECT NULL" )[ 0 ].as< std::optional< int > >() ); + + TEST_ASSERT( connection->execute( "SELECT 42" )[ 0 ][ 0 ].get() == std::string( "42" ) ); + TEST_ASSERT( connection->execute( "SELECT 42" )[ 0 ][ 0 ].as< int >() == 42 ); + TEST_ASSERT( connection->execute( "SELECT 42" )[ 0 ][ 0 ].optional< int >() == 42 ); + + TEST_ASSERT( connection->execute( "SELECT 1, 2" )[ 0 ].pair< int, int >() == std::pair< int, int >( 1, 2 ) ); + TEST_ASSERT( connection->execute( "SELECT 1, 2, 3, 4" )[ 0 ].tuple< int, int, int, int >() == std::tuple< int, int, int, int >( 1, 2, 3, 4 ) ); + + TEST_THROWS( connection->execute( "SELECT 42" )[ 0 ].as< bool >() ); + + const auto result = connection->execute( "SELECT 1 AS a, 2 AS B, 3 AS \"C\", 4 as \"A\"" ); + const auto& row = result[ 0 ]; + + TEST_ASSERT( row.columns() == 4 ); + + TEST_ASSERT( row.name( 0 ) == "a" ); + TEST_ASSERT( row.name( 1 ) == "b" ); + TEST_ASSERT( row.name( 2 ) == "C" ); + TEST_ASSERT( row.name( 3 ) == "A" ); + TEST_THROWS( row.name( 4 ) ); + + TEST_ASSERT( row.at( 0 ).name() == "a" ); + TEST_ASSERT( row[ 1 ].name() == "b" ); + TEST_ASSERT( row.at( 2 ).name() == "C" ); + TEST_ASSERT( row[ 3 ].name() == "A" ); + TEST_THROWS( row.at( 4 ) ); + + TEST_ASSERT( row.index( "a" ) == 0 ); + TEST_ASSERT( row.index( "A" ) == 0 ); + TEST_ASSERT( row.index( "\"a\"" ) == 0 ); + TEST_ASSERT( row.index( "\"A\"" ) == 3 ); + + TEST_ASSERT( row.index( "b" ) == 1 ); + TEST_ASSERT( row.index( "B" ) == 1 ); + TEST_ASSERT( row.index( "\"b\"" ) == 1 ); + TEST_THROWS( row.index( "\"B\"" ) ); + + TEST_THROWS( row.index( "c" ) ); + TEST_THROWS( row.index( "C" ) ); + TEST_THROWS( row.index( "\"c\"" ) ); + TEST_ASSERT( row.index( "\"C\"" ) == 2 ); + + TEST_THROWS( row.get< std::string >( 4 ) ); + TEST_THROWS( row.get< std::optional< std::string > >( 4 ) ); + TEST_THROWS( row.get< std::pair< std::string, std::string > >( 3 ) ); + + const auto result2 = connection->execute( "SELECT 1 AS a, 2 AS b, 3 AS a" ); + const auto& row2 = result2[ 0 ]; + + TEST_ASSERT( row2.index( "a" ) == 0 ); + TEST_ASSERT( row2.index( "A" ) == 0 ); + TEST_ASSERT( row2.slice( 1, 2 ).index( "a" ) == 1 ); + TEST_ASSERT( row2.slice( 1, 2 ).index( "A" ) == 1 ); + + TEST_THROWS( row2.slice( 1, 1 ).index( "a" ) ); + TEST_THROWS( row2.slice( 1, 1 ).index( "A" ) ); + TEST_THROWS( row2.slice( 2, 1 ).index( "b" ) ); + TEST_THROWS( row2.slice( 2, 1 ).index( "B" ) ); + + TEST_THROWS( row2.slice( 0, 0 ) ); + TEST_THROWS( row2.slice( 1, 0 ) ); + TEST_THROWS( row2.slice( 2, 0 ) ); + + TEST_THROWS( row2.slice( 0, 4 ) ); + TEST_THROWS( row2.slice( 1, 3 ) ); + TEST_THROWS( row2.slice( 2, 2 ) ); + } - TEST_THROWS( row2.slice( 0, 4 ) ); - TEST_THROWS( row2.slice( 1, 3 ) ); - TEST_THROWS( row2.slice( 2, 2 ) ); -} +} // namespace auto main() -> int // NOLINT(bugprone-exception-escape) { @@ -92,11 +96,11 @@ auto main() -> int // NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/strtox.cpp b/src/test/pq/strtox.cpp index b81885b..cce69d0 100644 --- a/src/test/pq/strtox.cpp +++ b/src/test/pq/strtox.cpp @@ -16,107 +16,111 @@ auto main() -> int {} #include -template< typename T > -void reject_floating_point( const char* input ) +namespace { - try { - std::ignore = tao::pq::internal::strtof( input ); - throw std::runtime_error( std::format( "strtof(): {}", input ) ); // LCOV_EXCL_LINE - } - catch( const T& e ) { - if( e.what() != "tao::pq::internal::strtof() failed for input: " + std::string( input ) ) { - throw; // LCOV_EXCL_LINE + template< typename T > + void reject_floating_point( const char* input ) + { + try { + std::ignore = tao::pq::internal::strtof( input ); + throw std::runtime_error( std::format( "strtof(): {}", input ) ); // LCOV_EXCL_LINE } - } - try { - std::ignore = tao::pq::internal::strtod( input ); - throw std::runtime_error( std::format( "strtod(): {}", input ) ); // LCOV_EXCL_LINE - } - catch( const T& e ) { - if( e.what() != "tao::pq::internal::strtod() failed for input: " + std::string( input ) ) { - throw; // LCOV_EXCL_LINE + catch( const T& e ) { + if( e.what() != "tao::pq::internal::strtof() failed for input: " + std::string( input ) ) { + throw; // LCOV_EXCL_LINE + } } - } - try { - std::ignore = tao::pq::internal::strtold( input ); - throw std::runtime_error( std::format( "strtold(): {}", input ) ); // LCOV_EXCL_LINE - } - catch( const T& e ) { - if( e.what() != "tao::pq::internal::strtold() failed for input: " + std::string( input ) ) { - throw; // LCOV_EXCL_LINE + try { + std::ignore = tao::pq::internal::strtod( input ); + throw std::runtime_error( std::format( "strtod(): {}", input ) ); // LCOV_EXCL_LINE + } + catch( const T& e ) { + if( e.what() != "tao::pq::internal::strtod() failed for input: " + std::string( input ) ) { + throw; // LCOV_EXCL_LINE + } + } + try { + std::ignore = tao::pq::internal::strtold( input ); + throw std::runtime_error( std::format( "strtold(): {}", input ) ); // LCOV_EXCL_LINE + } + catch( const T& e ) { + if( e.what() != "tao::pq::internal::strtold() failed for input: " + std::string( input ) ) { + throw; // LCOV_EXCL_LINE + } } } -} -void run() -{ - TEST_ASSERT( tao::pq::internal::strtof( "0" ) == 0 ); - TEST_ASSERT( tao::pq::internal::strtof( "1" ) == 1 ); - TEST_ASSERT( tao::pq::internal::strtof( "00" ) == 0 ); - TEST_ASSERT( tao::pq::internal::strtof( "01" ) == 1 ); - TEST_ASSERT( tao::pq::internal::strtof( "0." ) == 0 ); - TEST_ASSERT( tao::pq::internal::strtof( "1." ) == 1 ); - TEST_ASSERT( tao::pq::internal::strtof( "0.0" ) == 0 ); - TEST_ASSERT( tao::pq::internal::strtof( "1.0" ) == 1 ); - TEST_ASSERT( tao::pq::internal::strtof( "0.5" ) == .5 ); - TEST_ASSERT( tao::pq::internal::strtof( ".5" ) == .5 ); - TEST_ASSERT( tao::pq::internal::strtof( ".25" ) == .25 ); - TEST_ASSERT( tao::pq::internal::strtof( ".125" ) == .125 ); - TEST_ASSERT( tao::pq::internal::strtof( ".0625" ) == .0625 ); - TEST_ASSERT( tao::pq::internal::strtof( ".4375" ) == .4375 ); - - TEST_ASSERT( tao::pq::internal::strtof( "-0" ) == 0 ); - TEST_ASSERT( tao::pq::internal::strtof( "-1" ) == -1 ); - TEST_ASSERT( tao::pq::internal::strtof( "-00" ) == 0 ); - TEST_ASSERT( tao::pq::internal::strtof( "-01" ) == -1 ); - TEST_ASSERT( tao::pq::internal::strtof( "-0." ) == 0 ); - TEST_ASSERT( tao::pq::internal::strtof( "-1." ) == -1 ); - TEST_ASSERT( tao::pq::internal::strtof( "-0.0" ) == 0 ); - TEST_ASSERT( tao::pq::internal::strtof( "-1.0" ) == -1 ); - TEST_ASSERT( tao::pq::internal::strtof( "-0.5" ) == -.5 ); - TEST_ASSERT( tao::pq::internal::strtof( "-.5" ) == -.5 ); - TEST_ASSERT( tao::pq::internal::strtof( "-.25" ) == -.25 ); - TEST_ASSERT( tao::pq::internal::strtof( "-.125" ) == -.125 ); - TEST_ASSERT( tao::pq::internal::strtof( "-.0625" ) == -.0625 ); - TEST_ASSERT( tao::pq::internal::strtof( "-.4375" ) == -.4375 ); - - TEST_ASSERT( tao::pq::internal::strtof( "3.1415927410125732421875" ) == 3.1415927410125732421875 ); - TEST_ASSERT( tao::pq::internal::strtod( "3.1415927410125732421875" ) == 3.1415927410125732421875 ); - TEST_ASSERT( tao::pq::internal::strtold( "3.1415927410125732421875" ) == 3.1415927410125732421875 ); - - TEST_ASSERT( tao::pq::internal::strtof( "0000000000000000000000000000000000000.0000000000000000000000000000000000000" ) == 0 ); - TEST_ASSERT( tao::pq::internal::strtof( "0000000000000000000000000000000000001.0000000000000000000000000000000000000" ) == 1 ); - - TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "inf" ) ) ); - TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "INF" ) ) ); - TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "infinity" ) ) ); - TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "INFINITY" ) ) ); - TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "-inf" ) ) ); - TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "-INF" ) ) ); - TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "-infinity" ) ) ); - TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "-INFINITY" ) ) ); - TEST_ASSERT( std::isnan( tao::pq::internal::strtof( "nan" ) ) ); - TEST_ASSERT( std::isnan( tao::pq::internal::strtof( "NaN" ) ) ); - TEST_ASSERT( std::isnan( tao::pq::internal::strtof( "NAN" ) ) ); - - TEST_ASSERT( tao::pq::internal::strtof( "inf" ) > 0 ); - TEST_ASSERT( tao::pq::internal::strtof( "-inf" ) < 0 ); - - reject_floating_point< std::runtime_error >( "" ); - reject_floating_point< std::runtime_error >( " " ); - reject_floating_point< std::runtime_error >( "+" ); - reject_floating_point< std::runtime_error >( "-" ); - reject_floating_point< std::runtime_error >( " 0" ); - reject_floating_point< std::runtime_error >( "0 " ); - reject_floating_point< std::runtime_error >( "0x" ); - reject_floating_point< std::runtime_error >( " 1" ); - reject_floating_point< std::runtime_error >( "1 " ); - - reject_floating_point< std::overflow_error >( "1e10000" ); - reject_floating_point< std::overflow_error >( "-1e10000" ); - reject_floating_point< std::underflow_error >( "1e-10000" ); - reject_floating_point< std::underflow_error >( "-1e-10000" ); -} + void run() + { + TEST_ASSERT( tao::pq::internal::strtof( "0" ) == 0 ); + TEST_ASSERT( tao::pq::internal::strtof( "1" ) == 1 ); + TEST_ASSERT( tao::pq::internal::strtof( "00" ) == 0 ); + TEST_ASSERT( tao::pq::internal::strtof( "01" ) == 1 ); + TEST_ASSERT( tao::pq::internal::strtof( "0." ) == 0 ); + TEST_ASSERT( tao::pq::internal::strtof( "1." ) == 1 ); + TEST_ASSERT( tao::pq::internal::strtof( "0.0" ) == 0 ); + TEST_ASSERT( tao::pq::internal::strtof( "1.0" ) == 1 ); + TEST_ASSERT( tao::pq::internal::strtof( "0.5" ) == .5 ); + TEST_ASSERT( tao::pq::internal::strtof( ".5" ) == .5 ); + TEST_ASSERT( tao::pq::internal::strtof( ".25" ) == .25 ); + TEST_ASSERT( tao::pq::internal::strtof( ".125" ) == .125 ); + TEST_ASSERT( tao::pq::internal::strtof( ".0625" ) == .0625 ); + TEST_ASSERT( tao::pq::internal::strtof( ".4375" ) == .4375 ); + + TEST_ASSERT( tao::pq::internal::strtof( "-0" ) == 0 ); + TEST_ASSERT( tao::pq::internal::strtof( "-1" ) == -1 ); + TEST_ASSERT( tao::pq::internal::strtof( "-00" ) == 0 ); + TEST_ASSERT( tao::pq::internal::strtof( "-01" ) == -1 ); + TEST_ASSERT( tao::pq::internal::strtof( "-0." ) == 0 ); + TEST_ASSERT( tao::pq::internal::strtof( "-1." ) == -1 ); + TEST_ASSERT( tao::pq::internal::strtof( "-0.0" ) == 0 ); + TEST_ASSERT( tao::pq::internal::strtof( "-1.0" ) == -1 ); + TEST_ASSERT( tao::pq::internal::strtof( "-0.5" ) == -.5 ); + TEST_ASSERT( tao::pq::internal::strtof( "-.5" ) == -.5 ); + TEST_ASSERT( tao::pq::internal::strtof( "-.25" ) == -.25 ); + TEST_ASSERT( tao::pq::internal::strtof( "-.125" ) == -.125 ); + TEST_ASSERT( tao::pq::internal::strtof( "-.0625" ) == -.0625 ); + TEST_ASSERT( tao::pq::internal::strtof( "-.4375" ) == -.4375 ); + + TEST_ASSERT( tao::pq::internal::strtof( "3.1415927410125732421875" ) == 3.1415927410125732421875 ); + TEST_ASSERT( tao::pq::internal::strtod( "3.1415927410125732421875" ) == 3.1415927410125732421875 ); + TEST_ASSERT( tao::pq::internal::strtold( "3.1415927410125732421875" ) == 3.1415927410125732421875 ); + + TEST_ASSERT( tao::pq::internal::strtof( "0000000000000000000000000000000000000.0000000000000000000000000000000000000" ) == 0 ); + TEST_ASSERT( tao::pq::internal::strtof( "0000000000000000000000000000000000001.0000000000000000000000000000000000000" ) == 1 ); + + TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "inf" ) ) ); + TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "INF" ) ) ); + TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "infinity" ) ) ); + TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "INFINITY" ) ) ); + TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "-inf" ) ) ); + TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "-INF" ) ) ); + TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "-infinity" ) ) ); + TEST_ASSERT( std::isinf( tao::pq::internal::strtof( "-INFINITY" ) ) ); + TEST_ASSERT( std::isnan( tao::pq::internal::strtof( "nan" ) ) ); + TEST_ASSERT( std::isnan( tao::pq::internal::strtof( "NaN" ) ) ); + TEST_ASSERT( std::isnan( tao::pq::internal::strtof( "NAN" ) ) ); + + TEST_ASSERT( tao::pq::internal::strtof( "inf" ) > 0 ); + TEST_ASSERT( tao::pq::internal::strtof( "-inf" ) < 0 ); + + reject_floating_point< std::runtime_error >( "" ); + reject_floating_point< std::runtime_error >( " " ); + reject_floating_point< std::runtime_error >( "+" ); + reject_floating_point< std::runtime_error >( "-" ); + reject_floating_point< std::runtime_error >( " 0" ); + reject_floating_point< std::runtime_error >( "0 " ); + reject_floating_point< std::runtime_error >( "0x" ); + reject_floating_point< std::runtime_error >( " 1" ); + reject_floating_point< std::runtime_error >( "1 " ); + + reject_floating_point< std::overflow_error >( "1e10000" ); + reject_floating_point< std::overflow_error >( "-1e10000" ); + reject_floating_point< std::underflow_error >( "1e-10000" ); + reject_floating_point< std::underflow_error >( "-1e-10000" ); + } + +} // namespace auto main() -> int // NOLINT(bugprone-exception-escape) { @@ -125,11 +129,11 @@ auto main() -> int // NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/table_reader.cpp b/src/test/pq/table_reader.cpp index 584e516..8393b17 100644 --- a/src/test/pq/table_reader.cpp +++ b/src/test/pq/table_reader.cpp @@ -8,105 +8,109 @@ #include -void run() +namespace { - const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); - connection->execute( "DROP TABLE IF EXISTS tao_table_reader_test" ); - connection->execute( "CREATE TABLE tao_table_reader_test ( a INTEGER NOT NULL, b DOUBLE PRECISION, c TEXT )" ); - - // we use a table_writer to fill the table with 100.000 rows. + void run() { - tao::pq::table_writer tw( connection->direct(), "COPY tao_table_reader_test ( a, b, c ) FROM STDIN" ); - for( unsigned n = 0; n < 100000; ++n ) { - tw.insert( n, n / 100.0, "EUR" ); + const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); + connection->execute( "DROP TABLE IF EXISTS tao_table_reader_test" ); + connection->execute( "CREATE TABLE tao_table_reader_test ( a INTEGER NOT NULL, b DOUBLE PRECISION, c TEXT )" ); + + // we use a table_writer to fill the table with 100.000 rows. + { + tao::pq::table_writer tw( connection->direct(), "COPY tao_table_reader_test ( a, b, c ) FROM STDIN" ); + for( unsigned n = 0; n < 100000; ++n ) { + tw.insert( n, n / 100.0, "EUR" ); + } + TEST_ASSERT_MESSAGE( "validate reported result size", tw.commit() == 100000 ); + TEST_ASSERT_MESSAGE( "validate actual result size", connection->execute( "SELECT COUNT(*) FROM tao_table_reader_test" ).as< std::size_t >() == 100000 ); } - TEST_ASSERT_MESSAGE( "validate reported result size", tw.commit() == 100000 ); - TEST_ASSERT_MESSAGE( "validate actual result size", connection->execute( "SELECT COUNT(*) FROM tao_table_reader_test" ).as< std::size_t >() == 100000 ); - } - { - tao::pq::table_reader tr( connection->direct(), "COPY tao_table_reader_test ( a, b, c ) TO STDOUT" ); - TEST_THROWS( connection->direct() ); + { + tao::pq::table_reader tr( connection->direct(), "COPY tao_table_reader_test ( a, b, c ) TO STDOUT" ); + TEST_THROWS( connection->direct() ); - std::size_t count = 0; - for( const auto& row : tr ) { - for( const auto& field : row ) { - if( !field.is_null() ) { - ++count; + std::size_t count = 0; + for( const auto& row : tr ) { + for( const auto& field : row ) { + if( !field.is_null() ) { + ++count; + } } } + TEST_ASSERT_MESSAGE( "validate count", count == 300000 ); } - TEST_ASSERT_MESSAGE( "validate count", count == 300000 ); - } - TEST_THROWS( tao::pq::table_reader( connection->direct(), "SELECT 42" ) ); - TEST_THROWS( tao::pq::table_reader( connection->direct(), "" ) ); - TEST_THROWS( tao::pq::table_reader( connection->direct(), "COPY tao_table_reader_test ( a, b, c, d ) TO STDOUT" ) ); - TEST_THROWS( tao::pq::table_reader( connection->direct(), "COPY tao_table_reader_test ( a, b, c ) FROM STDIN" ) ); + TEST_THROWS( tao::pq::table_reader( connection->direct(), "SELECT 42" ) ); + TEST_THROWS( tao::pq::table_reader( connection->direct(), "" ) ); + TEST_THROWS( tao::pq::table_reader( connection->direct(), "COPY tao_table_reader_test ( a, b, c, d ) TO STDOUT" ) ); + TEST_THROWS( tao::pq::table_reader( connection->direct(), "COPY tao_table_reader_test ( a, b, c ) FROM STDIN" ) ); - TEST_THROWS( connection->execute( "COPY tao_table_reader_test ( a, b, c ) TO STDOUT" ) ); + TEST_THROWS( connection->execute( "COPY tao_table_reader_test ( a, b, c ) TO STDOUT" ) ); - connection->execute( "DROP TABLE IF EXISTS tao_table_reader_test" ); - connection->execute( "CREATE TABLE tao_table_reader_test ( a BYTEA )" ); - { - tao::pq::table_writer tw( connection->direct(), "COPY tao_table_reader_test ( a ) FROM STDIN" ); - tw.insert( tao::pq::to_binary_view( "1" ) ); - tw.insert( tao::pq::binary_view() ); - tw.insert( tao::pq::null ); - tw.insert( tao::pq::to_binary_view( "F\"O\\O" ) ); - tw.insert( tao::pq::to_binary_view( "NU\0LL" ) ); - TEST_ASSERT( tw.commit() == 5 ); + connection->execute( "DROP TABLE IF EXISTS tao_table_reader_test" ); + connection->execute( "CREATE TABLE tao_table_reader_test ( a BYTEA )" ); + { + tao::pq::table_writer tw( connection->direct(), "COPY tao_table_reader_test ( a ) FROM STDIN" ); + tw.insert( tao::pq::to_binary_view( "1" ) ); + tw.insert( tao::pq::binary_view() ); + tw.insert( tao::pq::null ); + tw.insert( tao::pq::to_binary_view( "F\"O\\O" ) ); + tw.insert( tao::pq::to_binary_view( "NU\0LL" ) ); + TEST_ASSERT( tw.commit() == 5 ); - tao::pq::table_reader tr( connection->direct(), "COPY tao_table_reader_test ( a ) TO STDOUT" ); - const auto result = tr.vector< std::optional< tao::pq::binary > >(); - TEST_ASSERT( result.size() == 5 ); - TEST_ASSERT( tao::pq::internal::compare( result[ 0 ].value(), tao::pq::to_binary_view( "1" ) ) ); - TEST_ASSERT( tao::pq::internal::compare( result[ 1 ].value(), tao::pq::binary_view() ) ); - TEST_ASSERT( !result[ 2 ] ); - TEST_ASSERT( tao::pq::internal::compare( result[ 3 ].value(), tao::pq::to_binary_view( "F\"O\\O" ) ) ); - TEST_ASSERT( tao::pq::internal::compare( result[ 4 ].value(), tao::pq::to_binary_view( "NU\0LL" ) ) ); - } + tao::pq::table_reader tr( connection->direct(), "COPY tao_table_reader_test ( a ) TO STDOUT" ); + const auto result = tr.vector< std::optional< tao::pq::binary > >(); + TEST_ASSERT( result.size() == 5 ); + TEST_ASSERT( tao::pq::internal::compare( result[ 0 ].value(), tao::pq::to_binary_view( "1" ) ) ); + TEST_ASSERT( tao::pq::internal::compare( result[ 1 ].value(), tao::pq::binary_view() ) ); + TEST_ASSERT( !result[ 2 ] ); + TEST_ASSERT( tao::pq::internal::compare( result[ 3 ].value(), tao::pq::to_binary_view( "F\"O\\O" ) ) ); + TEST_ASSERT( tao::pq::internal::compare( result[ 4 ].value(), tao::pq::to_binary_view( "NU\0LL" ) ) ); + } - connection->execute( "DROP TABLE IF EXISTS tao_table_reader_test" ); - connection->execute( "CREATE TABLE tao_table_reader_test ( a INTEGER NOT NULL, b DOUBLE PRECISION, c TEXT )" ); - connection->execute( "INSERT INTO tao_table_reader_test VALUES( $1, $2, $3 )", 1, 3.141592, "A\bB\fC\"D'E\n\rF\tGH\vI\\J" ); - connection->execute( "INSERT INTO tao_table_reader_test VALUES( $1, $2, $3 )", 2, tao::pq::null, tao::pq::null ); - connection->execute( "INSERT INTO tao_table_reader_test VALUES( $1, $2, $3 )", 3, 42, "FOO" ); + connection->execute( "DROP TABLE IF EXISTS tao_table_reader_test" ); + connection->execute( "CREATE TABLE tao_table_reader_test ( a INTEGER NOT NULL, b DOUBLE PRECISION, c TEXT )" ); + connection->execute( "INSERT INTO tao_table_reader_test VALUES( $1, $2, $3 )", 1, 1.234567, "A\bB\fC\"D'E\n\rF\tGH\vI\\J" ); + connection->execute( "INSERT INTO tao_table_reader_test VALUES( $1, $2, $3 )", 2, tao::pq::null, tao::pq::null ); + connection->execute( "INSERT INTO tao_table_reader_test VALUES( $1, $2, $3 )", 3, 42, "FOO" ); - { - tao::pq::table_reader tr( connection->direct(), "COPY tao_table_reader_test ( a, b, c ) TO STDOUT" ); - TEST_ASSERT( tr.columns() == 3 ); { - TEST_ASSERT( tr.get_row() ); - const auto& row = tr.row(); - auto [ a, b, c ] = row.tuple< int, std::optional< double >, std::optional< std::string_view > >(); - TEST_ASSERT( a == 1 ); - TEST_ASSERT( b == 3.141592 ); - TEST_ASSERT( c == "A\bB\fC\"D'E\n\rF\tGH\vI\\J" ); + tao::pq::table_reader tr( connection->direct(), "COPY tao_table_reader_test ( a, b, c ) TO STDOUT" ); + TEST_ASSERT( tr.columns() == 3 ); + { + TEST_ASSERT( tr.get_row() ); + const auto& row = tr.row(); + auto [ a, b, c ] = row.tuple< int, std::optional< double >, std::optional< std::string_view > >(); + TEST_ASSERT( a == 1 ); + TEST_ASSERT( b == 1.234567 ); + TEST_ASSERT( c == "A\bB\fC\"D'E\n\rF\tGH\vI\\J" ); - TEST_ASSERT( row.at( 0 ).as< int >() == 1 ); - TEST_ASSERT( !row[ 1 ].is_null() ); - TEST_ASSERT( row[ 1 ].get() == std::string_view( "3.141592" ) ); - TEST_ASSERT( row[ 1 ].optional< double >() == 3.141592 ); - TEST_THROWS( row.at( 3 ) ); - TEST_THROWS( row.slice( 0, 0 ) ); - TEST_THROWS( row.slice( 1, 0 ) ); - TEST_THROWS( row.slice( 0, 4 ) ); - TEST_THROWS( row.tuple< int, std::optional< double > >() ); - TEST_THROWS( row.tuple< int, std::optional< double >, std::optional< std::string_view >, std::optional< std::string_view > >() ); - } - { - TEST_ASSERT( tr.get_row() ); - auto [ a, b, c ] = tr.row().tuple< int, std::optional< double >, std::optional< std::string_view > >(); - TEST_ASSERT( a == 2 ); - TEST_ASSERT( !b ); - TEST_ASSERT( !c ); - TEST_THROWS( tr.row().tuple< int, double, std::string_view >() ); + TEST_ASSERT( row.at( 0 ).as< int >() == 1 ); + TEST_ASSERT( !row[ 1 ].is_null() ); + TEST_ASSERT( row[ 1 ].get() == std::string_view( "1.234567" ) ); + TEST_ASSERT( row[ 1 ].optional< double >() == 1.234567 ); + TEST_THROWS( row.at( 3 ) ); + TEST_THROWS( row.slice( 0, 0 ) ); + TEST_THROWS( row.slice( 1, 0 ) ); + TEST_THROWS( row.slice( 0, 4 ) ); + TEST_THROWS( row.tuple< int, std::optional< double > >() ); + TEST_THROWS( row.tuple< int, std::optional< double >, std::optional< std::string_view >, std::optional< std::string_view > >() ); + } + { + TEST_ASSERT( tr.get_row() ); + auto [ a, b, c ] = tr.row().tuple< int, std::optional< double >, std::optional< std::string_view > >(); + TEST_ASSERT( a == 2 ); + TEST_ASSERT( !b ); + TEST_ASSERT( !c ); + TEST_THROWS( tr.row().tuple< int, double, std::string_view >() ); + } + PQclear( PQexec( connection->underlying_raw_ptr(), "SELECT 42" ) ); + TEST_THROWS( tr.get_row() ); } - PQclear( PQexec( connection->underlying_raw_ptr(), "SELECT 42" ) ); - TEST_THROWS( tr.get_row() ); } -} + +} // namespace auto main() -> int // NOLINT(bugprone-exception-escape) { @@ -115,11 +119,11 @@ auto main() -> int // NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/table_writer.cpp b/src/test/pq/table_writer.cpp index fb797d3..cfde40d 100644 --- a/src/test/pq/table_writer.cpp +++ b/src/test/pq/table_writer.cpp @@ -7,81 +7,85 @@ #include -void run() +namespace { - const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); - connection->execute( "DROP TABLE IF EXISTS tao_table_writer_test" ); - connection->execute( "CREATE TABLE tao_table_writer_test ( a INTEGER NOT NULL, b DOUBLE PRECISION, c TEXT )" ); - - tao::pq::table_writer tw( connection->direct(), "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); - TEST_THROWS( connection->direct() ); - for( unsigned n = 0; n < 100000; ++n ) { - tw.insert( n, n + 23.45, "EUR" ); - } - - tw.insert( std::make_tuple( 123456, tao::pq::null, "EUR\nUSD\"FOO\\BAR" ) ); - - TEST_ASSERT_MESSAGE( "validate reported result size", tw.commit() == 100001 ); - TEST_ASSERT_MESSAGE( "validate actual result size", connection->execute( "SELECT COUNT(*) FROM tao_table_writer_test" ).as< std::size_t >() == 100001 ); - - { - const auto [ a, b, c ] = connection->execute( "SELECT a, b, c FROM tao_table_writer_test WHERE b IS NULL" ).tuple< unsigned, std::optional< double >, std::optional< std::string > >(); - - TEST_ASSERT_MESSAGE( "checking 'a' value", a == 123456 ); - TEST_ASSERT_MESSAGE( "checking 'b' value", !b ); - TEST_ASSERT_MESSAGE( "checking 'c' value", c == "EUR\nUSD\"FOO\\BAR" ); - } - - TEST_THROWS( tao::pq::table_writer( connection->direct(), "SELECT 42" ) ); - TEST_THROWS( tao::pq::table_writer( connection->direct(), "" ) ); - TEST_THROWS( tao::pq::table_writer( connection->direct(), "COPY tao_table_writer_test ( a, b, c, d ) FROM STDIN" ) ); - TEST_THROWS( tao::pq::table_writer( connection->direct(), "COPY tao_table_writer_test ( a, b, c ) TO STDOUT" ) ); - - TEST_THROWS( connection->execute( "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ) ); - - TEST_THROWS_MESSAGE( "mixed usage test #1", { - const auto tr = connection->direct(); - tao::pq::table_writer tw2( tr, "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); - tr->execute( "SELECT 42" ); - } ); - - TEST_THROWS_MESSAGE( "mixed usage test #2", { - const auto tr = connection->transaction(); - tao::pq::table_writer tw2( tr, "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); - tr->execute( "SELECT 42" ); - } ); - - connection->execute( "DROP TABLE tao_table_writer_test" ); - connection->execute( "CREATE TABLE tao_table_writer_test ( a INTEGER NOT NULL, b DOUBLE PRECISION, c TEXT )" ); - { - tao::pq::table_writer tw2( connection->direct(), "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); - tw2.insert_raw( "1\t0\tXXX\n" ); - tw2.commit(); - } - TEST_ASSERT( connection->execute( "SELECT COUNT(*) FROM tao_table_writer_test" ).as< std::size_t >() == 1 ); - { - tao::pq::table_writer tw2( connection->direct(), "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); - tw2.insert_raw( "2\t0\tXXX\n" ); - } - TEST_ASSERT( connection->execute( "SELECT COUNT(*) FROM tao_table_writer_test" ).as< std::size_t >() == 1 ); - - connection->execute( "DROP TABLE tao_table_writer_test" ); - connection->execute( "CREATE TABLE tao_table_writer_test ( a INTEGER NOT NULL, b DOUBLE PRECISION, c TEXT )" ); + void run() { - tao::pq::table_writer tw2( connection->direct(), "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); - tw2.insert_raw( "3\t0\tXXX\n" ); - PQclear( PQexec( connection->underlying_raw_ptr(), "SELECT 42" ) ); - TEST_THROWS( tw2.commit() ); - } - { - tao::pq::table_writer tw2( connection->direct(), "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); - tw2.insert_raw( "4\t0\tXXX\n" ); - PQclear( PQexec( connection->underlying_raw_ptr(), "SELECT 42" ) ); - TEST_THROWS( tw2.insert_raw( "5\t0\tXXX\n" ) ); + const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); + connection->execute( "DROP TABLE IF EXISTS tao_table_writer_test" ); + connection->execute( "CREATE TABLE tao_table_writer_test ( a INTEGER NOT NULL, b DOUBLE PRECISION, c TEXT )" ); + + tao::pq::table_writer tw( connection->direct(), "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); + TEST_THROWS( connection->direct() ); + for( unsigned n = 0; n < 100000; ++n ) { + tw.insert( n, n + 23.45, "EUR" ); + } + + tw.insert( std::make_tuple( 123456, tao::pq::null, "EUR\nUSD\"FOO\\BAR" ) ); + + TEST_ASSERT_MESSAGE( "validate reported result size", tw.commit() == 100001 ); + TEST_ASSERT_MESSAGE( "validate actual result size", connection->execute( "SELECT COUNT(*) FROM tao_table_writer_test" ).as< std::size_t >() == 100001 ); + + { + const auto [ a, b, c ] = connection->execute( "SELECT a, b, c FROM tao_table_writer_test WHERE b IS NULL" ).tuple< unsigned, std::optional< double >, std::optional< std::string > >(); + + TEST_ASSERT_MESSAGE( "checking 'a' value", a == 123456 ); + TEST_ASSERT_MESSAGE( "checking 'b' value", !b ); + TEST_ASSERT_MESSAGE( "checking 'c' value", c == "EUR\nUSD\"FOO\\BAR" ); + } + + TEST_THROWS( tao::pq::table_writer( connection->direct(), "SELECT 42" ) ); + TEST_THROWS( tao::pq::table_writer( connection->direct(), "" ) ); + TEST_THROWS( tao::pq::table_writer( connection->direct(), "COPY tao_table_writer_test ( a, b, c, d ) FROM STDIN" ) ); + TEST_THROWS( tao::pq::table_writer( connection->direct(), "COPY tao_table_writer_test ( a, b, c ) TO STDOUT" ) ); + + TEST_THROWS( connection->execute( "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ) ); + + TEST_THROWS_MESSAGE( "mixed usage test #1", { + const auto tr = connection->direct(); + const tao::pq::table_writer tw2( tr, "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); + tr->execute( "SELECT 42" ); + } ); + + TEST_THROWS_MESSAGE( "mixed usage test #2", { + const auto tr = connection->transaction(); + const tao::pq::table_writer tw2( tr, "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); + tr->execute( "SELECT 42" ); + } ); + + connection->execute( "DROP TABLE tao_table_writer_test" ); + connection->execute( "CREATE TABLE tao_table_writer_test ( a INTEGER NOT NULL, b DOUBLE PRECISION, c TEXT )" ); + { + tao::pq::table_writer tw2( connection->direct(), "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); + tw2.insert_raw( "1\t0\tXXX\n" ); + tw2.commit(); + } + TEST_ASSERT( connection->execute( "SELECT COUNT(*) FROM tao_table_writer_test" ).as< std::size_t >() == 1 ); + { + tao::pq::table_writer tw2( connection->direct(), "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); + tw2.insert_raw( "2\t0\tXXX\n" ); + } + TEST_ASSERT( connection->execute( "SELECT COUNT(*) FROM tao_table_writer_test" ).as< std::size_t >() == 1 ); + + connection->execute( "DROP TABLE tao_table_writer_test" ); + connection->execute( "CREATE TABLE tao_table_writer_test ( a INTEGER NOT NULL, b DOUBLE PRECISION, c TEXT )" ); + { + tao::pq::table_writer tw2( connection->direct(), "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); + tw2.insert_raw( "3\t0\tXXX\n" ); + PQclear( PQexec( connection->underlying_raw_ptr(), "SELECT 42" ) ); + TEST_THROWS( tw2.commit() ); + } + { + tao::pq::table_writer tw2( connection->direct(), "COPY tao_table_writer_test ( a, b, c ) FROM STDIN" ); + tw2.insert_raw( "4\t0\tXXX\n" ); + PQclear( PQexec( connection->underlying_raw_ptr(), "SELECT 42" ) ); + TEST_THROWS( tw2.insert_raw( "5\t0\tXXX\n" ) ); + } + + connection->execute( "DROP TABLE tao_table_writer_test" ); } - connection->execute( "DROP TABLE tao_table_writer_test" ); -} +} // namespace auto main() -> int // NOLINT(bugprone-exception-escape) { @@ -90,11 +94,11 @@ auto main() -> int // NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/traits.cpp b/src/test/pq/traits.cpp index 45be4ff..235a16a 100644 --- a/src/test/pq/traits.cpp +++ b/src/test/pq/traits.cpp @@ -60,7 +60,7 @@ namespace example {} }; - [[nodiscard]] auto to_taopq( const user3& v ) noexcept + [[nodiscard]] auto to_taopq( const user3& v ) noexcept // NOLINT(misc-use-internal-linkage) { return std::tie( v.a, v.b, v.c, v.d ); } @@ -81,81 +81,85 @@ struct tao::pq::bind< example::user2 > } }; -void run() +namespace { - const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); - - connection->execute( "DROP TABLE IF EXISTS tao_traits_test" ); - connection->execute( "CREATE TABLE tao_traits_test ( a INTEGER PRIMARY KEY, b INTEGER, c INTEGER, d INTEGER )" ); - - TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( 1, 2, 3, 4 )" ) ); - TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", 2, 3, 4, 5 ) ); - TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", 3, std::make_pair( 4, 5 ), 6 ) ); - TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", std::make_tuple( 4, 5 ), std::make_tuple( 6, 7 ) ) ); - TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", std::make_tuple( 5, std::make_pair( 6, 7 ), 8 ) ) ); - TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", example::user( 6 ) ) ); - TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", example::user2( 7 ) ) ); - - const auto result = connection->execute( "SELECT * FROM tao_traits_test" ); - TEST_ASSERT( result.size() == 7 ); - - for( const auto& row : result ) { - { - const auto v = row.tuple< int, int, int, int >(); - TEST_ASSERT( std::get< 1 >( v ) == std::get< 0 >( v ) + 1 ); - TEST_ASSERT( std::get< 2 >( v ) == std::get< 1 >( v ) + 1 ); - TEST_ASSERT( std::get< 3 >( v ) == std::get< 2 >( v ) + 1 ); + void run() + { + const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); + + connection->execute( "DROP TABLE IF EXISTS tao_traits_test" ); + connection->execute( "CREATE TABLE tao_traits_test ( a INTEGER PRIMARY KEY, b INTEGER, c INTEGER, d INTEGER )" ); + + TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( 1, 2, 3, 4 )" ) ); + TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", 2, 3, 4, 5 ) ); + TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", 3, std::make_pair( 4, 5 ), 6 ) ); + TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", std::make_tuple( 4, 5 ), std::make_tuple( 6, 7 ) ) ); + TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", std::make_tuple( 5, std::make_pair( 6, 7 ), 8 ) ) ); + TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", example::user( 6 ) ) ); + TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", example::user2( 7 ) ) ); + + const auto result = connection->execute( "SELECT * FROM tao_traits_test" ); + TEST_ASSERT( result.size() == 7 ); + + for( const auto& row : result ) { + { + const auto v = row.tuple< int, int, int, int >(); + TEST_ASSERT( std::get< 1 >( v ) == std::get< 0 >( v ) + 1 ); + TEST_ASSERT( std::get< 2 >( v ) == std::get< 1 >( v ) + 1 ); + TEST_ASSERT( std::get< 3 >( v ) == std::get< 2 >( v ) + 1 ); + } + { + const auto v = row.tuple< std::tuple< int, int >, std::tuple< int, int > >(); + TEST_ASSERT( std::get< 1 >( std::get< 0 >( v ) ) == std::get< 0 >( std::get< 0 >( v ) ) + 1 ); + TEST_ASSERT( std::get< 0 >( std::get< 1 >( v ) ) == std::get< 1 >( std::get< 0 >( v ) ) + 1 ); + TEST_ASSERT( std::get< 1 >( std::get< 1 >( v ) ) == std::get< 0 >( std::get< 1 >( v ) ) + 1 ); + } + { + const auto v = row.tuple< int, std::tuple< int, int >, int >(); + TEST_ASSERT( std::get< 0 >( std::get< 1 >( v ) ) == std::get< 0 >( v ) + 1 ); + TEST_ASSERT( std::get< 1 >( std::get< 1 >( v ) ) == std::get< 0 >( std::get< 1 >( v ) ) + 1 ); + TEST_ASSERT( std::get< 2 >( v ) == std::get< 1 >( std::get< 1 >( v ) ) + 1 ); + } + { + const auto [ a, b, c, d ] = row.tuple< int, int, int, int >(); + TEST_ASSERT( b == a + 1 ); + TEST_ASSERT( c == b + 1 ); + TEST_ASSERT( d == c + 1 ); + } } + + TEST_EXECUTE( connection->execute( "DELETE FROM tao_traits_test" ) ); + TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", example::user( 8 ) ) ); { - const auto v = row.tuple< std::tuple< int, int >, std::tuple< int, int > >(); - TEST_ASSERT( std::get< 1 >( std::get< 0 >( v ) ) == std::get< 0 >( std::get< 0 >( v ) ) + 1 ); - TEST_ASSERT( std::get< 0 >( std::get< 1 >( v ) ) == std::get< 1 >( std::get< 0 >( v ) ) + 1 ); - TEST_ASSERT( std::get< 1 >( std::get< 1 >( v ) ) == std::get< 0 >( std::get< 1 >( v ) ) + 1 ); + const auto user = connection->execute( "SELECT * FROM tao_traits_test" ).as< example::user >(); + TEST_ASSERT( user.a == 8 ); + TEST_ASSERT( user.b == 9 ); + TEST_ASSERT( user.c == 10 ); + TEST_ASSERT( user.d == 11 ); } + + TEST_EXECUTE( connection->execute( "DELETE FROM tao_traits_test" ) ); + TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", example::user2( 9 ) ) ); { - const auto v = row.tuple< int, std::tuple< int, int >, int >(); - TEST_ASSERT( std::get< 0 >( std::get< 1 >( v ) ) == std::get< 0 >( v ) + 1 ); - TEST_ASSERT( std::get< 1 >( std::get< 1 >( v ) ) == std::get< 0 >( std::get< 1 >( v ) ) + 1 ); - TEST_ASSERT( std::get< 2 >( v ) == std::get< 1 >( std::get< 1 >( v ) ) + 1 ); + const auto user = connection->execute( "SELECT * FROM tao_traits_test" ).as< example::user2 >(); + TEST_ASSERT( user.a == 9 ); + TEST_ASSERT( user.b == 10 ); + TEST_ASSERT( user.c == 11 ); + TEST_ASSERT( user.d == 12 ); } + + TEST_EXECUTE( connection->execute( "DELETE FROM tao_traits_test" ) ); + TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", example::user3( 10 ) ) ); { - const auto [ a, b, c, d ] = row.tuple< int, int, int, int >(); - TEST_ASSERT( b == a + 1 ); - TEST_ASSERT( c == b + 1 ); - TEST_ASSERT( d == c + 1 ); + const auto user = connection->execute( "SELECT * FROM tao_traits_test" ).as< example::user >(); + TEST_ASSERT( user.a == 10 ); + TEST_ASSERT( user.b == 11 ); + TEST_ASSERT( user.c == 12 ); + TEST_ASSERT( user.d == 13 ); } } - TEST_EXECUTE( connection->execute( "DELETE FROM tao_traits_test" ) ); - TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", example::user( 8 ) ) ); - { - const auto user = connection->execute( "SELECT * FROM tao_traits_test" ).as< example::user >(); - TEST_ASSERT( user.a == 8 ); - TEST_ASSERT( user.b == 9 ); - TEST_ASSERT( user.c == 10 ); - TEST_ASSERT( user.d == 11 ); - } - - TEST_EXECUTE( connection->execute( "DELETE FROM tao_traits_test" ) ); - TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", example::user2( 9 ) ) ); - { - const auto user = connection->execute( "SELECT * FROM tao_traits_test" ).as< example::user2 >(); - TEST_ASSERT( user.a == 9 ); - TEST_ASSERT( user.b == 10 ); - TEST_ASSERT( user.c == 11 ); - TEST_ASSERT( user.d == 12 ); - } - - TEST_EXECUTE( connection->execute( "DELETE FROM tao_traits_test" ) ); - TEST_EXECUTE( connection->execute( "INSERT INTO tao_traits_test VALUES ( $1, $2, $3, $4 )", example::user3( 10 ) ) ); - { - const auto user = connection->execute( "SELECT * FROM tao_traits_test" ).as< example::user >(); - TEST_ASSERT( user.a == 10 ); - TEST_ASSERT( user.b == 11 ); - TEST_ASSERT( user.c == 12 ); - TEST_ASSERT( user.d == 13 ); - } -} +} // namespace auto main() -> int //NOLINT(bugprone-exception-escape) { @@ -164,11 +168,11 @@ auto main() -> int //NOLINT(bugprone-exception-escape) } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP diff --git a/src/test/pq/transaction.cpp b/src/test/pq/transaction.cpp index db1abda..791e167 100644 --- a/src/test/pq/transaction.cpp +++ b/src/test/pq/transaction.cpp @@ -9,115 +9,119 @@ #include -template< typename Connection, typename Transaction > -void check_nested( const std::shared_ptr< Connection >& connection, const std::shared_ptr< Transaction >& tr ) +namespace { - TEST_THROWS( connection->direct() ); - TEST_THROWS( connection->transaction() ); - TEST_EXECUTE( tr->execute( "SELECT 42" ) ); + template< typename Connection, typename Transaction > + void check_nested( const std::shared_ptr< Connection >& connection, const std::shared_ptr< Transaction >& tr ) { - const auto tr2 = tr->subtransaction(); - TEST_THROWS( tr->subtransaction() ); - TEST_EXECUTE( tr2->execute( "SELECT 42" ) ); + TEST_THROWS( connection->direct() ); + TEST_THROWS( connection->transaction() ); + TEST_EXECUTE( tr->execute( "SELECT 42" ) ); { - const auto tr3 = tr2->subtransaction(); + const auto tr2 = tr->subtransaction(); + TEST_THROWS( tr->subtransaction() ); + TEST_EXECUTE( tr2->execute( "SELECT 42" ) ); + { + const auto tr3 = tr2->subtransaction(); + TEST_THROWS( tr2->subtransaction() ); + TEST_EXECUTE( tr3->execute( "SELECT 42" ) ); + TEST_THROWS( tr2->execute( "SELECT 42" ) ); + TEST_EXECUTE( tr3->commit() ); + TEST_THROWS( tr3->execute( "SELECT 42" ) ); + } + TEST_THROWS( tr->execute( "SELECT 42" ) ); + TEST_EXECUTE( tr2->commit() ); + TEST_THROWS( tr2->execute( "SELECT 42" ) ); TEST_THROWS( tr2->subtransaction() ); - TEST_EXECUTE( tr3->execute( "SELECT 42" ) ); + TEST_EXECUTE( std::ignore = tr->subtransaction() ); + } + tr->execute( "SELECT 42" ); + { + const auto tr2 = tr->subtransaction(); + TEST_EXECUTE( tr2->execute( "SELECT 42" ) ); + TEST_THROWS( tr->execute( "SELECT 42" ) ); + TEST_EXECUTE( tr2->rollback() ); TEST_THROWS( tr2->execute( "SELECT 42" ) ); - TEST_EXECUTE( tr3->commit() ); - TEST_THROWS( tr3->execute( "SELECT 42" ) ); } + TEST_EXECUTE( tr->execute( "SELECT 42" ) ); + TEST_EXECUTE( tr->commit() ); TEST_THROWS( tr->execute( "SELECT 42" ) ); - TEST_EXECUTE( tr2->commit() ); - TEST_THROWS( tr2->execute( "SELECT 42" ) ); - TEST_THROWS( tr2->subtransaction() ); - TEST_EXECUTE( std::ignore = tr->subtransaction() ); + TEST_EXECUTE( std::ignore = connection->direct() ); + TEST_EXECUTE( std::ignore = connection->transaction() ); } - tr->execute( "SELECT 42" ); + + void run() { - const auto tr2 = tr->subtransaction(); - TEST_EXECUTE( tr2->execute( "SELECT 42" ) ); - TEST_THROWS( tr->execute( "SELECT 42" ) ); - TEST_EXECUTE( tr2->rollback() ); - TEST_THROWS( tr2->execute( "SELECT 42" ) ); - } - TEST_EXECUTE( tr->execute( "SELECT 42" ) ); - TEST_EXECUTE( tr->commit() ); - TEST_THROWS( tr->execute( "SELECT 42" ) ); - TEST_EXECUTE( std::ignore = connection->direct() ); - TEST_EXECUTE( std::ignore = connection->transaction() ); -} + const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); -void run() -{ - const auto connection = tao::pq::connection::create( tao::pq::internal::getenv( "TAOPQ_TEST_DATABASE", "dbname=template1" ) ); + connection->execute( "DROP TABLE IF EXISTS tao_transaction_test" ); + connection->execute( "CREATE TABLE tao_transaction_test ( a INTEGER PRIMARY KEY )" ); - connection->execute( "DROP TABLE IF EXISTS tao_transaction_test" ); - connection->execute( "CREATE TABLE tao_transaction_test ( a INTEGER PRIMARY KEY )" ); + TEST_ASSERT( connection->execute( "SELECT * FROM tao_transaction_test" ).empty() ); - TEST_ASSERT( connection->execute( "SELECT * FROM tao_transaction_test" ).empty() ); + TEST_EXECUTE( connection->execute( "INSERT INTO tao_transaction_test VALUES ( 1 )" ) ); // auto-commit + TEST_ASSERT( connection->execute( "SELECT * FROM tao_transaction_test" ).size() == 1 ); - TEST_EXECUTE( connection->execute( "INSERT INTO tao_transaction_test VALUES ( 1 )" ) ); // auto-commit - TEST_ASSERT( connection->execute( "SELECT * FROM tao_transaction_test" ).size() == 1 ); + TEST_EXECUTE( connection->direct()->execute( "INSERT INTO tao_transaction_test VALUES ( 2 )" ) ); // auto-commit + TEST_ASSERT( connection->execute( "SELECT * FROM tao_transaction_test" ).size() == 2 ); - TEST_EXECUTE( connection->direct()->execute( "INSERT INTO tao_transaction_test VALUES ( 2 )" ) ); // auto-commit - TEST_ASSERT( connection->execute( "SELECT * FROM tao_transaction_test" ).size() == 2 ); + TEST_EXECUTE( connection->transaction()->execute( "INSERT INTO tao_transaction_test VALUES ( 3 )" ) ); // not committed + TEST_ASSERT( connection->execute( "SELECT * FROM tao_transaction_test" ).size() == 2 ); - TEST_EXECUTE( connection->transaction()->execute( "INSERT INTO tao_transaction_test VALUES ( 3 )" ) ); // not committed - TEST_ASSERT( connection->execute( "SELECT * FROM tao_transaction_test" ).size() == 2 ); + TEST_EXECUTE( connection->direct()->subtransaction()->execute( "INSERT INTO tao_transaction_test VALUES ( 3 )" ) ); // not committed + TEST_ASSERT( connection->execute( "SELECT * FROM tao_transaction_test" ).size() == 2 ); - TEST_EXECUTE( connection->direct()->subtransaction()->execute( "INSERT INTO tao_transaction_test VALUES ( 3 )" ) ); // not committed - TEST_ASSERT( connection->execute( "SELECT * FROM tao_transaction_test" ).size() == 2 ); + TEST_EXECUTE( connection->transaction()->subtransaction()->execute( "INSERT INTO tao_transaction_test VALUES ( 3 )" ) ); // not committed + TEST_ASSERT( connection->execute( "SELECT * FROM tao_transaction_test" ).size() == 2 ); - TEST_EXECUTE( connection->transaction()->subtransaction()->execute( "INSERT INTO tao_transaction_test VALUES ( 3 )" ) ); // not committed - TEST_ASSERT( connection->execute( "SELECT * FROM tao_transaction_test" ).size() == 2 ); + TEST_THROWS( connection->transaction( tao::pq::access_mode::read_only )->execute( "INSERT INTO tao_transaction_test VALUES ( 3 )" ) ); + TEST_ASSERT( connection->transaction( tao::pq::access_mode::read_only )->execute( "SELECT * FROM tao_transaction_test" ).size() == 2 ); - TEST_THROWS( connection->transaction( tao::pq::access_mode::read_only )->execute( "INSERT INTO tao_transaction_test VALUES ( 3 )" ) ); - TEST_ASSERT( connection->transaction( tao::pq::access_mode::read_only )->execute( "SELECT * FROM tao_transaction_test" ).size() == 2 ); + TEST_THROWS_MESSAGE( "THROWS connection->transaction()", const auto tr = connection->transaction(); std::ignore = connection->transaction() ); + TEST_THROWS_MESSAGE( "THROWS connection->direct()", const auto tr = connection->transaction(); std::ignore = connection->direct() ); + TEST_THROWS_MESSAGE( "THROWS connection->transaction()", const auto tr = connection->direct(); std::ignore = connection->transaction() ); + TEST_THROWS_MESSAGE( "THROWS connection->direct()", const auto tr = connection->direct(); std::ignore = connection->direct() ); - TEST_THROWS_MESSAGE( "THROWS connection->transaction()", const auto tr = connection->transaction(); std::ignore = connection->transaction() ); - TEST_THROWS_MESSAGE( "THROWS connection->direct()", const auto tr = connection->transaction(); std::ignore = connection->direct() ); - TEST_THROWS_MESSAGE( "THROWS connection->transaction()", const auto tr = connection->direct(); std::ignore = connection->transaction() ); - TEST_THROWS_MESSAGE( "THROWS connection->direct()", const auto tr = connection->direct(); std::ignore = connection->direct() ); + TEST_THROWS_MESSAGE( "THROWS tr->subtransaction()", const auto tr = connection->transaction(); const auto st = tr->subtransaction(); std::ignore = tr->subtransaction() ); + TEST_THROWS_MESSAGE( "THROWS tr->subtransaction()", const auto tr = connection->direct(); const auto st = tr->subtransaction(); std::ignore = tr->subtransaction() ); - TEST_THROWS_MESSAGE( "THROWS tr->subtransaction()", const auto tr = connection->transaction(); const auto st = tr->subtransaction(); std::ignore = tr->subtransaction() ); - TEST_THROWS_MESSAGE( "THROWS tr->subtransaction()", const auto tr = connection->direct(); const auto st = tr->subtransaction(); std::ignore = tr->subtransaction() ); + TEST_EXECUTE( std::ignore = connection->direct() ); + TEST_EXECUTE( connection->direct()->commit() ); + TEST_EXECUTE( connection->direct()->rollback() ); - TEST_EXECUTE( std::ignore = connection->direct() ); - TEST_EXECUTE( connection->direct()->commit() ); - TEST_EXECUTE( connection->direct()->rollback() ); + TEST_EXECUTE( std::ignore = connection->direct()->subtransaction() ); + TEST_EXECUTE( connection->direct()->subtransaction()->commit() ); + TEST_EXECUTE( connection->direct()->subtransaction()->rollback() ); - TEST_EXECUTE( std::ignore = connection->direct()->subtransaction() ); - TEST_EXECUTE( connection->direct()->subtransaction()->commit() ); - TEST_EXECUTE( connection->direct()->subtransaction()->rollback() ); + TEST_EXECUTE( std::ignore = connection->direct()->subtransaction()->subtransaction() ); + TEST_EXECUTE( connection->direct()->subtransaction()->subtransaction()->commit() ); + TEST_EXECUTE( connection->direct()->subtransaction()->subtransaction()->rollback() ); - TEST_EXECUTE( std::ignore = connection->direct()->subtransaction()->subtransaction() ); - TEST_EXECUTE( connection->direct()->subtransaction()->subtransaction()->commit() ); - TEST_EXECUTE( connection->direct()->subtransaction()->subtransaction()->rollback() ); + TEST_EXECUTE( std::ignore = connection->transaction() ); + TEST_EXECUTE( connection->transaction()->commit() ); + TEST_EXECUTE( connection->transaction()->rollback() ); - TEST_EXECUTE( std::ignore = connection->transaction() ); - TEST_EXECUTE( connection->transaction()->commit() ); - TEST_EXECUTE( connection->transaction()->rollback() ); + TEST_EXECUTE( std::ignore = connection->transaction()->subtransaction() ); + TEST_EXECUTE( connection->transaction()->subtransaction()->commit() ); + TEST_EXECUTE( connection->transaction()->subtransaction()->rollback() ); - TEST_EXECUTE( std::ignore = connection->transaction()->subtransaction() ); - TEST_EXECUTE( connection->transaction()->subtransaction()->commit() ); - TEST_EXECUTE( connection->transaction()->subtransaction()->rollback() ); + TEST_EXECUTE( std::ignore = connection->transaction()->subtransaction()->subtransaction() ); + TEST_EXECUTE( connection->transaction()->subtransaction()->subtransaction()->commit() ); + TEST_EXECUTE( connection->transaction()->subtransaction()->subtransaction()->rollback() ); - TEST_EXECUTE( std::ignore = connection->transaction()->subtransaction()->subtransaction() ); - TEST_EXECUTE( connection->transaction()->subtransaction()->subtransaction()->commit() ); - TEST_EXECUTE( connection->transaction()->subtransaction()->subtransaction()->rollback() ); + TEST_EXECUTE( std::ignore = connection->transaction( tao::pq::isolation_level::serializable ) ); + TEST_EXECUTE( std::ignore = connection->transaction( tao::pq::isolation_level::repeatable_read ) ); + TEST_EXECUTE( std::ignore = connection->transaction( tao::pq::isolation_level::read_committed ) ); + TEST_EXECUTE( std::ignore = connection->transaction( tao::pq::isolation_level::read_uncommitted ) ); - TEST_EXECUTE( std::ignore = connection->transaction( tao::pq::isolation_level::serializable ) ); - TEST_EXECUTE( std::ignore = connection->transaction( tao::pq::isolation_level::repeatable_read ) ); - TEST_EXECUTE( std::ignore = connection->transaction( tao::pq::isolation_level::read_committed ) ); - TEST_EXECUTE( std::ignore = connection->transaction( tao::pq::isolation_level::read_uncommitted ) ); + TEST_EXECUTE( std::ignore = connection->transaction( tao::pq::access_mode::read_write ) ); + TEST_EXECUTE( std::ignore = connection->transaction( tao::pq::access_mode::read_only ) ); - TEST_EXECUTE( std::ignore = connection->transaction( tao::pq::access_mode::read_write ) ); - TEST_EXECUTE( std::ignore = connection->transaction( tao::pq::access_mode::read_only ) ); + TEST_EXECUTE( check_nested( connection, connection->direct() ) ); + TEST_EXECUTE( check_nested( connection, connection->transaction() ) ); + } - TEST_EXECUTE( check_nested( connection, connection->direct() ) ); - TEST_EXECUTE( check_nested( connection, connection->transaction() ) ); -} +} // namespace auto main() -> int { @@ -126,11 +130,11 @@ auto main() -> int } // LCOV_EXCL_START catch( const std::exception& e ) { - std::cerr << "exception: " << e.what() << std::endl; + std::cerr << "exception: " << e.what() << '\n'; throw; } catch( ... ) { - std::cerr << "unknown exception" << std::endl; + std::cerr << "unknown exception\n"; throw; } // LCOV_EXCL_STOP