Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ffi: Add IrUnitHandlerInterface to perform user-defined handling for deserialized IR units. #540

Merged
merged 9 commits into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions components/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
62 changes: 62 additions & 0 deletions components/core/src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#ifndef CLP_FFI_IR_STREAM_IRUNITHANLERINTERFACE_HPP
#define CLP_FFI_IR_STREAM_IRUNITHANLERINTERFACE_HPP
LinZhihao-723 marked this conversation as resolved.
Show resolved Hide resolved

#include <concepts>
#include <utility>

#include "../../time_types.hpp"
#include "../KeyValuePairLogEvent.hpp"
#include "../SchemaTree.hpp"
#include "decoding_methods.hpp"

namespace clp::ffi::ir_stream {
/**
* Concept that defines IR unit handler interface.
LinZhihao-723 marked this conversation as resolved.
Show resolved Hide resolved
*/
template <typename Handler>
concept IrUnitHandlerInterface = requires(
Handler handler,
KeyValuePairLogEvent&& log_event,
UtcOffset utc_offset_old,
UtcOffset utc_offset_new,
SchemaTree::NodeLocator schema_tree_node_locator
) {
/**
* Handles log event IR unit.
LinZhihao-723 marked this conversation as resolved.
Show resolved Hide resolved
* @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<KeyValuePairLogEvent&&>(log_event))
} -> std::same_as<IRErrorCode>;

/**
* Handles UTC offset change IR unit.
LinZhihao-723 marked this conversation as resolved.
Show resolved Hide resolved
* @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<IRErrorCode>;

/**
* Handles schema tree node IR unit.
LinZhihao-723 marked this conversation as resolved.
Show resolved Hide resolved
* @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<IRErrorCode>;

/**
* Handles end-of-stream indicator IR unit.
LinZhihao-723 marked this conversation as resolved.
Show resolved Hide resolved
* @return IRErrorCode::Success on success, user-defined error code on failures.
*/
{
handler.handle_end_of_stream()
} -> std::same_as<IRErrorCode>;
};
} // namespace clp::ffi::ir_stream

#endif // CLP_FFI_IR_STREAM_IRUNITHANLERINTERFACE_HPP
140 changes: 140 additions & 0 deletions components/core/tests/test-ffi_IrUnitHandlerInterface.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#include <memory>
#include <optional>
#include <string_view>
#include <utility>

#include <Catch2/single_include/catch2/catch.hpp>

#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"

using clp::ffi::ir_stream::IRErrorCode;
using clp::ffi::KeyValuePairLogEvent;
using clp::ffi::SchemaTree;
using clp::ffi::SchemaTreeNode;
using clp::UtcOffset;
LinZhihao-723 marked this conversation as resolved.
Show resolved Hide resolved

namespace {
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<SchemaTree::NodeLocator> const& {
return m_schema_tree_node_locator;
}

[[nodiscard]] auto get_log_event() const -> std::optional<KeyValuePairLogEvent> const& {
return m_log_event;
}

private:
UtcOffset m_utc_offset_delta{0};
bool m_is_complete{false};
std::optional<SchemaTree::NodeLocator> m_schema_tree_node_locator;
std::optional<KeyValuePairLogEvent> 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<SchemaTree>(), {}, 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());
}
Loading