From 1c9c46d2c1811531a18b05b10ec0f33f8104ecee Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Wed, 24 Mar 2021 15:42:38 -0400 Subject: [PATCH] Add tests to cover python command --- src/PYTHON/python_impl.cpp | 1 + unittest/python/func.py | 8 ++ unittest/python/run.py | 2 + unittest/python/test_python_package.cpp | 100 +++++++++++++++++++++++- 4 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 unittest/python/run.py diff --git a/src/PYTHON/python_impl.cpp b/src/PYTHON/python_impl.cpp index 1f45ca6635..4c43ca3744 100644 --- a/src/PYTHON/python_impl.cpp +++ b/src/PYTHON/python_impl.cpp @@ -506,6 +506,7 @@ int PythonImpl::create_entry(char *name) "cannot be used unless output is a string"); pfuncs[ifunc].length_longstr = length_longstr; pfuncs[ifunc].longstr = new char[length_longstr+1]; + pfuncs[ifunc].longstr[length_longstr] = '\0'; } if (strstr(ostr,"v_") != ostr) error->all(FLERR,"Invalid python command"); diff --git a/unittest/python/func.py b/unittest/python/func.py index cc2269c435..cf8db41670 100644 --- a/unittest/python/func.py +++ b/unittest/python/func.py @@ -9,6 +9,11 @@ def bool_to_val(txt): return 1.0 return 0.0 +def val_to_bool(val): + if val != 0: + return "True" + return "False" + def printnum(): print("2.25") @@ -20,3 +25,6 @@ def getidxvar(lmpptr): lmp = lammps(ptr=lmpptr) val = lmp.extract_variable("idx") print(val) + +def longstr(): + return "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent metus." diff --git a/unittest/python/run.py b/unittest/python/run.py new file mode 100644 index 0000000000..7cdb205f50 --- /dev/null +++ b/unittest/python/run.py @@ -0,0 +1,2 @@ +from __future__ import print_function +print("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent metus.") diff --git a/unittest/python/test_python_package.cpp b/unittest/python/test_python_package.cpp index a7cf52c74e..f7a184b6b3 100644 --- a/unittest/python/test_python_package.cpp +++ b/unittest/python/test_python_package.cpp @@ -15,6 +15,7 @@ #include "info.h" #include "input.h" #include "variable.h" +#include "library.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -31,11 +32,14 @@ std::string INPUT_FOLDER = STRINGIFY(TEST_INPUT_FOLDER); // whether to print verbose output (i.e. not capturing LAMMPS screen output). bool verbose = false; +const char * LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent metus."; + using LAMMPS_NS::utils::split_words; namespace LAMMPS_NS { using ::testing::MatchesRegex; using ::testing::StrEq; +using ::testing::Eq; using ::testing::HasSubstr; class PythonPackageTest : public ::testing::Test { @@ -45,6 +49,8 @@ protected: void command(const std::string &line) { lmp->input->one(line.c_str()); } + void command_string(const std::string &lines) { lammps_commands_string(lmp, lines.c_str()); } + void HIDE_OUTPUT(std::function f) { if (!verbose) ::testing::internal::CaptureStdout(); f(); @@ -66,6 +72,10 @@ protected: return value; } + std::string get_variable_string(const std::string & name) { + return lmp->input->variable->retrieve(name.c_str()); + } + void SetUp() override { const char *args[] = {"PythonPackageTest", "-log", "none", "-echo", "screen", "-nocite"}; @@ -121,6 +131,7 @@ TEST_F(PythonPackageTest, InvokeFunctionPassInt) HIDE_OUTPUT([&] { command("variable sq python square"); command("python square input 1 2 format ii return v_sq file ${input_dir}/func.py"); + command("python square invoke"); }); ASSERT_EQ(get_variable_value("sq"), 4.0); @@ -169,6 +180,38 @@ TEST_F(PythonPackageTest, InvokeFunctionPassStringVariable) ASSERT_EQ(get_variable_value("val"), 0.0); } +TEST_F(PythonPackageTest, InvokeStringFunction) +{ + // execute python function, passing string variable as argument + HIDE_OUTPUT([&] { + command("variable str python val_to_bool"); + command("python val_to_bool input 1 v_val format is return v_str file ${input_dir}/func.py"); + }); + + HIDE_OUTPUT([&] { + command("variable val equal 0"); + }); + + ASSERT_THAT(get_variable_string("str"), StrEq("False")); + + HIDE_OUTPUT([&] { + command("variable val equal 1"); + }); + + ASSERT_THAT(get_variable_string("str"), StrEq("True")); +} + +TEST_F(PythonPackageTest, InvokeLongStringFunction) +{ + // execute python function, passing string variable as argument + HIDE_OUTPUT([&] { + command("variable str python longstr"); + command("python longstr format s length 72 return v_str file ${input_dir}/func.py"); + }); + + ASSERT_THAT(get_variable_string("str"), StrEq(LOREM_IPSUM)); +} + TEST_F(PythonPackageTest, InvokeOtherFunctionFromFile) { // execute another python function from same file @@ -211,6 +254,61 @@ TEST_F(PythonPackageTest, python_variable) ASSERT_THAT(output, MatchesRegex("print.*2.25.*")); } +TEST_F(PythonPackageTest, InlineFunction) +{ + // define variable that evaluates a python function + HIDE_OUTPUT([&] { + command("variable fact python factorial"); + command("python factorial input 1 v_n return v_fact format ii here \"\"\"\n" + "def factorial(n):\n" + " if n == 0 or n == 1: return 1\n" + " return n*factorial(n-1)\n" + "\"\"\""); + }); + + HIDE_OUTPUT([&] { + command("variable n equal 1"); + }); + + ASSERT_EQ(get_variable_value("fact"), 1.0); + + HIDE_OUTPUT([&] { + command("variable n equal 2"); + }); + + ASSERT_EQ(get_variable_value("fact"), 2.0); + + HIDE_OUTPUT([&] { + command("variable n equal 3"); + }); + + ASSERT_EQ(get_variable_value("fact"), 6.0); +} + +TEST_F(PythonPackageTest, RunSource) +{ + // execute python script from file + auto output = CAPTURE_OUTPUT([&] { + command("python xyz source ${input_dir}/run.py"); + }); + + ASSERT_THAT(output, HasSubstr(LOREM_IPSUM)); +} + +TEST_F(PythonPackageTest, RunSourceInline) +{ + // execute inline python script + auto output = CAPTURE_OUTPUT([&] { + command("python xyz source \"\"\"\n" + "from __future__ import print_function\n" + "print(2+2)\n" + "\"\"\"" + ); + }); + + ASSERT_THAT(output, HasSubstr("4")); +} + } // namespace LAMMPS_NS int main(int argc, char **argv) @@ -220,7 +318,7 @@ int main(int argc, char **argv) // handle arguments passed via environment variable if (const char *var = getenv("TEST_ARGS")) { - std::vector env = split_words(var); + auto env = split_words(var); for (auto arg : env) { if (arg == "-v") { verbose = true;