From 7b921f156ce760989f9870385d5205531e488e3a Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Fri, 27 Sep 2024 22:41:56 -0400 Subject: [PATCH] ffi: Add `IrUnitHandlerInterface` to perform user-defined handling for deserialized IR units. (#540) Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: davidlion --- components/core/CMakeLists.txt | 2 + .../ffi/ir_stream/IrUnitHandlerInterface.hpp | 62 ++++++++ .../tests/test-ffi_IrUnitHandlerInterface.cpp | 140 ++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 components/core/src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp create mode 100644 components/core/tests/test-ffi_IrUnitHandlerInterface.cpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index a7c6d5a90..66901ae6c 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -333,6 +333,7 @@ set(SOURCE_FILES_unitTest src/clp/ffi/ir_stream/decoding_methods.inc src/clp/ffi/ir_stream/encoding_methods.cpp src/clp/ffi/ir_stream/encoding_methods.hpp + src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp src/clp/ffi/ir_stream/protocol_constants.hpp src/clp/ffi/ir_stream/Serializer.cpp src/clp/ffi/ir_stream/Serializer.hpp @@ -498,6 +499,7 @@ set(SOURCE_FILES_unitTest tests/test-BufferedFileReader.cpp tests/test-EncodedVariableInterpreter.cpp tests/test-encoding_methods.cpp + tests/test-ffi_IrUnitHandlerInterface.cpp tests/test-ffi_KeyValuePairLogEvent.cpp tests/test-ffi_SchemaTree.cpp tests/test-FileDescriptorReader.cpp diff --git a/components/core/src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp b/components/core/src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp new file mode 100644 index 000000000..cb2f0ac18 --- /dev/null +++ b/components/core/src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp @@ -0,0 +1,62 @@ +#ifndef CLP_FFI_IR_STREAM_IRUNITHANDLERINTERFACE_HPP +#define CLP_FFI_IR_STREAM_IRUNITHANDLERINTERFACE_HPP + +#include +#include + +#include "../../time_types.hpp" +#include "../KeyValuePairLogEvent.hpp" +#include "../SchemaTree.hpp" +#include "decoding_methods.hpp" + +namespace clp::ffi::ir_stream { +/** + * Concept that defines the IR unit handler interface. + */ +template +concept IrUnitHandlerInterface = requires( + Handler handler, + KeyValuePairLogEvent&& log_event, + UtcOffset utc_offset_old, + UtcOffset utc_offset_new, + SchemaTree::NodeLocator schema_tree_node_locator +) { + /** + * Handles a log event IR unit. + * @param log_event The deserialized result from IR deserializer. + * @return IRErrorCode::Success on success, user-defined error code on failures. + */ + { + handler.handle_log_event(std::forward(log_event)) + } -> std::same_as; + + /** + * Handles a UTC offset change IR unit. + * @param utc_offset_old The offset before the change. + * @param utc_offset_new The deserialized new offset. + * @return IRErrorCode::Success on success, user-defined error code on failures. + */ + { + handler.handle_utc_offset_change(utc_offset_old, utc_offset_new) + } -> std::same_as; + + /** + * Handles a schema tree node insertion IR unit. + * @param schema_tree_node_locator The locator of the node to insert. + * @return IRErrorCode::Success on success, user-defined error code on failures. + */ + { + handler.handle_schema_tree_node_insertion(schema_tree_node_locator) + } -> std::same_as; + + /** + * Handles an end-of-stream indicator IR unit. + * @return IRErrorCode::Success on success, user-defined error code on failures. + */ + { + handler.handle_end_of_stream() + } -> std::same_as; +}; +} // namespace clp::ffi::ir_stream + +#endif // CLP_FFI_IR_STREAM_IRUNITHANDLERINTERFACE_HPP diff --git a/components/core/tests/test-ffi_IrUnitHandlerInterface.cpp b/components/core/tests/test-ffi_IrUnitHandlerInterface.cpp new file mode 100644 index 000000000..976cb259a --- /dev/null +++ b/components/core/tests/test-ffi_IrUnitHandlerInterface.cpp @@ -0,0 +1,140 @@ +#include +#include +#include +#include + +#include + +#include "../src/clp/ffi/ir_stream/decoding_methods.hpp" +#include "../src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp" +#include "../src/clp/ffi/KeyValuePairLogEvent.hpp" +#include "../src/clp/ffi/SchemaTree.hpp" +#include "../src/clp/ffi/SchemaTreeNode.hpp" +#include "../src/clp/time_types.hpp" + +namespace { +using clp::ffi::ir_stream::IRErrorCode; +using clp::ffi::KeyValuePairLogEvent; +using clp::ffi::SchemaTree; +using clp::ffi::SchemaTreeNode; +using clp::UtcOffset; + +constexpr UtcOffset cTestUtcOffset{100}; +constexpr UtcOffset cTestUtcOffsetDelta{1000}; +constexpr std::string_view cTestSchemaTreeNodeKeyName{"test_key"}; + +/** + * Class that implements `clp::ffi::ir_stream::IrUnitHandlerInterface` for testing purposes. + */ +class TrivialIrUnitHandler { +public: + // Implements `clp::ffi::ir_stream::IrUnitHandlerInterface` interface + [[nodiscard]] auto handle_log_event(KeyValuePairLogEvent&& log_event) -> IRErrorCode { + m_log_event.emplace(std::move(log_event)); + return IRErrorCode::IRErrorCode_Success; + } + + [[nodiscard]] auto + handle_utc_offset_change(UtcOffset utc_offset_old, UtcOffset utc_offset_new) -> IRErrorCode { + m_utc_offset_delta = utc_offset_new - utc_offset_old; + return IRErrorCode::IRErrorCode_Success; + } + + [[nodiscard]] auto handle_schema_tree_node_insertion( + SchemaTree::NodeLocator schema_tree_node_locator + ) -> IRErrorCode { + m_schema_tree_node_locator.emplace(schema_tree_node_locator); + return IRErrorCode::IRErrorCode_Success; + } + + [[nodiscard]] auto handle_end_of_stream() -> IRErrorCode { + m_is_complete = true; + return IRErrorCode::IRErrorCode_Success; + } + + // Methods + [[nodiscard]] auto get_utc_offset_delta() const -> UtcOffset { return m_utc_offset_delta; } + + [[nodiscard]] auto is_complete() const -> bool { return m_is_complete; } + + [[nodiscard]] auto get_schema_tree_node_locator( + ) const -> std::optional const& { + return m_schema_tree_node_locator; + } + + [[nodiscard]] auto get_log_event() const -> std::optional const& { + return m_log_event; + } + +private: + UtcOffset m_utc_offset_delta{0}; + bool m_is_complete{false}; + std::optional m_schema_tree_node_locator; + std::optional m_log_event; +}; + +/** + * Class that inherits `TrivialIrUnitHandler` which also implements + * `clp::ffi::ir_stream::IrUnitHandlerInterface`. + */ +class TriviallyInheritedIrUnitHandler : public TrivialIrUnitHandler {}; + +/** + * Simulates the use of an IR unit handler. It calls every method required by + * `clp::ffi::ir_stream::IrUnitHandlerInterface` and ensure they don't return errors. + * @param handler + */ +auto test_ir_unit_handler_interface(clp::ffi::ir_stream::IrUnitHandlerInterface auto& handler +) -> void; + +auto test_ir_unit_handler_interface(clp::ffi::ir_stream::IrUnitHandlerInterface auto& handler +) -> void { + auto test_log_event_result{ + KeyValuePairLogEvent::create(std::make_shared(), {}, cTestUtcOffset) + }; + REQUIRE( + (false == test_log_event_result.has_error() + && IRErrorCode::IRErrorCode_Success + == handler.handle_log_event(std::move(test_log_event_result.value()))) + ); + REQUIRE( + (IRErrorCode::IRErrorCode_Success + == handler.handle_utc_offset_change( + cTestUtcOffset, + cTestUtcOffset + cTestUtcOffsetDelta + )) + ); + REQUIRE( + (IRErrorCode::IRErrorCode_Success + == handler.handle_schema_tree_node_insertion( + {SchemaTree::cRootId, cTestSchemaTreeNodeKeyName, SchemaTreeNode::Type::Obj} + )) + ); + REQUIRE((IRErrorCode::IRErrorCode_Success == handler.handle_end_of_stream())); +} +} // namespace + +TEMPLATE_TEST_CASE( + "test_ir_unit_handler_interface_basic", + "[ffi][ir_stream]", + TrivialIrUnitHandler, + TriviallyInheritedIrUnitHandler +) { + TestType handler; + REQUIRE_FALSE(handler.is_complete()); + test_ir_unit_handler_interface(handler); + + REQUIRE((handler.get_utc_offset_delta() == cTestUtcOffsetDelta)); + auto const& optional_log_event{handler.get_log_event()}; + REQUIRE( + (optional_log_event.has_value() + && optional_log_event.value().get_utc_offset() == cTestUtcOffset + && optional_log_event.value().get_node_id_value_pairs().empty()) + ); + auto const& optional_schema_tree_locator{handler.get_schema_tree_node_locator()}; + REQUIRE( + (optional_schema_tree_locator.has_value() + && optional_schema_tree_locator.value().get_key_name() == cTestSchemaTreeNodeKeyName) + ); + REQUIRE(handler.is_complete()); +}