avoid having to use external test runner script by parsing environment variables directly

This commit is contained in:
Axel Kohlmeyer
2020-06-24 09:32:59 -04:00
parent 8cec13a038
commit ee5be42026
6 changed files with 137 additions and 28 deletions

View File

@ -430,6 +430,86 @@ size_t utils::trim_and_count_words(const std::string & text, const std::string &
return utils::count_words(utils::trim_comment(text), separators);
}
/* ----------------------------------------------------------------------
Convert string into words on whitespace while handling single and
double quotes.
------------------------------------------------------------------------- */
std::vector<std::string> utils::split_words(const std::string &text)
{
std::vector<std::string> list;
const char *buf = text.c_str();
std::size_t beg = 0;
std::size_t len = 0;
char c = *buf;
while (c) {
// leading whitespace
if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f') {
c = *++buf;
++beg;
continue;
};
len = 0;
// handle escaped/quoted text.
quoted:
// handle single quote
if (c == '\'') {
c = *++buf;
++len;
while (((c != '\'') && (c != '\0'))
|| ((c == '\\') && (buf[1] == '\''))) {
if ((c == '\\') && (buf[1] == '\'')) {
++buf;
++len;
}
c = *++buf;
++len;
}
c = *++buf;
++len;
// handle double quote
} else if (c == '"') {
c = *++buf;
++len;
while (((c != '"') && (c != '\0'))
|| ((c == '\\') && (buf[1] == '"'))) {
if ((c == '\\') && (buf[1] == '"')) {
++buf;
++len;
}
c = *++buf;
++len;
}
c = *++buf;
++len;
}
// unquoted
while (1) {
if ((c == '\'') || (c == '"')) goto quoted;
// skip escaped quote
if ((c == '\\') && ((buf[1] == '\'') || (buf[1] == '"'))) {
++buf;
++len;
c = *++buf;
++len;
}
if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n')
|| (c == '\f') || (c == '\0')) {
list.push_back(text.substr(beg,len));
beg += len;
break;
}
c = *++buf;
++len;
}
}
return list;
}
/* ----------------------------------------------------------------------
Return whether string is a valid integer number
------------------------------------------------------------------------- */

View File

