Instead of unconditionally attempting to clone from a fixed location
(GitHub) during the build / test process, honor the following two
configuration variables:

  TOML11_LANGSPEC_GIT_REPOSITORY
    Can be set to override the URL from which the repository is cloned.
    This allows using a local mirror, including file:// URLs for working
    offline or reducing network traffic.

  TOML11_LANGSPEC_SOURCE_DIR
    Can be set to configure the location at which the repository is
    expected.  If it already exists no download will be attempted.  This
    allows avoiding the additional git-clone(1) altogether and use an
    existing directory as-is.  This offers two new possibilities:
    (1) The same checkout can be reused for building multiple
    configurations (e.g. Debug versus Release) saving a little bit of
    time and disk space.
    (2) Experimental changes can easily be applied to the local source
    tree without having them destroyed by the build process.

In order for this flexible location to work, the unit tests which
attempt to read files from the repository had to be adjusted.  They now
honor an environment variable TOMLDIR which can be set to point to an
alternate root directory.

All defaults are set such that the previous behavior is maintained.

Instead of introducing the TOMLDIR environment variable, an alternative
solution would have been to set the WORKING_DIRECTORY of the tests to
the TOML11_LANGSPEC_SOURCE_DIR and leave the relative paths in these
tests hard-coded.  Alas, some tests also expect that they can /write/
into the current working directory which isn't desirable if it is
potentially pointing outside the build tree.  I personally prefer to
mount the source directory read-only and build in a fast tempfs, so this
would e a problem.  To be perfectly honest, I don't quite understand why
these tests need to write to the file system in the first place, though.
It seems to me that refactoring them to serialize to a std::ostrstream
instead of a std::ofstream would not only simplify but also speed up the
unit tests and avoid file system problems.  But there might have been a
hidden reason why actually using the real file system was considered
necessary for these tests, so I didn't went ahead with that change yet.
This commit is contained in:
Moritz Klammler 2022-09-16 11:51:32 +02:00
parent ac949437f8
commit b10348c576
4 changed files with 93 additions and 50 deletions

View File

