Browse Source

Genericize object:: type names; add operator[] for array_type

master
Jessica James 3 years ago
parent
commit
b85fa62861
  1. 2
      src/bot/console/console_command_context.cpp
  2. 60
      src/common/object.cpp
  3. 10
      src/common/parsers/json.cpp
  4. 130
      src/include/jessilib/object.hpp
  5. 36
      src/test/object.cpp

2
src/bot/console/console_command_context.cpp

@ -39,7 +39,7 @@ bool console_command_context::publicReply(const jessilib::io::formatted_message&
/** Additional contextual details */ /** Additional contextual details */
jessilib::object console_command_context::details() const { jessilib::object console_command_context::details() const {
static jessilib::object s_details { static jessilib::object s_details {
jessilib::object::map_t{ { "table", "console" } } jessilib::object::map_type{ { "table", "console" } }
}; };
return s_details; return s_details;

60
src/common/object.cpp

@ -29,12 +29,12 @@ object::object(object&& in_object) {
} }
object::object(const char* in_str) object::object(const char* in_str)
: m_value{ std::string{ in_str } } { : m_value{ string_type{ in_str } } {
// Empty ctor body // Empty ctor body
} }
object::object(const std::string_view& in_str) object::object(const string_view_type& in_str)
: m_value{ std::string{ in_str.begin(), in_str.end() } } { : m_value{ string_type{ in_str.begin(), in_str.end() } } {
// Empty ctor body // Empty ctor body
} }
@ -52,7 +52,7 @@ size_t object::size() const {
// Try array // Try array
{ {
const array_t* array = std::get_if<array_t>(&m_value); const array_type* array = std::get_if<array_type>(&m_value);
if (array != nullptr) { if (array != nullptr) {
return array->size(); return array->size();
} }
@ -60,7 +60,7 @@ size_t object::size() const {
// Try map // Try map
{ {
const map_t* map = std::get_if<map_t>(&m_value); const map_type* map = std::get_if<map_type>(&m_value);
if (map != nullptr) { if (map != nullptr) {
return map->size(); return map->size();
} }
@ -70,11 +70,11 @@ size_t object::size() const {
return 1; return 1;
} }
const object& object::operator[](const std::string& in_key) const { const object& object::operator[](const string_type& in_key) const {
auto result = std::get_if<map_t>(&m_value); auto map_ptr = std::get_if<map_type>(&m_value);
if (result != nullptr) { if (map_ptr != nullptr) {
auto itr = result->find(in_key); auto itr = map_ptr->find(in_key);
if (itr != result->end()) { if (itr != map_ptr->end()) {
return itr->second; return itr->second;
} }
} }
@ -83,14 +83,44 @@ const object& object::operator[](const std::string& in_key) const {
return s_null_object; return s_null_object;
} }
object& object::operator[](const std::string& in_key) { object& object::operator[](const string_type& in_key) {
if (null()) { if (null()) {
return m_value.emplace<map_t>()[in_key]; return m_value.emplace<map_type>()[in_key];
} }
auto result = std::get_if<map_t>(&m_value); auto map_ptr = std::get_if<map_type>(&m_value);
if (result != nullptr) { if (map_ptr != nullptr) {
return result->operator[](in_key); return map_ptr->operator[](in_key);
}
static thread_local object s_null_object;
s_null_object.m_value.emplace<null_variant_t>();
return s_null_object;
}
const object& object::operator[](index_type in_index) const {
auto array_ptr = std::get_if<array_type>(&m_value);
if (array_ptr != nullptr
&& in_index < array_ptr->size()) {
return array_ptr->at(in_index);
}
static const object s_null_object;
return s_null_object;
}
object& object::operator[](index_type in_index) {
if (null()) {
m_value.emplace<array_type>();
}
auto array_ptr = std::get_if<array_type>(&m_value);
if (array_ptr != nullptr) {
while (array_ptr->size() <= in_index) {
array_ptr->emplace_back();
}
return array_ptr->at(in_index);
} }
static thread_local object s_null_object; static thread_local object s_null_object;

10
src/common/parsers/json.cpp

@ -406,7 +406,7 @@ object read_json_object(std::string_view& in_data) {
advance_whitespace(in_data); advance_whitespace(in_data);
// Build and populate result // Build and populate result
object result{ object::map_t{} }; object result{ object::map_type{} };
while (true) { while (true) {
if (in_data.empty()) { if (in_data.empty()) {
throw std::invalid_argument{ "Invalid JSON data; unexpected end of data when parsing object map" }; throw std::invalid_argument{ "Invalid JSON data; unexpected end of data when parsing object map" };
@ -473,8 +473,8 @@ object json_parser::deserialize(std::string_view in_data) {
} }
std::string json_parser::serialize(const object& in_object) { std::string json_parser::serialize(const object& in_object) {
static const object::array_t s_null_array; static const object::array_type s_null_array;
static const object::map_t s_null_map; static const object::map_type s_null_map;
switch (in_object.type()) { switch (in_object.type()) {
case object::type::null: case object::type::null:
@ -504,7 +504,7 @@ std::string json_parser::serialize(const object& in_object) {
result = '['; result = '[';
// Serialize all objects in array // Serialize all objects in array
for (auto& obj : in_object.get<object::array_t>(s_null_array)) { for (auto& obj : in_object.get<object::array_type>(s_null_array)) {
result += json_parser::serialize(obj); result += json_parser::serialize(obj);
result += ','; result += ',';
} }
@ -523,7 +523,7 @@ std::string json_parser::serialize(const object& in_object) {
result = '{'; result = '{';
// Serialize all objects in map // Serialize all objects in map
for (auto& item : in_object.get<object::map_t>(s_null_map)) { for (auto& item : in_object.get<object::map_type>(s_null_map)) {
result += make_json_string(item.first); result += make_json_string(item.first);
result += ":"sv; result += ":"sv;
result += json_parser::serialize(item.second); result += json_parser::serialize(item.second);

130
src/include/jessilib/object.hpp

@ -30,8 +30,11 @@ namespace jessilib {
class object { class object {
public: public:
using array_t = std::vector<object>; using array_type = std::vector<object>;
using map_t = std::map<std::string, object>; using string_type = std::string;
using string_view_type = std::string_view;
using map_type = std::map<string_type, object>;
using index_type = std::size_t;
/** is_backing */ /** is_backing */
@ -59,21 +62,21 @@ public:
}; };
template<typename T> template<typename T>
struct is_backing<T, typename std::enable_if<std::is_same<T, std::string>::value>::type> { struct is_backing<T, typename std::enable_if<std::is_same<T, string_type>::value>::type> {
static constexpr bool value = true; static constexpr bool value = true;
using type = std::string; using type = string_type;
}; };
template<typename T> template<typename T>
struct is_backing<T, typename std::enable_if<is_sequence_container<T>::value>::type> { struct is_backing<T, typename std::enable_if<is_sequence_container<T>::value>::type> {
static constexpr bool value = true; static constexpr bool value = true;
using type = array_t; using type = array_type;
}; };
template<typename T> template<typename T>
struct is_backing<T, typename std::enable_if<is_associative_container<T>::value>::type> { struct is_backing<T, typename std::enable_if<is_associative_container<T>::value>::type> {
static constexpr bool value = std::is_same<typename is_associative_container<T>::key_type, std::string>::value; static constexpr bool value = std::is_same<typename is_associative_container<T>::key_type, string_type>::value;
using type = map_t; using type = map_type;
}; };
/** type */ /** type */
@ -83,7 +86,7 @@ public:
boolean, boolean,
integer, integer,
decimal, decimal,
string, // TODO: consider separating into 'binary' (std::vector<std::byte>) and 'text' (std::string) types string, // TODO: consider separating into 'binary' (std::vector<std::byte>) and 'text' (string_type) types
array, array,
map map
}; };
@ -98,7 +101,7 @@ public:
template<typename T, template<typename T,
typename std::enable_if<is_backing<typename std::decay<T>::type>::value typename std::enable_if<is_backing<typename std::decay<T>::type>::value
&& !is_sequence_container<typename std::decay<T>::type>::value && !is_sequence_container<typename std::decay<T>::type>::value
&& (!is_associative_container<typename std::decay<T>::type>::value || std::is_same<typename remove_cvref<T>::type, map_t>::value)>::type* = nullptr> && (!is_associative_container<typename std::decay<T>::type>::value || std::is_same<typename remove_cvref<T>::type, map_type>::value)>::type* = nullptr>
object(T&& in_value) object(T&& in_value)
: m_value{ typename is_backing<typename std::decay<T>::type>::type{ std::forward<T>(in_value) } } { : m_value{ typename is_backing<typename std::decay<T>::type>::type{ std::forward<T>(in_value) } } {
// Empty ctor body // Empty ctor body
@ -108,7 +111,7 @@ public:
typename std::enable_if<is_sequence_container<typename std::decay<T>::type>::value typename std::enable_if<is_sequence_container<typename std::decay<T>::type>::value
&& !std::is_same<typename std::decay<T>::type, std::vector<bool>>::value>::type* = nullptr> && !std::is_same<typename std::decay<T>::type, std::vector<bool>>::value>::type* = nullptr>
object(T&& in_value) object(T&& in_value)
: m_value{ array_t{ in_value.begin(), in_value.end() } } { : m_value{ array_type{ in_value.begin(), in_value.end() } } {
// Empty ctor body // Empty ctor body
} }
@ -116,8 +119,8 @@ public:
template<typename T, template<typename T,
typename std::enable_if<std::is_same<typename std::decay<T>::type, std::vector<bool>>::value>::type* = nullptr> typename std::enable_if<std::is_same<typename std::decay<T>::type, std::vector<bool>>::value>::type* = nullptr>
object(T&& in_value) object(T&& in_value)
: m_value{ array_t{} } { : m_value{ array_type{} } {
auto& array = std::get<array_t>(m_value); auto& array = std::get<array_type>(m_value);
array.reserve(in_value.size()); array.reserve(in_value.size());
for (const auto& item : in_value) { for (const auto& item : in_value) {
@ -125,32 +128,32 @@ public:
} }
} }
// std::unordered_map<std::string, object> // std::unordered_map<string_type, object>
template<typename T, template<typename T,
typename std::enable_if<is_unordered_map<typename std::decay<T>::type>::value typename std::enable_if<is_unordered_map<typename std::decay<T>::type>::value
&& std::is_same<typename is_unordered_map<typename std::decay<T>::type>::key_type, std::string>::value && std::is_same<typename is_unordered_map<typename std::decay<T>::type>::key_type, string_type>::value
&& std::is_same<typename is_unordered_map<typename std::decay<T>::type>::value_type, object>::value>::type* = nullptr> && std::is_same<typename is_unordered_map<typename std::decay<T>::type>::value_type, object>::value>::type* = nullptr>
object(T&& in_value) object(T&& in_value)
: m_value{ map_t{ in_value.begin(), in_value.end() } } { : m_value{ map_type{ in_value.begin(), in_value.end() } } {
// Empty ctor body // Empty ctor body
} }
// Non-map_t associative containers (container<std::string, T>) // Non-map_type associative containers (container<string_type, T>)
template<typename T, template<typename T,
typename std::enable_if<is_associative_container<typename remove_cvref<T>::type>::value typename std::enable_if<is_associative_container<typename remove_cvref<T>::type>::value
&& (std::is_convertible<typename is_associative_container<typename remove_cvref<T>::type>::key_type, std::string>::value && (std::is_convertible<typename is_associative_container<typename remove_cvref<T>::type>::key_type, string_type>::value
|| std::is_convertible<typename is_associative_container<typename remove_cvref<T>::type>::key_type, std::string_view>::value) || std::is_convertible<typename is_associative_container<typename remove_cvref<T>::type>::key_type, string_view_type>::value)
&& !std::is_same<typename is_associative_container<typename remove_cvref<T>::type>::value_type, object>::value>::type* = nullptr> && !std::is_same<typename is_associative_container<typename remove_cvref<T>::type>::value_type, object>::value>::type* = nullptr>
object(T&& in_value) object(T&& in_value)
: m_value{ map_t{} } { : m_value{ map_type{} } {
auto& map = std::get<map_t>(m_value); auto& map = std::get<map_type>(m_value);
for (auto& pair : in_value) { for (auto& pair : in_value) {
map.emplace(pair.first, pair.second); map.emplace(pair.first, pair.second);
} }
} }
object(const char* in_str); object(const char* in_str);
object(const std::string_view& in_str); object(const string_view_type& in_str);
// Comparison operators // Comparison operators
bool operator==(const object& rhs) const { bool operator==(const object& rhs) const {
@ -189,8 +192,10 @@ public:
return *this; return *this;
} }
const object& operator[](const std::string& in_key) const; const object& operator[](const string_type& in_key) const;
object& operator[](const std::string& in_key); object& operator[](const string_type& in_key);
const object& operator[](index_type in_index) const;
object& operator[](index_type in_index);
/** Accessors */ /** Accessors */
@ -226,9 +231,9 @@ public:
// TODO: support other basic_string types // TODO: support other basic_string types
template<typename T, typename DefaultT = T, template<typename T, typename DefaultT = T,
typename std::enable_if<std::is_same<T, std::string>::value && std::is_convertible<typename std::decay<DefaultT>::type, T>::value>::type* = nullptr> typename std::enable_if<std::is_same<T, string_type>::value && std::is_convertible<typename std::decay<DefaultT>::type, T>::value>::type* = nullptr>
T get(DefaultT&& in_default_value = {}) const { T get(DefaultT&& in_default_value = {}) const {
const std::string* result = std::get_if<std::string>(&m_value); const string_type* result = std::get_if<string_type>(&m_value);
if (result != nullptr) { if (result != nullptr) {
return *result; return *result;
} }
@ -238,9 +243,9 @@ public:
// TODO: support other basic_string_view types // TODO: support other basic_string_view types
template<typename T, typename DefaultT = T, template<typename T, typename DefaultT = T,
typename std::enable_if<std::is_same<T, std::string>::value && std::is_same<typename std::decay<DefaultT>::type, std::string_view>::value>::type* = nullptr> typename std::enable_if<std::is_same<T, string_type>::value && std::is_same<typename std::decay<DefaultT>::type, string_view_type>::value>::type* = nullptr>
T get(DefaultT&& in_default_value) const { T get(DefaultT&& in_default_value) const {
const std::string* result = std::get_if<std::string>(&m_value); const string_type* result = std::get_if<string_type>(&m_value);
if (result != nullptr) { if (result != nullptr) {
return *result; return *result;
} }
@ -250,11 +255,11 @@ public:
/** arrays */ /** arrays */
// reference getter (array_t) // reference getter (array_type)
template<typename T, template<typename T,
typename std::enable_if<std::is_same<T, array_t>::value>::type* = nullptr> typename std::enable_if<std::is_same<T, array_type>::value>::type* = nullptr>
const T& get(const T& in_default_value) const { const T& get(const T& in_default_value) const {
const array_t* result = std::get_if<array_t>(&m_value); const array_type* result = std::get_if<array_type>(&m_value);
if (result != nullptr) { if (result != nullptr) {
return *result; return *result;
} }
@ -262,11 +267,11 @@ public:
return in_default_value; return in_default_value;
} }
// copy getter (array_t) // copy getter (array_type)
template<typename T, template<typename T,
typename std::enable_if<std::is_same<T, array_t>::value>::type* = nullptr> typename std::enable_if<std::is_same<T, array_type>::value>::type* = nullptr>
T get(T&& in_default_value = {}) const { T get(T&& in_default_value = {}) const {
const array_t* result = std::get_if<array_t>(&m_value); const array_type* result = std::get_if<array_type>(&m_value);
if (result != nullptr) { if (result != nullptr) {
return *result; return *result;
} }
@ -274,13 +279,13 @@ public:
return std::move(in_default_value); return std::move(in_default_value);
} }
// conversion getter (non-array_t) // conversion getter (non-array_type)
template<typename T, typename DefaultT = T, template<typename T, typename DefaultT = T,
typename std::enable_if<is_sequence_container<T>::value && !std::is_same<T, array_t>::value && std::is_same<typename std::decay<DefaultT>::type, T>::value>::type* = nullptr> typename std::enable_if<is_sequence_container<T>::value && !std::is_same<T, array_type>::value && std::is_same<typename std::decay<DefaultT>::type, T>::value>::type* = nullptr>
T get(DefaultT&& in_default_value = {}) const { T get(DefaultT&& in_default_value = {}) const {
using backing_t = typename is_sequence_container<T>::type; using backing_t = typename is_sequence_container<T>::type;
const array_t* array = std::get_if<array_t>(&m_value); const array_type* array = std::get_if<array_type>(&m_value);
if (array != nullptr) { if (array != nullptr) {
T result; T result;
// Expand capacity to fit values (if possible) // Expand capacity to fit values (if possible)
@ -338,13 +343,13 @@ public:
/** maps */ /** maps */
// TODO: implement in a way that does not require exposing map_t // TODO: implement in a way that does not require exposing map_type
// reference getter (map_t) // reference getter (map_type)
template<typename T, template<typename T,
typename std::enable_if<std::is_same<T, map_t>::value>::type* = nullptr> typename std::enable_if<std::is_same<T, map_type>::value>::type* = nullptr>
const T& get(const T& in_default_value) const { const T& get(const T& in_default_value) const {
const map_t* result = std::get_if<map_t>(&m_value); const map_type* result = std::get_if<map_type>(&m_value);
if (result != nullptr) { if (result != nullptr) {
return *result; return *result;
} }
@ -352,11 +357,11 @@ public:
return in_default_value; return in_default_value;
} }
// copy getter (map_t) // copy getter (map_type)
template<typename T, template<typename T,
typename std::enable_if<std::is_same<T, map_t>::value>::type* = nullptr> typename std::enable_if<std::is_same<T, map_type>::value>::type* = nullptr>
T get(T&& in_default_value = {}) const { T get(T&& in_default_value = {}) const {
const map_t* result = std::get_if<map_t>(&m_value); const map_type* result = std::get_if<map_type>(&m_value);
if (result != nullptr) { if (result != nullptr) {
return *result; return *result;
} }
@ -364,7 +369,7 @@ public:
return std::move(in_default_value); return std::move(in_default_value);
} }
// TODO: conversion getter (non-map_t, i.e: unordered_map) // TODO: conversion getter (non-map_type, i.e: unordered_map)
/** set */ /** set */
@ -379,39 +384,39 @@ public:
// string // string
template<typename T, template<typename T,
typename std::enable_if<std::is_convertible<typename std::decay<T>::type, std::string>::value>::type* = nullptr> typename std::enable_if<std::is_convertible<typename std::decay<T>::type, string_type>::value>::type* = nullptr>
void set(T&& in_value) { void set(T&& in_value) {
m_value.emplace<std::string>(std::forward<T>(in_value)); m_value.emplace<string_type>(std::forward<T>(in_value));
} }
// string_view // string_view
template<typename T, template<typename T,
typename std::enable_if<std::is_same<T, std::string_view>::value>::type* = nullptr> typename std::enable_if<std::is_same<T, string_view_type>::value>::type* = nullptr>
void set(const T& in_value) { void set(const T& in_value) {
m_value.emplace<std::string>(in_value.begin(), in_value.end()); m_value.emplace<string_type>(in_value.begin(), in_value.end());
} }
// array_t // array_type
template<typename T, template<typename T,
typename std::enable_if<std::is_same<typename std::decay<T>::type, array_t>::value>::type* = nullptr> typename std::enable_if<std::is_same<typename std::decay<T>::type, array_type>::value>::type* = nullptr>
void set(T&& in_value) { void set(T&& in_value) {
m_value.emplace<array_t>(std::forward<T>(in_value)); m_value.emplace<array_type>(std::forward<T>(in_value));
} }
// is_sequence_container // is_sequence_container
template<typename T, template<typename T,
typename std::enable_if<is_sequence_container<typename std::decay<T>::type>::value typename std::enable_if<is_sequence_container<typename std::decay<T>::type>::value
&& !std::is_same<typename std::decay<T>::type, array_t>::value && !std::is_same<typename std::decay<T>::type, array_type>::value
&& !std::is_same<typename std::decay<T>::type, std::vector<bool>>::value>::type* = nullptr> && !std::is_same<typename std::decay<T>::type, std::vector<bool>>::value>::type* = nullptr>
void set(T&& in_value) { void set(T&& in_value) {
m_value.emplace<array_t>(in_value.begin(), in_value.end()); m_value.emplace<array_type>(in_value.begin(), in_value.end());
} }
// std::vector<bool> // std::vector<bool>
template<typename T, template<typename T,
typename std::enable_if<std::is_same<typename std::decay<T>::type, std::vector<bool>>::value>::type* = nullptr> typename std::enable_if<std::is_same<typename std::decay<T>::type, std::vector<bool>>::value>::type* = nullptr>
void set(T&& in_value) { void set(T&& in_value) {
auto& array = m_value.emplace<array_t>(); auto& array = m_value.emplace<array_type>();
array.reserve(in_value.size()); array.reserve(in_value.size());
for (const auto& item : in_value) { for (const auto& item : in_value) {
@ -433,7 +438,7 @@ public:
if constexpr (std::is_same<T, null_variant_t>::value) { if constexpr (std::is_same<T, null_variant_t>::value) {
return 0; return 0;
} }
else if constexpr (std::is_same<T, array_t>::value) { else if constexpr (std::is_same<T, array_type>::value) {
size_t result{}; size_t result{};
for (auto& obj : value) { for (auto& obj : value) {
result += obj.hash(); result += obj.hash();
@ -441,10 +446,10 @@ public:
return result; return result;
} }
else if constexpr (std::is_same<T, map_t>::value) { else if constexpr (std::is_same<T, map_type>::value) {
size_t result{}; size_t result{};
for (auto& pair : value) { for (auto& pair : value) {
result += std::hash<std::string>{}(pair.first); result += std::hash<string_type>{}(pair.first);
} }
return result; return result;
@ -457,7 +462,16 @@ public:
private: private:
using null_variant_t = void*; using null_variant_t = void*;
std::variant<null_variant_t, bool, intmax_t, long double, std::string, array_t, map_t> m_value; // TODO: consider replacing std::string with std::u8string (for strings) & std::vector<unsigned char> (for data)
// TODO: consider some more generic mechanism for underlying string type, to support utf-16 & utf-32 strings
std::variant<null_variant_t, bool, intmax_t, long double, string_type, array_type, map_type> m_value;
// TODO: note for future self, just use either first or last element in array_type to hold XML attributes
// OR, have every XML tag objects be a map, with all subobjects being in a "__values" array subobject or such
// For extra syntactical sugar, could have xml_object class extend object w/o additional members to allow arbitrary
// static_cast usage
// This may be a good justification for separate 'xml_config' and 'xml' parsers, as config files are easier to
// represent as a map, whereas an actual xml document is sequenced
}; // object }; // object
} // namespace jessilib } // namespace jessilib

36
src/test/object.cpp

@ -67,8 +67,8 @@ TEST(ObjectTest, basic_has) {
EXPECT_FALSE(obj.has<double>()); EXPECT_FALSE(obj.has<double>());
EXPECT_FALSE(obj.has<long double>()); EXPECT_FALSE(obj.has<long double>());
EXPECT_FALSE(obj.has<std::string>()); EXPECT_FALSE(obj.has<std::string>());
EXPECT_FALSE(obj.has<object::array_t>()); EXPECT_FALSE(obj.has<object::array_type>());
EXPECT_FALSE(obj.has<object::map_t>()); EXPECT_FALSE(obj.has<object::map_type>());
} }
TEST(ObjectTest, basic_has_vector) { TEST(ObjectTest, basic_has_vector) {
@ -200,8 +200,8 @@ TEST(ObjectTest, basic_get) {
EXPECT_EQ(obj.get<double>(), double{}); EXPECT_EQ(obj.get<double>(), double{});
EXPECT_EQ(obj.get<long double>(), long_double_t{}); EXPECT_EQ(obj.get<long double>(), long_double_t{});
EXPECT_EQ(obj.get<std::string>(), std::string{}); EXPECT_EQ(obj.get<std::string>(), std::string{});
EXPECT_TRUE(obj.get<object::array_t>().empty()); EXPECT_TRUE(obj.get<object::array_type>().empty());
EXPECT_TRUE(obj.get<object::map_t>().empty()); EXPECT_TRUE(obj.get<object::map_type>().empty());
} }
TEST(ObjectTest, basic_get_vector) { TEST(ObjectTest, basic_get_vector) {
@ -352,7 +352,7 @@ TEST(ObjectTest, basic_value_constructor) {
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(double); OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(double);
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(long_double_t); OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(long_double_t);
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::string); OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(std::string);
OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(object::array_t); OBJECT_BASIC_VALUE_CONSTRUCTOR_TEST(object::array_type);
// const char* // const char*
{ {
@ -503,7 +503,7 @@ TEST(ObjectTest, basic_set) {
OBJECT_BASIC_SET_TEST(obj, double); OBJECT_BASIC_SET_TEST(obj, double);
OBJECT_BASIC_SET_TEST(obj, long_double_t); OBJECT_BASIC_SET_TEST(obj, long_double_t);
OBJECT_BASIC_SET_TEST(obj, std::string); OBJECT_BASIC_SET_TEST(obj, std::string);
OBJECT_BASIC_SET_TEST(obj, object::array_t); OBJECT_BASIC_SET_TEST(obj, object::array_type);
// const char* // const char*
obj.set(""); obj.set("");
@ -664,7 +664,7 @@ TEST(ObjectTest, basic_assignment_operator) {
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, double); OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, double);
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, long_double_t); OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, long_double_t);
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::string); OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, std::string);
OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, object::array_t); OBJECT_BASIC_ASSIGNMENT_OPERATOR_TEST(obj, object::array_type);
// const char* // const char*
obj = ""; obj = "";
@ -805,7 +805,7 @@ TEST(ObjectTest, basic_assignment_operator_unordered_multiset) {
/** basic_access_operator */ /** basic_access_operator */
TEST(ObjectTest, basic_access_operator) { TEST(ObjectTest, basic_map_access_operator) {
object obj; object obj;
obj["test"] = 1234; obj["test"] = 1234;
@ -821,6 +821,26 @@ TEST(ObjectTest, basic_access_operator) {
EXPECT_EQ(obj["test2"].get<int>(), 1234); EXPECT_EQ(obj["test2"].get<int>(), 1234);
} }
TEST(ObjectTest, basic_array_access_operator) {
object obj;
obj[0] = 1234;
EXPECT_EQ(obj.size(), 1);
EXPECT_EQ(obj[0].get<int>(), 1234);
EXPECT_EQ(obj[1].get<int>(), 0);
EXPECT_EQ(obj.size(), 2);
obj[0] = 4567;
EXPECT_EQ(obj[0].get<int>(), 4567);
EXPECT_EQ(obj[1].get<int>(), 0);
EXPECT_EQ(obj.size(), 2);
obj[1] = 1234;
EXPECT_EQ(obj[0].get<int>(), 4567);
EXPECT_EQ(obj[1].get<int>(), 1234);
EXPECT_EQ(obj.size(), 2);
}
/** end basic tests */ /** end basic tests */
TEST(ObjectTest, set_bool) { TEST(ObjectTest, set_bool) {

Loading…
Cancel
Save