Skip to content

Commit

Permalink
Add StringMaker specialization for bsoncxx::types::bson_value types (#…
Browse files Browse the repository at this point in the history
…891)

* Add StringMaker specialization for bsoncxx::types::bson_value types

* Add StringMaker specialization for bsoncxx::document::view_or_value

* Fix missing return in StringMaker specialization for optionals
  • Loading branch information
eramongodb authored Aug 26, 2022
1 parent d1e7c98 commit f1f3f50
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 67 deletions.
1 change: 1 addition & 0 deletions src/bsoncxx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ set_local_dist (src_bsoncxx_DIST_local
string/view_or_value.hpp
test_util/catch.hh
test_util/export_for_testing.hh
test_util/to_string.hh
types.cpp
types.hpp
types/value.hpp
Expand Down
35 changes: 32 additions & 3 deletions src/bsoncxx/test_util/catch.hh
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@

#pragma once

#include "catch.hpp"
#include <bsoncxx/document/value.hpp>
#include <bsoncxx/document/view_or_value.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/oid.hpp>
#include <bsoncxx/stdx/optional.hpp>
#include <bsoncxx/test_util/to_string.hh>
#include <third_party/catch/include/catch.hpp>

#include <bsoncxx/config/private/prelude.hh>

Expand All @@ -41,18 +42,46 @@ struct StringMaker<bsoncxx::document::view> {
}
};

template <>
struct StringMaker<bsoncxx::document::view_or_value> {
static std::string convert(const bsoncxx::document::view_or_value& value) {
return StringMaker<bsoncxx::document::view>::convert(value.view());
}
};

template <>
struct StringMaker<bsoncxx::document::value> {
static std::string convert(const bsoncxx::document::value& value) {
return StringMaker<bsoncxx::document::view>::convert(value.view());
}
};

template <>
struct StringMaker<bsoncxx::types::bson_value::view> {
static std::string convert(const bsoncxx::types::bson_value::view& value) {
return '{' + to_string(value.type()) + ": " + to_string(value) + '}';
}
};

template <>
struct StringMaker<bsoncxx::types::bson_value::value> {
static std::string convert(const bsoncxx::types::bson_value::value& value) {
return StringMaker<bsoncxx::types::bson_value::view>::convert(value.view());
}
};

template <>
struct StringMaker<bsoncxx::types::bson_value::view_or_value> {
static std::string convert(const bsoncxx::types::bson_value::view_or_value& value) {
return StringMaker<bsoncxx::types::bson_value::view>::convert(value.view());
}
};

