diff --git a/cpp/Platform.Data.Tests/CLinksSimpleTest.cpp b/cpp/Platform.Data.Tests/CLinksSimpleTest.cpp new file mode 100644 index 0000000..d00dc2e --- /dev/null +++ b/cpp/Platform.Data.Tests/CLinksSimpleTest.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include + +namespace Platform::Data::Tests +{ + // Simple constants for testing + template + struct SimpleLinksConstants + { + static constexpr TLinkAddress Continue{1}; + static constexpr TLinkAddress Break{2}; + }; + + /// + /// Simple CLinks concept for testing without complex dependencies + /// + template + concept SimpleCLinks = requires(T links, + const std::vector& restriction, + const std::vector& substitution, + const typename T::ReadHandlerType& readHandler, + const typename T::WriteHandlerType& writeHandler) + { + typename T::LinkAddressType; + typename T::ReadHandlerType; + typename T::WriteHandlerType; + + // Test that Constants field exists and is accessible + T::Constants; + + // Core methods + { links.Count(restriction) } -> std::convertible_to; + { links.Each(restriction, readHandler) } -> std::convertible_to; + { links.Create(substitution, writeHandler) } -> std::convertible_to; + { links.Update(restriction, substitution, writeHandler) } -> std::convertible_to; + { links.Delete(restriction, writeHandler) } -> std::convertible_to; + }; + + // Test implementation that should satisfy the concept + struct SimpleLinksImpl + { + using LinkAddressType = std::uint64_t; + using ReadHandlerType = std::function&)>; + using WriteHandlerType = std::function&, const std::vector&)>; + static constexpr SimpleLinksConstants Constants{}; + + LinkAddressType Count(const std::vector& restriction) const { return 0; } + LinkAddressType Each(const std::vector& restriction, const ReadHandlerType& handler) const { return 0; } + LinkAddressType Create(const std::vector& substitution, const WriteHandlerType& handler) { return 0; } + LinkAddressType Update(const std::vector& restriction, const std::vector& substitution, const WriteHandlerType& handler) { return 0; } + LinkAddressType Delete(const std::vector& restriction, const WriteHandlerType& handler) { return 0; } + }; + + // Test implementation that should NOT satisfy the concept (missing methods) + struct IncompleteLinksImpl + { + using LinkAddressType = std::uint64_t; + using ReadHandlerType = std::function&)>; + using WriteHandlerType = std::function&, const std::vector&)>; + static constexpr SimpleLinksConstants Constants{}; + + // Only implementing Count method, missing others + LinkAddressType Count(const std::vector& restriction) const { return 0; } + }; + + // Compile-time tests + static_assert(SimpleCLinks, "SimpleLinksImpl should satisfy SimpleCLinks concept"); + static_assert(!SimpleCLinks, "IncompleteLinksImpl should NOT satisfy SimpleCLinks concept"); + + // Test with different address types + struct SimpleLinksImpl32 + { + using LinkAddressType = std::uint32_t; + using ReadHandlerType = std::function&)>; + using WriteHandlerType = std::function&, const std::vector&)>; + static constexpr SimpleLinksConstants Constants{}; + + LinkAddressType Count(const std::vector& restriction) const { return 0; } + LinkAddressType Each(const std::vector& restriction, const ReadHandlerType& handler) const { return 0; } + LinkAddressType Create(const std::vector& substitution, const WriteHandlerType& handler) { return 0; } + LinkAddressType Update(const std::vector& restriction, const std::vector& substitution, const WriteHandlerType& handler) { return 0; } + LinkAddressType Delete(const std::vector& restriction, const WriteHandlerType& handler) { return 0; } + }; + + static_assert(SimpleCLinks, "SimpleLinksImpl32 should satisfy SimpleCLinks concept"); +} \ No newline at end of file diff --git a/cpp/Platform.Data.Tests/CLinksTests.cpp b/cpp/Platform.Data.Tests/CLinksTests.cpp new file mode 100644 index 0000000..6675f2b --- /dev/null +++ b/cpp/Platform.Data.Tests/CLinksTests.cpp @@ -0,0 +1,87 @@ +namespace Platform::Data::Tests +{ + template VConstants = LinksConstants{true}, typename TLink = std::vector, typename TReadHandler = std::function, typename TWriteHandler = std::function> + struct TestLinksForConcept : public ILinks> + { + using base = ILinks>; + using typename base::LinkAddressType; + using typename base::LinkType; + using typename base::WriteHandlerType; + using typename base::ReadHandlerType; + using base::Constants; + + LinkAddressType Count(const std::vector& restriction) const override { return 0; }; + + LinkAddressType Each(const std::vector& restriction, const ReadHandlerType& handler) const override { return 0; }; + + LinkAddressType Create(const std::vector& restriction, const WriteHandlerType& handler) override { return 0; }; + + LinkAddressType Update(const std::vector& restriction, const std::vector& substitution, const WriteHandlerType& handler) override { return 0; }; + + LinkAddressType Delete(const std::vector& restriction, const WriteHandlerType& handler) override { return 0; }; + }; + + // Test that our TestLinksForConcept satisfies the CLinks concept + TEST(CLinksConceptTest, TestLinksForConceptSatisfiesConceptTest) + { + using TLinkAddress = uint64_t; + using TestLinks = TestLinksForConcept; + + // This should compile if the concept is satisfied + static_assert(CLinks, "TestLinksForConcept should satisfy CLinks concept"); + + // Additional runtime test to ensure instance creation works + TestLinks storage{}; + EXPECT_NO_THROW({ + std::vector restriction{1}; + std::vector substitution{1, 2}; + + // Test Count method + auto count = storage.Count(restriction); + EXPECT_EQ(count, 0); + + // Test Each method + auto eachResult = storage.Each(restriction, [](const std::vector& link){ return TLinkAddress{1}; }); + EXPECT_EQ(eachResult, 0); + + // Test Create method + auto createResult = storage.Create(substitution, [](const std::vector& before, const std::vector& after){ return TLinkAddress{1}; }); + EXPECT_EQ(createResult, 0); + + // Test Update method + auto updateResult = storage.Update(restriction, substitution, [](const std::vector& before, const std::vector& after){ return TLinkAddress{1}; }); + EXPECT_EQ(updateResult, 0); + + // Test Delete method + auto deleteResult = storage.Delete(restriction, [](const std::vector& before, const std::vector& after){ return TLinkAddress{1}; }); + EXPECT_EQ(deleteResult, 0); + }); + } + + // Test that a class missing required methods does not satisfy the concept + struct IncompleteLinks + { + using LinkAddressType = uint64_t; + using ReadHandlerType = std::function)>; + using WriteHandlerType = std::function, std::vector)>; + static constexpr LinksConstants Constants{true}; + + // Missing Count, Each, Create, Update, Delete methods + }; + + TEST(CLinksConceptTest, IncompleteLinksDoesNotSatisfyConceptTest) + { + // This should not satisfy the concept due to missing methods + static_assert(!CLinks, "IncompleteLinks should not satisfy CLinks concept"); + } + + // Test concept with different address types + TEST(CLinksConceptTest, DifferentAddressTypesTest) + { + using TestLinks32 = TestLinksForConcept; + using TestLinks16 = TestLinksForConcept; + + static_assert(CLinks, "TestLinksForConcept should satisfy CLinks concept"); + static_assert(CLinks, "TestLinksForConcept should satisfy CLinks concept"); + } +} \ No newline at end of file diff --git a/cpp/Platform.Data/CLinks.h b/cpp/Platform.Data/CLinks.h new file mode 100644 index 0000000..090611e --- /dev/null +++ b/cpp/Platform.Data/CLinks.h @@ -0,0 +1,94 @@ +#pragma once +#include +#include +#include + +namespace Platform::Data +{ + /// + /// Concept that defines the core requirements for ILinks interface implementation. + /// Концепт, который определяет основные требования для реализации интерфейса ILinks. + /// + /// + /// This concept includes only the main methods of ILinks without extensions. + /// Этот концепт включает только основные методы ILinks без расширений. + /// Based on selective polymorphism approach as suggested in the issue comment. + /// Основан на подходе селективного полиморфизма, как предложено в комментарии к задаче. + /// + template + concept CLinks = requires(T links, + const std::vector& restriction, + const std::vector& substitution, + const typename T::ReadHandlerType& readHandler, + const typename T::WriteHandlerType& writeHandler) + { + /// + /// Link address type used by the implementation. + /// Тип адреса связи, используемый реализацией. + /// + typename T::LinkAddressType; + + /// + /// Read handler type for traversal operations. + /// Тип обработчика чтения для операций обхода. + /// + typename T::ReadHandlerType; + + /// + /// Write handler type for modification operations. + /// Тип обработчика записи для операций изменения. + /// + typename T::WriteHandlerType; + + /// + /// Constants that provide necessary values for effective communication with interface methods. + /// Константы, которые предоставляют необходимые значения для эффективной коммуникации с методами интерфейса. + /// + T::Constants; + + /// + /// Counts and returns the total number of links in the storage that meet the specified restriction. + /// Подсчитывает и возвращает общее число связей находящихся в хранилище, соответствующих указанному ограничению. + /// + /// Restriction on the contents of links. + /// The total number of links in the storage that meet the specified restriction. + { links.Count(restriction) } -> std::convertible_to; + + /// + /// Passes through all the links matching the pattern, invoking a handler for each matching link. + /// Выполняет проход по всем связям, соответствующим шаблону, вызывая обработчик для каждой подходящей связи. + /// + /// Restriction on the contents of links. + /// A handler for each matching link. + /// Constants.Continue if the pass through the links was not interrupted, and Constants.Break otherwise. + { links.Each(restriction, readHandler) } -> std::convertible_to; + + /// + /// Creates a link. + /// Создаёт связь. + /// + /// The content of a new link. + /// A function to handle each executed change. + /// Constants.Continue if all executed changes are handled, Constants.Break if processing is stopped. + { links.Create(substitution, writeHandler) } -> std::convertible_to; + + /// + /// Updates links that match the specified restriction with new content. + /// Обновляет связи, соответствующие указанному ограничению, новым содержимым. + /// + /// Restriction on the contents of links to update. + /// New content for the links. + /// A function to handle each executed change. + /// Constants.Continue if all executed changes are handled, Constants.Break if processing is stopped. + { links.Update(restriction, substitution, writeHandler) } -> std::convertible_to; + + /// + /// Deletes links that match the specified restriction. + /// Удaляет связи соответствующие указанному ограничению. + /// + /// Restriction on the content of links to delete. + /// A function to handle each executed change. + /// Constants.Continue if all executed changes are handled, Constants.Break if processing is stopped. + { links.Delete(restriction, writeHandler) } -> std::convertible_to; + }; +} \ No newline at end of file diff --git a/cpp/Platform.Data/Platform.Data.h b/cpp/Platform.Data/Platform.Data.h index b4f3215..e8fe902 100644 --- a/cpp/Platform.Data/Platform.Data.h +++ b/cpp/Platform.Data/Platform.Data.h @@ -16,5 +16,6 @@ #include "LinksOptions.h" #include "LinksConstantsExtensions.h" #include "ILinks.h" +#include "CLinks.h" #include "ILinksExtensions.h"