@ -18,6 +18,7 @@
#include "lmptype.h"
#include <string>
#include <vector>
#include <cstdio>
namespace LAMMPS_NS {
@ -181,6 +182,20 @@ namespace LAMMPS_NS {
*/
size_t trim_and_count_words(const std::string & text, const std::string & separators = " \t\r\n\f");
/**
* \brief Take text and split into non-whitespace words.
*
* This can handle single and double quotes, escaped quotes,
* and escaped codes within quotes, but due to using an STL
* container and STL strings is rather slow because of making
* copies. Designed for parsing command lines and similar text
* and not for time critical processing. Use a tokenizer for that.
*
* \param text string that should be split
* \return STL vector with the words
*/
std::vector<std::string> split_words(const std::string &text);
/**
* \brief Check if string can be converted to valid integer
* \param text string that should be checked

View File

@ -37,20 +37,15 @@ target_link_libraries(pair_style PRIVATE lammps style_tests)
file(GLOB MOL_PAIR_TESTS LIST_DIRECTORIES false ${TEST_INPUT_FOLDER}/mol-pair-*.yaml)
foreach(TEST ${MOL_PAIR_TESTS})
string(REGEX REPLACE "^.*mol-pair-(.*)\.yaml" "MolPairStyle:\\1" TNAME ${TEST})
add_test(NAME ${TNAME}
COMMAND ${CMAKE_COMMAND} -DTEST_EXECUTABLE=$<TARGET_FILE:pair_style>
-DTEST_INPUT=${TEST} -DTEST_NAME=${TNAME} -P ${CMAKE_CURRENT_SOURCE_DIR}/TestRunner.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_test(NAME ${TNAME} COMMAND pair_style ${TEST} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(${TNAME} PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
endforeach()
# tests for metal-like atomic systems and related pair styles
file(GLOB ATOMIC_PAIR_TESTS LIST_DIRECTORIES false ${TEST_INPUT_FOLDER}/atomic-pair-*.yaml)
foreach(TEST ${ATOMIC_PAIR_TESTS})
string(REGEX REPLACE "^.*atomic-pair-(.*)\.yaml" "AtomicPairStyle:\\1" TNAME ${TEST})
add_test(NAME ${TNAME}
COMMAND ${CMAKE_COMMAND} -DTEST_EXECUTABLE=$<TARGET_FILE:pair_style>
-DTEST_INPUT=${TEST} -DTEST_NAME=${TNAME} -P ${CMAKE_CURRENT_SOURCE_DIR}/TestRunner.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_test(NAME ${TNAME} COMMAND pair_style ${TEST} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(${TNAME} PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
endforeach()
@ -58,10 +53,7 @@ endforeach()
file(GLOB MANYBODY_PAIR_TESTS LIST_DIRECTORIES false ${TEST_INPUT_FOLDER}/manybody-pair-*.yaml)
foreach(TEST ${MANYBODY_PAIR_TESTS})
string(REGEX REPLACE "^.*manybody-pair-(.*)\.yaml" "ManybodyPairStyle:\\1" TNAME ${TEST})
add_test(NAME ${TNAME}
COMMAND ${CMAKE_COMMAND} -DTEST_EXECUTABLE=$<TARGET_FILE:pair_style>
-DTEST_INPUT=${TEST} -DTEST_NAME=${TNAME} -P ${CMAKE_CURRENT_SOURCE_DIR}/TestRunner.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_test(NAME ${TNAME} COMMAND pair_style ${TEST} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(${TNAME} PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
endforeach()
@ -72,10 +64,8 @@ target_link_libraries(bond_style PRIVATE lammps style_tests)
file(GLOB BOND_TESTS LIST_DIRECTORIES false ${TEST_INPUT_FOLDER}/bond-*.yaml)
foreach(TEST ${BOND_TESTS})
string(REGEX REPLACE "^.*bond-(.*)\.yaml" "BondStyle:\\1" TNAME ${TEST})
add_test(NAME ${TNAME}
COMMAND ${CMAKE_COMMAND} -DTEST_EXECUTABLE=$<TARGET_FILE:bond_style>
-DTEST_INPUT=${TEST} -DTEST_NAME=${TNAME} -P ${CMAKE_CURRENT_SOURCE_DIR}/TestRunner.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_test(NAME ${TNAME} COMMAND bond_style ${TEST} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(${TNAME} PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
endforeach()
# angle style tester
@ -85,8 +75,6 @@ target_link_libraries(angle_style PRIVATE lammps style_tests)
file(GLOB ANGLE_TESTS LIST_DIRECTORIES false ${TEST_INPUT_FOLDER}/angle-*.yaml)
foreach(TEST ${ANGLE_TESTS})
string(REGEX REPLACE "^.*angle-(.*)\.yaml" "AngleStyle:\\1" TNAME ${TEST})
add_test(NAME ${TNAME}
COMMAND ${CMAKE_COMMAND} -DTEST_EXECUTABLE=$<TARGET_FILE:angle_style>
-DTEST_INPUT=${TEST} -DTEST_NAME=${TNAME} -P ${CMAKE_CURRENT_SOURCE_DIR}/TestRunner.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_test(NAME ${TNAME} COMMAND angle_style ${TEST} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(${TNAME} PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
endforeach()

View File

@ -1,8 +0,0 @@
# workaround to allow passing extra arguments to test runs
# through ctest via a TEST_ARGS environment variable
# This can be used to, e.g. reset reference data for individual
# tests from the build folder with "env TEST_ARGS=-u ctest -R sometest"
execute_process(COMMAND ${TEST_EXECUTABLE} ${TEST_INPUT} $ENV{TEST_ARGS} RESULT_VARIABLE rv)
if(NOT "${rv}" STREQUAL "0")
message(FATAL_ERROR "Test ${TEST_NAME} failed with status ${rv}")
endif()

View File

@ -17,9 +17,11 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <mpi.h>
#include <vector>
// common read_yaml_file function
bool read_yaml_file(const char *infile, TestConfig &config)
@ -76,6 +78,19 @@ int main(int argc, char **argv)
return 2;
}
// handle arguments passed via environment variable
std::vector<std::string> env = utils::split_words(getenv("TEST_ARGS"));
for (auto arg : env) {
if (arg == "-u") {
generate_yaml_file(argv[1], test_config);
return 0;
} else if (arg == "-s") {
print_stats = true;
} else if (arg == "-v") {
verbose = true;
}
}
int iarg = 2;
while (iarg < argc) {

View File

@ -18,6 +18,7 @@
#include <cstdio>
#include <cstdlib>
#include <string>
#include <vector>
using namespace LAMMPS_NS;
using ::testing::Eq;
@ -48,6 +49,24 @@ TEST(Utils, count_words_with_extra_spaces)
ASSERT_EQ(utils::count_words(" some text # comment "), 4);
}
TEST(Utils, split_words_simple)
{
std::vector<std::string> list = utils::split_words("one two three");
ASSERT_EQ(list.size(), 3);
}
TEST(Utils, split_words_quoted)
{
std::vector<std::string> list = utils::split_words("one 'two' \"three\"");
ASSERT_EQ(list.size(), 3);
}
TEST(Utils, split_words_escaped)
{
std::vector<std::string> list = utils::split_words("1\\' '\"two\"' 3\\\"");
ASSERT_EQ(list.size(), 3);
}
TEST(Utils, valid_integer1)
{
ASSERT_TRUE(utils::is_integer("10"));