From b88cda033f7657e12ff390b97a63a1d08dbc9c07 Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Fri, 19 Dec 2025 14:14:29 -0500 Subject: [PATCH] ENH: Use a python script to generate the skeleton code for a new filter --- scripts/filter.cpp.in | 70 ------- scripts/make_filter.py | 114 ++++++++++-- scripts/simplnx_algorithm.cpp.in | 42 +++++ scripts/simplnx_algorithm.hpp.in | 48 +++++ scripts/simplnx_docs.md.in | 35 ++++ scripts/simplnx_filter.cpp.in | 174 ++++++++++++++++++ .../{filter.hpp.in => simplnx_filter.hpp.in} | 62 +++++-- scripts/simplnx_unit_test.cpp.in | 85 +++++++++ 8 files changed, 536 insertions(+), 94 deletions(-) delete mode 100644 scripts/filter.cpp.in create mode 100644 scripts/simplnx_algorithm.cpp.in create mode 100644 scripts/simplnx_algorithm.hpp.in create mode 100644 scripts/simplnx_docs.md.in create mode 100644 scripts/simplnx_filter.cpp.in rename scripts/{filter.hpp.in => simplnx_filter.hpp.in} (66%) create mode 100644 scripts/simplnx_unit_test.cpp.in diff --git a/scripts/filter.cpp.in b/scripts/filter.cpp.in deleted file mode 100644 index 194fd6b4ca..0000000000 --- a/scripts/filter.cpp.in +++ /dev/null @@ -1,70 +0,0 @@ -#include "@FILTER_NAME@.hpp" - -//#include "simplnx/Common/StringLiteral.hpp" -// INSERT YOUR PARAMETER HEADERS -//#include "simplnx/Parameters/BoolParameter.hpp" -//#include "simplnx/Parameters/NumberParameter.hpp" - -using namespace nx::core; - -namespace -{ -// Use this section to set the "keys" for each parameter that your filter needs -// constexpr StringLiteral k_Param1Key = "param1"; -// constexpr StringLiteral k_Param2Key = "param2"; -} // namespace - -namespace nx::core -{ -std::string @FILTER_NAME@::name() const -{ - return FilterTraits<@FILTER_NAME@>::name; -} - -Uuid @FILTER_NAME@::uuid() const -{ - return FilterTraits<@FILTER_NAME@>::uuid; -} - -std::string @FILTER_NAME@::humanName() const -{ - return "@FILTER_NAME@"; -} - -Parameters @FILTER_NAME@::parameters() const -{ - Parameters params; - // Create the parameter descriptors that are needed for this filter - // params.insert(std::make_unique(k_Param1Key, "Parameter 1", "The 1st parameter", 0.1234f)); - // params.insert(std::make_unique(k_Param2Key, "Parameter 2", "The 2nd parameter", false)); - return params; -} - -IFilter::UniquePointer @FILTER_NAME@::clone() const -{ - return std::make_unique<@FILTER_NAME@>(); -} - -IFilter::PreflightResult @FILTER_NAME@::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs) const -{ - /**************************************************************************** - * Write any preflight sanity checking codes in this function - ***************************************************************************/ - return {}; -} - -Result<> @FILTER_NAME@::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs) const -{ - /**************************************************************************** - * Write your algorithm implementation in this function - ***************************************************************************/ - - /**************************************************************************** - * You will probably need to extract your parameters from the 'args' object - ***************************************************************************/ - // auto inputFloatValue = args.value(k_Param1Key); - // auto inputBoolValue = args.value(k_Param2Key); - - return {}; -} -} // namespace nx::core diff --git a/scripts/make_filter.py b/scripts/make_filter.py index 9337c4cca7..05d6fd2ddf 100644 --- a/scripts/make_filter.py +++ b/scripts/make_filter.py @@ -3,43 +3,130 @@ from pathlib import Path -def make_filter(output_dir: Path, name: str, template_dir: Path) -> None: - header_template_file = f'{template_dir}/filter.hpp.in' +def make_filter(plugin_dir: Path, name: str, template_dir: Path) -> None: + + plugin_name = plugin_dir.name + filter_name = f'{name}Filter' + header_template_file = f'{template_dir}/simplnx_filter.hpp.in' header_file_contents: str with open(header_template_file, 'r') as header_file: - header_file_contents = header_file.read().replace('@FILTER_NAME@', name).replace('@UUID@', str(uuid.uuid4())) + header_file_contents = header_file.read().replace('@FILTER_NAME@', filter_name).replace('@UUID@', str(uuid.uuid4())) + header_file_contents = header_file_contents.replace('@PLUGIN_NAME_UPPER@', plugin_name.upper()) + header_file_contents = header_file_contents.replace('@PLUGIN_NAME@', plugin_name) + header_file_contents = header_file_contents.replace('@PARAMETER_KEYS@', " // THESE NEED TO BE GENERATED\n") # write contents out to the new target header file - header_target_file = f'{output_dir}/{name}.hpp' + header_target_file = f'{plugin_dir}/src/{plugin_name}/Filters/{name}Filter.hpp' print(f'Writing Header file: {header_target_file}') with open(header_target_file, 'w') as header_file: header_file.write(header_file_contents) - cpp_template_file = f'{template_dir}/filter.cpp.in' + cpp_template_file = f'{template_dir}/simplnx_filter.cpp.in' cpp_file_contents: str with open(cpp_template_file, 'r') as cpp_file: - cpp_file_contents = cpp_file.read().replace('@FILTER_NAME@', name) + cpp_file_contents = cpp_file.read().replace('@ALGORITHM_NAME@', name) + cpp_file_contents = cpp_file_contents.replace('@FILTER_NAME@', filter_name) + cpp_file_contents = cpp_file_contents.replace('@PLUGIN_NAME@', plugin_name) + cpp_file_contents = cpp_file_contents.replace('@PARAMETER_KEYS@', " //TODO: THESE NEED TO BE GENERATED\n") + cpp_file_contents = cpp_file_contents.replace('@PARAMETER_INCLUDES@', "\n //TODO: PARAMETER_INCLUDES") + cpp_file_contents = cpp_file_contents.replace('@DEFAULT_TAGS@', "\"\"") + cpp_file_contents = cpp_file_contents.replace('@PARAMETER_DEFS@', "\n //TODO: PARAMETER_DEFS") + cpp_file_contents = cpp_file_contents.replace('@PREFLIGHT_DEFS@', "\n //TODO: PREFLIGHT_DEFS") + cpp_file_contents = cpp_file_contents.replace('@PROPOSED_ACTIONS@', "\n //TODO: PROPOSED_ACTIONS") + cpp_file_contents = cpp_file_contents.replace('@PREFLIGHT_UPDATED_DEFS@', "\n //TODO: PREFLIGHT_UPDATED_DEFS") + cpp_file_contents = cpp_file_contents.replace('@PREFLIGHT_UPDATED_VALUES@', "\n //TODO: PREFLIGHT_UPDATED_VALUES") + cpp_file_contents = cpp_file_contents.replace('@PARAMETER_JSON_CONSTANTS@', "\n //TODO: PARAMETER_JSON_CONSTANTS") + cpp_file_contents = cpp_file_contents.replace('@INPUT_VALUES_DEF@', "\n //TODO: INPUT_VALUES_DEF") + cpp_file_contents = cpp_file_contents.replace('@PARAMETER_JSON_CONVERSION@', "/* This is a NEW filter and not ported so this section does not matter */") + + # write contents out to the new target CPP file + cpp_target_file = f'{plugin_dir}/src/{plugin_name}/Filters/{name}Filter.cpp' + print(f'Writing CPP file: {cpp_target_file}') + with open(cpp_target_file, 'w') as cpp_file: + cpp_file.write(cpp_file_contents) + + # *************************************************************************** + # Algorithm File Generation + # *************************************************************************** + header_template_file = f'{template_dir}/simplnx_algorithm.hpp.in' + header_file_contents: str + with open(header_template_file, 'r') as header_file: + header_file_contents = header_file.read().replace('@FILTER_NAME@', name).replace('@UUID@', str(uuid.uuid4())) + header_file_contents = header_file_contents.replace('@PLUGIN_NAME_UPPER@', plugin_name.upper()) + header_file_contents = header_file_contents.replace('@PLUGIN_NAME@', plugin_name) + header_file_contents = header_file_contents.replace('@PARAMETER_KEYS@', " // THESE NEED TO BE GENERATED\n") + header_file_contents = header_file_contents.replace('@PARAMETER_INCLUDES@', "\n//TODO: PARAMETER_INCLUDES") + header_file_contents = header_file_contents.replace('@INPUT_VALUE_STRUCT_DEF@', "//TODO: INPUT_VALUE_STRUCT_DEF\n") # write contents out to the new target header file - cpp_target_file = f'{output_dir}/{name}.cpp' + header_target_file = f'{plugin_dir}/src/{plugin_name}/Filters/Algorithms/{name}.hpp' + print(f'Writing Header file: {header_target_file}') + with open(header_target_file, 'w') as header_file: + header_file.write(header_file_contents) + + cpp_template_file = f'{template_dir}/simplnx_algorithm.cpp.in' + cpp_file_contents: str + with open(cpp_template_file, 'r') as cpp_file: + cpp_file_contents = cpp_file.read().replace('@FILTER_NAME@', name) + + # write contents out to the new target CPP file + cpp_target_file = f'{plugin_dir}/src/{plugin_name}/Filters/Algorithms/{name}.cpp' print(f'Writing CPP file: {cpp_target_file}') with open(cpp_target_file, 'w') as cpp_file: cpp_file.write(cpp_file_contents) + # *************************************************************************** + # Unit test File Generation + # *************************************************************************** + cpp_template_file = f'{template_dir}/simplnx_unit_test.cpp.in' + cpp_file_contents: str + with open(cpp_template_file, 'r') as cpp_file: + cpp_file_contents = cpp_file.read().replace('@FILTER_NAME@', filter_name) + cpp_file_contents = cpp_file_contents.replace('@PARAMETER_INCLUDES@', "\n //TODO: PARAMETER_INCLUDES") + cpp_file_contents = cpp_file_contents.replace('@PLUGIN_NAME@', plugin_name) + cpp_file_contents = cpp_file_contents.replace('@PARAMETER_DEFS@', "\n //TODO: PARAMETER_DEFS") + + # write contents out to the new target CPP file + cpp_target_file = f'{plugin_dir}/test/{name}Test.cpp' + print(f'Writing Doc file: {cpp_target_file}') + with open(cpp_target_file, 'w') as cpp_file: + cpp_file.write(cpp_file_contents) + + + # *************************************************************************** + # Documentation File Generation + # *************************************************************************** + cpp_template_file = f'{template_dir}/simplnx_docs.md.in' + cpp_file_contents: str + with open(cpp_template_file, 'r') as cpp_file: + cpp_file_contents = cpp_file.read().replace('@FILTER_NAME@', name) + + # write contents out to the new target CPP file + cpp_target_file = f'{plugin_dir}/docs/{name}Filter.md' + print(f'Writing Doc file: {cpp_target_file}') + with open(cpp_target_file, 'w') as cpp_file: + cpp_file.write(cpp_file_contents) + + + print(f'===================================================================') - print(f'Do NOT forget to add your filter to the appropriate CMake Files') + print(f'Do NOT forget to add your filter and algorithm to the CMakeLists.txt file at:') + print(f'{plugin_dir}/CMakeLists.txt') + print(f'Update the unit test CMakeLists.txt file at:') + print(f'{plugin_dir}/test/CMakeLists.txt') + print(f'Do NOT forget to update the documentation file when you are done writing the file') print(f'===================================================================') def main() -> None: parser = argparse.ArgumentParser(description='Creates simplnx filter header and implementation skeleton codes') - parser.add_argument('-o', '--output_dir', type=Path, help='Input directory where files will be created') + parser.add_argument('-o', '--plugin_dir', type=Path, help='Plugin Directory to create the filter') parser.add_argument('-n', '--name', type=str, help='Name of filter') parser.add_argument('-t', '--template_dir', type=Path, help='Location of template files') args = parser.parse_args() print('args:') - print(f' output_dir = \"{args.output_dir}\"') + print(f' plugin_dir = \"{args.plugin_dir}\"') print(f' name = \"{args.name}\"') print(f' template_dir = \"{args.template_dir}\"') print('') @@ -48,7 +135,12 @@ def main() -> None: print(f' THIS WILL OVERWRITE ANY EXISTING FILE') print(f'===================================================================') - make_filter(args.output_dir, args.name, args.template_dir) + make_filter(args.plugin_dir, args.name, args.template_dir) if __name__ == '__main__': main() + +# ----------------------------------------------------------------------------- +# Example invocation +# python make_filter.py --plugin_dir /Users/mjackson/Workspace1/simplnx/src/Plugins/SimplnxCore --name "ReadNotesFile" --template_dir /Users/mjackson/Workspace1/simplnx/scripts +# ----------------------------------------------------------------------------- diff --git a/scripts/simplnx_algorithm.cpp.in b/scripts/simplnx_algorithm.cpp.in new file mode 100644 index 0000000000..647d173ec5 --- /dev/null +++ b/scripts/simplnx_algorithm.cpp.in @@ -0,0 +1,42 @@ +#include "@FILTER_NAME@.hpp" + +#include "simplnx/DataStructure/DataArray.hpp" +#include "simplnx/DataStructure/DataGroup.hpp" + +using namespace nx::core; + +// ----------------------------------------------------------------------------- +@FILTER_NAME@::@FILTER_NAME@(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, @FILTER_NAME@InputValues* inputValues) +: m_DataStructure(dataStructure) +, m_InputValues(inputValues) +, m_ShouldCancel(shouldCancel) +, m_MessageHandler(mesgHandler) +{ +} + +// ----------------------------------------------------------------------------- +@FILTER_NAME@::~@FILTER_NAME@() noexcept = default; + +// ----------------------------------------------------------------------------- +Result<> @FILTER_NAME@::operator()() +{ + /** + * This section of the code should contain the actual algorithmic codes that + * will accomplish the goal of the file. + * + * If you can parallelize the code there are a number of examples on how to do that. + * GenerateIPFColors is one example + * + * If you need to determine what kind of array you have (Int32Array, Float32Array, etc) + * look to the ExecuteDataFunction() in simplnx/Utilities/FilterUtilities.hpp template + * function to help with that code. + * An Example algorithm class is `CombineAttributeArrays` and `RemoveFlaggedVertices` + * + * There are other utility classes that can help alleviate the amount of code that needs + * to be written. + * + * REMOVE THIS COMMENT BLOCK WHEN YOU ARE FINISHED WITH THE FILTER_HUMAN_NAME + */ + + return {}; +} diff --git a/scripts/simplnx_algorithm.hpp.in b/scripts/simplnx_algorithm.hpp.in new file mode 100644 index 0000000000..7f30622807 --- /dev/null +++ b/scripts/simplnx_algorithm.hpp.in @@ -0,0 +1,48 @@ +#pragma once + +#include "@PLUGIN_NAME@/@PLUGIN_NAME@_export.hpp" + +#include "simplnx/DataStructure/DataPath.hpp" +#include "simplnx/DataStructure/DataStructure.hpp" +#include "simplnx/Filter/IFilter.hpp" +@PARAMETER_INCLUDES@ + +/** +* This is example code to put in the Execute Method of the filter. +@EXECUTE_EXAMPLE_CODE@ +*/ + +namespace nx::core +{ + +struct @PLUGIN_NAME_UPPER@_EXPORT @FILTER_NAME@InputValues +{ +@INPUT_VALUE_STRUCT_DEF@ +}; + +/** + * @class @FILTER_NAME@ + * @brief This algorithm implements support code for the @FILTER_NAME@Filter + */ + +class @PLUGIN_NAME_UPPER@_EXPORT @FILTER_NAME@ +{ +public: + @FILTER_NAME@(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, @FILTER_NAME@InputValues* inputValues); + ~@FILTER_NAME@() noexcept; + + @FILTER_NAME@(const @FILTER_NAME@&) = delete; + @FILTER_NAME@(@FILTER_NAME@&&) noexcept = delete; + @FILTER_NAME@& operator=(const @FILTER_NAME@&) = delete; + @FILTER_NAME@& operator=(@FILTER_NAME@&&) noexcept = delete; + + Result<> operator()(); + +private: + DataStructure& m_DataStructure; + const @FILTER_NAME@InputValues* m_InputValues = nullptr; + const std::atomic_bool& m_ShouldCancel; + const IFilter::MessageHandler& m_MessageHandler; +}; + +} // namespace complex diff --git a/scripts/simplnx_docs.md.in b/scripts/simplnx_docs.md.in new file mode 100644 index 0000000000..66b4db0404 --- /dev/null +++ b/scripts/simplnx_docs.md.in @@ -0,0 +1,35 @@ +# INSERT_HUMAN_NAME + +## Group (Subgroup) + +What group (and possibly subgroup) does the filter belong to + +## Description + +This **Filter** ..... + +Images can be used with this: + +![](Images/@FILTER_NAME@_1.png) + +## Warning + +## Notes + +## Caveats + +% Auto generated parameter table will be inserted here + +## Reference + + +## Example Pipelines + + +## License & Copyright + +Please see the description file distributed with this plugin. + +## DREAM3D Mailing Lists + +If you need help, need to file a bug report or want to request a new feature, please head over to the [DREAM3DNX-Issues](https://github.com/BlueQuartzSoftware/DREAM3DNX-Issues/discussions) GitHub site where the community of DREAM3D-NX users can help answer your questions. diff --git a/scripts/simplnx_filter.cpp.in b/scripts/simplnx_filter.cpp.in new file mode 100644 index 0000000000..3ec6850546 --- /dev/null +++ b/scripts/simplnx_filter.cpp.in @@ -0,0 +1,174 @@ +#include "@FILTER_NAME@.hpp" + +#include "@PLUGIN_NAME@/Filters/Algorithms/@ALGORITHM_NAME@.hpp" + +#include "simplnx/DataStructure/DataPath.hpp" +#include "simplnx/Filter/Actions/EmptyAction.hpp" +@PARAMETER_INCLUDES@ + +#include + +using namespace nx::core; + +namespace nx::core +{ +//------------------------------------------------------------------------------ +std::string @FILTER_NAME@::name() const +{ + return FilterTraits<@FILTER_NAME@>::name.str(); +} + +//------------------------------------------------------------------------------ +std::string @FILTER_NAME@::className() const +{ + return FilterTraits<@FILTER_NAME@>::className; +} + +//------------------------------------------------------------------------------ +Uuid @FILTER_NAME@::uuid() const +{ + return FilterTraits<@FILTER_NAME@>::uuid; +} + +//------------------------------------------------------------------------------ +std::string @FILTER_NAME@::humanName() const +{ + return "@FILTER_HUMAN_NAME@"; +} + +//------------------------------------------------------------------------------ +std::vector @FILTER_NAME@::defaultTags() const +{ + return {@DEFAULT_TAGS@}; +} + +//------------------------------------------------------------------------------ +Parameters @FILTER_NAME@::parameters() const +{ + Parameters params; + // Create the parameter descriptors that are needed for this filter + params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); + + /** + * Please separate the parameters into groups generally of the following: + * + * params.insertSeparator(Parameters::Separator{"Input Parameters"}); + * params.insertSeparator(Parameters::Separator{"Required Input Cell Data"}); + * params.insertSeparator(Parameters::Separator{"Required Input Feature Data"}); + * params.insertSeparator(Parameters::Separator{"Created Cell Data"}); + * params.insertSeparator(Parameters::Separator{"Created Cell Feature Data"}); + * + * .. or create appropriate separators as needed. The UI in COMPLEX no longer + * does this for the developer by using catgories as in SIMPL + */ + + // Create the parameter descriptors that are needed for this filter +@PARAMETER_DEFS@ + return params; +} + +//------------------------------------------------------------------------------ +IFilter::VersionType @FILTER_NAME@::parametersVersion() const +{ + return 1; +} + +//------------------------------------------------------------------------------ +IFilter::UniquePointer @FILTER_NAME@::clone() const +{ + return std::make_unique<@FILTER_NAME@>(); +} + +//------------------------------------------------------------------------------ +IFilter::PreflightResult @FILTER_NAME@::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel, const ExecutionContext& executionContext) const +{ + /**************************************************************************** + * Write any preflight sanity checking codes in this function + ***************************************************************************/ + + /** + * These are the values that were gathered from the UI or the pipeline file or + * otherwise passed into the filter. These are here for your convenience. If you + * do not need some of them remove them. + */ +@PREFLIGHT_DEFS@ + + + // Declare the preflightResult variable that will be populated with the results + // of the preflight. The PreflightResult type contains the output Actions and + // any preflight updated values that you want to be displayed to the user, typically + // through a user interface (UI). + PreflightResult preflightResult; + + // If your filter is making structural changes to the DataStructure then the filter + // is going to create OutputActions subclasses that need to be returned. This will + // store those actions. + nx::core::Result resultOutputActions; + + // If your filter is going to pass back some `preflight updated values` then this is where you + // would create the code to store those values in the appropriate object. Note that we + // in line creating the pair (NOT a std::pair<>) of Key:Value that will get stored in + // the std::vector object. + std::vector preflightUpdatedValues; + + // If the filter needs to pass back some updated values via a key:value string:string set of values + // you can declare and update that string here. +@PREFLIGHT_UPDATED_DEFS@ + // If this filter makes changes to the DataStructure in the form of + // creating/deleting/moving/renaming DataGroups, Geometries, DataArrays then you + // will need to use one of the `*Actions` classes located in complex/Filter/Actions + // to relay that information to the preflight and execute methods. This is done by + // creating an instance of the Action class and then storing it in the resultOutputActions variable. + // This is done through a `push_back()` method combined with a `std::move()`. For the + // newly initiated to `std::move` once that code is executed what was once inside the Action class + // instance variable is *no longer there*. The memory has been moved. If you try to access that + // variable after this line you will probably get a crash or have subtle bugs. To ensure that this + // does not happen we suggest using braces `{}` to scope each of the action's declaration and store + // so that the programmer is not tempted to use the action instance past where it should be used. + // You have to create your own Actions class if there isn't something specific for your filter's needs +@PROPOSED_ACTIONS@ + // Store the preflight updated value(s) into the preflightUpdatedValues vector using + // the appropriate methods. +@PREFLIGHT_UPDATED_VALUES@ + // Return both the resultOutputActions and the preflightUpdatedValues via std::move() + return {std::move(resultOutputActions), std::move(preflightUpdatedValues)}; +} + +//------------------------------------------------------------------------------ +Result<> @FILTER_NAME@::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel, const ExecutionContext& executionContext) const +{ + + @ALGORITHM_NAME@InputValues inputValues; + + @INPUT_VALUES_DEF@ + + return @ALGORITHM_NAME@(dataStructure, messageHandler, shouldCancel, &inputValues)(); +} + +namespace +{ +namespace SIMPL +{ + @PARAMETER_JSON_CONSTANTS@ +} // namespace SIMPL +} // namespace + + +//------------------------------------------------------------------------------ +Result @FILTER_NAME@::FromSIMPLJson(const nlohmann::json& json) +{ + Arguments args = @FILTER_NAME@().getDefaultArguments(); + + std::vector> results; + + @PARAMETER_JSON_CONVERSION@ + + Result<> conversionResult = MergeResults(std::move(results)); + + return ConvertResultTo(std::move(conversionResult), std::move(args)); +} + + +} // namespace nx::core diff --git a/scripts/filter.hpp.in b/scripts/simplnx_filter.hpp.in similarity index 66% rename from scripts/filter.hpp.in rename to scripts/simplnx_filter.hpp.in index 6bc4d9f95e..04535ce513 100644 --- a/scripts/filter.hpp.in +++ b/scripts/simplnx_filter.hpp.in @@ -1,12 +1,17 @@ #pragma once +#include "@PLUGIN_NAME@/@PLUGIN_NAME@_export.hpp" + #include "simplnx/Filter/FilterTraits.hpp" #include "simplnx/Filter/IFilter.hpp" -#include "simplnx/simplnx_export.hpp" namespace nx::core { -class SIMPLNX_EXPORT @FILTER_NAME@ : public IFilter +/** + * @class @FILTER_NAME@ + * @brief This filter will .... + */ +class @PLUGIN_NAME_UPPER@_EXPORT @FILTER_NAME@ : public IFilter { public: @FILTER_NAME@() = default; @@ -18,36 +23,66 @@ public: @FILTER_NAME@& operator=(const @FILTER_NAME@&) = delete; @FILTER_NAME@& operator=(@FILTER_NAME@&&) noexcept = delete; + // Parameter Keys +@PARAMETER_KEYS@ + /** + * @brief Reads SIMPL json and converts it simplnx Arguments. + * @param json + * @return Result + */ + static Result FromSIMPLJson(const nlohmann::json& json); + + /** + * @brief Returns the name of the filter. + * @return + */ + std::string name() const override; + /** - * @brief + * @brief Returns the C++ classname of this filter. * @return */ - [[nodiscard]] std::string name() const override; + std::string className() const override; /** - * @brief + * @brief Returns the uuid of the filter. * @return */ - [[nodiscard]] Uuid uuid() const override; + Uuid uuid() const override; /** - * @brief + * @brief Returns the human readable name of the filter. * @return */ - [[nodiscard]] std::string humanName() const override; + std::string humanName() const override; /** - * @brief + * @brief Returns the default tags for this filter. * @return */ - [[nodiscard]] Parameters parameters() const override; + std::vector defaultTags() const override; + + /** + * @brief Returns the parameters of the filter (i.e. its inputs) + * @return + */ + Parameters parameters() const override; + + /** + * @brief Returns parameters version integer. + * Initial version should always be 1. + * Should be incremented everytime the parameters change. + * @return VersionType + */ + VersionType parametersVersion() const override; /** - * @brief + * @brief Returns a copy of the filter. * @return */ - [[nodiscard]] UniquePointer clone() const override; + UniquePointer clone() const override; +protected: /** * @brief Takes in a DataStructure and checks that the filter can be run on it with the given arguments. * Returns any warnings/errors. Also returns the changes that would be applied to the DataStructure. @@ -76,6 +111,7 @@ public: Result<> executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel, const ExecutionContext& executionContext) const override; }; -} // namespace nx::core +} // namespace complex SIMPLNX_DEF_FILTER_TRAITS(nx::core, @FILTER_NAME@, "@UUID@"); +/* LEGACY UUID FOR THIS FILTER @OLD_UUID@ */ diff --git a/scripts/simplnx_unit_test.cpp.in b/scripts/simplnx_unit_test.cpp.in new file mode 100644 index 0000000000..24645d772c --- /dev/null +++ b/scripts/simplnx_unit_test.cpp.in @@ -0,0 +1,85 @@ +/** + * This file is auto generated from the original @PLUGIN_NAME@/@FILTER_NAME@ + * runtime information. These are the steps that need to be taken to utilize this + * unit test in the proper way. + * + * 1: Validate each of the default parameters that gets created. + * 2: Inspect the actual filter to determine if the filter in its default state + * would pass or fail BOTH the preflight() and execute() methods + * 3: UPDATE the ```REQUIRE(result.result.valid());``` code to have the proper + * + * 4: Add additional unit tests to actually test each code path within the filter + * + * There are some example Catch2 ```TEST_CASE``` sections for your inspiration. + * + * NOTE the format of the ```TEST_CASE``` macro. Please stick to this format to + * allow easier parsing of the unit tests. + * + * When you start working on this unit test remove "[@FILTER_NAME@][.][UNIMPLEMENTED]" + * from the TEST_CASE macro. This will enable this unit test to be run by default + * and report errors. + */ + + +#include + +@PARAMETER_INCLUDES@ +#include "@PLUGIN_NAME@/Filters/@FILTER_NAME@.hpp" +#include "@PLUGIN_NAME@/@PLUGIN_NAME@_test_dirs.hpp" + +#include "simplnx/UnitTest/UnitTestCommon.hpp" + +#include + +using namespace nx::core; +using namespace nx::core::UnitTest; +using namespace nx::core::Constants; + +TEST_CASE("@PLUGIN_NAME@::@FILTER_NAME@: Valid Filter Execution","[@PLUGIN_NAME@][@FILTER_NAME@]") +{ + UnitTest::LoadPlugins(); + + const nx::core::UnitTest::TestFileSentinel testDataSentinel(nx::core::unit_test::k_CMakeExecutable, + nx::core::unit_test::k_TestFilesDir, + "@FILTER_NAME@.tar.gz", + "@FILTER_NAME@"); + + // Read the Small IN100 Data set + auto baseDataFilePath = fs::path(fmt::format("{}/@FILTER_NAME@/@FILTER_NAME@.dream3d", nx::core::unit_test::k_TestFilesDir)); + DataStructure dataStructure = UnitTest::LoadDataStructure(baseDataFilePath); + + // Instantiate the filter, a DataStructure object and an Arguments Object + { + Arguments args; + @FILTER_NAME@ filter; + + // Create default Parameters for the filter. + // This next line is an example, your filter may be different + // args.insertOrAssign(@FILTER_NAME@::k_CreatedTriangleGeometryPath_Key, std::make_any(computedTriangleGeomPath)); + + // Preflight the filter and check result + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions) + + // Execute the filter and check the result + auto executeResult = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result) + + // Write the DataStructure out to the file system +#ifdef SIMPLNX_WRITE_TEST_OUTPUT + WriteTestDataStructure(dataStructure, fs::path(fmt::format("{}/@FILTER_NAME@Test.dream3d", unit_test::k_BinaryTestOutputDir))); +#endif + + } + // Compare exemplar data arrays with computed data arrays + //TODO: Insert verification codes + + // This should be in every unit test. If you think it does not apply, please review with another engineer + UnitTest::CheckArraysInheritTupleDims(dataStructure); + +} + +//TEST_CASE("@PLUGIN_NAME@::@FILTER_NAME@: InValid Filter Execution") +//{ +// +//}