@ -1,11 +1,20 @@
include(ExternalProject)
ExternalProject_Add(toml
SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/toml
GIT_REPOSITORY https://github.com/toml-lang/toml
GIT_TAG v0.5.0
set(TOML11_LANGSPEC_GIT_REPOSITORY "https://github.com/toml-lang/toml" CACHE STRING
"URL of the TOML language specification repository")
set(TOML11_LANGSPEC_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/toml" CACHE FILEPATH
"directory for the TOML language specification tree")
if(NOT EXISTS "${TOML11_LANGSPEC_SOURCE_DIR}/toml.abnf")
ExternalProject_Add(toml
SOURCE_DIR "${TOML11_LANGSPEC_SOURCE_DIR}"
GIT_REPOSITORY "${TOML11_LANGSPEC_GIT_REPOSITORY}"
GIT_TAG "v0.5.0"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
endif()
set(TEST_NAMES
test_datetime
@ -228,6 +237,13 @@ if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4265")
endif()
set(TEST_ENVIRON "TOMLDIR=${TOML11_LANGSPEC_SOURCE_DIR}")
if(WIN32)
# Set the PATH to be able to find Boost DLL
STRING(REPLACE ";" "\\;" PATH_STRING "$ENV{PATH}")
list(APPEND TEST_ENVIRON "PATH=${PATH_STRING}\;${Boost_LIBRARY_DIRS}")
endif()
foreach(TEST_NAME ${TEST_NAMES})
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
target_link_libraries(${TEST_NAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} toml11::toml11)
@ -257,14 +273,7 @@ foreach(TEST_NAME ${TEST_NAMES})
endif()
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
# Set the PATH to be able to find Boost DLL
if(WIN32)
STRING(REPLACE ";" "\\;" PATH_STRING "$ENV{PATH}")
set_tests_properties(${TEST_NAME}
PROPERTIES ENVIRONMENT "PATH=${PATH_STRING}\;${Boost_LIBRARY_DIRS}"
)
endif()
set_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT "${TEST_ENVIRON}")
endforeach(TEST_NAME)

View File

@ -9,10 +9,22 @@
#include <fstream>
#include <map>
#include <deque>
#include <cstdlib>
static auto testinput(const std::string& basename) -> std::string
{
const auto this_or_that = [](const char *const s, const char *const t) { return s ? s : t; };
std::string directory = this_or_that(std::getenv("TOMLDIR"), "toml");
if (!directory.empty() && directory.back() != '/')
{
directory.push_back('/');
}
return directory.append("tests/").append(basename);
}
BOOST_AUTO_TEST_CASE(test_example)
{
const auto data = toml::parse("toml/tests/example.toml");
const auto data = toml::parse(testinput("example.toml"));
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
const auto& owner = toml::find(data, "owner");
@ -75,7 +87,7 @@ BOOST_AUTO_TEST_CASE(test_example)
BOOST_AUTO_TEST_CASE(test_example_stream)
{
std::ifstream ifs("toml/tests/example.toml", std::ios::binary);
std::ifstream ifs(testinput("example.toml"), std::ios::binary);
const auto data = toml::parse(ifs);
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
@ -143,7 +155,7 @@ BOOST_AUTO_TEST_CASE(test_example_stream)
BOOST_AUTO_TEST_CASE(test_example_file_pointer)
{
FILE * file = fopen("toml/tests/example.toml", "rb");
FILE * file = fopen(testinput("example.toml").c_str(), "rb");
const auto data = toml::parse(file, "toml/tests/example.toml");
fclose(file);
@ -212,7 +224,7 @@ BOOST_AUTO_TEST_CASE(test_example_file_pointer)
BOOST_AUTO_TEST_CASE(test_fruit)
{
const auto data = toml::parse("toml/tests/fruit.toml");
const auto data = toml::parse(testinput("fruit.toml"));
const auto blah = toml::find<toml::array>(toml::find(data, "fruit"), "blah");
BOOST_TEST(toml::find<std::string>(blah.at(0), "name") == "apple");
BOOST_TEST(toml::find<std::string>(blah.at(1), "name") == "banana");
@ -230,7 +242,7 @@ BOOST_AUTO_TEST_CASE(test_fruit)
BOOST_AUTO_TEST_CASE(test_hard_example)
{
const auto data = toml::parse("toml/tests/hard_example.toml");
const auto data = toml::parse(testinput("hard_example.toml"));
const auto the = toml::find(data, "the");
BOOST_TEST(toml::find<std::string>(the, "test_string") ==
"You'll hate me after this - #");
@ -257,7 +269,7 @@ BOOST_AUTO_TEST_CASE(test_hard_example)
}
BOOST_AUTO_TEST_CASE(test_hard_example_comment)
{
const auto data = toml::parse<toml::preserve_comments>("toml/tests/hard_example.toml");
const auto data = toml::parse<toml::preserve_comments>(testinput("hard_example.toml"));
const auto the = toml::find(data, "the");
BOOST_TEST(toml::find<std::string>(the, "test_string") ==
"You'll hate me after this - #");
@ -286,7 +298,7 @@ BOOST_AUTO_TEST_CASE(test_hard_example_comment)
BOOST_AUTO_TEST_CASE(test_example_preserve_comment)
{
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
const auto data = toml::parse<toml::preserve_comments>(testinput("example.toml"));
BOOST_TEST(toml::find<std::string>(data, "title") == "TOML Example");
const auto& owner = toml::find(data, "owner");
@ -368,8 +380,8 @@ BOOST_AUTO_TEST_CASE(test_example_preserve_comment)
BOOST_AUTO_TEST_CASE(test_example_preserve_stdmap_stddeque)
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque
>("toml/tests/example.toml");
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
testinput("example.toml"));
static_assert(std::is_same<typename decltype(data)::table_type,
std::map<toml::key, typename std::remove_cv<decltype(data)>::type>
@ -992,38 +1004,36 @@ BOOST_AUTO_TEST_CASE(test_file_ends_without_lf)
BOOST_AUTO_TEST_CASE(test_parse_function_compiles)
{
const auto c = [](std::string& s) -> const std::string& { return s; };
/*mutable*/ std::string example = testinput("example.toml");
// toml::parse("");
const auto string_literal = toml::parse("toml/tests/example.toml");
using result_type = decltype(toml::parse("string literal"));
BOOST_TEST_MESSAGE("string_literal");
const char* fname_cstring = "toml/tests/example.toml";
// toml::parse(const char*);
const auto cstring = toml::parse(fname_cstring);
const result_type cstring = toml::parse(example.c_str());
BOOST_TEST_MESSAGE("const char*");
// toml::parse(char*);
std::array<char, 24> fname_char_ptr;
std::strncpy(fname_char_ptr.data(), fname_cstring, 24);
const auto char_ptr = toml::parse(fname_char_ptr.data());
const result_type char_ptr = toml::parse(&example.front());
BOOST_TEST_MESSAGE("char*");
// toml::parse(const std::string&);
const std::string fname_string("toml/tests/example.toml");
const auto string = toml::parse(fname_string);
std::string fname_string_mut("toml/tests/example.toml");
const result_type string = toml::parse(c(example));
// toml::parse(std::string&);
const auto string_mutref = toml::parse(fname_string_mut);
const result_type string_mutref = toml::parse(example);
// toml::parse(std::string&&);
const auto string_rref = toml::parse(std::move(fname_string_mut));
const result_type string_rref = toml::parse(std::move(example));
BOOST_TEST_MESSAGE("strings");
#ifdef TOML11_HAS_STD_FILESYSTEM
const std::filesystem::path fname_path(fname_string.begin(), fname_string.end());
const auto filesystem_path = toml::parse(fname_path);
const std::filesystem::path fname_path(example.begin(), example.end());
const result_type filesystem_path = toml::parse(fname_path);
BOOST_TEST_MESSAGE("path");
#endif
}

View File

@ -7,10 +7,22 @@
#include <toml.hpp>
#include <iostream>
#include <fstream>
#include <cstdlib>
static auto testinput(const std::string& basename) -> std::string
{
const auto this_or_that = [](const char *const s, const char *const t) { return s ? s : t; };
std::string directory = this_or_that(std::getenv("TOMLDIR"), "toml");
if (!directory.empty() && directory.back() != '/')
{
directory.push_back('/');
}
return directory.append("tests/").append(basename);
}
BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
{
const auto data = toml::parse("toml/tests/hard_example_unicode.toml");
const auto data = toml::parse(testinput("hard_example_unicode.toml"));
const auto the = toml::find<toml::table>(data, "the");
BOOST_TEST(toml::get<std::string>(the.at("test_string")) ==

View File

@ -5,6 +5,7 @@
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <cstdlib>
#include <deque>
#include <map>
#include <iostream>
@ -44,9 +45,20 @@ bool has_comment_inside(const toml::basic_value<Comment, Table, Array>& v)
return true;
}
static auto testinput(const std::string& basename) -> std::string
{
const auto this_or_that = [](const char *const s, const char *const t) { return s ? s : t; };
std::string directory = this_or_that(std::getenv("TOMLDIR"), "toml");
if (!directory.empty() && directory.back() != '/')
{
directory.push_back('/');
}
return directory.append("tests/").append(basename);
}
BOOST_AUTO_TEST_CASE(test_example)
{
const auto data = toml::parse("toml/tests/example.toml");
const auto data = toml::parse(testinput("example.toml"));
{
std::ofstream ofs("tmp1.toml");
ofs << std::setw(80) << data;
@ -68,7 +80,7 @@ BOOST_AUTO_TEST_CASE(test_example)
BOOST_AUTO_TEST_CASE(test_example_map_dq)
{
const auto data = toml::parse<toml::discard_comments, std::map, std::deque>(
"toml/tests/example.toml");
testinput("example.toml"));
{
std::ofstream ofs("tmp1_map_dq.toml");
ofs << std::setw(80) << data;
@ -90,7 +102,7 @@ BOOST_AUTO_TEST_CASE(test_example_map_dq)
BOOST_AUTO_TEST_CASE(test_example_with_comment)
{
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
const auto data = toml::parse<toml::preserve_comments>(testinput("example.toml"));
{
std::ofstream ofs("tmp1_com.toml");
ofs << std::setw(80) << data;
@ -116,7 +128,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment)
BOOST_AUTO_TEST_CASE(test_example_with_comment_nocomment)
{
{
const auto data = toml::parse<toml::preserve_comments>("toml/tests/example.toml");
const auto data = toml::parse<toml::preserve_comments>(testinput("example.toml"));
{
std::ofstream ofs("tmp1_com_nocomment.toml");
ofs << std::setw(80) << toml::nocomment << data;
@ -126,7 +138,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_nocomment)
BOOST_TEST(!has_comment_inside(serialized));
}
{
const auto data_nocomment = toml::parse<toml::discard_comments>("toml/tests/example.toml");
const auto data_nocomment = toml::parse<toml::discard_comments>(testinput("example.toml"));
auto serialized = toml::parse<toml::discard_comments>("tmp1_com_nocomment.toml");
{
auto& owner = toml::find(serialized, "owner");
@ -145,7 +157,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_nocomment)
BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq)
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
"toml/tests/example.toml");
testinput("example.toml"));
{
std::ofstream ofs("tmp1_com_map_dq.toml");
ofs << std::setw(80) << data;
@ -172,7 +184,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq)
BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq_nocomment)
{
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>("toml/tests/example.toml");
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(testinput("example.toml"));
{
std::ofstream ofs("tmp1_com_map_dq_nocomment.toml");
ofs << std::setw(80) << toml::nocomment << data;
@ -181,7 +193,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq_nocomment)
BOOST_TEST(!has_comment_inside(serialized));
}
{
const auto data_nocomment = toml::parse<toml::discard_comments>("toml/tests/example.toml");
const auto data_nocomment = toml::parse<toml::discard_comments>(testinput("example.toml"));
auto serialized = toml::parse<toml::discard_comments>("tmp1_com_map_dq_nocomment.toml");
{
auto& owner = toml::find(serialized, "owner");
@ -198,7 +210,7 @@ BOOST_AUTO_TEST_CASE(test_example_with_comment_map_dq_nocomment)
BOOST_AUTO_TEST_CASE(test_fruit)
{
const auto data = toml::parse("toml/tests/fruit.toml");
const auto data = toml::parse(testinput("fruit.toml"));
{
std::ofstream ofs("tmp2.toml");
ofs << std::setw(80) << data;
@ -210,7 +222,7 @@ BOOST_AUTO_TEST_CASE(test_fruit)
BOOST_AUTO_TEST_CASE(test_fruit_map_dq)
{
const auto data = toml::parse<toml::discard_comments, std::map, std::deque>(
"toml/tests/fruit.toml");
testinput("fruit.toml"));
{
std::ofstream ofs("tmp2.toml");
ofs << std::setw(80) << data;
@ -222,7 +234,7 @@ BOOST_AUTO_TEST_CASE(test_fruit_map_dq)
BOOST_AUTO_TEST_CASE(test_fruit_with_comments)
{
const auto data = toml::parse<toml::preserve_comments>("toml/tests/fruit.toml");
const auto data = toml::parse<toml::preserve_comments>(testinput("fruit.toml"));
{
std::ofstream ofs("tmp2_com.toml");
ofs << std::setw(80) << data;
@ -234,7 +246,7 @@ BOOST_AUTO_TEST_CASE(test_fruit_with_comments)
BOOST_AUTO_TEST_CASE(test_fruit_with_comments_map_dq)
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
"toml/tests/fruit.toml");
testinput("fruit.toml"));
{
std::ofstream ofs("tmp2_com.toml");
ofs << std::setw(80) << data;
@ -245,7 +257,7 @@ BOOST_AUTO_TEST_CASE(test_fruit_with_comments_map_dq)
BOOST_AUTO_TEST_CASE(test_hard_example)
{
const auto data = toml::parse("toml/tests/hard_example.toml");
const auto data = toml::parse(testinput("hard_example.toml"));
{
std::ofstream ofs("tmp3.toml");
ofs << std::setw(80) << data;
@ -257,7 +269,7 @@ BOOST_AUTO_TEST_CASE(test_hard_example)
BOOST_AUTO_TEST_CASE(test_hard_example_map_dq)
{
const auto data = toml::parse<toml::discard_comments, std::map, std::deque>(
"toml/tests/hard_example.toml");
testinput("hard_example.toml"));
{
std::ofstream ofs("tmp3.toml");
ofs << std::setw(80) << data;
@ -270,7 +282,7 @@ BOOST_AUTO_TEST_CASE(test_hard_example_map_dq)
BOOST_AUTO_TEST_CASE(test_hard_example_with_comment)
{
const auto data = toml::parse<toml::preserve_comments, std::map, std::deque>(
"toml/tests/hard_example.toml");
testinput("hard_example.toml"));
{
std::ofstream ofs("tmp3_com.toml");
ofs << std::setw(80) << data;