summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2017-05-02 09:16:56 -0400
committerMark Benvenuto <mark.benvenuto@mongodb.com>2017-05-02 09:16:56 -0400
commit49cf0ebd80e8b007a6bcd08d3c956b149afa6f81 (patch)
tree5426b926fda611d8f956ab05bf987895881c491e /src/mongo
parent3d06c50d9427ac64785d2b62ca368010890aa9be (diff)
downloadmongo-49cf0ebd80e8b007a6bcd08d3c956b149afa6f81.tar.gz
SERVER-28827 BinData for IDL
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/bson/bsonelement.h26
-rw-r--r--src/mongo/idl/basic_types.idl32
-rw-r--r--src/mongo/idl/idl_parser.cpp25
-rw-r--r--src/mongo/idl/idl_parser.h13
-rw-r--r--src/mongo/idl/idl_test.cpp270
-rw-r--r--src/mongo/idl/idl_test_types.h31
-rw-r--r--src/mongo/idl/unittest.idl52
-rw-r--r--src/mongo/idl/unittest_import.idl20
8 files changed, 456 insertions, 13 deletions
diff --git a/src/mongo/bson/bsonelement.h b/src/mongo/bson/bsonelement.h
index 2d815383b2c..dd68d333f63 100644
--- a/src/mongo/bson/bsonelement.h
+++ b/src/mongo/bson/bsonelement.h
@@ -35,6 +35,7 @@
#include <string>
#include <vector>
+#include "mongo/base/data_range.h"
#include "mongo/base/data_type_endian.h"
#include "mongo/base/data_view.h"
#include "mongo/base/string_data_comparator_interface.h"
@@ -468,6 +469,19 @@ public:
return (BinDataType)c;
}
+ std::vector<uint8_t> _binDataVector() const {
+ if (binDataType() != ByteArrayDeprecated) {
+ return std::vector<uint8_t>(reinterpret_cast<const uint8_t*>(value()) + 5,
+ reinterpret_cast<const uint8_t*>(value()) + 5 +
+ valuestrsize());
+ } else {
+ // Skip the extra int32 size
+ return std::vector<uint8_t>(reinterpret_cast<const uint8_t*>(value()) + 4,
+ reinterpret_cast<const uint8_t*>(value()) + 4 +
+ valuestrsize() - 4);
+ }
+ }
+
/** Retrieve the regex std::string for a Regex element */
const char* regex() const {
verify(type() == RegEx);
@@ -592,6 +606,18 @@ public:
return result;
}
+ const std::array<unsigned char, 16> md5() const {
+ int len = 0;
+ const char* data = nullptr;
+ if (type() == BinData && binDataType() == BinDataType::MD5Type)
+ data = binData(len);
+ uassert(550418, "md5 must be a 16-byte binary field with MD5 (5) subtype", len == 16);
+ std::array<unsigned char, 16> result;
+ memcpy(&result, data, len);
+ return result;
+ }
+
+
Date_t timestampTime() const {
unsigned long long t = ConstDataView(value() + 4).read<LittleEndian<unsigned int>>();
return Date_t::fromMillisSinceEpoch(t * 1000);
diff --git a/src/mongo/idl/basic_types.idl b/src/mongo/idl/basic_types.idl
index 76438ecc01f..1dd9495d65e 100644
--- a/src/mongo/idl/basic_types.idl
+++ b/src/mongo/idl/basic_types.idl
@@ -54,11 +54,33 @@ types:
cpp_type: "bool"
deserializer: "mongo::BSONElement::boolean"
- # TODO: support bindata
- # bindata:
- # bson_serialization_type: bindata
- # cpp_type: "std:"
- # deserializer: "mongo::BSONElement::str"
+ bindata_generic:
+ bson_serialization_type: bindata
+ bindata_subtype: generic
+ description: "A BSON bindata of "
+ cpp_type: "std::vector<std::uint8_t>"
+ deserializer: "mongo::BSONElement::_binDataVector"
+
+ bindata_function:
+ bson_serialization_type: bindata
+ bindata_subtype: function
+ description: "A BSON bindata of function sub type"
+ cpp_type: "std::vector<std::uint8_t>"
+ deserializer: "mongo::BSONElement::_binDataVector"
+
+ bindata_uuid:
+ bson_serialization_type: bindata
+ bindata_subtype: uuid
+ description: "A BSON bindata of uuid sub type"
+ cpp_type: "std::array<std::uint8_t, 16>"
+ deserializer: "mongo::BSONElement::uuid"
+
+ bindata_md5:
+ bson_serialization_type: bindata
+ bindata_subtype: md5
+ description: "A BSON bindata of uuid sub type"
+ cpp_type: "std::array<std::uint8_t, 16>"
+ deserializer: "mongo::BSONElement::md5"
objectid:
bson_serialization_type: objectid
diff --git a/src/mongo/idl/idl_parser.cpp b/src/mongo/idl/idl_parser.cpp
index fee9678f485..c9450664c71 100644
--- a/src/mongo/idl/idl_parser.cpp
+++ b/src/mongo/idl/idl_parser.cpp
@@ -218,4 +218,29 @@ std::vector<std::string> transformVector(const std::vector<StringData>& input) {
return output;
}
+std::vector<ConstDataRange> transformVector(const std::vector<std::vector<std::uint8_t>>& input) {
+ std::vector<ConstDataRange> output;
+
+ output.reserve(input.size());
+
+ std::transform(begin(input), end(input), std::back_inserter(output), [](auto&& vec) {
+ return makeCDR(vec);
+ });
+
+ return output;
+}
+
+std::vector<std::vector<std::uint8_t>> transformVector(const std::vector<ConstDataRange>& input) {
+ std::vector<std::vector<std::uint8_t>> output;
+
+ output.reserve(input.size());
+
+ std::transform(begin(input), end(input), std::back_inserter(output), [](auto&& cdr) {
+ return std::vector<std::uint8_t>(reinterpret_cast<const uint8_t*>(cdr.data()),
+ reinterpret_cast<const uint8_t*>(cdr.data()) +
+ cdr.length());
+ });
+
+ return output;
+}
} // namespace mongo
diff --git a/src/mongo/idl/idl_parser.h b/src/mongo/idl/idl_parser.h
index 2a6ee4a1db7..e249be26b87 100644
--- a/src/mongo/idl/idl_parser.h
+++ b/src/mongo/idl/idl_parser.h
@@ -142,5 +142,18 @@ private:
*/
std::vector<StringData> transformVector(const std::vector<std::string>& input);
std::vector<std::string> transformVector(const std::vector<StringData>& input);
+std::vector<ConstDataRange> transformVector(const std::vector<std::vector<std::uint8_t>>& input);
+std::vector<std::vector<std::uint8_t>> transformVector(const std::vector<ConstDataRange>& input);
+
+/**
+ * Get a ConstDataRange from a vector or an array of bytes.
+ */
+inline ConstDataRange makeCDR(const std::vector<uint8_t>& value) {
+ return ConstDataRange(reinterpret_cast<const char*>(value.data()), value.size());
+}
+
+inline ConstDataRange makeCDR(const std::array<uint8_t, 16>& value) {
+ return ConstDataRange(reinterpret_cast<const char*>(value.data()), value.size());
+}
} // namespace mongo
diff --git a/src/mongo/idl/idl_test.cpp b/src/mongo/idl/idl_test.cpp
index 55c1cf0b6f9..4f26af506c9 100644
--- a/src/mongo/idl/idl_test.cpp
+++ b/src/mongo/idl/idl_test.cpp
@@ -37,7 +37,41 @@ using namespace mongo::idl::test;
namespace mongo {
-// Use a seperate function to get better error messages when types do not match.
+namespace {
+
+bool isEquals(ConstDataRange left, const std::vector<uint8_t>& right) {
+ auto rightCDR = makeCDR(right);
+ return std::equal(left.data(),
+ left.data() + left.length(),
+ rightCDR.data(),
+ rightCDR.data() + rightCDR.length());
+}
+
+bool isEquals(const std::array<uint8_t, 16>& left, const std::array<uint8_t, 16>& right) {
+ return std::equal(
+ left.data(), left.data() + left.size(), right.data(), right.data() + right.size());
+}
+
+bool isEqual(const ConstDataRange& left, const ConstDataRange& right) {
+ return std::equal(
+ left.data(), left.data() + left.length(), right.data(), right.data() + right.length());
+}
+
+bool isEquals(const std::vector<ConstDataRange>& left,
+ const std::vector<std::vector<std::uint8_t>>& rightVector) {
+ auto right = transformVector(rightVector);
+ return std::equal(
+ left.data(), left.data() + left.size(), right.data(), right.data() + right.size(), isEqual);
+}
+
+bool isEquals(const std::vector<std::array<std::uint8_t, 16>>& left,
+ const std::vector<std::array<std::uint8_t, 16>>& right) {
+ return std::equal(
+ left.data(), left.data() + left.size(), right.data(), right.data() + right.size());
+}
+
+
+// Use a separate function to get better error messages when types do not match.
template <typename T1, typename T2>
void assert_same_types() {
MONGO_STATIC_ASSERT(std::is_same<T1, T2>::value);
@@ -187,8 +221,7 @@ TEST(IDLOneTypeTests, TestSafeInt32) {
TEST(IDLOneTypeTests, TestNamespaceString) {
IDLParserErrorContext ctxt("root");
- auto testDoc = BSON(One_namespacestring::kValueFieldName
- << "foo.bar");
+ auto testDoc = BSON(One_namespacestring::kValueFieldName << "foo.bar");
auto element = testDoc.firstElement();
ASSERT_EQUALS(element.type(), String);
@@ -440,6 +473,10 @@ TEST(IDLFieldTests, TestOptionalFields) {
const boost::optional<mongo::StringData>>();
assert_same_types<decltype(testStruct.getField3()),
const boost::optional<mongo::BSONObj>>();
+ assert_same_types<decltype(testStruct.getField4()),
+ const boost::optional<ConstDataRange>>();
+ assert_same_types<decltype(testStruct.getField5()),
+ const boost::optional<std::array<std::uint8_t, 16>>>();
ASSERT_EQUALS("Foo", testStruct.getField1().get());
ASSERT_FALSE(testStruct.getField2().is_initialized());
@@ -480,9 +517,8 @@ TEST(IDLFieldTests, TestOptionalFields) {
}
}
-
// Positive: Test a nested struct
-TEST(IDLNestedStruct, TestDuplicatTypes) {
+TEST(IDLNestedStruct, TestDuplicateTypes) {
IDLParserErrorContext ctxt("root");
@@ -544,6 +580,12 @@ TEST(IDLArrayTests, TestSimpleArrays) {
IDLParserErrorContext ctxt("root");
// Positive: Test document
+ uint8_t array1[] = {1, 2, 3};
+ uint8_t array2[] = {4, 6, 8};
+
+ uint8_t array15[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+ uint8_t array16[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+
auto testDoc = BSON("field1" << BSON_ARRAY("Foo"
<< "Bar"
<< "???")
@@ -551,13 +593,20 @@ TEST(IDLArrayTests, TestSimpleArrays) {
<< BSON_ARRAY(1 << 2 << 3)
<< "field3"
<< BSON_ARRAY(1.2 << 3.4 << 5.6)
-
- );
+ << "field4"
+ << BSON_ARRAY(BSONBinData(array1, 3, BinDataGeneral)
+ << BSONBinData(array2, 3, BinDataGeneral))
+ << "field5"
+ << BSON_ARRAY(BSONBinData(array15, 16, newUUID)
+ << BSONBinData(array16, 16, newUUID)));
auto testStruct = Simple_array_fields::parse(ctxt, testDoc);
assert_same_types<decltype(testStruct.getField1()), const std::vector<mongo::StringData>>();
assert_same_types<decltype(testStruct.getField2()), const std::vector<std::int32_t>&>();
assert_same_types<decltype(testStruct.getField3()), const std::vector<double>&>();
+ assert_same_types<decltype(testStruct.getField4()), const std::vector<ConstDataRange>>();
+ assert_same_types<decltype(testStruct.getField5()),
+ const std::vector<std::array<std::uint8_t, 16>>&>();
std::vector<StringData> field1{"Foo", "Bar", "???"};
ASSERT_TRUE(field1 == testStruct.getField1());
@@ -566,6 +615,14 @@ TEST(IDLArrayTests, TestSimpleArrays) {
std::vector<double> field3{1.2, 3.4, 5.6};
ASSERT_TRUE(field3 == testStruct.getField3());
+ std::vector<std::vector<uint8_t>> field4{{1, 2, 3}, {4, 6, 8}};
+ ASSERT_TRUE(isEquals(testStruct.getField4(), field4));
+
+ std::vector<std::array<uint8_t, 16>> field5{
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+ {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}};
+ ASSERT_TRUE(isEquals(testStruct.getField5(), field5));
+
// Positive: Test we can roundtrip from the just parsed document
{
BSONObjBuilder builder;
@@ -582,6 +639,8 @@ TEST(IDLArrayTests, TestSimpleArrays) {
array_fields.setField1(field1);
array_fields.setField2(field2);
array_fields.setField3(field3);
+ array_fields.setField4(transformVector(field4));
+ array_fields.setField5(field5);
array_fields.serialize(&builder);
auto serializedDoc = builder.obj();
@@ -611,6 +670,10 @@ TEST(IDLArrayTests, TestSimpleOptionalArrays) {
const boost::optional<std::vector<std::int32_t>>>();
assert_same_types<decltype(testStruct.getField3()),
const boost::optional<std::vector<double>>>();
+ assert_same_types<decltype(testStruct.getField4()),
+ const boost::optional<std::vector<ConstDataRange>>>();
+ assert_same_types<decltype(testStruct.getField5()),
+ const boost::optional<std::vector<std::array<std::uint8_t, 16>>>>();
std::vector<StringData> field1{"Foo", "Bar", "???"};
ASSERT_TRUE(field1 == testStruct.getField1().get());
@@ -736,6 +799,11 @@ TEST(IDLArrayTests, TestArraysOfComplexTypes) {
<< BSON_ARRAY(BSONObj() << BSONObj())
<< "field5"
<< BSON_ARRAY(BSONObj() << BSONObj() << BSONObj())
+ << "field6"
+ << BSON_ARRAY(BSON("value"
+ << "hello")
+ << BSON("value"
+ << "world"))
<< "field1o"
<< BSON_ARRAY(1 << 2 << 3)
<< "field2o"
@@ -744,7 +812,14 @@ TEST(IDLArrayTests, TestArraysOfComplexTypes) {
<< "field3o"
<< BSON_ARRAY(1 << "2")
<< "field4o"
- << BSON_ARRAY(BSONObj() << BSONObj()));
+ << BSON_ARRAY(BSONObj() << BSONObj())
+ << "field6o"
+ << BSON_ARRAY(BSON("value"
+ << "goodbye")
+ << BSON("value"
+ << "world"))
+
+ );
auto testStruct = Complex_array_fields::parse(ctxt, testDoc);
assert_same_types<decltype(testStruct.getField1()), const std::vector<std::int64_t>&>();
@@ -754,6 +829,7 @@ TEST(IDLArrayTests, TestArraysOfComplexTypes) {
assert_same_types<decltype(testStruct.getField4()),
const std::vector<mongo::ObjectBasicType>&>();
assert_same_types<decltype(testStruct.getField5()), const std::vector<mongo::BSONObj>&>();
+ assert_same_types<decltype(testStruct.getField6()), const std::vector<mongo::One_string>&>();
assert_same_types<decltype(testStruct.getField1o()),
const boost::optional<std::vector<std::int64_t>>>();
@@ -765,11 +841,188 @@ TEST(IDLArrayTests, TestArraysOfComplexTypes) {
const boost::optional<std::vector<mongo::ObjectBasicType>>>();
assert_same_types<decltype(testStruct.getField5o()),
const boost::optional<std::vector<mongo::BSONObj>>>();
+ assert_same_types<decltype(testStruct.getField6o()),
+ const boost::optional<std::vector<mongo::One_string>>>();
std::vector<std::int64_t> field1{1, 2, 3};
ASSERT_TRUE(field1 == testStruct.getField1());
std::vector<NamespaceString> field2{{"a", "b"}, {"c", "d"}};
ASSERT_TRUE(field2 == testStruct.getField2());
+
+ ASSERT_EQUALS(testStruct.getField6().size(), 2u);
+ ASSERT_EQUALS(testStruct.getField6()[0].getValue(), "hello");
+ ASSERT_EQUALS(testStruct.getField6()[1].getValue(), "world");
+ ASSERT_EQUALS(testStruct.getField6o().get().size(), 2u);
+ ASSERT_EQUALS(testStruct.getField6o().get()[0].getValue(), "goodbye");
+ ASSERT_EQUALS(testStruct.getField6o().get()[1].getValue(), "world");
+}
+
+template <typename ParserT, BinDataType bindata_type>
+void TestBinDataVector() {
+ IDLParserErrorContext ctxt("root");
+
+ // Positive: Test document with only a generic bindata field
+ uint8_t testData[] = {1, 2, 3};
+ auto testDoc = BSON("value" << BSONBinData(testData, 3, bindata_type));
+ auto testStruct = ParserT::parse(ctxt, testDoc);
+
+ assert_same_types<decltype(testStruct.getValue()), const ConstDataRange>();
+
+ std::vector<std::uint8_t> expected{1, 2, 3};
+
+ ASSERT_TRUE(isEquals(testStruct.getValue(), expected));
+
+ // Positive: Test we can roundtrip from the just parsed document
+ {
+ BSONObjBuilder builder;
+ testStruct.serialize(&builder);
+ auto loopbackDoc = builder.obj();
+
+ ASSERT_BSONOBJ_EQ(testDoc, loopbackDoc);
+ }
+
+ // Positive: Test we can serialize from nothing the same document
+ {
+ BSONObjBuilder builder;
+ ParserT one_new;
+ one_new.setValue(makeCDR(expected));
+ testStruct.serialize(&builder);
+
+ auto serializedDoc = builder.obj();
+ ASSERT_BSONOBJ_EQ(testDoc, serializedDoc);
+ }
+}
+
+TEST(IDLBinData, TestGeneric) {
+ TestBinDataVector<One_bindata, BinDataGeneral>();
+}
+
+TEST(IDLBinData, TestFunction) {
+ TestBinDataVector<One_function, Function>();
+}
+
+template <typename ParserT, BinDataType bindata_type>
+void TestBinDataArray() {
+ IDLParserErrorContext ctxt("root");
+
+ // Positive: Test document with only a generic bindata field
+ uint8_t testData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ auto testDoc = BSON("value" << BSONBinData(testData, 16, bindata_type));
+ auto testStruct = ParserT::parse(ctxt, testDoc);
+
+ assert_same_types<decltype(testStruct.getValue()), const std::array<uint8_t, 16>>();
+
+ std::array<std::uint8_t, 16> expected{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+
+ ASSERT_TRUE(isEquals(testStruct.getValue(), expected));
+
+ // Positive: Test we can roundtrip from the just parsed document
+ {
+ BSONObjBuilder builder;
+ testStruct.serialize(&builder);
+ auto loopbackDoc = builder.obj();
+
+ ASSERT_BSONOBJ_EQ(testDoc, loopbackDoc);
+ }
+
+ // Positive: Test we can serialize from nothing the same document
+ {
+ BSONObjBuilder builder;
+ ParserT one_new;
+ one_new.setValue(expected);
+ one_new.serialize(&builder);
+
+ auto serializedDoc = builder.obj();
+ ASSERT_BSONOBJ_EQ(testDoc, serializedDoc);
+ }
+}
+
+TEST(IDLBinData, TestUUID) {
+ TestBinDataArray<One_uuid, newUUID>();
+}
+
+TEST(IDLBinData, TestMD5) {
+ TestBinDataArray<One_md5, MD5Type>();
+
+ // Negative: Test document with a incorrectly size md5 field
+ {
+ IDLParserErrorContext ctxt("root");
+
+ uint8_t testData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+ auto testDoc = BSON("value" << BSONBinData(testData, 15, MD5Type));
+ ASSERT_THROWS(One_md5::parse(ctxt, testDoc), UserException);
+ }
+}
+
+// Test if a given value for a given bson document parses successfully or fails if the bson types
+// mismatch.
+template <typename ParserT, BinDataType Parser_bindata_type, BinDataType Test_bindata_type>
+void TestBinDataParse() {
+ IDLParserErrorContext ctxt("root");
+
+ uint8_t testData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ auto testDoc = BSON("value" << BSONBinData(testData, 16, Test_bindata_type));
+
+ auto element = testDoc.firstElement();
+ ASSERT_EQUALS(element.type(), BinData);
+ ASSERT_EQUALS(element.binDataType(), Test_bindata_type);
+
+ if (Parser_bindata_type != Test_bindata_type) {
+ ASSERT_THROWS(ParserT::parse(ctxt, testDoc), UserException);
+ } else {
+ (void)ParserT::parse(ctxt, testDoc);
+ }
+}
+
+template <typename ParserT, BinDataType Parser_bindata_type>
+void TestBinDataParser() {
+ TestBinDataParse<ParserT, Parser_bindata_type, BinDataGeneral>();
+ TestBinDataParse<ParserT, Parser_bindata_type, Function>();
+ TestBinDataParse<ParserT, Parser_bindata_type, MD5Type>();
+ TestBinDataParse<ParserT, Parser_bindata_type, newUUID>();
+}
+
+TEST(IDLBinData, TestParse) {
+ TestBinDataParser<One_bindata, BinDataGeneral>();
+ TestBinDataParser<One_function, Function>();
+ TestBinDataParser<One_uuid, newUUID>();
+ TestBinDataParser<One_md5, MD5Type>();
+}
+
+// Mixed: test a type that accepts a custom bindata type
+TEST(IDLBinData, TestCustomType) {
+ IDLParserErrorContext ctxt("root");
+
+ uint8_t testData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ auto testDoc = BSON("value" << BSONBinData(testData, 14, BinDataGeneral));
+
+ auto element = testDoc.firstElement();
+ ASSERT_EQUALS(element.type(), BinData);
+ ASSERT_EQUALS(element.binDataType(), BinDataGeneral);
+
+ auto testStruct = One_bindata_custom::parse(ctxt, testDoc);
+ std::vector<std::uint8_t> testVector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ ASSERT_TRUE(testStruct.getValue().getVector() == testVector);
+
+ // Positive: Test we can roundtrip from the just parsed document
+ {
+ BSONObjBuilder builder;
+ testStruct.serialize(&builder);
+ auto loopbackDoc = builder.obj();
+
+ ASSERT_BSONOBJ_EQ(testDoc, loopbackDoc);
+ }
+
+ // Positive: Test we can serialize from nothing the same document
+ {
+ BSONObjBuilder builder;
+ One_bindata_custom one_new;
+ one_new.setValue(testVector);
+ one_new.serialize(&builder);
+
+ auto serializedDoc = builder.obj();
+ ASSERT_BSONOBJ_EQ(testDoc, serializedDoc);
+ }
}
/**
@@ -831,4 +1084,5 @@ TEST(IDLCustomType, TestDerivedParser) {
}
}
+} // namespace
} // namespace mongo
diff --git a/src/mongo/idl/idl_test_types.h b/src/mongo/idl/idl_test_types.h
index 41f75c796f0..6e03d48b470 100644
--- a/src/mongo/idl/idl_test_types.h
+++ b/src/mongo/idl/idl_test_types.h
@@ -28,6 +28,9 @@
#pragma once
+#include <vector>
+
+#include "mongo/base/data_range.h"
#include "mongo/bson/bsonobj.h"
#include "mongo/bson/bsonobjbuilder.h"
@@ -82,4 +85,32 @@ private:
BSONObj _obj;
};
+/**
+ * Simple class that demonstrates the contract a class must implement to parse a BSON "bindata"
+ * variable length type
+ * from the IDL parser.
+ */
+class BinDataCustomType {
+public:
+ BinDataCustomType() {}
+ BinDataCustomType(std::vector<std::uint8_t>& vec) : _vec(std::move(vec)) {}
+
+ static BinDataCustomType parse(const std::vector<std::uint8_t> vec) {
+ BinDataCustomType b;
+ b._vec = std::move(vec);
+ return b;
+ }
+
+ ConstDataRange serialize() const {
+ return makeCDR(_vec);
+ }
+
+ const std::vector<std::uint8_t>& getVector() const {
+ return _vec;
+ }
+
+private:
+ std::vector<std::uint8_t> _vec;
+};
+
} // namespace mongo
diff --git a/src/mongo/idl/unittest.idl b/src/mongo/idl/unittest.idl
index 5d49ea37560..7aecd720ad4 100644
--- a/src/mongo/idl/unittest.idl
+++ b/src/mongo/idl/unittest.idl
@@ -41,6 +41,20 @@ types:
##################################################################################################
#
+# Test a custom non-BSONElement deserialization and serialization methods for a bindata type
+#
+##################################################################################################
+
+ bindata_custom:
+ bson_serialization_type: bindata
+ bindata_subtype: generic
+ description: "A MongoDB BinDataCustomType"
+ cpp_type: "mongo::BinDataCustomType"
+ serializer: mongo::BinDataCustomType::serialize
+ deserializer: mongo::BinDataCustomType::parse
+
+##################################################################################################
+#
# Test a custom non-BSONElement deserialization and serialization methods for an any type
#
##################################################################################################
@@ -81,6 +95,11 @@ types:
- double
deserializer: "mongo::BSONElement::numberInt"
+##################################################################################################
+#
+# Unit test structs for a single value to ensure type validation works correctly
+#
+##################################################################################################
structs:
@@ -172,6 +191,17 @@ structs:
##################################################################################################
#
+# Test a custom non-BSONElement deserialization and serialization methods for a bindata type
+#
+##################################################################################################
+
+ one_bindata_custom:
+ description: UnitTest for a custom bindata
+ fields:
+ value: bindata_custom
+
+##################################################################################################
+#
# Test a custom non-BSONElement deserialization and serialization methods for an any type
#
##################################################################################################
@@ -248,6 +278,12 @@ structs:
field3:
type: object
optional: true
+ field4:
+ type: bindata_generic
+ optional: true
+ field5:
+ type: bindata_uuid
+ optional: true
##################################################################################################
#
@@ -269,6 +305,10 @@ structs:
type: array<int>
field3:
type: array<double>
+ field4:
+ type: array<bindata_generic>
+ field5:
+ type: array<bindata_uuid>
optional_array_fields:
description: UnitTest for arrays of optional simple types
@@ -282,6 +322,12 @@ structs:
field3:
type: array<double>
optional: true
+ field4:
+ type: array<bindata_generic>
+ optional: true
+ field5:
+ type: array<bindata_uuid>
+ optional: true
##################################################################################################
#
@@ -302,6 +348,8 @@ structs:
type: array<object_basic_type>
field5:
type: array<object>
+ field6:
+ type: array<one_string>
field1o:
type: array<safeInt32>
optional: true
@@ -317,3 +365,7 @@ structs:
field5o:
type: array<object>
optional: true
+ field6o:
+ type: array<one_string>
+ optional: true
+#
diff --git a/src/mongo/idl/unittest_import.idl b/src/mongo/idl/unittest_import.idl
index a2064766133..0e9403f65d5 100644
--- a/src/mongo/idl/unittest_import.idl
+++ b/src/mongo/idl/unittest_import.idl
@@ -58,6 +58,26 @@ structs:
fields:
value: bool
+ one_bindata:
+ description: UnitTest for a single bindata_generic
+ fields:
+ value: bindata_generic
+
+ one_function:
+ description: UnitTest for a single bindata_function
+ fields:
+ value: bindata_function
+
+ one_uuid:
+ description: UnitTest for a single bindata_uuid
+ fields:
+ value: bindata_uuid
+
+ one_md5:
+ description: UnitTest for a single bindata_md5
+ fields:
+ value: bindata_md5
+
one_objectid:
description: UnitTest for a single objectid
fields: