Skip to content

Commit

Permalink
Test phase two order independence.
Browse files Browse the repository at this point in the history
  • Loading branch information
ColinH committed Apr 4, 2024
1 parent 3616d33 commit c4132c0
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 21 deletions.
2 changes: 1 addition & 1 deletion include/tao/config/internal/phase2_everything.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace tao::config::internal
{
[[nodiscard]] inline bool phase2_iteration( state& st, const function_map& fm )
{
return ( phase2_functions( st, fm ) + phase2_additions( st.root ) + phase2_references( st.root ) + phase2_asterisks( st.root ) ) > 0;
return ( phase2_functions( st, fm ) | phase2_additions( st.root ) | phase2_references( st.root ) | phase2_asterisks( st.root ) ) > 0;
}

inline void phase2_everything( state& st, const function_map& fm )
Expand Down
1 change: 1 addition & 0 deletions src/test/config/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(testsources
debug_traits.cpp
enumerations.cpp
failure.cpp
independence.cpp
key.cpp
key_part.cpp
multi_line_string_position.cpp
Expand Down
2 changes: 1 addition & 1 deletion src/test/config/failure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ int main()
}
}
if( tao::failed == 0 ) {
std::cerr << "All " << count << " testcases passed." << std::endl;
std::cerr << "All " << count << " failure testcases passed." << std::endl;
}
return std::min( int( tao::failed ), 127 );
}
107 changes: 107 additions & 0 deletions src/test/config/independence.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/config/

#include <algorithm>
#include <filesystem>
#include <iostream>
#include <set>
#include <stdexcept>
#include <vector>

#include "setenv.hpp"
#include "test.hpp"

#include <tao/config.hpp>

namespace tao::config
{
std::size_t iteration = 0;

[[nodiscard]] std::size_t p2fun( internal::state& st, const internal::function_map& fm )
{
return internal::phase2_functions( st, fm );
}

[[nodiscard]] std::size_t p2add( internal::state& st, const internal::function_map& /*unused*/ )
{
return internal::phase2_additions( st.root );
}

[[nodiscard]] std::size_t p2ref( internal::state& st, const internal::function_map& /*unused*/ )
{
return internal::phase2_references( st.root );
}

[[nodiscard]] std::size_t p2ast( internal::state& st, const internal::function_map& /*unused*/ )
{
return internal::phase2_asterisks( st.root );
}

using func_t = std::size_t( * )( internal::state&, const internal::function_map& );

std::set< func_t > p2funcs = { p2fun, p2add, p2ref, p2ast };

void unit_test( const std::filesystem::path& path )
{
try {
std::filesystem::path jaxn = path;
jaxn.replace_extension( ".jaxn" );
const auto cj = from_file( jaxn );
const auto cjs = json::jaxn::to_string( cj );

std::vector< func_t > v( p2funcs.begin(), p2funcs.end() );

do {
internal::config_parser p;
p.parse( path );

while( v[ 0 ]( p.st, p.fm ) | v[ 1 ]( p.st, p.fm ) | v[ 2 ]( p.st, p.fm ) | v[ 3 ]( p.st, p.fm ) );

internal::phase3_remove( p.st.root );
const auto cc = internal::phase5_repack< traits >( p.st.root );
const auto ccs = json::jaxn::to_string( cc );

if( ccs != cjs ) {
// LCOV_EXCL_START
++failed;
std::cerr << std::endl
<< "Testcase '" << path << "' failed identity test in iteration " << iteration << std::endl;
std::cerr << "<<< Config parsed as config <<<" << std::endl;
std::cerr << ccs << std::endl;
std::cerr << ">>> Config parsed as config >>>" << std::endl;
std::cerr << "<<< Reference data parsed as config <<<" << std::endl;
std::cerr << cjs << std::endl;
std::cerr << ">>> Reference data parsed as config >>>" << std::endl;
// LCOV_EXCL_STOP
}
++iteration;
} while( std::next_permutation( v.begin(), v.end() ) );
}
// LCOV_EXCL_START
catch( const std::exception& e ) {
std::cerr << "Testcase '" << path << "' failed with exception '" << e.what() << "' in iteration " << iteration << std::endl;
++failed;
}
// LCOV_EXCL_STOP
}

} // namespace tao::config

int main()
{
for( const auto& entry : std::filesystem::directory_iterator( "tests" ) ) {
if( const auto& path = entry.path(); path.extension() == ".success" ) {
#if defined( _MSC_VER )
if( entry.path().stem() == "shell" ) {
continue;
}
#endif
tao::config::internal::setenv_throws( "TAO_CONFIG", "env_value" );
tao::config::unit_test( path );
}
}
if( tao::config::failed == 0 ) {
std::cerr << "All " << tao::config::iteration << " order independence testcases passed." << std::endl;
}
return std::min( int( tao::config::failed ), 127 );
}
32 changes: 32 additions & 0 deletions src/test/config/setenv.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/config/

#ifndef TAO_CONFIG_SRC_TEST_CONFIG_SETENV_HPP
#define TAO_CONFIG_SRC_TEST_CONFIG_SETENV_HPP

#include <stdlib.h>
#include <stdexcept>
#include <string>

namespace tao::config::internal
{
void setenv_throws( const std::string& name, const std::string& value )
{
#if defined( _MSC_VER )
const auto e = ::_putenv_s( name.c_str(), value.c_str() );
if( e != 0 ) {
#else
errno = 0;
if( ::setenv( name.c_str(), value.c_str(), 1 ) != 0 ) {
// LCOV_EXCL_START
const auto e = errno;
#endif
(void)e;
throw std::runtime_error( "setenv failed" );
// LCOV_EXCL_STOP
}
}

} // namespace tao::config::internal

#endif
22 changes: 3 additions & 19 deletions src/test/config/success.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,13 @@
#include <iostream>
#include <stdexcept>

#include "setenv.hpp"
#include "test.hpp"

#include <tao/config.hpp>

namespace tao::config
{
void setenv_throws( const std::string& name, const std::string& value )
{
#if defined( _MSC_VER )
const auto e = ::_putenv_s( name.c_str(), value.c_str() );
if( e != 0 ) {
#else
errno = 0;
if( ::setenv( name.c_str(), value.c_str(), 1 ) != 0 ) {
// LCOV_EXCL_START
const auto e = errno;
#endif
(void)e;
throw std::runtime_error( "setenv failed" );
// LCOV_EXCL_STOP
}
}

template< template< typename... > class Traits >
void unit_test( const std::filesystem::path& path )
{
Expand Down Expand Up @@ -119,14 +103,14 @@ int main()
continue;
}
#endif
tao::config::setenv_throws( "TAO_CONFIG", "env_value" );
tao::config::internal::setenv_throws( "TAO_CONFIG", "env_value" );
tao::config::unit_test< tao::json::traits >( path );
tao::config::unit_test< tao::config::traits >( path );
++count;
}
}
if( tao::config::failed == 0 ) {
std::cerr << "All " << count << " testcases passed." << std::endl;
std::cerr << "All " << count << " success testcases passed." << std::endl;
}
return std::min( int( tao::config::failed ), 127 );
}

0 comments on commit c4132c0

Please sign in to comment.