TEST_F(UnsetNodeTest, UnsetNoOpDottedPath) { auto update = fromjson("{$unset: {'a.b': 1}}"); const CollatorInterface* collator = nullptr; UnsetNode node; ASSERT_OK(node.init(update["$unset"]["a.b"], collator)); mutablebson::Document doc(fromjson("{a: 5}")); setPathToCreate("b"); setPathTaken("a"); addIndexedPath("a"); auto result = node.apply(getApplyParams(doc.root()["a"])); ASSERT_TRUE(result.noop); ASSERT_FALSE(result.indexesAffected); ASSERT_EQUALS(fromjson("{a: 5}"), doc); ASSERT_TRUE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(fromjson("{}"), getLogDoc()); }
TEST_F(UnsetNodeTest, UnsetEntireArray) { auto update = fromjson("{$unset: {'a': 1}}"); boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); UnsetNode node; ASSERT_OK(node.init(update["$unset"]["a"], expCtx)); mutablebson::Document doc(fromjson("{a: [0, 1, 2]}")); setPathTaken("a"); addIndexedPath("a"); auto result = node.apply(getApplyParams(doc.root()["a"])); ASSERT_FALSE(result.noop); ASSERT_TRUE(result.indexesAffected); ASSERT_EQUALS(fromjson("{}"), doc); ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(fromjson("{$unset: {a: true}}"), getLogDoc()); ASSERT_EQUALS(getModifiedPaths(), "{a}"); }
TEST_F(UnsetNodeTest, UnsetPositional) { auto update = fromjson("{$unset: {'a.$': 1}}"); const CollatorInterface* collator = nullptr; UnsetNode node; ASSERT_OK(node.init(update["$unset"]["a.$"], collator)); mutablebson::Document doc(fromjson("{a: [0, 1, 2]}")); setPathTaken("a.1"); setMatchedField("1"); addIndexedPath("a"); auto result = node.apply(getApplyParams(doc.root()["a"]["1"])); ASSERT_FALSE(result.noop); ASSERT_TRUE(result.indexesAffected); ASSERT_EQUALS(fromjson("{a: [0, null, 2]}"), doc); ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(fromjson("{$unset: {'a.1': true}}"), getLogDoc()); }
TEST_F(PopNodeTest, NoopWhenNumericalPathComponentExceedsArrayLength) { auto update = fromjson("{$pop: {'a.0': 1}}"); boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; ASSERT_OK(popNode.init(update["$pop"]["a.0"], expCtx)); mmb::Document doc(fromjson("{a: []}")); setPathToCreate("0"); setPathTaken("a"); addIndexedPath("a.0"); auto result = popNode.apply(getApplyParams(doc.root()["a"])); ASSERT_TRUE(result.noop); ASSERT_FALSE(result.indexesAffected); ASSERT_EQUALS(fromjson("{a: []}"), doc); ASSERT_EQUALS(fromjson("{}"), getLogDoc()); ASSERT_EQUALS("{a.0}", getModifiedPaths()); }
TEST_F(PopNodeTest, NoopWhenPathPartiallyExists) { auto update = fromjson("{$pop: {'a.b.c': 1}}"); boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); PopNode popNode; ASSERT_OK(popNode.init(update["$pop"]["a.b.c"], expCtx)); mmb::Document doc(fromjson("{a: {}}")); setPathToCreate("b.c"); setPathTaken("a"); addIndexedPath("a.b.c"); auto result = popNode.apply(getApplyParams(doc.root()["a"])); ASSERT_TRUE(result.noop); ASSERT_FALSE(result.indexesAffected); ASSERT_EQUALS(fromjson("{a: {}}"), doc); ASSERT_EQUALS(fromjson("{}"), getLogDoc()); ASSERT_EQUALS("{a.b.c}", getModifiedPaths()); }
TEST_F(UnsetNodeTest, ApplyCanRemoveImmutablePathIfNoop) { 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: 1}}")); setPathToCreate("c"); setPathTaken("a.b"); addImmutablePath("a.b"); addIndexedPath("a"); auto result = node.apply(getApplyParams(doc.root()["a"]["b"])); ASSERT_TRUE(result.noop); ASSERT_FALSE(result.indexesAffected); ASSERT_EQUALS(fromjson("{a: {b: 1}}"), doc); ASSERT_TRUE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(fromjson("{}"), getLogDoc()); ASSERT_EQUALS(getModifiedPaths(), "{a.b.c}"); }
TEST_F(UnsetNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFalse) { 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"); addIndexedPath("a"); setValidateForStorage(false); auto result = node.apply(getApplyParams(doc.root()["a"]["$id"])); ASSERT_FALSE(result.noop); ASSERT_TRUE(result.indexesAffected); auto updated = BSON("a" << BSON("$ref" << "c")); ASSERT_EQUALS(updated, doc); ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(fromjson("{$unset: {'a.$id': true}}"), getLogDoc()); }
TEST_F(UnsetNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFalse) { 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"); addIndexedPath("a"); setValidateForStorage(false); auto result = node.apply(getApplyParams(doc.root()["a"]["$id"])); ASSERT_FALSE(result.noop); ASSERT_TRUE(result.indexesAffected); auto updated = BSON("a" << BSON("$ref" << "c")); ASSERT_EQUALS(updated, doc); ASSERT_FALSE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(fromjson("{$unset: {'a.$id': true}}"), getLogDoc()); ASSERT_EQUALS(getModifiedPaths(), "{a.$id}"); }
TEST_F(CompareNodeTest, ApplyMaxRespectsCollationFromSetCollator) { auto update = fromjson("{$max: {a: 'abd'}}"); const CollatorInterface* binaryComparisonCollator = nullptr; CompareNode node(CompareNode::CompareMode::kMax); ASSERT_OK(node.init(update["$max"]["a"], binaryComparisonCollator)); const CollatorInterfaceMock reverseStringCollator( CollatorInterfaceMock::MockType::kReverseString); node.setCollator(&reverseStringCollator); mutablebson::Document doc(fromjson("{a: 'cbc'}")); setPathTaken("a"); addIndexedPath("a"); auto result = node.apply(getApplyParams(doc.root()["a"])); ASSERT_FALSE(result.noop); ASSERT_TRUE(result.indexesAffected); ASSERT_EQUALS(fromjson("{a: 'abd'}"), doc); ASSERT_TRUE(doc.isInPlaceModeEnabled()); ASSERT_EQUALS(fromjson("{$set: {a: 'abd'}}"), getLogDoc()); }