From f4a9511949ae37df6ff070cf40ac14342df3253e Mon Sep 17 00:00:00 2001 From: Kevin Traini Date: Wed, 28 Aug 2024 18:30:25 +0200 Subject: [PATCH] feat: Add ValidationContext Part of #25 It will be used to store context of ValidationVisitor easily. Instead of creating a new member each time, just store it directly in the context. The stack/unstack allow to have a different context if we need it --- include/filc/validation/ValidationVisitor.h | 29 +++++++ src/validation/ValidationContext.cpp | 34 ++++++++ .../unit/validation/ValidationContextTest.cpp | 86 +++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 src/validation/ValidationContext.cpp create mode 100644 tests/unit/validation/ValidationContextTest.cpp diff --git a/include/filc/validation/ValidationVisitor.h b/include/filc/validation/ValidationVisitor.h index 47f577e..e8b45c4 100644 --- a/include/filc/validation/ValidationVisitor.h +++ b/include/filc/validation/ValidationVisitor.h @@ -25,8 +25,37 @@ #define FILC_VALIDATIONVISITOR_H #include "filc/grammar/Visitor.h" +#include +#include +#include +#include +#include namespace filc { +class ValidationContext final { + public: + explicit ValidationContext(ValidationContext* parent = nullptr); + + [[nodiscard]] auto stack() -> ValidationContext*; + + [[nodiscard]] auto unstack() const -> ValidationContext*; + + auto set(const std::string &key, const std::any &value) -> void; + + template + auto get(const std::string &key) const -> T { + if (_values.find(key) == _values.end()) { + throw std::logic_error("There is not value for key: " + key); + } + + return std::any_cast(_values.at(key)); + } + + private: + ValidationContext* _parent; + std::map _values; +}; + class ValidationVisitor final : public Visitor { public: auto visitProgram(Program *program) -> void override; diff --git a/src/validation/ValidationContext.cpp b/src/validation/ValidationContext.cpp new file mode 100644 index 0000000..54f79bb --- /dev/null +++ b/src/validation/ValidationContext.cpp @@ -0,0 +1,34 @@ +/** + * MIT License + * + * Copyright (c) 2024-Present Kevin Traini + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "filc/validation/ValidationVisitor.h" + +using namespace filc; + +ValidationContext::ValidationContext(ValidationContext *parent) : _parent(parent) {} + +auto ValidationContext::stack() -> ValidationContext * { return new ValidationContext(this); } + +auto ValidationContext::unstack() const -> ValidationContext * { return _parent; } + +auto ValidationContext::set(const std::string &key, const std::any &value) -> void { _values[key] = value; } diff --git a/tests/unit/validation/ValidationContextTest.cpp b/tests/unit/validation/ValidationContextTest.cpp new file mode 100644 index 0000000..6101dc7 --- /dev/null +++ b/tests/unit/validation/ValidationContextTest.cpp @@ -0,0 +1,86 @@ +/** + * MIT License + * + * Copyright (c) 2024-Present Kevin Traini + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include + +using namespace ::testing; + +TEST(ValidationContext, stack_unstack) { + filc::ValidationContext context; + auto new_context = context.stack(); + ASSERT_NE(&context, new_context); + ASSERT_EQ(&context, new_context->unstack()); +} + +TEST(ValidationContext, get_non_existing) { + filc::ValidationContext context; + ASSERT_THROW(context.get("non-existing"), std::logic_error); +} + +TEST(ValidationContext, get_set_scalar) { + filc::ValidationContext context; + context.set("int_value", 2); + ASSERT_EQ(2, context.get("int_value")); +} + +TEST(ValidationContext, get_set_string) { + filc::ValidationContext context; + context.set("string_value", std::string("Hello")); + ASSERT_STREQ("Hello", context.get("string_value").c_str()); +} + +typedef struct { + int _a; + std::string _b; + char _c[5]; +} SomeStructure; + +TEST(ValidationContext, get_set_structure) { + filc::ValidationContext context; + SomeStructure value = {2, "Hello World", {'a', 'b', 'c', 'd', 'e'}}; + context.set("struct_value", value); + auto found = context.get("struct_value"); + ASSERT_EQ(2, found._a); + ASSERT_STREQ("Hello World", found._b.c_str()); + ASSERT_THAT(found._c, ElementsAre('a', 'b', 'c', 'd', 'e')); +} + +class SomeClass { + public: + SomeClass() : _a(12), _b("foo") {} + + [[nodiscard]] auto equals(const SomeClass &other) const -> bool { return _a == other._a && _b == other._b; } + + private: + int _a; + std::string _b; +}; + +TEST(ValidationContext, get_set_object) { + filc::ValidationContext context; + SomeClass value; + context.set("object_value", value); + ASSERT_TRUE(value.equals(context.get("object_value"))); +}