summaryrefslogtreecommitdiff
path: root/src/mongo/db/ops/path_support_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/ops/path_support_test.cpp')
-rw-r--r--src/mongo/db/ops/path_support_test.cpp1606
1 files changed, 812 insertions, 794 deletions
diff --git a/src/mongo/db/ops/path_support_test.cpp b/src/mongo/db/ops/path_support_test.cpp
index a502a39a0c3..62e6ded46c2 100644
--- a/src/mongo/db/ops/path_support_test.cpp
+++ b/src/mongo/db/ops/path_support_test.cpp
@@ -49,834 +49,852 @@
namespace {
- using namespace mongo;
- using namespace mutablebson;
- using namespace pathsupport;
- using mongoutils::str::stream;
- using std::unique_ptr;
- using std::string;
+using namespace mongo;
+using namespace mutablebson;
+using namespace pathsupport;
+using mongoutils::str::stream;
+using std::unique_ptr;
+using std::string;
- class EmptyDoc : public mongo::unittest::Test {
- public:
- EmptyDoc() : _doc() {}
+class EmptyDoc : public mongo::unittest::Test {
+public:
+ EmptyDoc() : _doc() {}
- Document& doc() { return _doc; }
-
- Element root() { return _doc.root(); }
-
- FieldRef& field() { return _field; }
-
- void setField(StringData str) { _field.parse(str); }
-
- private:
- Document _doc;
- FieldRef _field;
- };
-
- TEST_F(EmptyDoc, EmptyPath) {
- setField("");
-
- size_t idxFound;
- Element elemFound = root();
- Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
- ASSERT_EQUALS(status, ErrorCodes::NonExistentPath);
- }
-
- TEST_F(EmptyDoc, NewField) {
- setField("a");
-
- size_t idxFound;
- Element elemFound = root();
- Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
- ASSERT_EQUALS(status, ErrorCodes::NonExistentPath);
-
- Element newElem = doc().makeElementInt("a", 1);
- ASSERT_TRUE(newElem.ok());
- ASSERT_OK(createPathAt(field(), 0, root(), newElem));
- ASSERT_EQUALS(fromjson("{a: 1}"), doc());
- }
-
- class SimpleDoc : public mongo::unittest::Test {
- public:
- SimpleDoc() : _doc() {}
-
- virtual void setUp() {
- // {a: 1}
- ASSERT_OK(root().appendInt("a", 1));
- }
-
- Document& doc() { return _doc; }
-
- Element root() { return _doc.root(); }
-
- FieldRef& field() { return _field; }
- void setField(StringData str) { _field.parse(str); }
-
- private:
- Document _doc;
- FieldRef _field;
- };
-
- TEST_F(SimpleDoc, EmptyPath) {
- setField("");
-
- size_t idxFound;
- Element elemFound = root();
- Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
- ASSERT_EQUALS(status, ErrorCodes::NonExistentPath);
- }
-
- TEST_F(SimpleDoc, SimplePath) {
- setField("a");
-
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 0U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]), 0);
- }
-
- TEST_F(SimpleDoc, LongerPath) {
- setField("a.b");
-
- size_t idxFound;
- Element elemFound = root();
- Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
- ASSERT_EQUALS(status, ErrorCodes::PathNotViable);
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 0U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]), 0);
+ Document& doc() {
+ return _doc;
}
- TEST_F(SimpleDoc, NotCommonPrefix) {
- setField("b");
-
- size_t idxFound;
- Element elemFound = root();
- Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
- ASSERT_EQUALS(status, ErrorCodes::NonExistentPath);
-
- // From this point on, handles the creation of the '.b' part that wasn't found.
- Element newElem = doc().makeElementInt("b", 1);
- ASSERT_TRUE(newElem.ok());
- ASSERT_EQUALS(countChildren(root()), 1u);
-
- ASSERT_OK(createPathAt(field(), 0, root(), newElem));
- ASSERT_EQUALS(newElem.getFieldName(), "b");
- ASSERT_EQUALS(newElem.getType(), NumberInt);
- ASSERT_TRUE(newElem.hasValue());
- ASSERT_EQUALS(newElem.getValueInt(), 1);
-
- ASSERT_TRUE(newElem.parent().ok() /* root an ok parent */);
- ASSERT_EQUALS(countChildren(root()), 2u);
- ASSERT_EQUALS(root().leftChild().getFieldName(), "a");
- ASSERT_EQUALS(root().leftChild().rightSibling().getFieldName(), "b");
- ASSERT_EQUALS(root().rightChild().getFieldName(), "b");
- ASSERT_EQUALS(root().rightChild().leftSibling().getFieldName(), "a");
+ Element root() {
+ return _doc.root();
}
- class NestedDoc : public mongo::unittest::Test {
- public:
- NestedDoc() : _doc() {}
-
- virtual void setUp() {
- // {a: {b: {c: 1}}}
- Element elemA = _doc.makeElementObject("a");
- ASSERT_TRUE(elemA.ok());
- Element elemB = _doc.makeElementObject("b");
- ASSERT_TRUE(elemB.ok());
- Element elemC = _doc.makeElementInt("c", 1);
- ASSERT_TRUE(elemC.ok());
-
- ASSERT_OK(elemB.pushBack(elemC));
- ASSERT_OK(elemA.pushBack(elemB));
- ASSERT_OK(root().pushBack(elemA));
- }
-
- Document& doc() { return _doc; }
-
- Element root() { return _doc.root(); }
-
- FieldRef& field() { return _field; }
- void setField(StringData str) { _field.parse(str); }
-
- private:
- Document _doc;
- FieldRef _field;
- };
-
- TEST_F(NestedDoc, SimplePath) {
- setField("a");
-
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 0U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]), 0);
+ FieldRef& field() {
+ return _field;
}
- TEST_F(NestedDoc, ShorterPath) {
- setField("a.b");
-
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
- ASSERT_EQUALS(idxFound, 1U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]["b"]), 0);
+ void setField(StringData str) {
+ _field.parse(str);
}
- TEST_F(NestedDoc, ExactPath) {
- setField("a.b.c");
+private:
+ Document _doc;
+ FieldRef _field;
+};
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 2U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]["b"]["c"]), 0);
- }
-
- TEST_F(NestedDoc, LongerPath) {
- // This would for 'c' to change from NumberInt to Object, which is invalid.
- setField("a.b.c.d");
+TEST_F(EmptyDoc, EmptyPath) {
+ setField("");
- size_t idxFound;
- Element elemFound = root();
- Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
- ASSERT_EQUALS(status.code(), ErrorCodes::PathNotViable);
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 2U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]["b"]["c"]), 0);
+ size_t idxFound;
+ Element elemFound = root();
+ Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
+ ASSERT_EQUALS(status, ErrorCodes::NonExistentPath);
+}
- }
+TEST_F(EmptyDoc, NewField) {
+ setField("a");
- TEST_F(NestedDoc, NewFieldNested) {
- setField("a.b.d");
+ size_t idxFound;
+ Element elemFound = root();
+ Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
+ ASSERT_EQUALS(status, ErrorCodes::NonExistentPath);
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
- ASSERT_EQUALS(idxFound, 1U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]["b"]), 0);
+ Element newElem = doc().makeElementInt("a", 1);
+ ASSERT_TRUE(newElem.ok());
+ ASSERT_OK(createPathAt(field(), 0, root(), newElem));
+ ASSERT_EQUALS(fromjson("{a: 1}"), doc());
+}
- // From this point on, handles the creation of the '.d' part that wasn't found.
- Element newElem = doc().makeElementInt("d", 1);
- ASSERT_TRUE(newElem.ok());
- ASSERT_EQUALS(countChildren(elemFound), 1u); // 'c' is a child of 'b'
+class SimpleDoc : public mongo::unittest::Test {
+public:
+ SimpleDoc() : _doc() {}
- ASSERT_OK(createPathAt(field(), idxFound+1, elemFound, newElem));
- ASSERT_EQUALS(fromjson("{a: {b: {c: 1, d: 1}}}"), doc());
+ virtual void setUp() {
+ // {a: 1}
+ ASSERT_OK(root().appendInt("a", 1));
}
- TEST_F(NestedDoc, NotStartingFromRoot) {
- setField("b.c");
-
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root()["a"], &idxFound, &elemFound));
- ASSERT_EQUALS(idxFound, 1U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]["b"]["c"]), 0);
+ Document& doc() {
+ return _doc;
}
- class ArrayDoc : public mongo::unittest::Test {
- public:
- ArrayDoc() : _doc() {}
-
- virtual void setUp() {
- // {a: []}
- Element elemA = _doc.makeElementArray("a");
- ASSERT_TRUE(elemA.ok());
- ASSERT_OK(root().pushBack(elemA));
-
- // {a: [], b: [{c: 1}]}
- Element elemB = _doc.makeElementArray("b");
- ASSERT_TRUE(elemB.ok());
- Element elemObj = _doc.makeElementObject("dummy" /* field name not used in array */);
- ASSERT_TRUE(elemObj.ok());
- ASSERT_OK(elemObj.appendInt("c",1));
- ASSERT_OK(elemB.pushBack(elemObj));
- ASSERT_OK(root().pushBack(elemB));
- }
-
- Document& doc() { return _doc; }
-
- Element root() { return _doc.root(); }
-
- FieldRef& field() { return _field; }
-
- void setField(StringData str) { _field.parse(str); }
-
- private:
- Document _doc;
- FieldRef _field;
- };
-
- TEST_F(ArrayDoc, PathOnEmptyArray) {
- setField("a.0");
-
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 0U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]), 0);
+ Element root() {
+ return _doc.root();
}
- TEST_F(ArrayDoc, PathOnPopulatedArray) {
- setField("b.0");
-
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 1U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["b"][0]), 0);
+ FieldRef& field() {
+ return _field;
}
-
- TEST_F(ArrayDoc, MixedArrayAndObjectPath) {
- setField("b.0.c");
-
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 2U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["b"][0]["c"]), 0);
+ void setField(StringData str) {
+ _field.parse(str);
}
- TEST_F(ArrayDoc, ExtendingExistingObject) {
- setField("b.0.d");
-
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 1U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["b"][0]), 0);
+private:
+ Document _doc;
+ FieldRef _field;
+};
- // From this point on, handles the creation of the '.0.d' part that wasn't found.
- Element newElem = doc().makeElementInt("d", 1);
- ASSERT_TRUE(newElem.ok());
- ASSERT_EQUALS(countChildren(elemFound), 1u); // '{c:1}' is a child of b.0
+TEST_F(SimpleDoc, EmptyPath) {
+ setField("");
- ASSERT_OK(createPathAt(field(), idxFound+1, elemFound, newElem));
- ASSERT_EQUALS(fromjson("{a: [], b: [{c:1, d:1}]}"), doc());
- }
+ size_t idxFound;
+ Element elemFound = root();
+ Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
+ ASSERT_EQUALS(status, ErrorCodes::NonExistentPath);
+}
- TEST_F(ArrayDoc, NewObjectInsideArray) {
- setField("b.1.c");
+TEST_F(SimpleDoc, SimplePath) {
+ setField("a");
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 0U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["b"]), 0);
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 0U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]), 0);
+}
- // From this point on, handles the creation of the '.1.c' part that wasn't found.
- Element newElem = doc().makeElementInt("c", 2);
- ASSERT_TRUE(newElem.ok());
- ASSERT_EQUALS(countChildren(elemFound), 1u); // '{c:1}' is a child of 'b'
-
- ASSERT_OK(createPathAt(field(), idxFound+1, elemFound, newElem));
- ASSERT_EQUALS(fromjson("{a: [], b: [{c:1},{c:2}]}"), doc());
- }
+TEST_F(SimpleDoc, LongerPath) {
+ setField("a.b");
- TEST_F(ArrayDoc, NewNestedObjectInsideArray) {
- setField("b.1.c.d");
+ size_t idxFound;
+ Element elemFound = root();
+ Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
+ ASSERT_EQUALS(status, ErrorCodes::PathNotViable);
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 0U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]), 0);
+}
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 0U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["b"]), 0);
+TEST_F(SimpleDoc, NotCommonPrefix) {
+ setField("b");
- // From this point on, handles the creation of the '.1.c.d' part that wasn't found.
- Element newElem = doc().makeElementInt("d", 2);
- ASSERT_TRUE(newElem.ok());
- ASSERT_EQUALS(countChildren(elemFound), 1u); // '{c:1}' is a child of 'b'
+ size_t idxFound;
+ Element elemFound = root();
+ Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
+ ASSERT_EQUALS(status, ErrorCodes::NonExistentPath);
+
+ // From this point on, handles the creation of the '.b' part that wasn't found.
+ Element newElem = doc().makeElementInt("b", 1);
+ ASSERT_TRUE(newElem.ok());
+ ASSERT_EQUALS(countChildren(root()), 1u);
+
+ ASSERT_OK(createPathAt(field(), 0, root(), newElem));
+ ASSERT_EQUALS(newElem.getFieldName(), "b");
+ ASSERT_EQUALS(newElem.getType(), NumberInt);
+ ASSERT_TRUE(newElem.hasValue());
+ ASSERT_EQUALS(newElem.getValueInt(), 1);
+
+ ASSERT_TRUE(newElem.parent().ok() /* root an ok parent */);
+ ASSERT_EQUALS(countChildren(root()), 2u);
+ ASSERT_EQUALS(root().leftChild().getFieldName(), "a");
+ ASSERT_EQUALS(root().leftChild().rightSibling().getFieldName(), "b");
+ ASSERT_EQUALS(root().rightChild().getFieldName(), "b");
+ ASSERT_EQUALS(root().rightChild().leftSibling().getFieldName(), "a");
+}
+
+class NestedDoc : public mongo::unittest::Test {
+public:
+ NestedDoc() : _doc() {}
+
+ virtual void setUp() {
+ // {a: {b: {c: 1}}}
+ Element elemA = _doc.makeElementObject("a");
+ ASSERT_TRUE(elemA.ok());
+ Element elemB = _doc.makeElementObject("b");
+ ASSERT_TRUE(elemB.ok());
+ Element elemC = _doc.makeElementInt("c", 1);
+ ASSERT_TRUE(elemC.ok());
+
+ ASSERT_OK(elemB.pushBack(elemC));
+ ASSERT_OK(elemA.pushBack(elemB));
+ ASSERT_OK(root().pushBack(elemA));
+ }
+
+ Document& doc() {
+ return _doc;
+ }
+
+ Element root() {
+ return _doc.root();
+ }
+
+ FieldRef& field() {
+ return _field;
+ }
+ void setField(StringData str) {
+ _field.parse(str);
+ }
+
+private:
+ Document _doc;
+ FieldRef _field;
+};
+
+TEST_F(NestedDoc, SimplePath) {
+ setField("a");
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 0U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]), 0);
+}
+
+TEST_F(NestedDoc, ShorterPath) {
+ setField("a.b");
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+ ASSERT_EQUALS(idxFound, 1U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]["b"]), 0);
+}
+
+TEST_F(NestedDoc, ExactPath) {
+ setField("a.b.c");
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 2U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]["b"]["c"]), 0);
+}
+
+TEST_F(NestedDoc, LongerPath) {
+ // This would for 'c' to change from NumberInt to Object, which is invalid.
+ setField("a.b.c.d");
+
+ size_t idxFound;
+ Element elemFound = root();
+ Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
+ ASSERT_EQUALS(status.code(), ErrorCodes::PathNotViable);
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 2U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]["b"]["c"]), 0);
+}
+
+TEST_F(NestedDoc, NewFieldNested) {
+ setField("a.b.d");
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+ ASSERT_EQUALS(idxFound, 1U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]["b"]), 0);
+
+ // From this point on, handles the creation of the '.d' part that wasn't found.
+ Element newElem = doc().makeElementInt("d", 1);
+ ASSERT_TRUE(newElem.ok());
+ ASSERT_EQUALS(countChildren(elemFound), 1u); // 'c' is a child of 'b'
+
+ ASSERT_OK(createPathAt(field(), idxFound + 1, elemFound, newElem));
+ ASSERT_EQUALS(fromjson("{a: {b: {c: 1, d: 1}}}"), doc());
+}
+
+TEST_F(NestedDoc, NotStartingFromRoot) {
+ setField("b.c");
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root()["a"], &idxFound, &elemFound));
+ ASSERT_EQUALS(idxFound, 1U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]["b"]["c"]), 0);
+}
+
+class ArrayDoc : public mongo::unittest::Test {
+public:
+ ArrayDoc() : _doc() {}
+
+ virtual void setUp() {
+ // {a: []}
+ Element elemA = _doc.makeElementArray("a");
+ ASSERT_TRUE(elemA.ok());
+ ASSERT_OK(root().pushBack(elemA));
+
+ // {a: [], b: [{c: 1}]}
+ Element elemB = _doc.makeElementArray("b");
+ ASSERT_TRUE(elemB.ok());
+ Element elemObj = _doc.makeElementObject("dummy" /* field name not used in array */);
+ ASSERT_TRUE(elemObj.ok());
+ ASSERT_OK(elemObj.appendInt("c", 1));
+ ASSERT_OK(elemB.pushBack(elemObj));
+ ASSERT_OK(root().pushBack(elemB));
+ }
+
+ Document& doc() {
+ return _doc;
+ }
+
+ Element root() {
+ return _doc.root();
+ }
+
+ FieldRef& field() {
+ return _field;
+ }
+
+ void setField(StringData str) {
+ _field.parse(str);
+ }
+
+private:
+ Document _doc;
+ FieldRef _field;
+};
+
+TEST_F(ArrayDoc, PathOnEmptyArray) {
+ setField("a.0");
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 0U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["a"]), 0);
+}
+
+TEST_F(ArrayDoc, PathOnPopulatedArray) {
+ setField("b.0");
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 1U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["b"][0]), 0);
+}
+
+TEST_F(ArrayDoc, MixedArrayAndObjectPath) {
+ setField("b.0.c");
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 2U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["b"][0]["c"]), 0);
+}
+
+TEST_F(ArrayDoc, ExtendingExistingObject) {
+ setField("b.0.d");
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 1U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["b"][0]), 0);
+
+ // From this point on, handles the creation of the '.0.d' part that wasn't found.
+ Element newElem = doc().makeElementInt("d", 1);
+ ASSERT_TRUE(newElem.ok());
+ ASSERT_EQUALS(countChildren(elemFound), 1u); // '{c:1}' is a child of b.0
+
+ ASSERT_OK(createPathAt(field(), idxFound + 1, elemFound, newElem));
+ ASSERT_EQUALS(fromjson("{a: [], b: [{c:1, d:1}]}"), doc());
+}
+
+TEST_F(ArrayDoc, NewObjectInsideArray) {
+ setField("b.1.c");
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 0U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["b"]), 0);
+
+ // From this point on, handles the creation of the '.1.c' part that wasn't found.
+ Element newElem = doc().makeElementInt("c", 2);
+ ASSERT_TRUE(newElem.ok());
+ ASSERT_EQUALS(countChildren(elemFound), 1u); // '{c:1}' is a child of 'b'
+
+ ASSERT_OK(createPathAt(field(), idxFound + 1, elemFound, newElem));
+ ASSERT_EQUALS(fromjson("{a: [], b: [{c:1},{c:2}]}"), doc());
+}
+
+TEST_F(ArrayDoc, NewNestedObjectInsideArray) {
+ setField("b.1.c.d");
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 0U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["b"]), 0);
+
+ // From this point on, handles the creation of the '.1.c.d' part that wasn't found.
+ Element newElem = doc().makeElementInt("d", 2);
+ ASSERT_TRUE(newElem.ok());
+ ASSERT_EQUALS(countChildren(elemFound), 1u); // '{c:1}' is a child of 'b'
+
+ ASSERT_OK(createPathAt(field(), idxFound + 1, elemFound, newElem));
+ ASSERT_EQUALS(fromjson("{a: [], b: [{c:1},{c:{d:2}}]}"), doc());
+}
+
+TEST_F(ArrayDoc, ArrayPaddingNecessary) {
+ setField("b.5");
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 0U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["b"]), 0);
+
+ // From this point on, handles the creation of the '.5' part that wasn't found.
+ Element newElem = doc().makeElementInt("", 1);
+ ASSERT_TRUE(newElem.ok());
+ ASSERT_EQUALS(countChildren(elemFound), 1u); // '{c:1}' is a child of 'b'
+
+ ASSERT_OK(createPathAt(field(), idxFound + 1, elemFound, newElem));
+ ASSERT_EQUALS(fromjson("{a: [], b: [{c:1},null,null,null,null,1]}"), doc());
+}
+
+TEST_F(ArrayDoc, ExcessivePaddingRequested) {
+ // Try to create an array item beyond what we're allowed to pad.
+ string paddedField = stream() << "b." << mongo::pathsupport::kMaxPaddingAllowed + 1;
+ ;
+ setField(paddedField);
+
+ size_t idxFound;
+ Element elemFound = root();
+ ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
+
+ // From this point on, try to create the padded part that wasn't found.
+ Element newElem = doc().makeElementInt("", 1);
+ ASSERT_TRUE(newElem.ok());
+ ASSERT_EQUALS(countChildren(elemFound), 1u); // '{c:1}' is a child of 'b'
+
+ Status status = createPathAt(field(), idxFound + 1, elemFound, newElem);
+ ASSERT_EQUALS(status.code(), ErrorCodes::CannotBackfillArray);
+}
+
+TEST_F(ArrayDoc, NonNumericPathInArray) {
+ setField("b.z");
+
+ size_t idxFound;
+ Element elemFound = root();
+ Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
+ ASSERT_EQUALS(status.code(), ErrorCodes::PathNotViable);
+ ASSERT_TRUE(elemFound.ok());
+ ASSERT_EQUALS(idxFound, 0U);
+ ASSERT_EQUALS(elemFound.compareWithElement(root()["b"]), 0);
+}
+
+//
+// Tests of equality extraction from MatchExpressions
+// NONGOAL: Testing query/match expression parsing and optimization
+//
+
+static MatchExpression* makeExpr(const BSONObj& exprBSON) {
+ static const WhereCallbackNoop callbackNoop;
+ return MatchExpressionParser::parse(exprBSON, callbackNoop).getValue();
+}
+
+static void assertContains(const EqualityMatches& equalities, const BSONObj& wrapped) {
+ BSONElement value = wrapped.firstElement();
+ StringData path = value.fieldNameStringData();
+
+ EqualityMatches::const_iterator it = equalities.find(path);
+ if (it == equalities.end()) {
+ FAIL(stream() << "Equality matches did not contain path \"" << path << "\"");
+ }
+ if (!it->second->getData().valuesEqual(value)) {
+ FAIL(stream() << "Equality match at path \"" << path << "\" contains value "
+ << it->second->getData() << ", not value " << value);
+ }
+}
+
+static void assertContains(const EqualityMatches& equalities, StringData path, int value) {
+ assertContains(equalities, BSON(path << value));
+}
+
+// NOTE: For tests below, BSONObj expr must exist for lifetime of MatchExpression
+
+TEST(ExtractEqualities, Basic) {
+ BSONObj exprBSON = fromjson("{a:1}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+ ASSERT_EQUALS(equalities.size(), 1u);
+ assertContains(equalities, "a", 1);
+}
+
+TEST(ExtractEqualities, Multiple) {
+ BSONObj exprBSON = fromjson("{a:1, b:2}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+ ASSERT_EQUALS(equalities.size(), 2u);
+ assertContains(equalities, "a", 1);
+ assertContains(equalities, "b", 2);
+}
+
+TEST(ExtractEqualities, EqOperator) {
+ BSONObj exprBSON = fromjson("{a:{$eq:1}}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+ ASSERT_EQUALS(equalities.size(), 1u);
+ assertContains(equalities, "a", 1);
+}
+
+TEST(ExtractEqualities, AndOperator) {
+ BSONObj exprBSON = fromjson("{$and:[{a:{$eq:1}},{b:2}]}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+ ASSERT_EQUALS(equalities.size(), 2u);
+ assertContains(equalities, "a", 1);
+ assertContains(equalities, "b", 2);
+}
+
+TEST(ExtractEqualities, NestedAndOperator) {
+ BSONObj exprBSON = fromjson("{$and:[{$and:[{a:{$eq:1}},{b:2}]},{c:3}]}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+ ASSERT_EQUALS(equalities.size(), 3u);
+ assertContains(equalities, "a", 1);
+ assertContains(equalities, "b", 2);
+ assertContains(equalities, "c", 3);
+}
+
+TEST(ExtractEqualities, NestedPaths) {
+ BSONObj exprBSON = fromjson("{'a.a':1}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+ ASSERT_EQUALS(equalities.size(), 1u);
+ assertContains(equalities, "a.a", 1);
+}
+
+TEST(ExtractEqualities, SiblingPaths) {
+ BSONObj exprBSON = fromjson("{'a.a':1,'a.b':{$eq:2}}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+ ASSERT_EQUALS(equalities.size(), 2u);
+ assertContains(equalities, "a.a", 1);
+ assertContains(equalities, "a.b", 2);
+}
+
+TEST(ExtractEqualities, NestedAndNestedPaths) {
+ BSONObj exprBSON = fromjson("{$and:[{$and:[{'a.a':{$eq:1}},{'a.b':2}]},{'c.c.c':3}]}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+ ASSERT_EQUALS(equalities.size(), 3u);
+ assertContains(equalities, "a.a", 1);
+ assertContains(equalities, "a.b", 2);
+ assertContains(equalities, "c.c.c", 3);
+}
+
+TEST(ExtractEqualities, IdOnly) {
+ BSONObj exprBSON = fromjson("{_id:1}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+ ASSERT_EQUALS(equalities.size(), 1u);
+ assertContains(equalities, "_id", 1);
+}
- ASSERT_OK(createPathAt(field(), idxFound+1, elemFound, newElem));
- ASSERT_EQUALS(fromjson("{a: [], b: [{c:1},{c:{d:2}}]}"), doc());
- }
-
- TEST_F(ArrayDoc, ArrayPaddingNecessary) {
- setField("b.5");
-
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 0U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["b"]), 0);
-
- // From this point on, handles the creation of the '.5' part that wasn't found.
- Element newElem = doc().makeElementInt("", 1);
- ASSERT_TRUE(newElem.ok());
- ASSERT_EQUALS(countChildren(elemFound), 1u); // '{c:1}' is a child of 'b'
-
- ASSERT_OK(createPathAt(field(), idxFound+1, elemFound, newElem));
- ASSERT_EQUALS(fromjson("{a: [], b: [{c:1},null,null,null,null,1]}"), doc());
- }
-
- TEST_F(ArrayDoc, ExcessivePaddingRequested) {
- // Try to create an array item beyond what we're allowed to pad.
- string paddedField = stream() << "b." << mongo::pathsupport::kMaxPaddingAllowed + 1;;
- setField(paddedField);
-
- size_t idxFound;
- Element elemFound = root();
- ASSERT_OK(findLongestPrefix(field(), root(), &idxFound, &elemFound));
-
- // From this point on, try to create the padded part that wasn't found.
- Element newElem = doc().makeElementInt("", 1);
- ASSERT_TRUE(newElem.ok());
- ASSERT_EQUALS(countChildren(elemFound), 1u); // '{c:1}' is a child of 'b'
-
- Status status = createPathAt(field(), idxFound+1, elemFound, newElem);
- ASSERT_EQUALS(status.code(), ErrorCodes::CannotBackfillArray);
- }
-
- TEST_F(ArrayDoc, NonNumericPathInArray) {
- setField("b.z");
-
- size_t idxFound;
- Element elemFound = root();
- Status status = findLongestPrefix(field(), root(), &idxFound, &elemFound);
- ASSERT_EQUALS(status.code(), ErrorCodes::PathNotViable);
- ASSERT_TRUE(elemFound.ok());
- ASSERT_EQUALS(idxFound, 0U);
- ASSERT_EQUALS(elemFound.compareWithElement(root()["b"]), 0);
- }
-
- //
- // Tests of equality extraction from MatchExpressions
- // NONGOAL: Testing query/match expression parsing and optimization
- //
-
- static MatchExpression* makeExpr(const BSONObj& exprBSON) {
- static const WhereCallbackNoop callbackNoop;
- return MatchExpressionParser::parse(exprBSON, callbackNoop).getValue();
- }
-
- static void assertContains(const EqualityMatches& equalities, const BSONObj& wrapped) {
-
- BSONElement value = wrapped.firstElement();
- StringData path = value.fieldNameStringData();
-
- EqualityMatches::const_iterator it = equalities.find(path);
- if (it == equalities.end()) {
- FAIL(stream() << "Equality matches did not contain path \"" << path << "\"");
- }
- if (!it->second->getData().valuesEqual(value)) {
- FAIL(stream() << "Equality match at path \"" << path << "\" contains value "
- << it->second->getData() << ", not value " << value);
- }
- }
-
- static void assertContains(const EqualityMatches& equalities,
- StringData path,
- int value) {
- assertContains(equalities, BSON(path << value));
- }
-
- // NOTE: For tests below, BSONObj expr must exist for lifetime of MatchExpression
-
- TEST(ExtractEqualities, Basic) {
- BSONObj exprBSON = fromjson("{a:1}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
- ASSERT_EQUALS(equalities.size(), 1u);
- assertContains(equalities, "a", 1);
- }
-
- TEST(ExtractEqualities, Multiple) {
- BSONObj exprBSON = fromjson("{a:1, b:2}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
- ASSERT_EQUALS(equalities.size(), 2u);
- assertContains(equalities, "a", 1);
- assertContains(equalities, "b", 2);
- }
-
- TEST(ExtractEqualities, EqOperator) {
- BSONObj exprBSON = fromjson("{a:{$eq:1}}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
- ASSERT_EQUALS(equalities.size(), 1u);
- assertContains(equalities, "a", 1);
- }
-
- TEST(ExtractEqualities, AndOperator) {
- BSONObj exprBSON = fromjson("{$and:[{a:{$eq:1}},{b:2}]}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
- ASSERT_EQUALS(equalities.size(), 2u);
- assertContains(equalities, "a", 1);
- assertContains(equalities, "b", 2);
- }
-
- TEST(ExtractEqualities, NestedAndOperator) {
- BSONObj exprBSON = fromjson("{$and:[{$and:[{a:{$eq:1}},{b:2}]},{c:3}]}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
- ASSERT_EQUALS(equalities.size(), 3u);
- assertContains(equalities, "a", 1);
- assertContains(equalities, "b", 2);
- assertContains(equalities, "c", 3);
- }
-
- TEST(ExtractEqualities, NestedPaths) {
- BSONObj exprBSON = fromjson("{'a.a':1}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
- ASSERT_EQUALS(equalities.size(), 1u);
- assertContains(equalities, "a.a", 1);
- }
-
- TEST(ExtractEqualities, SiblingPaths) {
- BSONObj exprBSON = fromjson("{'a.a':1,'a.b':{$eq:2}}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
- ASSERT_EQUALS(equalities.size(), 2u);
- assertContains(equalities, "a.a", 1);
- assertContains(equalities, "a.b", 2);
- }
-
- TEST(ExtractEqualities, NestedAndNestedPaths) {
- BSONObj exprBSON = fromjson("{$and:[{$and:[{'a.a':{$eq:1}},{'a.b':2}]},{'c.c.c':3}]}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
- ASSERT_EQUALS(equalities.size(), 3u);
- assertContains(equalities, "a.a", 1);
- assertContains(equalities, "a.b", 2);
- assertContains(equalities, "c.c.c", 3);
- }
-
- TEST(ExtractEqualities, IdOnly) {
- BSONObj exprBSON = fromjson("{_id:1}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
- ASSERT_EQUALS(equalities.size(), 1u);
- assertContains(equalities, "_id", 1);
- }
-
- /**
- * Helper class to allow easy construction of immutable paths
- */
- class ImmutablePaths {
- public:
- ImmutablePaths() {}
-
- void addPath(const string& path) {
- _ownedPaths.mutableVector().push_back(new FieldRef(path));
- FieldRef const* conflictPath = NULL;
- ASSERT(_immutablePathSet.insert(_ownedPaths.vector().back(), &conflictPath));
- }
-
- const FieldRefSet& getPathSet() {
- return _immutablePathSet;
- }
-
- private:
-
- FieldRefSet _immutablePathSet;
- OwnedPointerVector<FieldRef> _ownedPaths;
- };
-
- TEST(ExtractEqualities, IdOnlyMulti) {
- BSONObj exprBSON = fromjson("{_id:{$eq:1},a:1}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- ImmutablePaths immutablePaths;
- immutablePaths.addPath("_id");
-
- EqualityMatches equalities;
- ASSERT_OK(extractFullEqualityMatches(*expr, immutablePaths.getPathSet(), &equalities));
- ASSERT_EQUALS(equalities.size(), 1u);
- assertContains(equalities, "_id", 1);
- }
-
- TEST(ExtractEqualities, IdOnlyIgnoreConflict) {
- BSONObj exprBSON = fromjson("{_id:1,a:1,'a.b':1}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- ImmutablePaths immutablePaths;
- immutablePaths.addPath("_id");
-
- EqualityMatches equalities;
- ASSERT_OK(extractFullEqualityMatches(*expr, immutablePaths.getPathSet(), &equalities));
- ASSERT_EQUALS(equalities.size(), 1u);
- assertContains(equalities, "_id", 1);
- }
-
- TEST(ExtractEqualities, IdOnlyNested) {
- BSONObj exprBSON = fromjson("{'_id.a':1,'_id.b':{$eq:2},c:3}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- ImmutablePaths immutablePaths;
- immutablePaths.addPath("_id");
-
- EqualityMatches equalities;
- Status status = extractFullEqualityMatches(*expr, immutablePaths.getPathSet(), &equalities);
- ASSERT_EQUALS(status.code(), ErrorCodes::NotExactValueField);
- }
-
- TEST(ExtractEqualities, IdAndOtherImmutable) {
- BSONObj exprBSON = fromjson("{_id:1,a:1,b:2}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- ImmutablePaths immutablePaths;
- immutablePaths.addPath("_id");
- immutablePaths.addPath("a");
-
- EqualityMatches equalities;
- ASSERT_OK(extractFullEqualityMatches(*expr, immutablePaths.getPathSet(), &equalities));
- ASSERT_EQUALS(equalities.size(), 2u);
- assertContains(equalities, "_id", 1);
- assertContains(equalities, "a", 1);
- }
-
- TEST(ExtractEqualities, IdAndNestedImmutable) {
- BSONObj exprBSON = fromjson("{_id:1,a:1,'c.d':3}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- ImmutablePaths immutablePaths;
- immutablePaths.addPath("_id");
- immutablePaths.addPath("a.b");
- immutablePaths.addPath("c.d");
-
- EqualityMatches equalities;
- ASSERT_OK(extractFullEqualityMatches(*expr, immutablePaths.getPathSet(), &equalities));
- ASSERT_EQUALS(equalities.size(), 3u);
- assertContains(equalities, "_id", 1);
- assertContains(equalities, "a", 1);
- assertContains(equalities, "c.d", 3);
- }
-
- TEST(ExtractEqualities, NonFullImmutable) {
- BSONObj exprBSON = fromjson("{'a.b':1}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- ImmutablePaths immutablePaths;
- immutablePaths.addPath("a");
-
- EqualityMatches equalities;
- Status status = extractFullEqualityMatches(*expr, immutablePaths.getPathSet(), &equalities);
- ASSERT_EQUALS(status.code(), ErrorCodes::NotExactValueField);
- }
-
- TEST(ExtractEqualities, Empty) {
- BSONObj exprBSON = fromjson("{'':0}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
- ASSERT_EQUALS(equalities.size(), 1u);
- assertContains(equalities, "", 0);
- }
-
- TEST(ExtractEqualities, EmptyMulti) {
- BSONObj exprBSON = fromjson("{'':0,a:{$eq:1}}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
- ASSERT_EQUALS(equalities.size(), 2u);
- assertContains(equalities, "", 0);
- assertContains(equalities, "a", 1);
- }
-
- TEST(ExtractEqualities, EqConflict) {
- BSONObj exprBSON = fromjson("{a:1,a:1}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_EQUALS(extractEqualityMatches(*expr, &equalities).code(),
- ErrorCodes::NotSingleValueField);
- }
-
- TEST(ExtractEqualities, PrefixConflict) {
- BSONObj exprBSON = fromjson("{a:1,'a.b':{$eq:1}}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_EQUALS(extractEqualityMatches(*expr, &equalities).code(),
- ErrorCodes::NotSingleValueField);
- }
-
- TEST(ExtractEqualities, AndPrefixConflict) {
- BSONObj exprBSON = fromjson("{$and:[{a:1},{'a.b':{$eq:1}}]}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_EQUALS(extractEqualityMatches(*expr, &equalities).code(),
- ErrorCodes::NotSingleValueField);
- }
-
- TEST(ExtractEqualities, EmptyConflict) {
- BSONObj exprBSON = fromjson("{'':0,'':{$eq:0}}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
-
- EqualityMatches equalities;
- ASSERT_EQUALS(extractEqualityMatches(*expr, &equalities).code(),
- ErrorCodes::NotSingleValueField);
- }
-
- //
- // Tests for finding parent equality from equalities found in expression
- // NONGOALS: Testing complex equality match extraction - tested above
- //
-
- static void assertParent(const EqualityMatches& equalities,
- StringData pathStr,
- const BSONObj& wrapped) {
-
- FieldRef path(pathStr);
- BSONElement value = wrapped.firstElement();
- StringData parentPath = value.fieldNameStringData();
-
- int parentPathPart;
- BSONElement parentEl = findParentEqualityElement(equalities, path, &parentPathPart);
-
- if (parentEl.eoo()) {
- FAIL(stream() << "Equality matches did not contain parent for \"" << pathStr
- << "\"");
- }
+/**
+ * Helper class to allow easy construction of immutable paths
+ */
+class ImmutablePaths {
+public:
+ ImmutablePaths() {}
+
+ void addPath(const string& path) {
+ _ownedPaths.mutableVector().push_back(new FieldRef(path));
+ FieldRef const* conflictPath = NULL;
+ ASSERT(_immutablePathSet.insert(_ownedPaths.vector().back(), &conflictPath));
+ }
+
+ const FieldRefSet& getPathSet() {
+ return _immutablePathSet;
+ }
+
+private:
+ FieldRefSet _immutablePathSet;
+ OwnedPointerVector<FieldRef> _ownedPaths;
+};
+
+TEST(ExtractEqualities, IdOnlyMulti) {
+ BSONObj exprBSON = fromjson("{_id:{$eq:1},a:1}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ ImmutablePaths immutablePaths;
+ immutablePaths.addPath("_id");
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractFullEqualityMatches(*expr, immutablePaths.getPathSet(), &equalities));
+ ASSERT_EQUALS(equalities.size(), 1u);
+ assertContains(equalities, "_id", 1);
+}
+
+TEST(ExtractEqualities, IdOnlyIgnoreConflict) {
+ BSONObj exprBSON = fromjson("{_id:1,a:1,'a.b':1}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ ImmutablePaths immutablePaths;
+ immutablePaths.addPath("_id");
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractFullEqualityMatches(*expr, immutablePaths.getPathSet(), &equalities));
+ ASSERT_EQUALS(equalities.size(), 1u);
+ assertContains(equalities, "_id", 1);
+}
+
+TEST(ExtractEqualities, IdOnlyNested) {
+ BSONObj exprBSON = fromjson("{'_id.a':1,'_id.b':{$eq:2},c:3}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ ImmutablePaths immutablePaths;
+ immutablePaths.addPath("_id");
+
+ EqualityMatches equalities;
+ Status status = extractFullEqualityMatches(*expr, immutablePaths.getPathSet(), &equalities);
+ ASSERT_EQUALS(status.code(), ErrorCodes::NotExactValueField);
+}
+
+TEST(ExtractEqualities, IdAndOtherImmutable) {
+ BSONObj exprBSON = fromjson("{_id:1,a:1,b:2}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ ImmutablePaths immutablePaths;
+ immutablePaths.addPath("_id");
+ immutablePaths.addPath("a");
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractFullEqualityMatches(*expr, immutablePaths.getPathSet(), &equalities));
+ ASSERT_EQUALS(equalities.size(), 2u);
+ assertContains(equalities, "_id", 1);
+ assertContains(equalities, "a", 1);
+}
+
+TEST(ExtractEqualities, IdAndNestedImmutable) {
+ BSONObj exprBSON = fromjson("{_id:1,a:1,'c.d':3}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ ImmutablePaths immutablePaths;
+ immutablePaths.addPath("_id");
+ immutablePaths.addPath("a.b");
+ immutablePaths.addPath("c.d");
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractFullEqualityMatches(*expr, immutablePaths.getPathSet(), &equalities));
+ ASSERT_EQUALS(equalities.size(), 3u);
+ assertContains(equalities, "_id", 1);
+ assertContains(equalities, "a", 1);
+ assertContains(equalities, "c.d", 3);
+}
+
+TEST(ExtractEqualities, NonFullImmutable) {
+ BSONObj exprBSON = fromjson("{'a.b':1}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ ImmutablePaths immutablePaths;
+ immutablePaths.addPath("a");
+
+ EqualityMatches equalities;
+ Status status = extractFullEqualityMatches(*expr, immutablePaths.getPathSet(), &equalities);
+ ASSERT_EQUALS(status.code(), ErrorCodes::NotExactValueField);
+}
+
+TEST(ExtractEqualities, Empty) {
+ BSONObj exprBSON = fromjson("{'':0}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+ ASSERT_EQUALS(equalities.size(), 1u);
+ assertContains(equalities, "", 0);
+}
+
+TEST(ExtractEqualities, EmptyMulti) {
+ BSONObj exprBSON = fromjson("{'':0,a:{$eq:1}}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+ ASSERT_EQUALS(equalities.size(), 2u);
+ assertContains(equalities, "", 0);
+ assertContains(equalities, "a", 1);
+}
+
+TEST(ExtractEqualities, EqConflict) {
+ BSONObj exprBSON = fromjson("{a:1,a:1}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_EQUALS(extractEqualityMatches(*expr, &equalities).code(),
+ ErrorCodes::NotSingleValueField);
+}
+
+TEST(ExtractEqualities, PrefixConflict) {
+ BSONObj exprBSON = fromjson("{a:1,'a.b':{$eq:1}}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_EQUALS(extractEqualityMatches(*expr, &equalities).code(),
+ ErrorCodes::NotSingleValueField);
+}
+
+TEST(ExtractEqualities, AndPrefixConflict) {
+ BSONObj exprBSON = fromjson("{$and:[{a:1},{'a.b':{$eq:1}}]}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_EQUALS(extractEqualityMatches(*expr, &equalities).code(),
+ ErrorCodes::NotSingleValueField);
+}
+
+TEST(ExtractEqualities, EmptyConflict) {
+ BSONObj exprBSON = fromjson("{'':0,'':{$eq:0}}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+
+ EqualityMatches equalities;
+ ASSERT_EQUALS(extractEqualityMatches(*expr, &equalities).code(),
+ ErrorCodes::NotSingleValueField);
+}
+
+//
+// Tests for finding parent equality from equalities found in expression
+// NONGOALS: Testing complex equality match extraction - tested above
+//
+
+static void assertParent(const EqualityMatches& equalities,
+ StringData pathStr,
+ const BSONObj& wrapped) {
+ FieldRef path(pathStr);
+ BSONElement value = wrapped.firstElement();
+ StringData parentPath = value.fieldNameStringData();
+
+ int parentPathPart;
+ BSONElement parentEl = findParentEqualityElement(equalities, path, &parentPathPart);
+
+ if (parentEl.eoo()) {
+ FAIL(stream() << "Equality matches did not contain parent for \"" << pathStr << "\"");
+ }
+
+ StringData foundParentPath = path.dottedSubstring(0, parentPathPart);
+ if (foundParentPath != parentPath) {
+ FAIL(stream() << "Equality match parent at path \"" << foundParentPath
+ << "\" does not match \"" << parentPath << "\"");
+ }
+
+ if (!parentEl.valuesEqual(value)) {
+ FAIL(stream() << "Equality match parent for \"" << pathStr << "\" at path \"" << parentPath
+ << "\" contains value " << parentEl << ", not value " << value);
+ }
+}
+static void assertParent(const EqualityMatches& equalities,
+ StringData path,
+ StringData parentPath,
+ int value) {
+ assertParent(equalities, path, BSON(parentPath << value));
+}
+
+static void assertNoParent(const EqualityMatches& equalities, StringData pathStr) {
+ FieldRef path(pathStr);
+
+ int parentPathPart;
+ BSONElement parentEl = findParentEqualityElement(equalities, path, &parentPathPart);
+
+ if (!parentEl.eoo()) {
StringData foundParentPath = path.dottedSubstring(0, parentPathPart);
- if (foundParentPath != parentPath) {
- FAIL(stream() << "Equality match parent at path \"" << foundParentPath
- << "\" does not match \"" << parentPath << "\"");
- }
-
- if (!parentEl.valuesEqual(value)) {
- FAIL(stream() << "Equality match parent for \"" << pathStr << "\" at path \""
- << parentPath << "\" contains value " << parentEl << ", not value "
- << value);
- }
- }
-
- static void assertParent(const EqualityMatches& equalities,
- StringData path,
- StringData parentPath,
- int value) {
- assertParent(equalities, path, BSON(parentPath << value));
- }
-
- static void assertNoParent(const EqualityMatches& equalities, StringData pathStr) {
-
- FieldRef path(pathStr);
-
- int parentPathPart;
- BSONElement parentEl = findParentEqualityElement(equalities, path, &parentPathPart);
-
- if (!parentEl.eoo()) {
- StringData foundParentPath = path.dottedSubstring(0, parentPathPart);
- FAIL(stream() << "Equality matches contained parent for \"" << pathStr << "\" at \""
- << foundParentPath << "\"");
- }
- }
-
-
- TEST(FindParentEquality, Basic) {
-
- BSONObj exprBSON = fromjson("{a:1}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
-
- assertNoParent(equalities, "");
- assertParent(equalities, "a", "a", 1);
- assertParent(equalities, "a.b", "a", 1);
- }
-
- TEST(FindParentEquality, Multi) {
-
- BSONObj exprBSON = fromjson("{a:1,b:2}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
-
- assertNoParent(equalities, "");
- assertParent(equalities, "a", "a", 1);
- assertParent(equalities, "a.b", "a", 1);
- assertParent(equalities, "b", "b", 2);
- assertParent(equalities, "b.b", "b", 2);
- }
-
- TEST(FindParentEquality, Nested) {
-
- BSONObj exprBSON = fromjson("{'a.a':1}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
-
- assertNoParent(equalities, "");
- assertNoParent(equalities, "a");
- assertParent(equalities, "a.a", "a.a", 1);
- assertParent(equalities, "a.a.b", "a.a", 1);
- }
-
- TEST(FindParentEquality, NestedMulti) {
-
- BSONObj exprBSON = fromjson("{'a.a':1,'a.b':2,'c.c':3}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
-
- assertNoParent(equalities, "");
- assertNoParent(equalities, "a");
- assertNoParent(equalities, "c");
- assertParent(equalities, "a.a", "a.a", 1);
- assertParent(equalities, "a.a.a", "a.a", 1);
- assertParent(equalities, "a.b", "a.b", 2);
- assertParent(equalities, "a.b.b", "a.b", 2);
- assertParent(equalities, "c.c", "c.c", 3);
- assertParent(equalities, "c.c.c", "c.c", 3);
- }
-
- TEST(FindParentEquality, Empty) {
-
- BSONObj exprBSON = fromjson("{'':0}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
-
- assertParent(equalities, "", "", 0);
- }
-
- TEST(FindParentEquality, EmptyMulti) {
-
- BSONObj exprBSON = fromjson("{'':0,a:1}");
- unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
- EqualityMatches equalities;
- ASSERT_OK(extractEqualityMatches(*expr, &equalities));
-
- assertParent(equalities, "", "", 0);
- assertParent(equalities, "a", "a", 1);
- assertParent(equalities, "a.b", "a", 1);
- }
-
-} // unnamed namespace
+ FAIL(stream() << "Equality matches contained parent for \"" << pathStr << "\" at \""
+ << foundParentPath << "\"");
+ }
+}
+
+
+TEST(FindParentEquality, Basic) {
+ BSONObj exprBSON = fromjson("{a:1}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+
+ assertNoParent(equalities, "");
+ assertParent(equalities, "a", "a", 1);
+ assertParent(equalities, "a.b", "a", 1);
+}
+
+TEST(FindParentEquality, Multi) {
+ BSONObj exprBSON = fromjson("{a:1,b:2}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+
+ assertNoParent(equalities, "");
+ assertParent(equalities, "a", "a", 1);
+ assertParent(equalities, "a.b", "a", 1);
+ assertParent(equalities, "b", "b", 2);
+ assertParent(equalities, "b.b", "b", 2);
+}
+
+TEST(FindParentEquality, Nested) {
+ BSONObj exprBSON = fromjson("{'a.a':1}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+
+ assertNoParent(equalities, "");
+ assertNoParent(equalities, "a");
+ assertParent(equalities, "a.a", "a.a", 1);
+ assertParent(equalities, "a.a.b", "a.a", 1);
+}
+
+TEST(FindParentEquality, NestedMulti) {
+ BSONObj exprBSON = fromjson("{'a.a':1,'a.b':2,'c.c':3}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+
+ assertNoParent(equalities, "");
+ assertNoParent(equalities, "a");
+ assertNoParent(equalities, "c");
+ assertParent(equalities, "a.a", "a.a", 1);
+ assertParent(equalities, "a.a.a", "a.a", 1);
+ assertParent(equalities, "a.b", "a.b", 2);
+ assertParent(equalities, "a.b.b", "a.b", 2);
+ assertParent(equalities, "c.c", "c.c", 3);
+ assertParent(equalities, "c.c.c", "c.c", 3);
+}
+
+TEST(FindParentEquality, Empty) {
+ BSONObj exprBSON = fromjson("{'':0}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+
+ assertParent(equalities, "", "", 0);
+}
+
+TEST(FindParentEquality, EmptyMulti) {
+ BSONObj exprBSON = fromjson("{'':0,a:1}");
+ unique_ptr<MatchExpression> expr(makeExpr(exprBSON));
+ EqualityMatches equalities;
+ ASSERT_OK(extractEqualityMatches(*expr, &equalities));
+
+ assertParent(equalities, "", "", 0);
+ assertParent(equalities, "a", "a", 1);
+ assertParent(equalities, "a.b", "a", 1);
+}
+
+} // unnamed namespace