summaryrefslogtreecommitdiff
path: root/src/mongo/db/ops/modifier_add_to_set_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/ops/modifier_add_to_set_test.cpp')
-rw-r--r--src/mongo/db/ops/modifier_add_to_set_test.cpp678
1 files changed, 337 insertions, 341 deletions
diff --git a/src/mongo/db/ops/modifier_add_to_set_test.cpp b/src/mongo/db/ops/modifier_add_to_set_test.cpp
index 45741b4c000..43335cb4847 100644
--- a/src/mongo/db/ops/modifier_add_to_set_test.cpp
+++ b/src/mongo/db/ops/modifier_add_to_set_test.cpp
@@ -40,354 +40,350 @@
namespace {
- using mongo::BSONObj;
- using mongo::LogBuilder;
- using mongo::ModifierAddToSet;
- using mongo::ModifierInterface;
- using mongo::Status;
- using mongo::StringData;
- using mongo::fromjson;
- using mongo::mutablebson::Document;
- using mongo::mutablebson::Element;
-
- /** Helper to build and manipulate a $addToSet mod. */
- class Mod {
- public:
- Mod() : _mod() {}
-
- explicit Mod(BSONObj modObj)
- : _modObj(modObj)
- , _mod() {
- ASSERT_OK(_mod.init(_modObj["$addToSet"].embeddedObject().firstElement(),
- ModifierInterface::Options::normal()));
- }
-
- Status prepare(Element root,
- StringData matchedField,
- ModifierInterface::ExecInfo* execInfo) {
- return _mod.prepare(root, matchedField, execInfo);
- }
-
- Status apply() const {
- return _mod.apply();
- }
-
- Status log(LogBuilder* logBuilder) const {
- return _mod.log(logBuilder);
- }
-
- ModifierAddToSet& mod() {
- return _mod;
- }
-
- private:
- BSONObj _modObj;
- ModifierAddToSet _mod;
- };
-
- TEST(Init, FailToInitWithInvalidValue) {
- BSONObj modObj;
- ModifierAddToSet mod;
-
- modObj = fromjson("{ $addToSet : { a : { 'x.$.y' : 'bad' } } }");
- ASSERT_NOT_OK(mod.init(modObj["$addToSet"].embeddedObject().firstElement(),
- ModifierInterface::Options::normal()));
- modObj = fromjson("{ $addToSet : { a : { $each : [ { 'x.$.y' : 'bad' } ] } } }");
- ASSERT_NOT_OK(mod.init(modObj["$addToSet"].embeddedObject().firstElement(),
- ModifierInterface::Options::normal()));
-
- // An int is not valid after $each
- modObj = fromjson("{ $addToSet : { a : { $each : 0 } } }");
- ASSERT_NOT_OK(mod.init(modObj["$addToSet"].embeddedObject().firstElement(),
- ModifierInterface::Options::normal()));
-
- // An object is not valid after $each
- modObj = fromjson("{ $addToSet : { a : { $each : { a : 1 } } } }");
- ASSERT_NOT_OK(mod.init(modObj["$addToSet"].embeddedObject().firstElement(),
- ModifierInterface::Options::normal()));
+using mongo::BSONObj;
+using mongo::LogBuilder;
+using mongo::ModifierAddToSet;
+using mongo::ModifierInterface;
+using mongo::Status;
+using mongo::StringData;
+using mongo::fromjson;
+using mongo::mutablebson::Document;
+using mongo::mutablebson::Element;
+
+/** Helper to build and manipulate a $addToSet mod. */
+class Mod {
+public:
+ Mod() : _mod() {}
+
+ explicit Mod(BSONObj modObj) : _modObj(modObj), _mod() {
+ ASSERT_OK(_mod.init(_modObj["$addToSet"].embeddedObject().firstElement(),
+ ModifierInterface::Options::normal()));
}
- TEST(Init, ParsesSimple) {
- Mod(fromjson("{ $addToSet : { a : 1 } }"));
- Mod(fromjson("{ $addToSet : { a : 'foo' } }"));
- Mod(fromjson("{ $addToSet : { a : {} } }"));
- Mod(fromjson("{ $addToSet : { a : { x : 1 } } }"));
- Mod(fromjson("{ $addToSet : { a : [] } }"));
- Mod(fromjson("{ $addToSet : { a : [1, 2] } } }"));
- Mod(fromjson("{ $addToSet : { 'a.b' : 1 } }"));
- Mod(fromjson("{ $addToSet : { 'a.b' : 'foo' } }"));
- Mod(fromjson("{ $addToSet : { 'a.b' : {} } }"));
- Mod(fromjson("{ $addToSet : { 'a.b' : { x : 1} } }"));
- Mod(fromjson("{ $addToSet : { 'a.b' : [] } }"));
- Mod(fromjson("{ $addToSet : { 'a.b' : [1, 2] } } }"));
+ Status prepare(Element root, StringData matchedField, ModifierInterface::ExecInfo* execInfo) {
+ return _mod.prepare(root, matchedField, execInfo);
}
- TEST(Init, ParsesEach) {
- Mod(fromjson("{ $addToSet : { a : { $each : [] } } }"));
- Mod(fromjson("{ $addToSet : { a : { $each : [ 1 ] } } }"));
- Mod(fromjson("{ $addToSet : { a : { $each : [ 1, 2 ] } } }"));
- Mod(fromjson("{ $addToSet : { a : { $each : [ 1, 2, 1 ] } } }"));
- Mod(fromjson("{ $addToSet : { a : { $each : [ {} ] } } }"));
- Mod(fromjson("{ $addToSet : { a : { $each : [ { x : 1 } ] } } }"));
- Mod(fromjson("{ $addToSet : { a : { $each : [ { x : 1 }, { y : 2 } ] } } }"));
- Mod(fromjson("{ $addToSet : { a : { $each : [ { x : 1 }, { y : 2 }, { x : 1 } ] } } }"));
+ Status apply() const {
+ return _mod.apply();
}
- TEST(SimpleMod, PrepareOKTargetNotFound) {
- Document doc(fromjson("{}"));
- Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_FALSE(execInfo.noOp);
- }
-
- TEST(SimpleMod, PrepareOKTargetFound) {
- Document doc(fromjson("{ a : [ 1 ] }"));
- Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_TRUE(execInfo.noOp);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { a : [ 1 ] } }"), logDoc);
- }
-
- TEST(SimpleMod, PrepareInvalidTargetNumber) {
- Document doc(fromjson("{ a : 1 }"));
- Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_NOT_OK(mod.prepare(doc.root(), "", &execInfo));
- }
-
- TEST(SimpleMod, PrepareInvalidTarget) {
- Document doc(fromjson("{ a : {} }"));
- Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_NOT_OK(mod.prepare(doc.root(), "", &execInfo));
- }
-
- TEST(SimpleMod, ApplyAndLogEmptyDocument) {
- Document doc(fromjson("{}"));
- Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_FALSE(execInfo.noOp);
-
- ASSERT_OK(mod.apply());
- ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{ a : [ 1 ] }"), doc);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { a : [ 1 ] } }"), logDoc);
- }
-
- TEST(SimpleMod, ApplyAndLogEmptyArray) {
- Document doc(fromjson("{ a : [] }"));
- Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_FALSE(execInfo.noOp);
-
- ASSERT_OK(mod.apply());
- ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{ a : [ 1 ] }"), doc);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { a : [ 1 ] } }"), logDoc);
- }
-
- TEST(SimpleEachMod, ApplyAndLogEmptyDocument) {
- Document doc(fromjson("{}"));
- Mod mod(fromjson("{ $addToSet : { a : { $each : [1, 2, 3] } } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_FALSE(execInfo.noOp);
-
- ASSERT_OK(mod.apply());
- ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{ a : [ 1, 2, 3 ] }"), doc);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
- }
-
- TEST(SimpleEachMod, ApplyAndLogEmptyArray) {
- Document doc(fromjson("{ a : [] }"));
- Mod mod(fromjson("{ $addToSet : { a : { $each : [1, 2, 3] } } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_FALSE(execInfo.noOp);
-
- ASSERT_OK(mod.apply());
- ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{ a : [ 1, 2, 3 ] }"), doc);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
+ Status log(LogBuilder* logBuilder) const {
+ return _mod.log(logBuilder);
}
- TEST(SimpleMod, ApplyAndLogPopulatedArray) {
- Document doc(fromjson("{ a : [ 'x' ] }"));
- Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_FALSE(execInfo.noOp);
-
- ASSERT_OK(mod.apply());
- ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{ a : [ 'x', 1 ] }"), doc);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { a : [ 'x', 1 ] } }"), logDoc);
- }
-
- TEST(SimpleEachMod, ApplyAndLogPopulatedArray) {
- Document doc(fromjson("{ a : [ 'x' ] }"));
- Mod mod(fromjson("{ $addToSet : { a : { $each : [1, 2, 3] } } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_FALSE(execInfo.noOp);
-
- ASSERT_OK(mod.apply());
- ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{ a : [ 'x', 1, 2, 3 ] }"), doc);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { a : [ 'x', 1, 2, 3 ] } }"), logDoc);
- }
-
- TEST(NoOp, AddOneExistingIsNoOp) {
- Document doc(fromjson("{ a : [ 1, 2, 3 ] }"));
- Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_TRUE(execInfo.noOp);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
- }
-
- TEST(NoOp, AddSeveralExistingIsNoOp) {
- Document doc(fromjson("{ a : [ 1, 2, 3 ] }"));
- Mod mod(fromjson("{ $addToSet : { a : { $each : [1, 2] } } }"));
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_TRUE(execInfo.noOp);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
- }
-
- TEST(NoOp, AddAllExistingIsNoOp) {
- Document doc(fromjson("{ a : [ 1, 2, 3 ] }"));
- Mod mod(fromjson("{ $addToSet : { a : { $each : [1, 2, 3] } } }"));
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_TRUE(execInfo.noOp);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
- }
-
- TEST(Deduplication, ExistingDuplicatesArePreserved) {
- Document doc(fromjson("{ a : [ 1, 1, 2, 1, 2, 2 ] }"));
- Mod mod(fromjson("{ $addToSet : { a : 3 } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_FALSE(execInfo.noOp);
-
- ASSERT_OK(mod.apply());
- ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{ a : [ 1, 1, 2, 1, 2, 2, 3] }"), doc);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 1, 2, 1, 2, 2, 3] } }"), logDoc);
- }
-
- TEST(Deduplication, NewDuplicatesAreElided) {
- Document doc(fromjson("{ a : [ 1, 1, 2, 1, 2, 2 ] }"));
- Mod mod(fromjson("{ $addToSet : { a : { $each : [ 4, 1, 3, 2, 3, 1, 3, 3, 2, 4] } } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
- ASSERT_FALSE(execInfo.noOp);
-
- ASSERT_OK(mod.apply());
- ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{ a : [ 1, 1, 2, 1, 2, 2, 4, 3] }"), doc);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 1, 2, 1, 2, 2, 4, 3] } }"), logDoc);
- }
-
- TEST(Regressions, SERVER_12848) {
- // Proof that the mod works ok (the real issue was in validate).
-
- Document doc(fromjson("{ _id : 1, a : [ 1, [ ] ] }"));
- Mod mod(fromjson("{ $addToSet : { 'a.1' : 1 } }"));
-
- ModifierInterface::ExecInfo execInfo;
- ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
-
- ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a.1");
- ASSERT_FALSE(execInfo.noOp);
-
- ASSERT_OK(mod.apply());
- ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{ _id : 1, a : [ 1, [ 1 ] ] }"), doc);
-
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- ASSERT_OK(mod.log(&logBuilder));
- ASSERT_EQUALS(fromjson("{ $set : { 'a.1' : [ 1 ] } }"), logDoc);
+ ModifierAddToSet& mod() {
+ return _mod;
}
-} // namespace
+private:
+ BSONObj _modObj;
+ ModifierAddToSet _mod;
+};
+
+TEST(Init, FailToInitWithInvalidValue) {
+ BSONObj modObj;
+ ModifierAddToSet mod;
+
+ modObj = fromjson("{ $addToSet : { a : { 'x.$.y' : 'bad' } } }");
+ ASSERT_NOT_OK(mod.init(modObj["$addToSet"].embeddedObject().firstElement(),
+ ModifierInterface::Options::normal()));
+ modObj = fromjson("{ $addToSet : { a : { $each : [ { 'x.$.y' : 'bad' } ] } } }");
+ ASSERT_NOT_OK(mod.init(modObj["$addToSet"].embeddedObject().firstElement(),
+ ModifierInterface::Options::normal()));
+
+ // An int is not valid after $each
+ modObj = fromjson("{ $addToSet : { a : { $each : 0 } } }");
+ ASSERT_NOT_OK(mod.init(modObj["$addToSet"].embeddedObject().firstElement(),
+ ModifierInterface::Options::normal()));
+
+ // An object is not valid after $each
+ modObj = fromjson("{ $addToSet : { a : { $each : { a : 1 } } } }");
+ ASSERT_NOT_OK(mod.init(modObj["$addToSet"].embeddedObject().firstElement(),
+ ModifierInterface::Options::normal()));
+}
+
+TEST(Init, ParsesSimple) {
+ Mod(fromjson("{ $addToSet : { a : 1 } }"));
+ Mod(fromjson("{ $addToSet : { a : 'foo' } }"));
+ Mod(fromjson("{ $addToSet : { a : {} } }"));
+ Mod(fromjson("{ $addToSet : { a : { x : 1 } } }"));
+ Mod(fromjson("{ $addToSet : { a : [] } }"));
+ Mod(fromjson("{ $addToSet : { a : [1, 2] } } }"));
+ Mod(fromjson("{ $addToSet : { 'a.b' : 1 } }"));
+ Mod(fromjson("{ $addToSet : { 'a.b' : 'foo' } }"));
+ Mod(fromjson("{ $addToSet : { 'a.b' : {} } }"));
+ Mod(fromjson("{ $addToSet : { 'a.b' : { x : 1} } }"));
+ Mod(fromjson("{ $addToSet : { 'a.b' : [] } }"));
+ Mod(fromjson("{ $addToSet : { 'a.b' : [1, 2] } } }"));
+}
+
+TEST(Init, ParsesEach) {
+ Mod(fromjson("{ $addToSet : { a : { $each : [] } } }"));
+ Mod(fromjson("{ $addToSet : { a : { $each : [ 1 ] } } }"));
+ Mod(fromjson("{ $addToSet : { a : { $each : [ 1, 2 ] } } }"));
+ Mod(fromjson("{ $addToSet : { a : { $each : [ 1, 2, 1 ] } } }"));
+ Mod(fromjson("{ $addToSet : { a : { $each : [ {} ] } } }"));
+ Mod(fromjson("{ $addToSet : { a : { $each : [ { x : 1 } ] } } }"));
+ Mod(fromjson("{ $addToSet : { a : { $each : [ { x : 1 }, { y : 2 } ] } } }"));
+ Mod(fromjson("{ $addToSet : { a : { $each : [ { x : 1 }, { y : 2 }, { x : 1 } ] } } }"));
+}
+
+TEST(SimpleMod, PrepareOKTargetNotFound) {
+ Document doc(fromjson("{}"));
+ Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_FALSE(execInfo.noOp);
+}
+
+TEST(SimpleMod, PrepareOKTargetFound) {
+ Document doc(fromjson("{ a : [ 1 ] }"));
+ Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_TRUE(execInfo.noOp);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : [ 1 ] } }"), logDoc);
+}
+
+TEST(SimpleMod, PrepareInvalidTargetNumber) {
+ Document doc(fromjson("{ a : 1 }"));
+ Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_NOT_OK(mod.prepare(doc.root(), "", &execInfo));
+}
+
+TEST(SimpleMod, PrepareInvalidTarget) {
+ Document doc(fromjson("{ a : {} }"));
+ Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_NOT_OK(mod.prepare(doc.root(), "", &execInfo));
+}
+
+TEST(SimpleMod, ApplyAndLogEmptyDocument) {
+ Document doc(fromjson("{}"));
+ Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(mod.apply());
+ ASSERT_FALSE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ a : [ 1 ] }"), doc);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : [ 1 ] } }"), logDoc);
+}
+
+TEST(SimpleMod, ApplyAndLogEmptyArray) {
+ Document doc(fromjson("{ a : [] }"));
+ Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(mod.apply());
+ ASSERT_FALSE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ a : [ 1 ] }"), doc);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : [ 1 ] } }"), logDoc);
+}
+
+TEST(SimpleEachMod, ApplyAndLogEmptyDocument) {
+ Document doc(fromjson("{}"));
+ Mod mod(fromjson("{ $addToSet : { a : { $each : [1, 2, 3] } } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(mod.apply());
+ ASSERT_FALSE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ a : [ 1, 2, 3 ] }"), doc);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
+}
+
+TEST(SimpleEachMod, ApplyAndLogEmptyArray) {
+ Document doc(fromjson("{ a : [] }"));
+ Mod mod(fromjson("{ $addToSet : { a : { $each : [1, 2, 3] } } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(mod.apply());
+ ASSERT_FALSE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ a : [ 1, 2, 3 ] }"), doc);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
+}
+
+TEST(SimpleMod, ApplyAndLogPopulatedArray) {
+ Document doc(fromjson("{ a : [ 'x' ] }"));
+ Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(mod.apply());
+ ASSERT_FALSE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ a : [ 'x', 1 ] }"), doc);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : [ 'x', 1 ] } }"), logDoc);
+}
+
+TEST(SimpleEachMod, ApplyAndLogPopulatedArray) {
+ Document doc(fromjson("{ a : [ 'x' ] }"));
+ Mod mod(fromjson("{ $addToSet : { a : { $each : [1, 2, 3] } } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(mod.apply());
+ ASSERT_FALSE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ a : [ 'x', 1, 2, 3 ] }"), doc);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : [ 'x', 1, 2, 3 ] } }"), logDoc);
+}
+
+TEST(NoOp, AddOneExistingIsNoOp) {
+ Document doc(fromjson("{ a : [ 1, 2, 3 ] }"));
+ Mod mod(fromjson("{ $addToSet : { a : 1 } }"));
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_TRUE(execInfo.noOp);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
+}
+
+TEST(NoOp, AddSeveralExistingIsNoOp) {
+ Document doc(fromjson("{ a : [ 1, 2, 3 ] }"));
+ Mod mod(fromjson("{ $addToSet : { a : { $each : [1, 2] } } }"));
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_TRUE(execInfo.noOp);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
+}
+
+TEST(NoOp, AddAllExistingIsNoOp) {
+ Document doc(fromjson("{ a : [ 1, 2, 3 ] }"));
+ Mod mod(fromjson("{ $addToSet : { a : { $each : [1, 2, 3] } } }"));
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_TRUE(execInfo.noOp);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
+}
+
+TEST(Deduplication, ExistingDuplicatesArePreserved) {
+ Document doc(fromjson("{ a : [ 1, 1, 2, 1, 2, 2 ] }"));
+ Mod mod(fromjson("{ $addToSet : { a : 3 } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(mod.apply());
+ ASSERT_FALSE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ a : [ 1, 1, 2, 1, 2, 2, 3] }"), doc);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 1, 2, 1, 2, 2, 3] } }"), logDoc);
+}
+
+TEST(Deduplication, NewDuplicatesAreElided) {
+ Document doc(fromjson("{ a : [ 1, 1, 2, 1, 2, 2 ] }"));
+ Mod mod(fromjson("{ $addToSet : { a : { $each : [ 4, 1, 3, 2, 3, 1, 3, 3, 2, 4] } } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a");
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(mod.apply());
+ ASSERT_FALSE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ a : [ 1, 1, 2, 1, 2, 2, 4, 3] }"), doc);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 1, 2, 1, 2, 2, 4, 3] } }"), logDoc);
+}
+
+TEST(Regressions, SERVER_12848) {
+ // Proof that the mod works ok (the real issue was in validate).
+
+ Document doc(fromjson("{ _id : 1, a : [ 1, [ ] ] }"));
+ Mod mod(fromjson("{ $addToSet : { 'a.1' : 1 } }"));
+
+ ModifierInterface::ExecInfo execInfo;
+ ASSERT_OK(mod.prepare(doc.root(), "", &execInfo));
+
+ ASSERT_EQUALS(execInfo.fieldRef[0]->dottedField(), "a.1");
+ ASSERT_FALSE(execInfo.noOp);
+
+ ASSERT_OK(mod.apply());
+ ASSERT_FALSE(doc.isInPlaceModeEnabled());
+ ASSERT_EQUALS(fromjson("{ _id : 1, a : [ 1, [ 1 ] ] }"), doc);
+
+ Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
+ ASSERT_EQUALS(fromjson("{ $set : { 'a.1' : [ 1 ] } }"), logDoc);
+}
+
+} // namespace