From 8672f985aa3d554504325498a9ce5d18d4d7b9ba Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Thu, 10 Mar 2022 18:37:31 -0800 Subject: [PATCH] Create Extendable Enumeration base class (#3421) * Created extendableenumeration class * Convert attestation to use extendable enumeration; added test for extendable enumerations Co-authored-by: Casey Carter --- .../attestation/attestation_client_models.hpp | 52 +++--------- .../test/samples/policy/policy.cpp | 4 +- .../test/ut/policygetset_test.cpp | 9 +-- sdk/core/azure-core/CMakeLists.txt | 1 + .../core/internal/extendable_enumeration.hpp | 81 +++++++++++++++++++ sdk/core/azure-core/test/ut/CMakeLists.txt | 1 + .../test/ut/extendable_enumeration_test.cpp | 57 +++++++++++++ 7 files changed, 157 insertions(+), 48 deletions(-) create mode 100644 sdk/core/azure-core/inc/azure/core/internal/extendable_enumeration.hpp create mode 100644 sdk/core/azure-core/test/ut/extendable_enumeration_test.cpp diff --git a/sdk/attestation/azure-security-attestation/inc/azure/attestation/attestation_client_models.hpp b/sdk/attestation/azure-security-attestation/inc/azure/attestation/attestation_client_models.hpp index aadb053e5..343d1ab5e 100644 --- a/sdk/attestation/azure-security-attestation/inc/azure/attestation/attestation_client_models.hpp +++ b/sdk/attestation/azure-security-attestation/inc/azure/attestation/attestation_client_models.hpp @@ -12,6 +12,7 @@ #include "azure/attestation/dll_import_export.hpp" #include #include +#include #include #include #include @@ -29,34 +30,19 @@ namespace Azure { namespace Security { namespace Attestation { namespace Models * the attestation service. * */ - class AttestationType final { - private: - std::string m_attestationType; - + class AttestationType final + : public Azure::Core::_internal::ExtendableEnumeration { public: /** * @brief Construct a new AttestationType object * * @param attestationType The string attestationType used for the attestation policy operation. */ - AttestationType(std::string attestationType) : m_attestationType(std::move(attestationType)) {} - - /** - * @brief Enable comparing the ext enum. - * - * @param other Another #AttestationType to be compared. - */ - bool operator==(AttestationType const& other) const + explicit AttestationType(std::string attestationType) + : ExtendableEnumeration(std::move(attestationType)) { - return m_attestationType == other.m_attestationType; } - /** - * @brief Return the #AttestationType string representation. - * - */ - std::string const& ToString() const { return m_attestationType; } - /** * @brief Specifies that this should apply to SGX enclaves. * @@ -427,10 +413,8 @@ namespace Azure { namespace Security { namespace Attestation { namespace Models * policy modification. * */ - class PolicyModification final { - private: - std::string m_policyModification; - + class PolicyModification final + : public Azure::Core::_internal::ExtendableEnumeration { public: /** * @brief Construct a new PolicyResolution object @@ -438,23 +422,11 @@ namespace Azure { namespace Security { namespace Attestation { namespace Models * @param modification The string resolution used for the result of an attestation policy * operation. */ - PolicyModification(std::string modification) : m_policyModification(std::move(modification)) {} - - /** - * @brief Enable comparing the ext enum. - * - * @param other Another #PolicyModification to be compared. - */ - bool operator==(PolicyModification const& other) const + explicit PolicyModification(std::string modification) + : ExtendableEnumeration(std::move(modification)) { - return m_policyModification == other.m_policyModification; } - - /** - * @brief Return the #PolicyModification string representation. - * - */ - std::string const& ToString() const { return m_policyModification; } + PolicyModification() = default; /** * @brief Specifies that the policy object was updated. @@ -477,12 +449,12 @@ namespace Azure { namespace Security { namespace Attestation { namespace Models /** * @brief Result of a modification. */ - Azure::Nullable PolicyResolution; + PolicyModification PolicyResolution; /** * @brief The SHA256 hash of the policy object which was received by the service. */ - Azure::Nullable> PolicyTokenHash; + std::vector PolicyTokenHash; /** * @brief A JSON Web Key containing the signer of the policy token. If not present, the token diff --git a/sdk/attestation/azure-security-attestation/test/samples/policy/policy.cpp b/sdk/attestation/azure-security-attestation/test/samples/policy/policy.cpp index 52f282afd..c0799c9a5 100644 --- a/sdk/attestation/azure-security-attestation/test/samples/policy/policy.cpp +++ b/sdk/attestation/azure-security-attestation/test/samples/policy/policy.cpp @@ -87,7 +87,7 @@ authorizationrules Azure::Response> setResult = adminClient.SetAttestationPolicy(AttestationType::SgxEnclave, policyToSet); - if (*setResult.Value.Body.PolicyResolution == PolicyModification::Updated) + if (setResult.Value.Body.PolicyResolution == PolicyModification::Updated) { std::cout << "Attestation policy was updated." << std::endl; } @@ -108,7 +108,7 @@ authorizationrules setPolicyToken.RawToken.size()); std::cout << "Expected token hash: " << Convert::Base64Encode(policyTokenHash) << std::endl; std::cout << "Actual token hash: " - << Convert::Base64Encode(*setResult.Value.Body.PolicyTokenHash) << std::endl; + << Convert::Base64Encode(setResult.Value.Body.PolicyTokenHash) << std::endl; } int main() diff --git a/sdk/attestation/azure-security-attestation/test/ut/policygetset_test.cpp b/sdk/attestation/azure-security-attestation/test/ut/policygetset_test.cpp index 3b7e170ee..3cfe125cb 100644 --- a/sdk/attestation/azure-security-attestation/test/ut/policygetset_test.cpp +++ b/sdk/attestation/azure-security-attestation/test/ut/policygetset_test.cpp @@ -97,10 +97,9 @@ namespace Azure { namespace Security { namespace Attestation { namespace Test { EXPECT_EQ(result.RawResponse->GetStatusCode(), Azure::Core::Http::HttpStatusCode::Ok); // SetPolicy responses should have updated or reset the policy value. - EXPECT_TRUE(result.Value.Body.PolicyResolution); if (policyToValidate) { - EXPECT_EQ(PolicyModification::Updated, *result.Value.Body.PolicyResolution); + EXPECT_EQ(PolicyModification::Updated, result.Value.Body.PolicyResolution); // The attestation service only returns the PolicySigner and PolicySigningHash on // SetPolicy calls, not ResetPolicy calls. @@ -128,8 +127,6 @@ namespace Azure { namespace Security { namespace Attestation { namespace Test { EXPECT_FALSE(result.Value.Body.PolicySigner); } - EXPECT_TRUE(result.Value.Body.PolicyTokenHash); - // The returned PolicyTokenHash value is the hash of the entire policy JWS that was sent // to the service. In playback mode, the JWS which is calculated for the tests is // different from the JWS which was recorded (because the signing certificate is @@ -145,12 +142,12 @@ namespace Azure { namespace Security { namespace Attestation { namespace Test { std::vector rawTokenHash = hasher.Final( reinterpret_cast(sentToken.RawToken.data()), sentToken.RawToken.size()); - EXPECT_EQ(*result.Value.Body.PolicyTokenHash, rawTokenHash); + EXPECT_EQ(result.Value.Body.PolicyTokenHash, rawTokenHash); } } else { - EXPECT_EQ(PolicyModification::Removed, *result.Value.Body.PolicyResolution); + EXPECT_EQ(PolicyModification::Removed, result.Value.Body.PolicyResolution); } return true; diff --git a/sdk/core/azure-core/CMakeLists.txt b/sdk/core/azure-core/CMakeLists.txt index d3b2ac4e6..b3c85925e 100644 --- a/sdk/core/azure-core/CMakeLists.txt +++ b/sdk/core/azure-core/CMakeLists.txt @@ -71,6 +71,7 @@ set( inc/azure/core/internal/cryptography/sha_hash.hpp inc/azure/core/internal/diagnostics/log.hpp inc/azure/core/internal/environment.hpp + inc/azure/core/internal/extendable_enumeration.hpp inc/azure/core/internal/http/pipeline.hpp inc/azure/core/internal/io/null_body_stream.hpp inc/azure/core/internal/json/json_serializable.hpp diff --git a/sdk/core/azure-core/inc/azure/core/internal/extendable_enumeration.hpp b/sdk/core/azure-core/inc/azure/core/internal/extendable_enumeration.hpp new file mode 100644 index 000000000..103912bee --- /dev/null +++ b/sdk/core/azure-core/inc/azure/core/internal/extendable_enumeration.hpp @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +/** + * @file + * @brief Internal utility functions for extendable enumerations. + * + */ +#include + +namespace Azure { namespace Core { namespace _internal { + /** @brief Template base class helper for implementing extendable enumerations. + * + * This template exists to simplify the experience of authoring ["extendable + * enumerations"](https://azure.github.io/azure-sdk/cpp_implementation.html#cpp-enums). + * + * An extendable enumeration derives publicly from the #ExtendableEnumeration base class passing + * in the extendable enumeration type as the template argument. + * + * Example: + * + * \code{.cpp} + * class MyEnumeration final : public ExtendableEnumeration { + * public: + * explicit MyEnumeration(std::string attestationType) : + * ExtendableEnumeration(std::move(attestationType)) {} + * MyEnumeration() = default; + * static const MyEnumeration Enumerator1; + * static const MyEnumeration Enumerator2; + * static const MyEnumeration Enumerator3; + * }; + * \endcode + * + */ + template class ExtendableEnumeration { + private: + std::string m_enumerationValue; + + protected: + ~ExtendableEnumeration() = default; + + public: + /** + * @brief Construct a new extensable enumeration object + * + * @param enumerationValue The string enumerationValue used for the value. + */ + explicit ExtendableEnumeration(std::string enumerationValue) + : m_enumerationValue(std::move(enumerationValue)) + { + } + + /** + * @brief Construct a default extendable enumeration. + */ + ExtendableEnumeration() = default; + + /** + * @brief Enable comparing the ext enum. + * + * @param other Another extendable enumeration to be compared. + */ + bool operator==(T const& other) const noexcept + { + return m_enumerationValue == other.m_enumerationValue; + } + + /** + * @brief Enable comparing the ext enum. + * + * @param other Another extendable enumeration to be compared. + */ + bool operator!=(T const& other) const noexcept { return !operator==(other); } + + /** + * @brief Return the ExtendableEnumeration string representation. + * + */ + std::string const& ToString() const { return m_enumerationValue; } + }; +}}} // namespace Azure::Core::_internal diff --git a/sdk/core/azure-core/test/ut/CMakeLists.txt b/sdk/core/azure-core/test/ut/CMakeLists.txt index 95a5ef8ed..30f1a2225 100644 --- a/sdk/core/azure-core/test/ut/CMakeLists.txt +++ b/sdk/core/azure-core/test/ut/CMakeLists.txt @@ -47,6 +47,7 @@ add_executable ( ${CURL_SESSION_TESTS} datetime_test.cpp environment_log_level_listener_test.cpp + extendable_enumeration_test.cpp etag_test.cpp http_test.cpp http_test.hpp diff --git a/sdk/core/azure-core/test/ut/extendable_enumeration_test.cpp b/sdk/core/azure-core/test/ut/extendable_enumeration_test.cpp new file mode 100644 index 000000000..2747466f4 --- /dev/null +++ b/sdk/core/azure-core/test/ut/extendable_enumeration_test.cpp @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#include +#include +#include + +using namespace Azure::Core; + +class MyEnum : public Azure::Core::_internal::ExtendableEnumeration { +public: + MyEnum(std::string initialValue) : ExtendableEnumeration(std::move(initialValue)) {} + MyEnum() = default; + + static const MyEnum Value1; + static const MyEnum Value2; + static const MyEnum Value3; +}; + +const MyEnum MyEnum::Value1("Value1"); +const MyEnum MyEnum::Value2("Value2"); +const MyEnum MyEnum::Value3("Value3"); + +TEST(ExtendableEnumeration, BasicTests) +{ + { + MyEnum enum1 = MyEnum::Value1; + EXPECT_EQ(enum1, MyEnum::Value1); + } + { + MyEnum enumToTest(MyEnum::Value2); + EXPECT_NE(enumToTest, MyEnum::Value3); + } + + { + MyEnum enumVal; + GTEST_LOG_(INFO) << enumVal.ToString(); + } + + { + MyEnum enumVal(MyEnum::Value3); + EXPECT_EQ(enumVal.ToString(), "Value3"); + } + + { + MyEnum enumVal(MyEnum::Value1); + MyEnum enumVal2(enumVal); + EXPECT_EQ(enumVal, enumVal2); + } + { + MyEnum enumVal(MyEnum::Value1); + MyEnum enumVal2; + EXPECT_EQ(enumVal, MyEnum::Value1); + enumVal2 = enumVal; + EXPECT_EQ(enumVal, enumVal2); + } +}