summaryrefslogtreecommitdiff
path: root/src/mongo/idl
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2017-05-03 13:09:03 -0400
committerMark Benvenuto <mark.benvenuto@mongodb.com>2017-05-03 13:09:03 -0400
commit606b3930d1ca73f0184f4b29bb52917cc15e94cf (patch)
tree061bf56c07fb5250cc250105d66ec7d8ec4d2469 /src/mongo/idl
parentd949767b4ee2294cf3bd0d2e7433be29313cab03 (diff)
downloadmongo-606b3930d1ca73f0184f4b29bb52917cc15e94cf.tar.gz
SERVER-28828 Parser Chaining support for IDL
Diffstat (limited to 'src/mongo/idl')
-rw-r--r--src/mongo/idl/idl_test.cpp227
-rw-r--r--src/mongo/idl/idl_test_types.h50
-rw-r--r--src/mongo/idl/unittest.idl74
3 files changed, 350 insertions, 1 deletions
diff --git a/src/mongo/idl/idl_test.cpp b/src/mongo/idl/idl_test.cpp
index 4f26af506c9..00328d11648 100644
--- a/src/mongo/idl/idl_test.cpp
+++ b/src/mongo/idl/idl_test.cpp
@@ -227,6 +227,8 @@ TEST(IDLOneTypeTests, TestNamespaceString) {
ASSERT_EQUALS(element.type(), String);
auto testStruct = One_namespacestring::parse(ctxt, testDoc);
+ assert_same_types<decltype(testStruct.getValue()), const NamespaceString&>();
+
ASSERT_EQUALS(testStruct.getValue(), NamespaceString("foo.bar"));
// Positive: Test we can roundtrip from the just parsed document
@@ -1084,5 +1086,230 @@ TEST(IDLCustomType, TestDerivedParser) {
}
}
+// Chained type testing
+// Check each of types
+// Check for round-tripping of fields and documents
+
+// Positive: demonstrate a class struct chained types
+TEST(IDLChainedType, TestChainedType) {
+ IDLParserErrorContext ctxt("root");
+
+ auto testDoc = BSON("field1"
+ << "abc"
+ << "field2"
+ << 5);
+
+ auto testStruct = Chained_struct_only::parse(ctxt, testDoc);
+
+ assert_same_types<decltype(testStruct.getChainedType()), const mongo::ChainedType&>();
+ assert_same_types<decltype(testStruct.getAnotherChainedType()),
+ const mongo::AnotherChainedType&>();
+
+ ASSERT_EQUALS(testStruct.getChainedType().getField1(), "abc");
+ ASSERT_EQUALS(testStruct.getAnotherChainedType().getField2(), 5);
+
+ // 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;
+ Chained_struct_only one_new;
+ ChainedType ct;
+ ct.setField1("abc");
+ one_new.setChainedType(ct);
+ AnotherChainedType act;
+ act.setField2(5);
+ one_new.setAnotherChainedType(act);
+ one_new.serialize(&builder);
+
+ auto serializedDoc = builder.obj();
+ ASSERT_BSONOBJ_EQ(testDoc, serializedDoc);
+ }
+}
+
+// Positive: demonstrate a struct with chained types ignoring extra fields
+TEST(IDLChainedType, TestExtraFields) {
+ IDLParserErrorContext ctxt("root");
+
+ auto testDoc = BSON("field1"
+ << "abc"
+ << "field2"
+ << 5
+ << "field3"
+ << 123456);
+
+ auto testStruct = Chained_struct_only::parse(ctxt, testDoc);
+ ASSERT_EQUALS(testStruct.getChainedType().getField1(), "abc");
+ ASSERT_EQUALS(testStruct.getAnotherChainedType().getField2(), 5);
+}
+
+
+// Negative: demonstrate a struct with chained types with duplicate fields
+TEST(IDLChainedType, TestDuplicateFields) {
+ IDLParserErrorContext ctxt("root");
+
+ auto testDoc = BSON("field1"
+ << "abc"
+ << "field2"
+ << 5
+ << "field2"
+ << 123456);
+
+ ASSERT_THROWS(Chained_struct_only::parse(ctxt, testDoc), UserException);
+}
+
+
+// Positive: demonstrate a struct with chained structs
+TEST(IDLChainedType, TestChainedStruct) {
+ IDLParserErrorContext ctxt("root");
+
+ auto testDoc = BSON("anyField" << 123.456 << "objectField" << BSON("random"
+ << "pair")
+ << "field3"
+ << "abc");
+
+ auto testStruct = Chained_struct_mixed::parse(ctxt, testDoc);
+
+ assert_same_types<decltype(testStruct.getChained_any_basic_type()),
+ const Chained_any_basic_type&>();
+ assert_same_types<decltype(testStruct.getChained_object_basic_type()),
+ const Chained_object_basic_type&>();
+
+ ASSERT_EQUALS(testStruct.getField3(), "abc");
+
+ // Positive: Test we can roundtrip from the just parsed document
+ {
+ BSONObjBuilder builder;
+ testStruct.serialize(&builder);
+ auto loopbackDoc = builder.obj();
+
+ ASSERT_BSONOBJ_EQ(testDoc, loopbackDoc);
+ }
+}
+
+// Negative: demonstrate a struct with chained structs and extra fields
+TEST(IDLChainedType, TestChainedStructWithExtraFields) {
+ IDLParserErrorContext ctxt("root");
+
+ // Extra field
+ {
+ auto testDoc = BSON("field3"
+ << "abc"
+ << "anyField"
+ << 123.456
+ << "objectField"
+ << BSON("random"
+ << "pair")
+ << "extraField"
+ << 787);
+ ASSERT_THROWS(Chained_struct_mixed::parse(ctxt, testDoc), UserException);
+ }
+
+
+ // Duplicate any
+ {
+ auto testDoc = BSON("field3"
+ << "abc"
+ << "anyField"
+ << 123.456
+ << "objectField"
+ << BSON("random"
+ << "pair")
+ << "anyField"
+ << 787);
+ ASSERT_THROWS(Chained_struct_mixed::parse(ctxt, testDoc), UserException);
+ }
+
+ // Duplicate object
+ {
+ auto testDoc = BSON("objectField" << BSON("fake"
+ << "thing")
+ << "field3"
+ << "abc"
+ << "anyField"
+ << 123.456
+ << "objectField"
+ << BSON("random"
+ << "pair"));
+ ASSERT_THROWS(Chained_struct_mixed::parse(ctxt, testDoc), UserException);
+ }
+
+ // Duplicate field3
+ {
+ auto testDoc = BSON("field3"
+ << "abc"
+ << "anyField"
+ << 123.456
+ << "objectField"
+ << BSON("random"
+ << "pair")
+ << "field3"
+ << "def");
+ ASSERT_THROWS(Chained_struct_mixed::parse(ctxt, testDoc), UserException);
+ }
+}
+
+
+// Positive: demonstrate a struct with chained structs and types
+TEST(IDLChainedType, TestChainedMixedStruct) {
+ IDLParserErrorContext ctxt("root");
+
+ auto testDoc = BSON("field1"
+ << "abc"
+ << "field2"
+ << 5
+ << "stringField"
+ << "def"
+ << "field3"
+ << 456);
+
+ auto testStruct = Chained_struct_type_mixed::parse(ctxt, testDoc);
+
+ assert_same_types<decltype(testStruct.getChainedType()), const mongo::ChainedType&>();
+ assert_same_types<decltype(testStruct.getAnotherChainedType()),
+ const mongo::AnotherChainedType&>();
+
+ ASSERT_EQUALS(testStruct.getChainedType().getField1(), "abc");
+ ASSERT_EQUALS(testStruct.getAnotherChainedType().getField2(), 5);
+ ASSERT_EQUALS(testStruct.getChained_string_basic_type().getStringField(), "def");
+ ASSERT_EQUALS(testStruct.getField3(), 456);
+
+ // 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;
+ Chained_struct_type_mixed one_new;
+ ChainedType ct;
+ ct.setField1("abc");
+ one_new.setChainedType(ct);
+ AnotherChainedType act;
+ act.setField2(5);
+ one_new.setAnotherChainedType(act);
+ one_new.setField3(456);
+ Chained_string_basic_type csbt;
+ csbt.setStringField("def");
+ one_new.setChained_string_basic_type(csbt);
+ one_new.serialize(&builder);
+
+ auto serializedDoc = builder.obj();
+ ASSERT_BSONOBJ_EQ(testDoc, serializedDoc);
+ }
+}
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/idl/idl_test_types.h b/src/mongo/idl/idl_test_types.h
index 6e03d48b470..44e26c47912 100644
--- a/src/mongo/idl/idl_test_types.h
+++ b/src/mongo/idl/idl_test_types.h
@@ -113,4 +113,54 @@ private:
std::vector<std::uint8_t> _vec;
};
+/**
+ * Simple class that demonstrates the contract a class must implement to parse an IDL "chain" type
+ * from the IDL parser.
+ */
+class ChainedType {
+public:
+ static ChainedType parse(const BSONObj& obj) {
+ ChainedType object;
+ object._str = obj["field1"].str();
+ return object;
+ }
+
+ void serialize(BSONObjBuilder* builder) const {
+ builder->append("field1", _str);
+ }
+
+ StringData getField1() const {
+ return _str;
+ }
+ void setField1(StringData value) {
+ _str = value.toString();
+ }
+
+private:
+ std::string _str;
+};
+
+class AnotherChainedType {
+public:
+ static AnotherChainedType parse(const BSONObj& obj) {
+ AnotherChainedType object;
+ object._num = obj["field2"].numberLong();
+ return object;
+ }
+
+ void serialize(BSONObjBuilder* builder) const {
+ builder->append("field2", _num);
+ }
+
+ std::int64_t getField2() const {
+ return _num;
+ }
+ void setField2(std::int64_t value) {
+ _num = value;
+ }
+
+private:
+ std::int64_t _num;
+};
+
} // namespace mongo
diff --git a/src/mongo/idl/unittest.idl b/src/mongo/idl/unittest.idl
index 7aecd720ad4..6b6337ed69a 100644
--- a/src/mongo/idl/unittest.idl
+++ b/src/mongo/idl/unittest.idl
@@ -97,6 +97,27 @@ types:
##################################################################################################
#
+# Test types used in parser chaining testing
+#
+##################################################################################################
+
+ ChainedType:
+ bson_serialization_type: chain
+ description: "An Chain Type to test chaining"
+ cpp_type: "mongo::ChainedType"
+ serializer: mongo::ChainedType::serialize
+ deserializer: mongo::ChainedType::parse
+
+ AnotherChainedType:
+ bson_serialization_type: chain
+ description: "Another Chain Type to test chaining"
+ cpp_type: "mongo::AnotherChainedType"
+ serializer: mongo::AnotherChainedType::serialize
+ deserializer: mongo::AnotherChainedType::parse
+
+
+##################################################################################################
+#
# Unit test structs for a single value to ensure type validation works correctly
#
##################################################################################################
@@ -368,4 +389,55 @@ structs:
field6o:
type: array<one_string>
optional: true
-#
+
+##################################################################################################
+#
+# Test Chained Types
+#
+##################################################################################################
+
+ chained_string_basic_type:
+ description: Base struct type for a chained string
+ strict: false
+ fields:
+ stringField: string
+
+ chained_any_basic_type:
+ description: Base struct type for a chained any
+ strict: false
+ fields:
+ anyField: any_basic_type
+
+ chained_object_basic_type:
+ description: Base struct type for a chained object
+ strict: false
+ fields:
+ objectField: object_basic_type
+
+ chained_struct_only:
+ description: UnitTest for chained struct with only chained types
+ strict: false
+ chained_types:
+ - ChainedType
+ - AnotherChainedType
+
+ chained_struct_mixed:
+ description: Chained struct with chained structs and fields
+ strict: true
+ chained_structs:
+ - chained_any_basic_type
+ - chained_object_basic_type
+ fields:
+ field3: string
+
+ chained_struct_type_mixed:
+ description: Chained struct with chained types, structs, and fields
+ strict: false
+ chained_types:
+ - ChainedType
+ - AnotherChainedType
+ chained_structs:
+ - chained_string_basic_type
+ fields:
+ field3:
+ type: int