diff options
author | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2017-05-12 09:45:03 -0400 |
---|---|---|
committer | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2017-05-12 09:45:03 -0400 |
commit | 638339bd4de36914e7e15d17c43bce99b2faf36d (patch) | |
tree | 9feab30709e68597cfd3a5cca8fb65c4a658406f /src/mongo/idl | |
parent | d897cf74293736d8edca4da3c4a1679f9e5da356 (diff) | |
download | mongo-638339bd4de36914e7e15d17c43bce99b2faf36d.tar.gz |
SERVER-29004 IDL support for enums
Diffstat (limited to 'src/mongo/idl')
-rw-r--r-- | src/mongo/idl/idl_parser.cpp | 16 | ||||
-rw-r--r-- | src/mongo/idl/idl_parser.h | 18 | ||||
-rw-r--r-- | src/mongo/idl/idl_test.cpp | 78 | ||||
-rw-r--r-- | src/mongo/idl/unittest.idl | 45 |
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 |