TEST(AddToSetNodeTest, ApplyFailsOnNonArray) { auto update = fromjson("{$addToSet: {a: 1}}"); const CollatorInterface* collator = nullptr; AddToSetNode node; ASSERT_OK(node.init(update["$addToSet"]["a"], collator)); Document doc(fromjson("{a: 2}")); FieldRef pathToCreate(""); FieldRef pathTaken("a"); StringData matchedField; auto fromReplication = false; auto validateForStorage = true; FieldRefSet immutablePaths; const UpdateIndexData* indexData = nullptr; LogBuilder* logBuilder = nullptr; auto indexesAffected = false; auto noop = false; ASSERT_THROWS_CODE_AND_WHAT( node.apply(doc.root()["a"], &pathToCreate, &pathTaken, matchedField, fromReplication, validateForStorage, immutablePaths, indexData, logBuilder, &indexesAffected, &noop), UserException, ErrorCodes::BadValue, "Cannot apply $addToSet to non-array field. Field named 'a' has non-array type int"); }
TEST_F(UnsetNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) { auto update = fromjson("{$unset: {'a.$id': true}}"); boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; ASSERT_OK(node.init(update["$unset"]["a.$id"], expCtx)); mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}")); setPathTaken("a.$id"); ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"]["$id"])), AssertionException, ErrorCodes::InvalidDBRef, "The DBRef $ref field must be followed by a $id field"); }
TEST_F(UnsetNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) { auto update = fromjson("{$unset: {'a.$id': true}}"); const CollatorInterface* collator = nullptr; UnsetNode node; ASSERT_OK(node.init(update["$unset"]["a.$id"], collator)); mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}")); setPathTaken("a.$id"); ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"]["$id"])), AssertionException, ErrorCodes::InvalidDBRef, "The DBRef $ref field must be followed by a $id field"); }
TEST_F(UnsetNodeTest, ApplyCannotRemovePrefixOfImmutablePath) { auto update = fromjson("{$unset: {a: true}}"); const CollatorInterface* collator = nullptr; UnsetNode node; ASSERT_OK(node.init(update["$unset"]["a"], collator)); mutablebson::Document doc(fromjson("{a: {b: 1}}")); setPathTaken("a"); addImmutablePath("a.b"); ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])), AssertionException, ErrorCodes::ImmutableField, "Unsetting the path 'a' would modify the immutable field 'a.b'"); }
TEST_F(UnsetNodeTest, ApplyCannotRemoveSuffixOfImmutablePath) { auto update = fromjson("{$unset: {'a.b.c': true}}"); boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; ASSERT_OK(node.init(update["$unset"]["a.b.c"], expCtx)); mutablebson::Document doc(fromjson("{a: {b: {c: 1}}}")); setPathTaken("a.b.c"); addImmutablePath("a.b"); ASSERT_THROWS_CODE_AND_WHAT( node.apply(getApplyParams(doc.root()["a"]["b"]["c"])), AssertionException, ErrorCodes::ImmutableField, "Performing an update on the path 'a.b.c' would modify the immutable field 'a.b'"); }
TEST_F(PopNodeTest, ThrowsWhenPathIsBlockedByAScalar) { auto update = fromjson("{$pop: {'a.b': 1}}"); boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx)); mmb::Document doc(fromjson("{a: 'foo'}")); setPathToCreate("b"); setPathTaken("a"); addIndexedPath("a.b"); ASSERT_THROWS_CODE_AND_WHAT( popNode.apply(getApplyParams(doc.root()["a"])), AssertionException, ErrorCodes::PathNotViable, "Cannot use the part (b) of (a.b) to traverse the element ({a: \"foo\"})"); }