summaryrefslogtreecommitdiff
path: root/src/mongo/idl
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2017-05-12 09:45:03 -0400
committerMark Benvenuto <mark.benvenuto@mongodb.com>2017-05-12 09:45:03 -0400
commit638339bd4de36914e7e15d17c43bce99b2faf36d (patch)
tree9feab30709e68597cfd3a5cca8fb65c4a658406f /src/mongo/idl
parentd897cf74293736d8edca4da3c4a1679f9e5da356 (diff)
downloadmongo-638339bd4de36914e7e15d17c43bce99b2faf36d.tar.gz
SERVER-29004 IDL support for enums
Diffstat (limited to 'src/mongo/idl')
-rw-r--r--src/mongo/idl/idl_parser.cpp16
-rw-r--r--src/mongo/idl/idl_parser.h18
-rw-r--r--src/mongo/idl/idl_test.cpp78
-rw-r--r--src/mongo/idl/unittest.idl45
4 files changed, 151 insertions, 6 deletions
diff --git a/src/mongo/idl/idl_parser.cpp b/src/mongo/idl/idl_parser.cpp
index c9450664c71..548f8c32375 100644
--- a/src/mongo/idl/idl_parser.cpp
+++ b/src/mongo/idl/idl_parser.cpp
@@ -191,6 +191,7 @@ void IDLParserErrorContext::throwBadArrayFieldNumberValue(StringData value) cons
str::stream() << "BSON array field '" << path << "' has an invalid value '" << value
<< "' for an array field name.");
}
+
void IDLParserErrorContext::throwBadArrayFieldNumberSequence(std::uint32_t actualValue,
std::uint32_t expectedValue) const {
std::string path = getElementPath(StringData());
@@ -202,6 +203,21 @@ void IDLParserErrorContext::throwBadArrayFieldNumberSequence(std::uint32_t actua
<< "'.");
}
+
+void IDLParserErrorContext::throwBadEnumValue(int enumValue) const {
+ std::string path = getElementPath(StringData());
+ uasserted(40440,
+ str::stream() << "Enumeration value '" << enumValue << "' for field '" << path
+ << "' is not a valid value.");
+}
+
+void IDLParserErrorContext::throwBadEnumValue(StringData enumValue) const {
+ std::string path = getElementPath(StringData());
+ uasserted(40441,
+ str::stream() << "Enumeration value '" << enumValue << "' for field '" << path
+ << "' is not a valid value.");
+}
+
std::vector<StringData> transformVector(const std::vector<std::string>& input) {
return std::vector<StringData>(begin(input), end(input));
}
diff --git a/src/mongo/idl/idl_parser.h b/src/mongo/idl/idl_parser.h
index e249be26b87..dd9b6a06c11 100644
--- a/src/mongo/idl/idl_parser.h
+++ b/src/mongo/idl/idl_parser.h
@@ -90,28 +90,34 @@ public:
/**
* Throw an error message about the BSONElement being a duplicate field.
*/
- void throwDuplicateField(const BSONElement& element) const;
+ MONGO_COMPILER_NORETURN void throwDuplicateField(const BSONElement& element) const;
/**
* Throw an error message about the required field missing from the document.
*/
- void throwMissingField(StringData fieldName) const;
+ MONGO_COMPILER_NORETURN void throwMissingField(StringData fieldName) const;
/**
* Throw an error message about an unknown field in a document.
*/
- void throwUnknownField(StringData fieldName) const;
+ MONGO_COMPILER_NORETURN void throwUnknownField(StringData fieldName) const;
/**
* Throw an error message about an array field name not being a valid unsigned integer.
*/
- void throwBadArrayFieldNumberValue(StringData value) const;
+ MONGO_COMPILER_NORETURN void throwBadArrayFieldNumberValue(StringData value) const;
/**
* Throw an error message about the array field name not being the next number in the sequence.
*/
- void throwBadArrayFieldNumberSequence(std::uint32_t actualValue,
- std::uint32_t expectedValue) const;
+ MONGO_COMPILER_NORETURN void throwBadArrayFieldNumberSequence(
+ std::uint32_t actualValue, std::uint32_t expectedValue) const;
+
+ /**
+ * Throw an error message about an unrecognized enum value.
+ */
+ MONGO_COMPILER_NORETURN void throwBadEnumValue(StringData enumValue) const;
+ MONGO_COMPILER_NORETURN void throwBadEnumValue(int enumValue) const;
private:
/**
diff --git a/src/mongo/idl/idl_test.cpp b/src/mongo/idl/idl_test.cpp
index 6182368dce0..c255baaa321 100644
--- a/src/mongo/idl/idl_test.cpp
+++ b/src/mongo/idl/idl_test.cpp
@@ -1310,6 +1310,84 @@ TEST(IDLChainedType, TestChainedMixedStruct) {
ASSERT_BSONOBJ_EQ(testDoc, serializedDoc);
}
}
+// Positive: demonstrate a class derived from an IDL parser.
+TEST(IDLEnum, TestEnum) {
+
+ IDLParserErrorContext ctxt("root");
+
+ auto testDoc = BSON("field1" << 2 << "field2"
+ << "zero");
+ auto testStruct = StructWithEnum::parse(ctxt, testDoc);
+ ASSERT_TRUE(testStruct.getField1() == IntEnum::c2);
+ ASSERT_TRUE(testStruct.getField2() == StringEnumEnum::s0);
+
+ assert_same_types<decltype(testStruct.getField1()), IntEnum>();
+ assert_same_types<decltype(testStruct.getField1o()), const boost::optional<IntEnum>>();
+ assert_same_types<decltype(testStruct.getField2()), StringEnumEnum>();
+ assert_same_types<decltype(testStruct.getField2o()), const boost::optional<StringEnumEnum>>();
+ // 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;
+ StructWithEnum one_new;
+ one_new.setField1(IntEnum::c2);
+ one_new.setField2(StringEnumEnum::s0);
+ one_new.serialize(&builder);
+
+ auto serializedDoc = builder.obj();
+ ASSERT_BSONOBJ_EQ(testDoc, serializedDoc);
+ }
+}
+
+
+// Negative: test bad values
+TEST(IDLEnum, TestIntEnumNegative) {
+ IDLParserErrorContext ctxt("root");
+
+ // Test string
+ {
+ auto testDoc = BSON("value"
+ << "2");
+ ASSERT_THROWS(One_int_enum::parse(ctxt, testDoc), UserException);
+ }
+
+ // Test a value out of range
+ {
+ auto testDoc = BSON("value" << 4);
+ ASSERT_THROWS(One_int_enum::parse(ctxt, testDoc), UserException);
+ }
+
+ // Test a negative number
+ {
+ auto testDoc = BSON("value" << -1);
+ ASSERT_THROWS(One_int_enum::parse(ctxt, testDoc), UserException);
+ }
+}
+
+TEST(IDLEnum, TestStringEnumNegative) {
+ IDLParserErrorContext ctxt("root");
+
+ // Test int
+ {
+ auto testDoc = BSON("value" << 2);
+ ASSERT_THROWS(One_string_enum::parse(ctxt, testDoc), UserException);
+ }
+
+ // Test a value out of range
+ {
+ auto testDoc = BSON("value"
+ << "foo");
+ ASSERT_THROWS(One_string_enum::parse(ctxt, testDoc), UserException);
+ }
+}
} // namespace
} // namespace mongo
diff --git a/src/mongo/idl/unittest.idl b/src/mongo/idl/unittest.idl
index 18802861cdc..a686f2ff2cd 100644
--- a/src/mongo/idl/unittest.idl
+++ b/src/mongo/idl/unittest.idl
@@ -121,6 +121,23 @@ types:
# Unit test structs for a single value to ensure type validation works correctly
#
##################################################################################################
+enums:
+
+ IntEnum:
+ description: "An example int enum"
+ type: int
+ values:
+ a0: 0
+ b1: 1
+ c2: 2
+
+ StringEnum:
+ description: "An example string enum"
+ type: string
+ values:
+ s0: "zero"
+ s1: "one"
+ s2: "two"
structs:
@@ -441,3 +458,31 @@ structs:
fields:
field3:
type: int
+
+
+##################################################################################################
+#
+# Test struct with enum
+#
+##################################################################################################
+ one_int_enum:
+ description: mock
+ fields:
+ value: IntEnum
+
+ one_string_enum:
+ description: mock
+ fields:
+ value: StringEnum
+
+ StructWithEnum:
+ description: mock
+ fields:
+ field1: IntEnum
+ field2: StringEnum
+ field1o:
+ type: IntEnum
+ optional: true
+ field2o:
+ type: StringEnum
+ optional: true