From bbe40c5ba40af123cc971a9c5f893c0133a3c1ad Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 21 Mar 2018 14:10:10 -0400 Subject: [PATCH] Feature unittest (#157) * Adding support for unit testing using boost unit test and ctest * Adding libboost-test to Travis config. * Adding libboost-test to Travis config. * Modifying per element comparison * Modifying per element comparison * Fixing typo * Fixing typo * Adding custom comparison for strings * Updating Travis to run unit tests * Updating Travis to run unit tests * Fixing typo * Preparing unit testing to run on Appveyor * Preparing unit testing to run on Appveyor * Preparing unit testing to run on Appveyor * Preparing unit testing to run on Appveyor and Travis * Preparing unit testing to run on Appveyor and Travis * Preparing unit testing to run on Appveyor and Travis * Preparing unit testing to run on Appveyor * Preparing unit testing to run on Appveyor * Fixing unit testing path issue in CMake * Fixing unit testing path issue in CMake * Fixing bugs in cmake and appveyor scripts * Rolling back generate_export_header in cmake --- .travis.yml | 13 +- CMakeLists.txt | 35 +- appveyor.yml | 30 +- include/epanet2.h | 1 + tests/CMakeLists.txt | 46 +++ tests/data/net1.out | Bin 0 -> 16832 bytes tests/test_output.cpp | 358 ++++++++++++++++++ tools/epanet-output/CMakeLists.txt | 40 ++ .../{src => include}/epanet_output.h | 22 +- tools/epanet-output/setup.py | 2 + tools/requirements.txt | 3 +- 11 files changed, 520 insertions(+), 30 deletions(-) create mode 100644 tests/CMakeLists.txt create mode 100644 tests/data/net1.out create mode 100644 tests/test_output.cpp create mode 100644 tools/epanet-output/CMakeLists.txt rename tools/epanet-output/{src => include}/epanet_output.h (93%) diff --git a/.travis.yml b/.travis.yml index 69f29f6..0551ffe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,15 +3,15 @@ language: python env: global: - EPANET_HOME=`pwd` - - BUILD_HOME=buildproducts + - BUILD_HOME=buildprod - TEST_HOME=tests/epanet-nrtestsuite before_install: - sudo apt-get -qq update + - sudo apt-get install -y libboost-test-dev - sudo apt-get install -y swig -install: - - pip install --src build/packages -r tools/requirements.txt +#install: before_script: - mkdir -p $BUILD_HOME @@ -19,7 +19,12 @@ before_script: - cmake .. script: - - make + - cmake --build . + # run unit tests + - cd tests + - ctest + # run regression tests - cd $EPANET_HOME + - pip install -r tools/requirements.txt - tools/gen-config.sh $EPANET_HOME/$BUILD_HOME/bin > $TEST_HOME/apps/epanet-$TRAVIS_COMMIT.json - tools/run-nrtest.sh $TEST_HOME $TRAVIS_COMMIT diff --git a/CMakeLists.txt b/CMakeLists.txt index 787806c..808b836 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,11 +41,19 @@ cmake_minimum_required (VERSION 2.8.8) project(EPANET) +add_subdirectory(tools/epanet-output) +add_subdirectory(tests) -SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) -SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) + +# Sets for output directory for executables and libraries. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + +# Sets the position independent code property for all targets SET(CMAKE_POSITION_INDEPENDENT_CODE ON) + IF (APPLE) SET(CMAKE_INSTALL_NAME_DIR @executable_path) SET(CMAKE_BUILD_WITH_INSTALL_RPATH ON) @@ -56,20 +64,35 @@ IF (MSVC) add_definitions(-D_CRT_SECURE_NO_DEPRECATE) ENDIF (MSVC) -# create object library for reuse in other targets -include_directories(include src) + +#include_directories(include src) + # configure file groups file(GLOB EPANET_SOURCES src/*.c) -set(EPANET_API_HEADER include/epanet2.h) +#set(EPANET_API_HEADER include/epanet2.h) set(EPANET_CLI_SOURCES run/main.c) file(GLOB EPANET_LIB_ALL src/*) source_group("Library" FILES ${EPANET_LIB_ALL}) source_group("CLI" REGULAR_EXPRESSION "run/.*") + # the shared library -add_library(epanet SHARED ${EPANET_SOURCES} ${EPANET_API_HEADER}) +add_library(epanet SHARED ${EPANET_SOURCES}) #${EPANET_API_HEADER}) +target_include_directories(epanet PUBLIC ${PROJECT_SOURCE_DIR}/include) + +# create export lib so we can link against dll using Visual Studio +#include(GenerateExportHeader) +#GENERATE_EXPORT_HEADER(epanet +# BASE_NAME epanet +# EXPORT_MACRO_NAME DLLEXPORT +# EXPORT_FILE_NAME epanet_export.h +# STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC) +# +#file(COPY ${CMAKE_CURRENT_BINARY_DIR}/epanet_export.h +# DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/include) + # the standalone executable add_executable(runepanet ${EPANET_CLI_SOURCES}) diff --git a/appveyor.yml b/appveyor.yml index 42eece6..56ef02d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ # US EPA - ORD/NRMRL # -version: 2.0.{build} +version: 2.0.{build} image: - Visual Studio 2013 @@ -17,32 +17,42 @@ init: - set EPANET_HOME=%APPVEYOR_BUILD_FOLDER% - set BUILD_HOME=buildprod - set TEST_HOME=tests\epanet-nrtestsuite - - set NRTEST_SCRIPT=%EPANET_HOME%\%BUILD_HOME%\packages\nrtest\scripts + - set NRTEST_SCRIPT=C:\Python27\Scripts - set GENERATOR="Visual Studio 10 2010" - -cache: - - C:\ProgramData\chocolatey\bin -> appveyor.yml - - C:\ProgramData\chocolatey\lib -> appveyor.yml - - '%BUILD_HOME% -> CMakeLists.txt' + - set BOOST_ROOT="C:\\Libraries\\boost" + - set BOOST_LIB="C:\\Libraries\\boost\\lib32-msvc-12.0" # called after repo clone install: - choco install swig - - python -m pip install --src %BUILD_HOME%\packages -r tools\requirements.txt # called before build before_build: + - mkdir %BUILD_HOME% - cd %BUILD_HOME% - - cmake -G %GENERATOR% -DCMAKE_BUILD_TYPE=Release .. + - cmake -G %GENERATOR% + -DBOOST_ROOT="%BOOST_ROOT%" + -DBOOST_LIBRARYDIR="%BOOST_LIB%" + -DBoost_USE_STATIC_LIBS="ON" .. # run custom build script build_script: - - cmake --build . --target runepanet --config Release + - cmake --build . --config Release before_test: - cd %EPANET_HOME% + - python -m pip install -r tools\requirements.txt - tools\gen-config.cmd %EPANET_HOME%\%BUILD_HOME%\bin\Release > %TEST_HOME%\apps\epanet-%APPVEYOR_REPO_COMMIT%.json # run custom test script test_script: + # run unit tests + - cd %BUILD_HOME%\tests + - ctest -C Release + # run regression tests + - cd %EPANET_HOME% - tools\run-nrtest.cmd %NRTEST_SCRIPT% %TEST_HOME% %APPVEYOR_REPO_COMMIT% + +cache: + - C:\ProgramData\chocolatey\bin -> appveyor.yml + - C:\ProgramData\chocolatey\lib -> appveyor.yml diff --git a/include/epanet2.h b/include/epanet2.h index 55250f8..ebd367b 100644 --- a/include/epanet2.h +++ b/include/epanet2.h @@ -60,6 +60,7 @@ #endif #endif +//#include "epanet_export.h" // --- Define the EPANET toolkit constants diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..609d0b4 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,46 @@ +# +# CMakeLists.txt - CMake configuration file for epanet/tests +# +# Created: February 13, 2018 +# Author: Constantin Savtchenko +# Ref: http://neyasystems.com/an-engineers-guide-to-unit-testing-cmake-and-boost-unit-tests/ +# +# Modified by: Michael E. Tryby +# US EPA ORD/NRMRL +# + +#Setup CMake to run tests +enable_testing() + + +# Sets for output directory for executables and libraries. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + + +#Prep ourselves for compiling boost +find_package(Boost REQUIRED) +include_directories (${Boost_INCLUDE_DIRS}) + + +#I like to keep test files in a separate source directory called test +file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test_*.cpp) + + +#Run through each source +foreach(testSrc ${TEST_SRCS}) + #Extract the filename without an extension (NAME_WE) + get_filename_component(testName ${testSrc} NAME_WE) + + #Add compile target + add_executable(${testName} ${testSrc}) + + #link to Boost libraries AND your targets and dependencies + target_link_libraries(${testName} ${Boost_LIBRARIES} epanet epanet-output) + + + #Finally add it to test execution - + #Notice the WORKING_DIRECTORY and COMMAND + add_test(NAME ${testName} + COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${testName} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data) +endforeach(testSrc) diff --git a/tests/data/net1.out b/tests/data/net1.out new file mode 100644 index 0000000000000000000000000000000000000000..6cede26b23767e4bd91a30d2ccaba14f34904ba3 GIT binary patch literal 16832 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 VZ{1BMO!v?feK@&oH21$7{s%(sdMW?_ literal 0 HcmV?d00001 diff --git a/tests/test_output.cpp b/tests/test_output.cpp new file mode 100644 index 0000000..cd55f4f --- /dev/null +++ b/tests/test_output.cpp @@ -0,0 +1,358 @@ +/* + * test_epanet_output.cpp + * + * Created: 8/4/2017 + * Author: Michael E. Tryby + * US EPA - ORD/NRMRL + * + * Unit testing for EPANET Output API. +*/ + +// NOTE: Travis installs libboost test version 1.5.4 +// NOTE: Can not dyn link boost using Visual Studio 10 2010 +//#define BOOST_TEST_DYN_LINK + +#define BOOST_TEST_MODULE "output" +#include + +#include +#include +#include +#include + +#include "epanet_output.h" + + +#define DATA_PATH "./net1.out" + +using namespace std; + +// Custom test to check the minimum number of correct decimal digits between +// the test and the ref vectors. +boost::test_tools::predicate_result check_cdd(std::vector& test, + std::vector& ref, long cdd_tol) +{ + float tmp, min_cdd = 100.0; + + // TODO: What is the vectors aren't the same length? + + std::vector::iterator test_it; + std::vector::iterator ref_it; + + for (test_it = test.begin(); test_it < test.end(); ++test_it) { + for (ref_it = ref.begin(); ref_it < ref.end(); ++ref_it) { + + if (*test_it != *ref_it) { + tmp = - log10f(abs(*test_it - *ref_it)); + if (tmp < min_cdd) min_cdd = tmp; + } + } + } + + if (min_cdd == 100.0) + return true; + else + return floor(min_cdd) <= cdd_tol; +} + +boost::test_tools::predicate_result check_string(std::string test, std::string ref) +{ + if (ref.compare(test) == 0) + return true; + else + return false; +} + +BOOST_AUTO_TEST_SUITE (test_output_auto) + +BOOST_AUTO_TEST_CASE(InitTest) { + ENR_Handle p_handle = NULL; + + int error = ENR_init(&p_handle); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(p_handle != NULL); +} + +BOOST_AUTO_TEST_CASE(OpenTest) { + std::string path = std::string(DATA_PATH); + ENR_Handle p_handle = NULL; + ENR_init(&p_handle); + + int error = ENR_open(p_handle, path.c_str()); + BOOST_REQUIRE(error == 0); + ENR_close(&p_handle); +} + +BOOST_AUTO_TEST_CASE(CloseTest) { + ENR_Handle p_handle = NULL; + int error = ENR_init(&p_handle); + + error = ENR_close(&p_handle); + BOOST_REQUIRE(error == -1); + BOOST_CHECK(p_handle != NULL); +} + +BOOST_AUTO_TEST_SUITE_END() + + +struct Fixture{ + Fixture() { + path = std::string(DATA_PATH); + + error = ENR_init(&p_handle); + ENR_clearError(p_handle); + error = ENR_open(p_handle, path.c_str()); + + array = NULL; + array_dim = 0; + } + ~Fixture() { + ENR_free((void**)&array); + error = ENR_close(&p_handle); + } + + std::string path; + int error; + ENR_Handle p_handle; + + float* array; + int array_dim; + +}; + +BOOST_AUTO_TEST_SUITE(test_output_fixture) + +BOOST_FIXTURE_TEST_CASE(test_getNetSize, Fixture) +{ + int *i_array = NULL; + + error = ENR_getNetSize(p_handle, &i_array, &array_dim); + BOOST_REQUIRE(error == 0); + + // nodes, tanks, links, pumps, valves + std::vector test; + test.assign(i_array, i_array + array_dim); + + const int ref_dim = 5; + int ref_array[ref_dim] = {11,2,13,1,0}; + + std::vector ref; + ref.assign(ref_array, ref_array + ref_dim); + + BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), test.end()); + + ENR_free((void**)&i_array); +} + +BOOST_FIXTURE_TEST_CASE(test_getElementName, Fixture) { + char* name = new char[MAXID]; + int length, index = 1; + + error = ENR_getElementName(p_handle, ENR_node, index, &name, &length); + BOOST_REQUIRE(error == 0); + + std::string test (name); + std::string ref ("10"); + BOOST_CHECK(check_string(test, ref)); + + delete(name); +} + +BOOST_FIXTURE_TEST_CASE(test_getNodeAttribute, Fixture) { + + error = ENR_getNodeAttribute(p_handle, 1, ENR_quality, &array, &array_dim); + BOOST_REQUIRE(error == 0); + + const int ref_dim = 11; + float ref_array[ref_dim] = { 1.0f, + 0.44407997f, + 0.43766347f, + 0.42827705f, + 0.41342604f, + 0.42804748f, + 0.44152543f, + 0.40502965f, + 0.38635802f, + 1.0f, + 0.96745253f}; + + std::vector ref_vec; + ref_vec.assign(ref_array, ref_array + ref_dim); + + + std::vector test_vec; + test_vec.assign(array, array + array_dim); + + BOOST_CHECK(check_cdd(test_vec, ref_vec, 3)); +} + +BOOST_FIXTURE_TEST_CASE(test_getLinkAttribute, Fixture) { + + error = ENR_getLinkAttribute(p_handle, 1, ENR_flow, &array ,&array_dim); + BOOST_REQUIRE(error == 0); + + const int ref_dim = 13; + float ref_array[ref_dim] = { 1848.5812f, + 1220.4274f, + 130.11162f, + 187.6893f, + 119.8884f, + 40.464489f, + -748.58112f, + 478.15378f, + 191.73459f, + 30.111609f, + 140.46449f, + 59.535515f, + 1848.5812f}; + + std::vector ref_vec; + ref_vec.assign(ref_array, ref_array + ref_dim); + + std::vector test_vec; + test_vec.assign(array, array + array_dim); + + BOOST_CHECK(check_cdd(test_vec, ref_vec, 3)); +} + +BOOST_FIXTURE_TEST_CASE(test_getNodeResult, Fixture) { + + error = ENR_getNodeResult(p_handle, 1, 2, &array, &array_dim); + BOOST_REQUIRE(error == 0); + + const int ref_dim = 4; + float ref_array[ref_dim] = {0.041142918f, + 150.0f, + 987.98358f, + 120.45029f}; + + std::vector ref_vec; + ref_vec.assign(ref_array, ref_array + ref_dim); + + std::vector test_vec; + test_vec.assign(array, array + array_dim); + + BOOST_CHECK(check_cdd(test_vec, ref_vec, 3)); +} + +BOOST_FIXTURE_TEST_CASE(test_getLinkResult, Fixture) { + + error = ENR_getLinkResult(p_handle, 24, 13, &array, &array_dim); + BOOST_REQUIRE(error == 0); + + const int ref_dim = 8; + float ref_array[ref_dim] = {0.58586824f, + 1892.2433f, + 0.0f, + -200.71875f, + 1.0f, + 3.0f, + 1.0f, + 0.0f}; + + std::vector ref_vec; + ref_vec.assign(ref_array, ref_array + ref_dim); + + std::vector test_vec; + test_vec.assign(array, array + array_dim); + + BOOST_CHECK(check_cdd(test_vec, ref_vec, 3)); +} + +BOOST_FIXTURE_TEST_CASE(test_getNodeSeries, Fixture){ + + error = ENR_getNodeSeries(p_handle, 2, ENR_pressure, 0, 10, &array, &array_dim); + BOOST_REQUIRE(error == 0); + + const int ref_dim = 10; + float ref_array[ref_dim] = {119.25731f, + 120.45029f, + 121.19854f, + 122.00622f, + 122.37414f, + 122.8122f, + 122.82034f, + 122.90379f, + 123.40434f, + 123.81807f}; + + std::vector ref_vec; + ref_vec.assign(ref_array, ref_array + ref_dim); + + std::vector test_vec; + test_vec.assign(array, array + array_dim); + + BOOST_CHECK(check_cdd(test_vec, ref_vec, 3)); +} + +BOOST_FIXTURE_TEST_CASE(test_getLinkSeries, Fixture) { + + error = ENR_getLinkSeries(p_handle, 2, ENR_flow, 0, 10, &array, &array_dim); + BOOST_REQUIRE(error == 0); + + const int ref_dim = 10; + float ref_array[ref_dim] = {1234.2072f, + 1220.4274f, + 1164.4f, + 1154.8175f, + 1100.0635f, + 1094.759f, + 1041.7854f, + 1040.7617f, + 1087.556f, + 1082.5011f}; + + std::vector ref_vec; + ref_vec.assign(ref_array, ref_array + ref_dim); + + std::vector test_vec; + test_vec.assign(array, array + array_dim); + + BOOST_CHECK(check_cdd(test_vec, ref_vec, 3)); +} + +BOOST_FIXTURE_TEST_CASE(test_getNetReacts, Fixture) { + + error = ENR_getNetReacts(p_handle, &array, &array_dim); + BOOST_REQUIRE(error == 0); + + const int ref_dim = 4; + float ref_array[ref_dim] = {18806.59f, + 85424.438f, + 115174.05f, + 238972.66f}; + + std::vector ref_vec; + ref_vec.assign(ref_array, ref_array + ref_dim); + + std::vector test_vec; + test_vec.assign(array, array + array_dim); + + BOOST_CHECK(check_cdd(test_vec, ref_vec, 2)); +} + +BOOST_FIXTURE_TEST_CASE(test_getEnergyUsage, Fixture) { + + int linkIdx; + + error = ENR_getEnergyUsage(p_handle, 1, &linkIdx, &array, &array_dim); + BOOST_REQUIRE(error == 0); + + const int ref_dim = 6; + float ref_array[ref_dim] = {57.712959f, + 75.0f, + 880.41583f, + 96.254318f, + 96.707115f, + 0.0f}; + + std::vector ref_vec; + ref_vec.assign(ref_array, ref_array + ref_dim); + + std::vector test_vec; + test_vec.assign(array, array + array_dim); + + BOOST_CHECK(check_cdd(test_vec, ref_vec, 3)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/epanet-output/CMakeLists.txt b/tools/epanet-output/CMakeLists.txt new file mode 100644 index 0000000..01002d7 --- /dev/null +++ b/tools/epanet-output/CMakeLists.txt @@ -0,0 +1,40 @@ +# +# CMakeLists.txt - CMake configuration file for epanet-output library +# +# Created: March 9, 2018 +# Author: Michael E. Tryby +# US EPA ORD/NRMRL +# + +cmake_minimum_required (VERSION 3.0) + + +# Sets for output directory for executables and libraries. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + + +set(CMAKE_C_VISIBILITY_PRESET hidden) +set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + + +# configure file groups +set(EPANET_OUT_SOURCES src/epanet_output.c src/errormanager.c) + + +# the binary output file API +add_library(epanet-output SHARED ${EPANET_OUT_SOURCES}) +target_include_directories(epanet-output PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) + +include(GenerateExportHeader) +generate_export_header(epanet-output + BASE_NAME epanet_output + EXPORT_MACRO_NAME DLLEXPORT + EXPORT_FILE_NAME epanet_output_export.h + STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC) + +file(COPY ${CMAKE_CURRENT_BINARY_DIR}/epanet_output_export.h DESTINATION + ${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/tools/epanet-output/src/epanet_output.h b/tools/epanet-output/include/epanet_output.h similarity index 93% rename from tools/epanet-output/src/epanet_output.h rename to tools/epanet-output/include/epanet_output.h index 36f826c..0066d16 100644 --- a/tools/epanet-output/src/epanet_output.h +++ b/tools/epanet-output/include/epanet_output.h @@ -61,15 +61,19 @@ typedef enum { } ENR_LinkAttribute; -#ifdef WINDOWS -#ifdef __cplusplus -#define DLLEXPORT __declspec(dllexport) __cdecl -#else -#define DLLEXPORT __declspec(dllexport) __stdcall -#endif -#else -#define DLLEXPORT -#endif +// #ifdef WINDOWS +// #ifdef __cplusplus +// #define DLLEXPORT __declspec(dllexport) __cdecl +// #else +// #define DLLEXPORT __declspec(dllexport) __stdcall +// #endif +// #else +// #define DLLEXPORT +// #endif + + +#include "epanet_output_export.h" + #ifdef __cplusplus extern "C" { diff --git a/tools/epanet-output/setup.py b/tools/epanet-output/setup.py index 90d57e0..d1ce65d 100644 --- a/tools/epanet-output/setup.py +++ b/tools/epanet-output/setup.py @@ -25,6 +25,8 @@ setup( version = "1.0", ext_modules = [ Extension("_epanet_output", + define_macros = [('epanet_output_EXPORTS', None)], + include_dirs = ['include'], sources = ['src/epanet_output.i', 'src/epanet_output.c', 'src/errormanager.c'], swig_opts=['-modern'], language = 'C' diff --git a/tools/requirements.txt b/tools/requirements.txt index 68b8c20..5a50cbd 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -11,6 +11,7 @@ # $ pip install --src build/packages -r tools/requirements.txt # --e git+https://github.com/OpenWaterAnalytics/nrtest.git@master#egg=nrtest +#-e git+https://github.com/OpenWaterAnalytics/nrtest.git@master#egg=nrtest +nrtest>=0.2.3 -e ./tools/epanet-output -e ./tools/nrtest-epanet