// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause /** * @class vtkTestUtilities * @brief Utility functions used for regression testing. * * vtkTestUtilities provides methods to perform common testing operations. * These include getting a command line argument or an environment variable, * or a default value. Particularly, there are specialized methods to get the * root directory for VTK Data, expanding a filename with this root directory. * * It also provides methods for testing whether two `vtkDataObjects`, * `vtkFieldData`, or `vtkAbstractArray` are equal up to numerical precision. * * Near-equality is defined as follows for floating point tuples u and v represented as vectors: * * \f[ || u - v ||^2 < k \epsilon (||u||^2 + ||v||^2) \f] * * Where \f$\epsilon\f$ is the smallest * positive floating-point number such that \f$ 1.0 + \epsilon \neq 1.0\f]$, and \f$k\f$ is what we * call the tolerance factor in this class, which is a `double` greater or equal than 1.0. The * tolerance factor shall not be strictly smaller than 1.0 as we would be below numerical precision. * A typical range for it is between 1.0 and 100.0. */ #ifndef vtkTestUtilities_h #define vtkTestUtilities_h #include "vtkSystemIncludes.h" #include "vtkTestingCoreModule.h" // for export macro #ifdef __EMSCRIPTEN__ #include "vtkEmscriptenTestUtilities.h" #endif #if defined(_MSC_VER) /* Visual C++ (and Intel C++) */ #pragma warning(disable : 4996) // 'function': was declared deprecated #endif VTK_ABI_NAMESPACE_BEGIN class vtkAbstractArray; class vtkDataObject; class vtkDataSet; class vtkFieldData; class vtkPartitionedDataSetCollection; class vtkCompositeDataSet; class vtkUnsignedCharArray; struct VTKTESTINGCORE_EXPORT vtkTestUtilities { /** * Function necessary for accessing the root directory for VTK data. Try the * -D command line argument or VTK_DATA_ROOT or a default value. The returned * string has to be deleted (with delete[]) by the user. */ static inline char* GetDataRoot(int argc, char* argv[]); /** * Given a file name, this function returns a new string which is (in theory) * the full path. This path is constructed by prepending the file name with a * command line argument (-D path) or VTK_DATA_ROOT env. variable. If slash * is true, appends a slash to the resulting string. The returned string has * to be deleted (with delete[]) by the user. */ static inline VTK_FILEPATH char* ExpandDataFileName( int argc, char* argv[], VTK_FILEPATH const char* fname, int slash = 0); /** * Function returning either a command line argument, an environment variable * or a default value. The returned string has to be deleted (with delete[]) * by the user. */ static inline char* GetArgOrEnvOrDefault( const char* arg, int argc, char* argv[], const char* env, const char* def); ///@{ /** * Given a file name, this function returns a new string which is (in theory) * the full path. This path is constructed by prepending the file name with a * command line argument, an environment variable or a default value. If * slash is true, appends a slash to the resulting string. The returned * string has to be deleted (with delete[]) by the user. */ static inline VTK_FILEPATH char* ExpandFileNameWithArgOrEnvOrDefault(const char* arg, int argc, char* argv[], const char* env, const char* def, VTK_FILEPATH const char* fname, int slash = 0); ///@} /** * Returns true if the 2 input `vtkDataObject` are identical. For the `vtkDataSet` case, this * function is invariant to point ordering and cell ordering, as well as point permutations within * cells, as long as they span the same topology. If the 2 inputs do not share the same typing, * this function will return false. In the case of `vtkDataSet` inputs, the cell types must match. * * Some ghost elements are discarded from the comparison, however the ghost arrays * (accessible through `vtkFieldData::GetGhostArray()`) must match. Within a `vtkFieldData` stored * inside an input `vtkDataObject`, ghosts elements are discarded if their bit representations * intersect `vtkFieldData::GetGhostsToSkip()`. * * @sa vtkCellData * @sa vtkDataSetAttributes * @sa vtkFieldData * @sa vtkPointData */ static bool CompareDataObjects( vtkDataObject* do1, vtkDataObject* do2, double toleranceFactor = 1.0); /** * Returns true if the 2 input `vtkDataSet` share the same point positions and `vtkPointData` at * those positions. This function is invariant to the point ordering between the 2 inputs. * * Some ghost elements are discarded from the comparison, however the ghost arrays * (accessible through `vtkFieldData::GetGhostArray()`) must match. Within a `vtkFieldData` stored * inside an input `vtkDataObject`, ghosts elements are discarded if their bit representations * intersect `vtkFieldData::GetGhostsToSkip()`. * * @sa vtkDataSetAttributes * @sa vtkFieldData * @sa vtkPointData */ static bool ComparePoints(vtkDataSet* ds1, vtkDataSet* ds2, double toleranceFactor = 1.0); /** * Returns true if the 2 input `vtkDataObject`'s cells are identical, assuming the input have * cells. This function supports `vtkDataSet` and `vtkHyperTreeGrid` inputs, and is * invariant to their cell ordering, as well as point permutations within * cells, as long as they span the same topology. * * Some ghost elements are discarded from the comparison, however the ghost arrays * (accessible through `vtkFieldData::GetGhostArray()`) must match. Within a `vtkFieldData` stored * inside an input `vtkDataObject`, ghosts elements are discarded if their bit representations * intersect `vtkFieldData::GetGhostsToSkip()`. * * @sa vtkCellData * @sa vtkDataSetAttributes * @sa vtkFieldData */ static bool CompareCells(vtkDataObject* do1, vtkDataObject* do2, double toleranceFactor = 1.0); /** * Returns true if the 2 input `vtkFieldData` are identical. * * Some ghost elements are discarded from the comparison, however the ghost arrays * (accessible through `vtkFieldData::GetGhostArray()`) must match. Within a `vtkFieldData` stored * inside an input `vtkDataObject`, ghosts elements are discarded if their bit representations * intersect `vtkFieldData::GetGhostsToSkip()`. * * @sa vtkCellData * @sa vtkDataSetAttributes * @sa vtkFieldData */ static bool CompareFieldData(vtkFieldData* fd1, vtkFieldData* fd2, double toleranceFactor = 1.0); /** * Returns true if the 2 input `vtkAbstractArray` are identical. The 2 arrays are assumed * to be ordered in the same manner. One can provide an input ghost array accompanied with * a bit mask `ghostsToSkip`, which will make this function skip corresponding tuples * in the input arrays. */ static bool CompareAbstractArray(vtkAbstractArray* array1, vtkAbstractArray* array2, double toleranceFactor = 1.0, vtkUnsignedCharArray* ghosts = nullptr, unsigned char ghostsToSkip = 0); #ifdef __EMSCRIPTEN__ static void PreloadDataFile(const char* fileName, const char* sandboxName); #endif }; inline char* vtkTestUtilities::GetDataRoot(int argc, char* argv[]) { return vtkTestUtilities::GetArgOrEnvOrDefault( "-D", argc, argv, "VTK_DATA_ROOT", "../../../../VTKData"); } inline char* vtkTestUtilities::ExpandDataFileName( int argc, char* argv[], const char* fname, int slash) { #ifdef __EMSCRIPTEN__ // determine where the file is located on the host file system using args/env. char* hostPath = vtkTestUtilities::ExpandFileNameWithArgOrEnvOrDefault( "-D", argc, argv, "VTK_DATA_ROOT", "../../../../VTKData", fname, slash); // preload file from host into the sandbox const size_t n = strlen(fname) + 1; char* sandboxPath = new char[n]; strncpy(sandboxPath, fname, n); vtkEmscriptenTestUtilities::PreloadDataFile(hostPath, sandboxPath); delete[] hostPath; return sandboxPath; #else return vtkTestUtilities::ExpandFileNameWithArgOrEnvOrDefault( "-D", argc, argv, "VTK_DATA_ROOT", "../../../../VTKData", fname, slash); #endif } inline char* vtkTestUtilities::GetArgOrEnvOrDefault( const char* arg, int argc, char* argv[], const char* env, const char* def) { int index = -1; for (int i = 0; i < argc; i++) { if (strcmp(arg, argv[i]) == 0 && i < argc - 1) { index = i + 1; } } char* value; if (index != -1) { value = new char[strlen(argv[index]) + 1]; strcpy(value, argv[index]); } else { char* foundenv = getenv(env); if (foundenv) { value = new char[strlen(foundenv) + 1]; strcpy(value, foundenv); } else if (def) { value = new char[strlen(def) + 1]; strcpy(value, def); } else { value = nullptr; } } return value; } inline char* vtkTestUtilities::ExpandFileNameWithArgOrEnvOrDefault(const char* arg, int argc, char* argv[], const char* env, const char* def, const char* fname, int slash) { char* fullName; char* value = vtkTestUtilities::GetArgOrEnvOrDefault(arg, argc, argv, env, def); if (value) { fullName = new char[strlen(value) + strlen(fname) + 2 + static_cast(slash ? 1 : 0)]; fullName[0] = 0; strcat(fullName, value); size_t len = strlen(fullName); fullName[len] = '/'; fullName[len + 1] = 0; strcat(fullName, fname); } else { fullName = new char[strlen(fname) + 1 + static_cast(slash ? 1 : 0)]; strcpy(fullName, fname); } if (slash) { strcat(fullName, "/"); } delete[] value; return fullName; } VTK_ABI_NAMESPACE_END #endif // vtkTestUtilities_h // VTK-HeaderTest-Exclude: vtkTestUtilities.h