template <typename T>
struct StringMaker<stdx::optional<T>> {
static std::string convert(const bsoncxx::stdx::optional<T>& value) {
if (value) {
StringMaker<T>::convert(value.value());
return StringMaker<T>::convert(value.value());
}

return "{nullopt}";
Expand Down
96 changes: 96 additions & 0 deletions src/bsoncxx/test_util/to_string.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright 2022 MongoDB Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <iomanip>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>

#include <bsoncxx/exception/error_code.hpp>
#include <bsoncxx/exception/exception.hpp>
#include <bsoncxx/string/to_string.hpp>
#include <bsoncxx/types/bson_value/view_or_value.hpp>

#include <bsoncxx/config/private/prelude.hh>

namespace bsoncxx {
BSONCXX_INLINE_NAMESPACE_BEGIN

inline std::string to_string(types::bson_value::view_or_value val) {
switch (val.view().type()) {
case bsoncxx::type::k_string:
return string::to_string(val.view().get_string().value);
case bsoncxx::type::k_int32:
return std::to_string(val.view().get_int32().value);
case bsoncxx::type::k_int64:
return std::to_string(val.view().get_int64().value);
case bsoncxx::type::k_document:
return to_json(val.view().get_document().value);
case bsoncxx::type::k_array:
return to_json(val.view().get_array().value);
case bsoncxx::type::k_oid:
return val.view().get_oid().value.to_string();
case bsoncxx::type::k_binary: {
const auto& binary = val.view().get_binary();
std::stringstream ss;
ss << std::hex;
for (auto&& byte :
std::vector<unsigned int>(binary.bytes, binary.bytes + binary.size)) {
ss << std::setw(2) << std::setfill('0') << byte;
}
return ss.str();
}
case bsoncxx::type::k_bool:
return val.view().get_bool().value ? "true" : "false";
case bsoncxx::type::k_code:
return string::to_string(val.view().get_code().code);
case bsoncxx::type::k_codewscope:
return "code={" + string::to_string(val.view().get_codewscope().code) + "}, scope={" +
to_json(val.view().get_codewscope().scope) + "}";
case bsoncxx::type::k_date:
return std::to_string(val.view().get_date().value.count());
case bsoncxx::type::k_double:
return std::to_string(val.view().get_double());
case bsoncxx::type::k_null:
return "null";
case bsoncxx::type::k_undefined:
return "undefined";
case bsoncxx::type::k_timestamp:
return "timestamp={" + std::to_string(val.view().get_timestamp().timestamp) +
"}, increment={" + std::to_string(val.view().get_timestamp().increment) + "}";
case bsoncxx::type::k_regex:
return "regex={" + string::to_string(val.view().get_regex().regex) + "}, options={" +
string::to_string(val.view().get_regex().options) + "}";
case bsoncxx::type::k_minkey:
return "minkey";
case bsoncxx::type::k_maxkey:
return "maxkey";
case bsoncxx::type::k_decimal128:
return val.view().get_decimal128().value.to_string();
case bsoncxx::type::k_symbol:
return string::to_string(val.view().get_symbol().symbol);
case bsoncxx::type::k_dbpointer:
return val.view().get_dbpointer().value.to_string();
default:
return "?"; // Match bsoncxx::to_string(bsoncxx::type) behavior.
}
}

BSONCXX_INLINE_NAMESPACE_END
} // namespace bsoncxx

#include <bsoncxx/config/private/postlude.hh>
3 changes: 2 additions & 1 deletion src/mongocxx/test/spec/monitoring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <bsoncxx/builder/basic/document.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/test_util/to_string.hh>
#include <mongocxx/exception/error_code.hpp>
#include <mongocxx/test/spec/monitoring.hh>
#include <mongocxx/test/spec/unified_tests/assert.hh>
Expand Down Expand Up @@ -53,7 +54,7 @@ void apm_checker::compare_unified(bsoncxx::array::view expectations,

// This will throw an exception on unmatched fields and return true in all other cases.
auto compare = [&](const bsoncxx::array::element& exp, const bsoncxx::document::view actual) {
CAPTURE(print_all(), to_json(actual), assert::to_string(exp.get_value()));
CAPTURE(print_all(), to_json(actual), bsoncxx::to_string(exp.get_value()));

// Extra fields are only allowed in root-level documents. Here, each k in keys is treated
// as its own root-level document, allowing extra fields.
Expand Down
63 changes: 1 addition & 62 deletions src/mongocxx/test/spec/unified_tests/assert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <bsoncxx/json.hpp>
#include <bsoncxx/string/to_string.hpp>
#include <bsoncxx/test_util/to_string.hh>
#include <bsoncxx/types.hpp>
#include <bsoncxx/types/bson_value/value.hpp>
#include <mongocxx/test_util/client_helpers.hh>
Expand All @@ -29,7 +30,6 @@
using namespace bsoncxx;
using namespace mongocxx;

using assert::to_string;
using bsoncxx::types::bson_value::value;

namespace {
Expand Down Expand Up @@ -74,67 +74,6 @@ std::string match_doc_current_path() noexcept {

} // namespace

std::string binary_to_string(types::b_binary binary) {
std::stringstream ss;
ss << std::hex;
for (auto&& byte : std::vector<unsigned int>(binary.bytes, binary.bytes + binary.size)) {
ss << std::setw(2) << std::setfill('0') << byte;
}
return ss.str();
}

std::string assert::to_string(types::bson_value::view_or_value val) {
switch (val.view().type()) {
case bsoncxx::type::k_string:
return string::to_string(val.view().get_string().value);
case bsoncxx::type::k_int32:
return std::to_string(val.view().get_int32().value);
case bsoncxx::type::k_int64:
return std::to_string(val.view().get_int64().value);
case bsoncxx::type::k_document:
return to_json(val.view().get_document().value);
case bsoncxx::type::k_array:
return to_json(val.view().get_array().value);
case bsoncxx::type::k_oid:
return val.view().get_oid().value.to_string();
case bsoncxx::type::k_binary:
return binary_to_string(val.view().get_binary());
case bsoncxx::type::k_bool:
return val.view().get_bool().value ? "true" : "false";
case bsoncxx::type::k_code:
return string::to_string(val.view().get_code().code);
case bsoncxx::type::k_codewscope:
return "code={" + string::to_string(val.view().get_codewscope().code) + "}, scope={" +
to_json(val.view().get_codewscope().scope) + "}";
case bsoncxx::type::k_date:
return std::to_string(val.view().get_date().value.count());
case bsoncxx::type::k_double:
return std::to_string(val.view().get_double());
case bsoncxx::type::k_null:
return "null";
case bsoncxx::type::k_undefined:
return "undefined";
case bsoncxx::type::k_timestamp:
return "timestamp={" + std::to_string(val.view().get_timestamp().timestamp) +
"}, increment={" + std::to_string(val.view().get_timestamp().increment) + "}";
case bsoncxx::type::k_regex:
return "regex={" + string::to_string(val.view().get_regex().regex) + "}, options={" +
string::to_string(val.view().get_regex().options) + "}";
case bsoncxx::type::k_minkey:
return "minkey";
case bsoncxx::type::k_maxkey:
return "maxkey";
case bsoncxx::type::k_decimal128:
return val.view().get_decimal128().value.to_string();
case bsoncxx::type::k_symbol:
return string::to_string(val.view().get_symbol().symbol);
case bsoncxx::type::k_dbpointer:
return val.view().get_dbpointer().value.to_string();
default:
MONGOCXX_UNREACHABLE;
}
}

template <typename Element>
type to_type(const Element& type) {
auto type_str = string::to_string(type.get_string().value);
Expand Down
1 change: 0 additions & 1 deletion src/mongocxx/test/spec/unified_tests/assert.hh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ void matches(bsoncxx::types::bson_value::view actual,
bool is_root = true,
bool is_array_of_root_docs = false);

std::string to_string(bsoncxx::types::bson_value::view_or_value val);
} // namespace assert
MONGOCXX_INLINE_NAMESPACE_END
} // namespace mongocxx
Expand Down

0 comments on commit f1f3f50

Please sign in to comment.