From c4d238e85cbf39fe14e083a0cc8f2382e4fdad12 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 31 Jul 2018 12:37:34 +1200 Subject: [PATCH 1/3] Fix some compilation warnings. --- src/bindings/c/exports.c | 1 + src/bindings/c/geometry.c | 2 +- src/bindings/c/pressure_resistance_flow.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bindings/c/exports.c b/src/bindings/c/exports.c index 590f872b..6c057156 100644 --- a/src/bindings/c/exports.c +++ b/src/bindings/c/exports.c @@ -17,6 +17,7 @@ void export_node_geometry_2d_c(const char *EXNODEFILE, int *EXNODEFILE_LEN, cons void export_data_geometry_c(const char *EXDATAFILE, int *EXDATAFILE_LEN, const char *name, int *name_len, int *offset); void export_elem_field_c(const char *EXELEMFIELD, int *EXELEMFIELD_LEN, const char *name, int *name_len, const char *field_name, int *field_name_len); +void export_terminal_ssgexch_c(const char *EXNODEFILE, int *EXNODEFILE_LEN, const char *name, int *name_len); void export_1d_elem_field(int ne_field, const char *EXELEMFILE, const char *group_name, const char *field_name ) { diff --git a/src/bindings/c/geometry.c b/src/bindings/c/geometry.c index 94f75eaf..60d992b1 100644 --- a/src/bindings/c/geometry.c +++ b/src/bindings/c/geometry.c @@ -99,7 +99,7 @@ int get_local_node_f(const char *ndimension, const char *np_global) { int dimension_len = strlen(ndimension); int np_global_len = strlen(np_global); - get_local_node_f_c(ndimension, &dimension_len, np_global, &np_global_len); + return get_local_node_f_c(ndimension, &dimension_len, np_global, &np_global_len); } void define_rad_from_geom(const char *order_system, double control_param, const char *start_from, diff --git a/src/bindings/c/pressure_resistance_flow.c b/src/bindings/c/pressure_resistance_flow.c index 9eb7973f..99cb4a41 100644 --- a/src/bindings/c/pressure_resistance_flow.c +++ b/src/bindings/c/pressure_resistance_flow.c @@ -1,5 +1,7 @@ #include "pressure_resistance_flow.h" +#include + void evaluate_prq_c(const char *mesh_type, int *mesh_type_len, int *grav_dirn, double *grav_factor, const char *bc_type, int *bc_type_len, double *inlet_bc, double *outlet_bc); void evaluate_prq(const char *mesh_type, int grav_dirn, double grav_factor, const char *bc_type, double inlet_bc, double outlet_bc) From ae33750ed06fc33400629181a2b9cc8d1d06ca94 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 31 Jul 2018 16:57:10 +1200 Subject: [PATCH 2/3] Add initial Python testing framework along with some documentation. --- .gitignore | 3 + cmake/PythonVirtualEnv.cmake | 50 ++++++++ documentation/testing.rst | 119 ++++++++++++++++-- src/bindings/CMakeLists.txt | 1 - tests/CMakeLists.txt | 1 + tests/bindings/CMakeLists.txt | 3 + tests/bindings/python/CMakeLists.txt | 25 ++++ tests/bindings/python/geometry_test.py | 27 ++++ tests/bindings/python/resources/square.ipnode | 68 ++++++++++ 9 files changed, 289 insertions(+), 8 deletions(-) create mode 100644 cmake/PythonVirtualEnv.cmake create mode 100644 tests/bindings/CMakeLists.txt create mode 100644 tests/bindings/python/CMakeLists.txt create mode 100644 tests/bindings/python/geometry_test.py create mode 100644 tests/bindings/python/resources/square.ipnode diff --git a/.gitignore b/.gitignore index f4f1a1e1..26e9c9f0 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,6 @@ CMakeLists.txt.user *.pyc __pycache__/ +# PyCharm +.idea/ + diff --git a/cmake/PythonVirtualEnv.cmake b/cmake/PythonVirtualEnv.cmake new file mode 100644 index 00000000..6c82d552 --- /dev/null +++ b/cmake/PythonVirtualEnv.cmake @@ -0,0 +1,50 @@ + + +set(VIRTUALENV_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/venv_for_tests" + CACHE INTERNAL "Path to virtualenv" ) +if (WIN32) + set(PYTHON_PLATFORM_BIN_DIR Scripts) +else () + set(PYTHON_PLATFORM_BIN_DIR bin) +endif () + +find_program(VIRTUALENV_PYTHON_EXECUTABLE python PATHS "${VIRTUALENV_DIRECTORY}/${PYTHON_PLATFORM_BIN_DIR}" NO_DEFAULT_PATH) +mark_as_advanced(VIRTUALENV_PYTHON_EXECTUABLE) + +if (NOT EXISTS "${VIRTUALENV_PYTHON_EXECTUABLE}") + function(_create_virtualenv_from_exec call) + execute_process(COMMAND + ${call} --python=${PYTHON_EXECUTABLE} ${VIRTUALENV_DIRECTORY} + RESULT_VARIABLE RESULT + ERROR_VARIABLE ERROR + OUTPUT_VARIABLE OUTPUT + ) + if(NOT "${RESULT}" STREQUAL "0") + message(STATUS "${RESULT}") + message(STATUS "${OUTPUT}") + message(STATUS "${ERROR}") + message(FATAL_ERROR "Could not create virtual environment.") + endif() + endfunction() + + get_filename_component(_PYTHON_BIN "${PYTHON_EXECUTABLE}" PATH) + find_program(VIRTUALENV_EXECUTABLE virtualenv) + mark_as_advanced(VIRTUALENV_EXECUTABLE) + + # Could also check for 'venv' and 'virtualenv' Python packages as we could use these instead of + # the virtualenv executable. + if (VIRTUALENV_EXECUTABLE) + message(STATUS "Creating virtual environment ...") + _create_virtualenv_from_exec("${VIRTUALENV_EXECUTABLE}") + else () + message(FATAL_ERROR "Could not find virtualenv.") + endif () + + find_program(VIRTUALENV_PYTHON_EXECUTABLE python PATHS "${VIRTUALENV_DIRECTORY}/${PYTHON_PLATFORM_BIN_DIR}" NO_DEFAULT_PATH) + + if (VIRTUALENV_PYTHON_EXECUTABLE) + message(STATUS "Creating virtual environment ... success") + else () + message(FATAL_ERROR "Virtual environment Python executable does not exist.") + endif () +endif () diff --git a/documentation/testing.rst b/documentation/testing.rst index 0d3abff0..9b4c0c45 100644 --- a/documentation/testing.rst +++ b/documentation/testing.rst @@ -5,10 +5,10 @@ Testing Testing is an integral part of developing software and validating the code. It is also builds trust in users of the software that the software will work as expected. When adding new code to the library itself a test must also be added. Ideally the tests test every single line of code so that we have 100% code coverage. When we have good coverage of tests over the library we inherently get regression testing. We don't want to have new code changes breaking code that is already considered to be working. -For the testing of the Fortran code the pFUnit testing framework has been chosen. The pFUnit testing framework uses Python to manage some of the test generation, without Python we cannot build the tests. +For the testing of the Fortran code the pFUnit testing framework has been chosen. The pFUnit testing framework uses Python to manage some of the test generation, therefore without Python we cannot build the tests. For testing the code from Python we use the *unittest* testing module that is part of the Python distribution. -How to add a test -================= +How to add a Fortran test +========================= All tests live under the *tests* tree and mirror what is in the source tree. In the following example we are going to add a new testing module for the *diagnostics* module in the *lib* directory from the *src* tree. @@ -19,11 +19,11 @@ To start we are first going to make sure we have the correct structure that matc tests/lib -exists and if not create it, from the command line on UNIX based oses this can be done with the *mkdir* command:: +exists and if not create it, from the command line on UNIX based oses this can be done with the *mkdir* command (of course this should already be done, so there are big problems if you have to run this command!):: - mkdir tests/lib + mkdir -p tests/lib -Once the directory structure is correct we then create the testing module. Because we want to test the diagnostics module from the library we will create a test file named *test_diagnostics.pf* in the *tests/lib* directory. The *pf* extension indicates that this file is a hybrid Python fortran file, this file is a preprocessor input file which is Fortran free format file with preprocessor directives added. To create the test a Python script will generate a valid Fortran file from directives written into this file. With your favourite text editor create a file named *test_diagnostics.pf*. We could choose *vi* for this task as shown below but any text editor will work:: +Once the directory structure is correct we then create the testing module. Because we want to test the *diagnostics* module from the library we will create a test file named *test_diagnostics.pf* in the *tests/lib* directory. The *pf* extension indicates that this file is a hybrid Python fortran file, this file is a preprocessor input file which is Fortran free format file with preprocessor directives added. To create the test a Python script will generate a valid Fortran file from directives written into this file. With your favourite text editor create a file named *test_diagnostics.pf*. We could choose *vi* for this task as shown below but any text editor will work:: vi tests/lib/test_diagnostics.pf @@ -47,7 +47,6 @@ Into this file we will write our first test for the module. This test will chec With our test written we now need to add this into the CMake build generation system. - Add test to CMake ----------------- @@ -99,3 +98,109 @@ we will also execute all tests if we execute the command:: A handy flag to add to both of these commands is the *--verbose* flag. This gives us the details output from each test and not just the summary statement. + +How to add a Python test +======================== + +In the following example we are going to add a new testing module for the *geometry* module for the *Python* bindings in the *src* tree. + +Write test +---------- + +To start we are first going to make sure we have the correct structure that matches the *src* tree. Starting from the root directory of the lungsim repository we need to make sure that the directory:: + + tests/bindings/python + +exists and if not create it, from the command line on UNIX based oses this can be done with the *mkdir* command (of course this should already be done, so there are big problems if you have to run this command!):: + + mkdir -p tests/bindings/python + +Once the directory structure is correct we then create the testing module. Because we want to test the *geometry* module from the library we will create a test file named *geometry_test.py* in the *tests/bindings/python* directory. We could choose *vi* for this task as shown below but any text editor will work:: + + vi tests/bindings/python/geometry_test.py + +This file is going to be a standard Python file that makes use of the *unittest* unit testing framework. In this file we are going to write our first test for the module. This test will check that the *define_node_geometry_2d* method correctly sets the value of the nodes read from the *square.ipnode* file:: + + import os + import unittest + + from aether.diagnostics import set_diagnostics_on + from aether.geometry import define_node_geometry_2d + from aether.arrays import check_node_xyz_2d + + # Look to see if the 'TEST_RESOURCES_DIR' is set otherwise fallback to a path + # relative to this file. + if 'TEST_RESOURCES_DIR' in os.environ: + resources_dir = os.environ['TEST_RESOURCES_DIR'] + else: + here = os.path.abspath(os.path.dirname(__file__)) + resources_dir = os.path.join(here, 'resources') + + + class GeometryTestCase(unittest.TestCase): + + def test_read_square(self): + set_diagnostics_on(False) + define_node_geometry_2d(os.path.join(resources_dir, 'square.ipnode')) + value = check_node_xyz_2d(1, 1, 10) + self.assertEqual(10, value) + + + if __name__ == '__main__': + unittest.main() + + +The first thing to note is that when we are handling external resources like files we should be explicit in where they are coming from. This is reason for the following statement:: + + if 'TEST_RESOURCES_DIR' in os.environ: + resources_dir = os.environ['TEST_RESOURCES_DIR'] + else: + here = os.path.abspath(os.path.dirname(__file__)) + resources_dir = os.path.join(here, 'resources') + +When we are using ctest to run the tests the *TEST_RESOURCES_DIR* environment variable defines the location of the resources directory. If this environment variable is not found then the fallback is to set the resources directory relative to the file itself. This allows us to run the test file in different environments. The end result is that we can explicitly state (in a relative sense) the location of the *square.ipnode* file resource for this test. + +The second point to note is that our test is defined within a **class** that derives from *unittest.TestCase*. Any class deriving from *unittest.TestCase* found in this file will be run as a test. This means we are free to have multiple classes derived from *unittest.testcase* if we so choose. The benefit of this is that we can group our tests by some heuristic. + +The third point is on the test itself. In this test we are testing to make sure that the correct value for the node is set when reading in a node geometry file. We use the *unittest* framework to assert that the value of the node is indeed 10. + +The final point is about the last two lines of the file. It is these two lines that get executed by ctest if they are missing the test will actually pass this is because no tests will have been run therefor it is important that these two lines are present at the bottom of every file that defines classes derived from *unittest.TestCase*. + +With our test written we now need to add this into the CMake build generation system. + +Add test to CMake +----------------- + +To make CMake aware of the new test we need to add an new entry in to the *TEST_SRCS* CMake variable in the file *tests/bindings/python/CMakeLists.txt*. For this example we need to add *geometry_test.py*. With this being our first Python test our *TEST_SRCS* variable will look like the following:: + + set(TEST_SRCS + geometry_test.py + ) + +Over time we should have a list of test files defined here. + +Run test +-------- + +The Python tests do not need building, as such, they do however require a little preprocessing for ctest to run them. We can make sure the preprocessing is done in one of two ways. + +1. Execute the test command:: + + make test + +2. Make CMake perform the preprocessing, and then run the tests with ctest:: + + cmake . + ctest + +All of these commands must of course be executed from within the build directory. + +We can of course run just some of the tests using the *-R* flag to ctest. To run just the Python tests we could execute the following command:: + + ctest -R python_ + +Don't forget about the verbose flag:: + + ctest -R python_ -V + +This command will show us more detailed output from the Python tests. diff --git a/src/bindings/CMakeLists.txt b/src/bindings/CMakeLists.txt index eb4f61a0..ea78bcc4 100644 --- a/src/bindings/CMakeLists.txt +++ b/src/bindings/CMakeLists.txt @@ -7,7 +7,6 @@ mark_as_advanced(SWIG_EXECUTABLE) if(SWIG_FOUND) option(AETHER_BUILD_PYTHON_BINDINGS "Build Python bindings for ${PROJECT_NAME}" YES) - if(AETHER_BUILD_PYTHON_BINDINGS) find_package(PythonInterp) find_package(PythonLibs) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 70566462..4135f489 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,3 +5,4 @@ add_subdirectory(pFUnit-3.2.9) include("${CMAKE_CURRENT_BINARY_DIR}/pFUnit-3.2.9/pFUnitConfig.cmake") add_subdirectory(lib) +add_subdirectory(bindings) diff --git a/tests/bindings/CMakeLists.txt b/tests/bindings/CMakeLists.txt new file mode 100644 index 00000000..915d0eca --- /dev/null +++ b/tests/bindings/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_subdirectory(python) + diff --git a/tests/bindings/python/CMakeLists.txt b/tests/bindings/python/CMakeLists.txt new file mode 100644 index 00000000..6f715ec0 --- /dev/null +++ b/tests/bindings/python/CMakeLists.txt @@ -0,0 +1,25 @@ + +# Create a Python virtual environment to use for testing. This is only done once. +include(PythonVirtualEnv) + +set(TEST_SRCS + geometry_test.py +) + +foreach(_TEST ${TEST_SRCS}) + # We'll actually take a copy of the test and run it from the build directory and not the source directory. + configure_file(${_TEST} ${_TEST} COPYONLY) + + # Set up the test. + get_filename_component(_TEST_NAME ${_TEST} NAME_WE) + set(_TEST_NAME python_${_TEST_NAME}) + add_test(NAME ${_TEST_NAME} COMMAND ${VIRTUALENV_PYTHON_EXECUTABLE} ${_TEST}) + if (WIN32) + set_tests_properties(${_TEST_NAME} PROPERTIES + ENVIRONMENT "PATH=$\;%PATH%;PYTHONPATH=${PROJECT_BINARY_DIR}/src/bindings/python;TEST_RESOURCES_DIR=${CMAKE_CURRENT_SOURCE_DIR}/resources") + else () + set_tests_properties(${_TEST_NAME} PROPERTIES + ENVIRONMENT "PYTHONPATH=${PROJECT_BINARY_DIR}/src/bindings/python;TEST_RESOURCES_DIR=${CMAKE_CURRENT_SOURCE_DIR}/resources") + endif () + +endforeach() diff --git a/tests/bindings/python/geometry_test.py b/tests/bindings/python/geometry_test.py new file mode 100644 index 00000000..c3e790ab --- /dev/null +++ b/tests/bindings/python/geometry_test.py @@ -0,0 +1,27 @@ +import os +import unittest + +from aether.diagnostics import set_diagnostics_on +from aether.geometry import define_node_geometry_2d +from aether.arrays import check_node_xyz_2d + +# Look to see if the 'TEST_RESOURCES_DIR' is set otherwise fallback to a path +# relative to this file. +if 'TEST_RESOURCES_DIR' in os.environ: + resources_dir = os.environ['TEST_RESOURCES_DIR'] +else: + here = os.path.abspath(os.path.dirname(__file__)) + resources_dir = os.path.join(here, 'resources') + + +class GeometryTestCase(unittest.TestCase): + + def test_read_square(self): + set_diagnostics_on(False) + define_node_geometry_2d(os.path.join(resources_dir, 'square.ipnode')) + value = check_node_xyz_2d(1, 1, 10) + self.assertEqual(10, value) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/bindings/python/resources/square.ipnode b/tests/bindings/python/resources/square.ipnode new file mode 100644 index 00000000..df934eb3 --- /dev/null +++ b/tests/bindings/python/resources/square.ipnode @@ -0,0 +1,68 @@ + CMISS Version 1.21 ipnode File Version 2 + Heading: 52 + + The number of nodes is [ 35]: 4 + Number of coordinates [ 3]: 3 + Do you want prompting for different versions of nj=1 [N]? N + Do you want prompting for different versions of nj=2 [N]? N + Do you want prompting for different versions of nj=3 [N]? N + The number of derivatives for coordinate 1 is [0]: 3 + The number of derivatives for coordinate 2 is [0]: 3 + The number of derivatives for coordinate 3 is [0]: 3 + + Node number [ 52]: 52 + The Xj(1) coordinate is [ 0.00000E+00]: 1.00000000e+02 + The derivative wrt direction 1 is [ 0.00000E+00]: 1.0000000000e+00 + The derivative wrt direction 2 is [ 0.00000E+00]: 0.0000000000e+00 + The derivative wrt directions 1 & 2 is [ 0.00000E+00]: 0.0000000000e+00 + The Xj(2) coordinate is [ 0.00000E+00]: 0.000000000e+00 + The derivative wrt direction 1 is [ 0.00000E+00]: 0.00000000e+00 + The derivative wrt direction 2 is [ 0.00000E+00]: -1.00000000e+00 + The derivative wrt directions 1 & 2 is [ 0.00000E+00]: 0.0000000000e+00 + The Xj(3) coordinate is [ 0.00000E+00]: 0.00000000e+00 + The derivative wrt direction 1 is [ 0.00000E+00]: 0.000000001e+00 + The derivative wrt direction 2 is [ 0.00000E+00]: 0.000000000e+00 + The derivative wrt directions 1 & 2 is [ 0.00000E+00]: 0.000000000e+00 + + Node number [ 53]: 53 + The Xj(1) coordinate is [ 0.00000E+00]: 2.00000000000e+02 + The derivative wrt direction 1 is [ 0.00000E+00]: 1.000000000e+00 + The derivative wrt direction 2 is [ 0.00000E+00]: 0.000000000e-00 + The derivative wrt directions 1 & 2 is [ 0.00000E+00]: 0.000000000e+00 + The Xj(2) coordinate is [ 0.00000E+00]: 0.000000000e+00 + The derivative wrt direction 1 is [ 0.00000E+00]: 0.000000000e+00 + The derivative wrt direction 2 is [ 0.00000E+00]: -1.000000000e+00 + The derivative wrt directions 1 & 2 is [ 0.00000E+00]: 0.000000000e+00 + The Xj(3) coordinate is [ 0.00000E+00]: 0.000000000e+00 + The derivative wrt direction 1 is [ 0.00000E+00]: 0.000000000e+00 + The derivative wrt direction 2 is [ 0.00000E+00]: 0.000000000e+00 + The derivative wrt directions 1 & 2 is [ 0.00000E+00]: 0.000000000e+00 + + Node number [ 54]: 54 + The Xj(1) coordinate is [ 0.00000E+00]: 1.000000000e+02 + The derivative wrt direction 1 is [ 0.00000E+00]: 1.0000000000e+00 + The derivative wrt direction 2 is [ 0.00000E+00]: 0.0000000000e+00 + The derivative wrt directions 1 & 2 is [ 0.00000E+00]: 0.0000000000e+00 + The Xj(2) coordinate is [ 0.00000E+00]: -1.00000000e+02 + The derivative wrt direction 1 is [ 0.00000E+00]: 0.00000000000e+00 + The derivative wrt direction 2 is [ 0.00000E+00]: -1.00000000000e+00 + The derivative wrt directions 1 & 2 is [ 0.00000E+00]: 0.00000000000e+00 + The Xj(3) coordinate is [ 0.00000E+00]: 0.000000000e+00 + The derivative wrt direction 1 is [ 0.00000E+00]: 0.0000000000e+00 + The derivative wrt direction 2 is [ 0.00000E+00]: 0.0000000000e+00 + The derivative wrt directions 1 & 2 is [ 0.00000E+00]: 0.0000000000e+00 + + Node number [ 56]: 56 + The Xj(1) coordinate is [ 0.00000E+00]: 2.00000000e+02 + The derivative wrt direction 1 is [ 0.00000E+00]: 1.000000000e+00 + The derivative wrt direction 2 is [ 0.00000E+00]: 0.000000000e+00 + The derivative wrt directions 1 & 2 is [ 0.00000E+00]: 0.000000000e+00 + The Xj(2) coordinate is [ 0.00000E+00]: -1.00000000e+02 + The derivative wrt direction 1 is [ 0.00000E+00]: 0.000000000e+00 + The derivative wrt direction 2 is [ 0.00000E+00]: -1.000000001e+00 + The derivative wrt directions 1 & 2 is [ 0.00000E+00]: 0.000000000e+00 + The Xj(3) coordinate is [ 0.00000E+00]: 0.00000000e+00 + The derivative wrt direction 1 is [ 0.00000E+00]: 0.0000000e+00 + The derivative wrt direction 2 is [ 0.00000E+00]: 0.0000000e+00 + The derivative wrt directions 1 & 2 is [ 0.00000E+00]: 0.0000000e+00 + From eead7680a119497f81a61e53af4ae3555ecd6546 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 31 Jul 2018 17:03:46 +1200 Subject: [PATCH 3/3] Rejig check_node_xyz_2d function to return a value. This is a more c-like way of returning a single variable. --- src/bindings/c/arrays.c | 7 +++++++ src/bindings/c/arrays.h | 1 + tests/bindings/python/geometry_test.py | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/bindings/c/arrays.c b/src/bindings/c/arrays.c index e64c8f72..2f7badf8 100644 --- a/src/bindings/c/arrays.c +++ b/src/bindings/c/arrays.c @@ -7,3 +7,10 @@ void set_node_field_value(int row, int col, double value) { set_node_field_value_c(&row, &col, &value); } + +double check_node_xyz_2d(int row, int col) +{ + double value; + check_node_xyz_2d_c(&row, &col, &value); + return value; +} diff --git a/src/bindings/c/arrays.h b/src/bindings/c/arrays.h index 1468b841..5ebdeb20 100644 --- a/src/bindings/c/arrays.h +++ b/src/bindings/c/arrays.h @@ -5,5 +5,6 @@ #include "symbol_export.h" SHO_PUBLIC void set_node_field_value(int row, int col, double value); +SHO_PUBLIC double check_node_xyz_2d(int row, int col); #endif /* AETHER_ARRAYS_H */ diff --git a/tests/bindings/python/geometry_test.py b/tests/bindings/python/geometry_test.py index c3e790ab..bdbb63a1 100644 --- a/tests/bindings/python/geometry_test.py +++ b/tests/bindings/python/geometry_test.py @@ -19,8 +19,8 @@ class GeometryTestCase(unittest.TestCase): def test_read_square(self): set_diagnostics_on(False) define_node_geometry_2d(os.path.join(resources_dir, 'square.ipnode')) - value = check_node_xyz_2d(1, 1, 10) - self.assertEqual(10, value) + value = check_node_xyz_2d(1, 1) + self.assertEqual(100, value) if __name__ == '__main__':