Context improvements (#457)

* Expose the ContextValueType so callers can use it to get at key values.

* Add a const char * overload for construction

* Remove explicit conversion which adds an extra move construction.
const char* implicitly converts to std::string
This commit is contained in:
Rick Winter 2020-08-14 13:02:16 -07:00 committed by GitHub
parent e031696bce
commit 0b2b688e72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 183 additions and 5 deletions

View File

@ -1,7 +1,7 @@
{
"configurations": [
{
"name": "x64-Debug",
"name": "x64-DebugWithTests",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],

View File

@ -21,6 +21,7 @@ namespace Azure { namespace Core {
* @brief ContextValue exists as a substitute for variant which isn't available until C++17
*/
class ContextValue {
public:
enum class ContextValueType
{
Undefined,
@ -30,6 +31,7 @@ namespace Azure { namespace Core {
UniquePtr
};
private:
ContextValueType m_contextValueType;
union
{
@ -40,12 +42,23 @@ namespace Azure { namespace Core {
};
public:
ContextValue() noexcept : m_contextValueType(ContextValueType::Undefined), m_b(false) {}
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 26495)
#endif
ContextValue() noexcept : m_contextValueType(ContextValueType::Undefined) {}
ContextValue(bool b) noexcept : m_contextValueType(ContextValueType::Bool), m_b(b) {}
ContextValue(int i) noexcept : m_contextValueType(ContextValueType::Int), m_i(i) {}
ContextValue(const std::string& s) : m_contextValueType(ContextValueType::StdString), m_s(s) {}
ContextValue(std::string&& s) noexcept
: m_contextValueType(ContextValueType::UniquePtr), m_s(std::move(s))
ContextValue(const char* s)
: m_contextValueType(ContextValueType::StdString), m_s(s)
{
}
ContextValue(std::string&& s)
: m_contextValueType(ContextValueType::StdString), m_s(std::move(s))
{
}
@ -74,6 +87,9 @@ namespace Azure { namespace Core {
break;
}
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
~ContextValue()
{

View File

@ -31,7 +31,7 @@ add_executable (
transport_adapter.cpp
transport_adapter.hpp
uuid.cpp
)
context.cpp)
target_link_libraries(${TARGET_NAME} PRIVATE azure-core)
add_gtest(${TARGET_NAME})

View File

@ -0,0 +1,162 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "gtest/gtest.h"
#include "context.hpp"
#include <chrono>
#include <memory>
#include <string>
#include <vector>
using namespace Azure::Core;
TEST(Context, Basic)
{
Context context;
auto& valueT = context["key"];
EXPECT_FALSE(context.HasKey(""));
EXPECT_FALSE(context.HasKey("key"));
auto kind = valueT.Alternative();
EXPECT_TRUE(kind == ContextValue::ContextValueType::Undefined);
}
TEST(Context, BasicBool)
{
Context context;
// New context from previous
auto c2 = context.WithValue("key", true);
auto& valueT = c2["key"];
auto value = valueT.Get<bool>();
EXPECT_TRUE(value == true);
auto kind = valueT.Alternative();
EXPECT_TRUE(kind == ContextValue::ContextValueType::Bool);
}
TEST(Context, BasicInt)
{
Context context;
// New context from previous
auto c2 = context.WithValue("key", 123);
auto& valueT = c2["key"];
auto value = valueT.Get<int>();
EXPECT_TRUE(value == 123);
auto kind = valueT.Alternative();
EXPECT_TRUE(kind == ContextValue::ContextValueType::Int);
}
TEST(Context, BasicStdString)
{
std::string s("Test String");
Context context;
// New context from previous
auto c2 = context.WithValue("key", s);
auto& valueT = c2["key"];
auto value = valueT.Get<std::string>();
EXPECT_TRUE(value == s);
auto kind = valueT.Alternative();
EXPECT_TRUE(kind == ContextValue::ContextValueType::StdString);
}
TEST(Context, BasicChar)
{
const char* str = "Test String";
std::string s(str);
Context context;
// New context from previous
auto c2 = context.WithValue("key", str);
auto& valueT = c2["key"];
auto value = valueT.Get<std::string>();
EXPECT_TRUE(value == s);
auto kind = valueT.Alternative();
EXPECT_TRUE(kind == ContextValue::ContextValueType::StdString);
}
TEST(Context, Alternative)
{
Context context;
// New context from previous
auto c2 = context.WithValue("key", 123);
auto& valueT1 = c2["key"];
auto& valueT2 = c2["otherKey"];
EXPECT_TRUE(valueT1.Alternative() == ContextValue::ContextValueType::Int);
EXPECT_TRUE(valueT2.Alternative() == ContextValue::ContextValueType::Undefined);
}
TEST(Context, Chain)
{
Context context;
// New context from previous
auto c2 = context.WithValue("c2", 123);
auto c3 = c2.WithValue("c3", 456);
auto c4 = c3.WithValue("c4", 789);
auto c5 = c4.WithValue("c5", "5");
auto c6 = c5.WithValue("c6", "6");
auto c7 = c6.WithValue("c7", "7");
auto finalContext = c7.WithValue("finalContext", "Final");
auto& valueT2 = finalContext["c2"];
auto& valueT3 = finalContext["c3"];
auto& valueT4 = finalContext["c4"];
auto& valueT5 = finalContext["c5"];
auto& valueT6 = finalContext["c6"];
auto& valueT7 = finalContext["c7"];
auto& valueT8 = finalContext["finalContext"];
auto& valueT9 = finalContext["otherKey"];
EXPECT_TRUE(valueT2.Alternative() == ContextValue::ContextValueType::Int);
EXPECT_TRUE(valueT3.Alternative() == ContextValue::ContextValueType::Int);
EXPECT_TRUE(valueT4.Alternative() == ContextValue::ContextValueType::Int);
EXPECT_TRUE(valueT5.Alternative() == ContextValue::ContextValueType::StdString);
EXPECT_TRUE(valueT6.Alternative() == ContextValue::ContextValueType::StdString);
EXPECT_TRUE(valueT7.Alternative() == ContextValue::ContextValueType::StdString);
EXPECT_TRUE(valueT8.Alternative() == ContextValue::ContextValueType::StdString);
EXPECT_TRUE(valueT9.Alternative() == ContextValue::ContextValueType::Undefined);
auto value = valueT2.Get<int>();
EXPECT_TRUE(value == 123);
value = valueT3.Get<int>();
EXPECT_TRUE(value == 456);
value = valueT4.Get<int>();
EXPECT_TRUE(value == 789);
auto str = valueT5.Get<std::string>();
EXPECT_TRUE(str == "5");
str = valueT6.Get<std::string>();
EXPECT_TRUE(str == "6");
str = valueT7.Get<std::string>();
EXPECT_TRUE(str == "7");
str = valueT8.Get<std::string>();
EXPECT_TRUE(str == "Final");
}
TEST(Context, MatchingKeys)
{
Context context;
// New context from previous
auto c2 = context.WithValue("key", 123);
auto c3 = c2.WithValue("key", 456);
auto& valueT2 = c2["key"];
auto& valueT3 = c3["key"];
auto& missing = c3["otherKey"];
EXPECT_TRUE(valueT2.Alternative() == ContextValue::ContextValueType::Int);
EXPECT_TRUE(valueT3.Alternative() == ContextValue::ContextValueType::Int);
EXPECT_TRUE(missing.Alternative() == ContextValue::ContextValueType::Undefined);
auto value = valueT2.Get<int>();
EXPECT_TRUE(value == 123);
value = valueT3.Get<int>();
EXPECT_TRUE(value == 456);
}