Skip to content

Commit f1f3f50

Browse files
authored
Add StringMaker specialization for bsoncxx::types::bson_value types (#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
1 parent d1e7c98 commit f1f3f50

File tree

6 files changed

+132
-67
lines changed

6 files changed

+132
-67
lines changed

src/bsoncxx/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ set_local_dist (src_bsoncxx_DIST_local
289289
string/view_or_value.hpp
290290
test_util/catch.hh
291291
test_util/export_for_testing.hh
292+
test_util/to_string.hh
292293
types.cpp
293294
types.hpp
294295
types/value.hpp

src/bsoncxx/test_util/catch.hh

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@
1414

1515
#pragma once
1616

17-
#include "catch.hpp"
18-
#include <bsoncxx/document/value.hpp>
17+
#include <bsoncxx/document/view_or_value.hpp>
1918
#include <bsoncxx/json.hpp>
2019
#include <bsoncxx/oid.hpp>
2120
#include <bsoncxx/stdx/optional.hpp>
21+
#include <bsoncxx/test_util/to_string.hh>
22+
#include <third_party/catch/include/catch.hpp>
2223

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

@@ -41,18 +42,46 @@ struct StringMaker<bsoncxx::document::view> {
4142
}
4243
};
4344

45+
template <>
46+
struct StringMaker<bsoncxx::document::view_or_value> {
47+
static std::string convert(const bsoncxx::document::view_or_value& value) {
48+
return StringMaker<bsoncxx::document::view>::convert(value.view());
49+
}
50+
};
51+
4452
template <>
4553
struct StringMaker<bsoncxx::document::value> {
4654
static std::string convert(const bsoncxx::document::value& value) {
4755
return StringMaker<bsoncxx::document::view>::convert(value.view());
4856
}
4957
};
5058

59+
template <>
60+
struct StringMaker<bsoncxx::types::bson_value::view> {
61+
static std::string convert(const bsoncxx::types::bson_value::view& value) {
62+
return '{' + to_string(value.type()) + ": " + to_string(value) + '}';
63+
}
64+
};
65+
66+
template <>
67+
struct StringMaker<bsoncxx::types::bson_value::value> {
68+
static std::string convert(const bsoncxx::types::bson_value::value& value) {
69+
return StringMaker<bsoncxx::types::bson_value::view>::convert(value.view());
70+
}
71+
};
72+
73+
template <>
74+
struct StringMaker<bsoncxx::types::bson_value::view_or_value> {
75+
static std::string convert(const bsoncxx::types::bson_value::view_or_value& value) {
76+
return StringMaker<bsoncxx::types::bson_value::view>::convert(value.view());
77+
}
78+
};
79+
5180
template <typename T>
5281
struct StringMaker<stdx::optional<T>> {
5382
static std::string convert(const bsoncxx::stdx::optional<T>& value) {
5483
if (value) {
55-
StringMaker<T>::convert(value.value());
84+
return StringMaker<T>::convert(value.value());
5685
}
5786

5887
return "{nullopt}";

src/bsoncxx/test_util/to_string.hh

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright 2022 MongoDB Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#pragma once
16+
17+
#include <iomanip>
18+
#include <sstream>
19+
#include <stdexcept>
20+
#include <string>
21+
#include <vector>
22+
23+
#include <bsoncxx/exception/error_code.hpp>
24+
#include <bsoncxx/exception/exception.hpp>
25+
#include <bsoncxx/string/to_string.hpp>
26+
#include <bsoncxx/types/bson_value/view_or_value.hpp>
27+
28+
#include <bsoncxx/config/private/prelude.hh>
29+
30+
namespace bsoncxx {
31+
BSONCXX_INLINE_NAMESPACE_BEGIN
32+
33+
inline std::string to_string(types::bson_value::view_or_value val) {
34+
switch (val.view().type()) {
35+
case bsoncxx::type::k_string:
36+
return string::to_string(val.view().get_string().value);
37+
case bsoncxx::type::k_int32:
38+
return std::to_string(val.view().get_int32().value);
39+
case bsoncxx::type::k_int64:
40+
return std::to_string(val.view().get_int64().value);
41+
case bsoncxx::type::k_document:
42+
return to_json(val.view().get_document().value);
43+
case bsoncxx::type::k_array:
44+
return to_json(val.view().get_array().value);
45+
case bsoncxx::type::k_oid:
46+
return val.view().get_oid().value.to_string();
47+
case bsoncxx::type::k_binary: {
48+
const auto& binary = val.view().get_binary();
49+
std::stringstream ss;
50+
ss << std::hex;
51+
for (auto&& byte :
52+
std::vector<unsigned int>(binary.bytes, binary.bytes + binary.size)) {
53+
ss << std::setw(2) << std::setfill('0') << byte;
54+
}
55+
return ss.str();
56+
}
57+
case bsoncxx::type::k_bool:
58+
return val.view().get_bool().value ? "true" : "false";
59+
case bsoncxx::type::k_code:
60+
return string::to_string(val.view().get_code().code);
61+
case bsoncxx::type::k_codewscope:
62+
return "code={" + string::to_string(val.view().get_codewscope().code) + "}, scope={" +
63+
to_json(val.view().get_codewscope().scope) + "}";
64+
case bsoncxx::type::k_date:
65+
return std::to_string(val.view().get_date().value.count());
66+
case bsoncxx::type::k_double:
67+
return std::to_string(val.view().get_double());
68+
case bsoncxx::type::k_null:
69+
return "null";
70+
case bsoncxx::type::k_undefined:
71+
return "undefined";
72+
case bsoncxx::type::k_timestamp:
73+
return "timestamp={" + std::to_string(val.view().get_timestamp().timestamp) +
74+
"}, increment={" + std::to_string(val.view().get_timestamp().increment) + "}";
75+
case bsoncxx::type::k_regex:
76+
return "regex={" + string::to_string(val.view().get_regex().regex) + "}, options={" +
77+
string::to_string(val.view().get_regex().options) + "}";
78+
case bsoncxx::type::k_minkey:
79+
return "minkey";
80+
case bsoncxx::type::k_maxkey:
81+
return "maxkey";
82+
case bsoncxx::type::k_decimal128:
83+
return val.view().get_decimal128().value.to_string();
84+
case bsoncxx::type::k_symbol:
85+
return string::to_string(val.view().get_symbol().symbol);
86+
case bsoncxx::type::k_dbpointer:
87+
return val.view().get_dbpointer().value.to_string();
88+
default:
89+
return "?"; // Match bsoncxx::to_string(bsoncxx::type) behavior.
90+
}
91+
}
92+
93+
BSONCXX_INLINE_NAMESPACE_END
94+
} // namespace bsoncxx
95+
96+
#include <bsoncxx/config/private/postlude.hh>

src/mongocxx/test/spec/monitoring.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <bsoncxx/builder/basic/document.hpp>
1919
#include <bsoncxx/json.hpp>
20+
#include <bsoncxx/test_util/to_string.hh>
2021
#include <mongocxx/exception/error_code.hpp>
2122
#include <mongocxx/test/spec/monitoring.hh>
2223
#include <mongocxx/test/spec/unified_tests/assert.hh>
@@ -53,7 +54,7 @@ void apm_checker::compare_unified(bsoncxx::array::view expectations,
5354

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

5859
// Extra fields are only allowed in root-level documents. Here, each k in keys is treated
5960
// as its own root-level document, allowing extra fields.

src/mongocxx/test/spec/unified_tests/assert.cpp

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <bsoncxx/json.hpp>
2323
#include <bsoncxx/string/to_string.hpp>
24+
#include <bsoncxx/test_util/to_string.hh>
2425
#include <bsoncxx/types.hpp>
2526
#include <bsoncxx/types/bson_value/value.hpp>
2627
#include <mongocxx/test_util/client_helpers.hh>
@@ -29,7 +30,6 @@
2930
using namespace bsoncxx;
3031
using namespace mongocxx;
3132

32-
using assert::to_string;
3333
using bsoncxx::types::bson_value::value;
3434

3535
namespace {
@@ -74,67 +74,6 @@ std::string match_doc_current_path() noexcept {
7474

7575
} // namespace
7676

77-
std::string binary_to_string(types::b_binary binary) {
78-
std::stringstream ss;
79-
ss << std::hex;
80-
for (auto&& byte : std::vector<unsigned int>(binary.bytes, binary.bytes + binary.size)) {
81-
ss << std::setw(2) << std::setfill('0') << byte;
82-
}
83-
return ss.str();
84-
}
85-
86-
std::string assert::to_string(types::bson_value::view_or_value val) {
87-
switch (val.view().type()) {
88-
case bsoncxx::type::k_string:
89-
return string::to_string(val.view().get_string().value);
90-
case bsoncxx::type::k_int32:
91-
return std::to_string(val.view().get_int32().value);
92-
case bsoncxx::type::k_int64:
93-
return std::to_string(val.view().get_int64().value);
94-
case bsoncxx::type::k_document:
95-
return to_json(val.view().get_document().value);
96-
case bsoncxx::type::k_array:
97-
return to_json(val.view().get_array().value);
98-
case bsoncxx::type::k_oid:
99-
return val.view().get_oid().value.to_string();
100-
case bsoncxx::type::k_binary:
101-
return binary_to_string(val.view().get_binary());
102-
case bsoncxx::type::k_bool:
103-
return val.view().get_bool().value ? "true" : "false";
104-
case bsoncxx::type::k_code:
105-
return string::to_string(val.view().get_code().code);
106-
case bsoncxx::type::k_codewscope:
107-
return "code={" + string::to_string(val.view().get_codewscope().code) + "}, scope={" +
108-
to_json(val.view().get_codewscope().scope) + "}";
109-
case bsoncxx::type::k_date:
110-
return std::to_string(val.view().get_date().value.count());
111-
case bsoncxx::type::k_double:
112-
return std::to_string(val.view().get_double());
113-
case bsoncxx::type::k_null:
114-
return "null";
115-
case bsoncxx::type::k_undefined:
116-
return "undefined";
117-
case bsoncxx::type::k_timestamp:
118-
return "timestamp={" + std::to_string(val.view().get_timestamp().timestamp) +
119-
"}, increment={" + std::to_string(val.view().get_timestamp().increment) + "}";
120-
case bsoncxx::type::k_regex:
121-
return "regex={" + string::to_string(val.view().get_regex().regex) + "}, options={" +
122-
string::to_string(val.view().get_regex().options) + "}";
123-
case bsoncxx::type::k_minkey:
124-
return "minkey";
125-
case bsoncxx::type::k_maxkey:
126-
return "maxkey";
127-
case bsoncxx::type::k_decimal128:
128-
return val.view().get_decimal128().value.to_string();
129-
case bsoncxx::type::k_symbol:
130-
return string::to_string(val.view().get_symbol().symbol);
131-
case bsoncxx::type::k_dbpointer:
132-
return val.view().get_dbpointer().value.to_string();
133-
default:
134-
MONGOCXX_UNREACHABLE;
135-
}
136-
}
137-
13877
template <typename Element>
13978
type to_type(const Element& type) {
14079
auto type_str = string::to_string(type.get_string().value);

src/mongocxx/test/spec/unified_tests/assert.hh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ void matches(bsoncxx::types::bson_value::view actual,
2929
bool is_root = true,
3030
bool is_array_of_root_docs = false);
3131

32-
std::string to_string(bsoncxx::types::bson_value::view_or_value val);
3332
} // namespace assert
3433
MONGOCXX_INLINE_NAMESPACE_END
3534
} // namespace mongocxx

0 commit comments

Comments
 (0)