diff options
Diffstat (limited to 'src/mongo/db/matcher/path_test.cpp')
-rw-r--r-- | src/mongo/db/matcher/path_test.cpp | 716 |
1 files changed, 355 insertions, 361 deletions
diff --git a/src/mongo/db/matcher/path_test.cpp b/src/mongo/db/matcher/path_test.cpp index 12091c4749c..73bbba4961f 100644 --- a/src/mongo/db/matcher/path_test.cpp +++ b/src/mongo/db/matcher/path_test.cpp @@ -37,451 +37,445 @@ namespace mongo { - using std::string; +using std::string; - TEST( Path, Root1 ) { - ElementPath p; - ASSERT( p.init( "a" ).isOK() ); +TEST(Path, Root1) { + ElementPath p; + ASSERT(p.init("a").isOK()); - BSONObj doc = BSON( "x" << 4 << "a" << 5 ); + BSONObj doc = BSON("x" << 4 << "a" << 5); - BSONElementIterator cursor( &p, doc ); - ASSERT( cursor.more() ); - ElementIterator::Context e = cursor.next(); - ASSERT_EQUALS( (string)"a", e.element().fieldName() ); - ASSERT_EQUALS( 5, e.element().numberInt() ); - ASSERT( !cursor.more() ); - } + BSONElementIterator cursor(&p, doc); + ASSERT(cursor.more()); + ElementIterator::Context e = cursor.next(); + ASSERT_EQUALS((string) "a", e.element().fieldName()); + ASSERT_EQUALS(5, e.element().numberInt()); + ASSERT(!cursor.more()); +} - TEST( Path, RootArray1 ) { - ElementPath p; - ASSERT( p.init( "a" ).isOK() ); +TEST(Path, RootArray1) { + ElementPath p; + ASSERT(p.init("a").isOK()); - BSONObj doc = BSON( "x" << 4 << "a" << BSON_ARRAY( 5 << 6 ) ); + BSONObj doc = BSON("x" << 4 << "a" << BSON_ARRAY(5 << 6)); - BSONElementIterator cursor( &p, doc ); + BSONElementIterator cursor(&p, doc); - ASSERT( cursor.more() ); - BSONElementIterator::Context e = cursor.next(); - ASSERT_EQUALS( 5, e.element().numberInt() ); + ASSERT(cursor.more()); + BSONElementIterator::Context e = cursor.next(); + ASSERT_EQUALS(5, e.element().numberInt()); - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( 6, e.element().numberInt() ); + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(6, e.element().numberInt()); - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( Array, e.element().type() ); + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(Array, e.element().type()); - ASSERT( !cursor.more() ); - } + ASSERT(!cursor.more()); +} - TEST( Path, RootArray2 ) { - ElementPath p; - ASSERT( p.init( "a" ).isOK() ); - p.setTraverseLeafArray( false ); +TEST(Path, RootArray2) { + ElementPath p; + ASSERT(p.init("a").isOK()); + p.setTraverseLeafArray(false); - BSONObj doc = BSON( "x" << 4 << "a" << BSON_ARRAY( 5 << 6 ) ); + BSONObj doc = BSON("x" << 4 << "a" << BSON_ARRAY(5 << 6)); - BSONElementIterator cursor( &p, doc ); + BSONElementIterator cursor(&p, doc); - ASSERT( cursor.more() ); - BSONElementIterator::Context e = cursor.next(); - ASSERT( e.element().type() == Array ); + ASSERT(cursor.more()); + BSONElementIterator::Context e = cursor.next(); + ASSERT(e.element().type() == Array); - ASSERT( !cursor.more() ); - } + ASSERT(!cursor.more()); +} - TEST( Path, Nested1 ) { - ElementPath p; - ASSERT( p.init( "a.b" ).isOK() ); - - BSONObj doc = BSON( "a" << BSON_ARRAY( BSON( "b" << 5 ) << - 3 << - BSONObj() << - BSON( "b" << BSON_ARRAY( 9 << 11 ) ) << - BSON( "b" << 7 ) ) ); - - BSONElementIterator cursor( &p, doc ); - - ASSERT( cursor.more() ); - BSONElementIterator::Context e = cursor.next(); - ASSERT_EQUALS( 5, e.element().numberInt() ); - ASSERT( !e.outerArray() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT( e.element().eoo() ); - ASSERT_EQUALS( (string)"2", e.arrayOffset().fieldName() ); - ASSERT( !e.outerArray() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( 9, e.element().numberInt() ); - ASSERT( !e.outerArray() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( 11, e.element().numberInt() ); - ASSERT( !e.outerArray() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( Array, e.element().type() ); - ASSERT_EQUALS( 2, e.element().Obj().nFields() ); - ASSERT( e.outerArray() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( 7, e.element().numberInt() ); - ASSERT( !e.outerArray() ); - - ASSERT( !cursor.more() ); - } +TEST(Path, Nested1) { + ElementPath p; + ASSERT(p.init("a.b").isOK()); + + BSONObj doc = + BSON("a" << BSON_ARRAY(BSON("b" << 5) << 3 << BSONObj() << BSON("b" << BSON_ARRAY(9 << 11)) + << BSON("b" << 7))); + + BSONElementIterator cursor(&p, doc); + + ASSERT(cursor.more()); + BSONElementIterator::Context e = cursor.next(); + ASSERT_EQUALS(5, e.element().numberInt()); + ASSERT(!e.outerArray()); + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT(e.element().eoo()); + ASSERT_EQUALS((string) "2", e.arrayOffset().fieldName()); + ASSERT(!e.outerArray()); + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(9, e.element().numberInt()); + ASSERT(!e.outerArray()); + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(11, e.element().numberInt()); + ASSERT(!e.outerArray()); + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(Array, e.element().type()); + ASSERT_EQUALS(2, e.element().Obj().nFields()); + ASSERT(e.outerArray()); + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(7, e.element().numberInt()); + ASSERT(!e.outerArray()); + + ASSERT(!cursor.more()); +} - TEST( Path, NestedPartialMatchScalar ) { - ElementPath p; - ASSERT( p.init( "a.b" ).isOK() ); +TEST(Path, NestedPartialMatchScalar) { + ElementPath p; + ASSERT(p.init("a.b").isOK()); - BSONObj doc = BSON( "a" << 4 ); + BSONObj doc = BSON("a" << 4); - BSONElementIterator cursor( &p, doc ); + BSONElementIterator cursor(&p, doc); - ASSERT( cursor.more() ); - BSONElementIterator::Context e = cursor.next(); - ASSERT( e.element().eoo() ); - ASSERT( e.arrayOffset().eoo() ); - ASSERT( !e.outerArray() ); + ASSERT(cursor.more()); + BSONElementIterator::Context e = cursor.next(); + ASSERT(e.element().eoo()); + ASSERT(e.arrayOffset().eoo()); + ASSERT(!e.outerArray()); - ASSERT( !cursor.more() ); - } + ASSERT(!cursor.more()); +} - // When the path (partially or in its entirety) refers to an array, - // the iteration logic does not return an EOO. - // what we want ideally. - TEST( Path, NestedPartialMatchArray ) { - ElementPath p; - ASSERT( p.init( "a.b" ).isOK() ); +// When the path (partially or in its entirety) refers to an array, +// the iteration logic does not return an EOO. +// what we want ideally. +TEST(Path, NestedPartialMatchArray) { + ElementPath p; + ASSERT(p.init("a.b").isOK()); - BSONObj doc = BSON( "a" << BSON_ARRAY( 4 ) ); + BSONObj doc = BSON("a" << BSON_ARRAY(4)); - BSONElementIterator cursor( &p, doc ); + BSONElementIterator cursor(&p, doc); - ASSERT( !cursor.more() ); - } + ASSERT(!cursor.more()); +} - // Note that this describes existing behavior and not necessarily - TEST( Path, NestedEmptyArray ) { - ElementPath p; - ASSERT( p.init( "a.b" ).isOK() ); +// Note that this describes existing behavior and not necessarily +TEST(Path, NestedEmptyArray) { + ElementPath p; + ASSERT(p.init("a.b").isOK()); - BSONObj doc = BSON( "a" << BSON( "b" << BSONArray() ) ); + BSONObj doc = BSON("a" << BSON("b" << BSONArray())); - BSONElementIterator cursor( &p, doc ); + BSONElementIterator cursor(&p, doc); - ASSERT( cursor.more() ); - BSONElementIterator::Context e = cursor.next(); - ASSERT_EQUALS( Array, e.element().type() ); - ASSERT_EQUALS( 0, e.element().Obj().nFields() ); - ASSERT( e.outerArray() ); + ASSERT(cursor.more()); + BSONElementIterator::Context e = cursor.next(); + ASSERT_EQUALS(Array, e.element().type()); + ASSERT_EQUALS(0, e.element().Obj().nFields()); + ASSERT(e.outerArray()); - ASSERT( !cursor.more() ); - } + ASSERT(!cursor.more()); +} - TEST( Path, NestedNoLeaf1 ) { - ElementPath p; - ASSERT( p.init( "a.b" ).isOK() ); - p.setTraverseLeafArray( false ); - - BSONObj doc = BSON( "a" << BSON_ARRAY( BSON( "b" << 5 ) << - 3 << - BSONObj() << - BSON( "b" << BSON_ARRAY( 9 << 11 ) ) << - BSON( "b" << 7 ) ) ); - - BSONElementIterator cursor( &p, doc ); - - ASSERT( cursor.more() ); - BSONElementIterator::Context e = cursor.next(); - ASSERT_EQUALS( 5, e.element().numberInt() ); - ASSERT( !e.outerArray() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT( e.element().eoo() ); - ASSERT_EQUALS( (string)"2", e.arrayOffset().fieldName() ); - ASSERT( !e.outerArray() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( Array, e.element().type() ); - ASSERT_EQUALS( 2, e.element().Obj().nFields() ); - ASSERT( e.outerArray() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( 7, e.element().numberInt() ); - ASSERT( !e.outerArray() ); - - ASSERT( !cursor.more() ); - } +TEST(Path, NestedNoLeaf1) { + ElementPath p; + ASSERT(p.init("a.b").isOK()); + p.setTraverseLeafArray(false); + BSONObj doc = + BSON("a" << BSON_ARRAY(BSON("b" << 5) << 3 << BSONObj() << BSON("b" << BSON_ARRAY(9 << 11)) + << BSON("b" << 7))); - TEST( Path, ArrayIndex1 ) { - ElementPath p; - ASSERT( p.init( "a.1" ).isOK() ); + BSONElementIterator cursor(&p, doc); - BSONObj doc = BSON( "a" << BSON_ARRAY( 5 << 7 << 3 ) ); + ASSERT(cursor.more()); + BSONElementIterator::Context e = cursor.next(); + ASSERT_EQUALS(5, e.element().numberInt()); + ASSERT(!e.outerArray()); - BSONElementIterator cursor( &p, doc ); + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT(e.element().eoo()); + ASSERT_EQUALS((string) "2", e.arrayOffset().fieldName()); + ASSERT(!e.outerArray()); - ASSERT( cursor.more() ); - BSONElementIterator::Context e = cursor.next(); - ASSERT_EQUALS( 7, e.element().numberInt() ); + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(Array, e.element().type()); + ASSERT_EQUALS(2, e.element().Obj().nFields()); + ASSERT(e.outerArray()); - ASSERT( !cursor.more() ); - } + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(7, e.element().numberInt()); + ASSERT(!e.outerArray()); - TEST( Path, ArrayIndex2 ) { - ElementPath p; - ASSERT( p.init( "a.1" ).isOK() ); + ASSERT(!cursor.more()); +} - BSONObj doc = BSON( "a" << BSON_ARRAY( 5 << BSON_ARRAY( 2 << 4 ) << 3 ) ); - BSONElementIterator cursor( &p, doc ); +TEST(Path, ArrayIndex1) { + ElementPath p; + ASSERT(p.init("a.1").isOK()); - ASSERT( cursor.more() ); - BSONElementIterator::Context e = cursor.next(); - ASSERT_EQUALS( Array, e.element().type() ); + BSONObj doc = BSON("a" << BSON_ARRAY(5 << 7 << 3)); - ASSERT( !cursor.more() ); - } + BSONElementIterator cursor(&p, doc); - TEST( Path, ArrayIndex3 ) { - ElementPath p; - ASSERT( p.init( "a.1" ).isOK() ); + ASSERT(cursor.more()); + BSONElementIterator::Context e = cursor.next(); + ASSERT_EQUALS(7, e.element().numberInt()); - BSONObj doc = BSON( "a" << BSON_ARRAY( 5 << BSON( "1" << 4 ) << 3 ) ); + ASSERT(!cursor.more()); +} - BSONElementIterator cursor( &p, doc ); +TEST(Path, ArrayIndex2) { + ElementPath p; + ASSERT(p.init("a.1").isOK()); - ASSERT( cursor.more() ); - BSONElementIterator::Context e = cursor.next(); - ASSERT_EQUALS( 4, e.element().numberInt() ); - ASSERT( !e.outerArray() ); + BSONObj doc = BSON("a" << BSON_ARRAY(5 << BSON_ARRAY(2 << 4) << 3)); - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( BSON( "1" << 4 ), e.element().Obj() ); - ASSERT( e.outerArray() ); + BSONElementIterator cursor(&p, doc); - ASSERT( !cursor.more() ); - } + ASSERT(cursor.more()); + BSONElementIterator::Context e = cursor.next(); + ASSERT_EQUALS(Array, e.element().type()); - TEST( Path, ArrayIndexNested1 ) { - ElementPath p; - ASSERT( p.init( "a.1.b" ).isOK() ); + ASSERT(!cursor.more()); +} - BSONObj doc = BSON( "a" << BSON_ARRAY( 5 << BSON( "b" << 4 ) << 3 ) ); +TEST(Path, ArrayIndex3) { + ElementPath p; + ASSERT(p.init("a.1").isOK()); - BSONElementIterator cursor( &p, doc ); + BSONObj doc = BSON("a" << BSON_ARRAY(5 << BSON("1" << 4) << 3)); - ASSERT( cursor.more() ); - BSONElementIterator::Context e = cursor.next(); - ASSERT( e.element().eoo() ); + BSONElementIterator cursor(&p, doc); - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( 4, e.element().numberInt() ); + ASSERT(cursor.more()); + BSONElementIterator::Context e = cursor.next(); + ASSERT_EQUALS(4, e.element().numberInt()); + ASSERT(!e.outerArray()); + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(BSON("1" << 4), e.element().Obj()); + ASSERT(e.outerArray()); - ASSERT( !cursor.more() ); - } + ASSERT(!cursor.more()); +} - TEST( Path, ArrayIndexNested2 ) { - ElementPath p; - ASSERT( p.init( "a.1.b" ).isOK() ); +TEST(Path, ArrayIndexNested1) { + ElementPath p; + ASSERT(p.init("a.1.b").isOK()); - BSONObj doc = BSON( "a" << BSON_ARRAY( 5 << BSON_ARRAY( BSON( "b" << 4 ) ) << 3 ) ); + BSONObj doc = BSON("a" << BSON_ARRAY(5 << BSON("b" << 4) << 3)); - BSONElementIterator cursor( &p, doc ); + BSONElementIterator cursor(&p, doc); - ASSERT( cursor.more() ); - BSONElementIterator::Context e = cursor.next(); - ASSERT_EQUALS( 4, e.element().numberInt() ); + ASSERT(cursor.more()); + BSONElementIterator::Context e = cursor.next(); + ASSERT(e.element().eoo()); + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(4, e.element().numberInt()); - ASSERT( !cursor.more() ); - } - // SERVER-15899: test iteration using a path that generates no elements, but traverses a long - // array containing subdocuments with nested arrays. - TEST( Path, NonMatchingLongArrayOfSubdocumentsWithNestedArrays ) { - ElementPath p; - ASSERT( p.init( "a.b.x" ).isOK() ); + ASSERT(!cursor.more()); +} - // Build the document {a: [{b: []}, {b: []}, {b: []}, ...]}. - BSONObj subdoc = BSON( "b" << BSONArray() ); - BSONArrayBuilder builder; - for ( int i = 0; i < 100 * 1000; ++i ) { - builder.append( subdoc ); - } - BSONObj doc = BSON( "a" << builder.arr() ); +TEST(Path, ArrayIndexNested2) { + ElementPath p; + ASSERT(p.init("a.1.b").isOK()); - BSONElementIterator cursor( &p, doc ); + BSONObj doc = BSON("a" << BSON_ARRAY(5 << BSON_ARRAY(BSON("b" << 4)) << 3)); - // The path "a.b.x" matches no elements. - ASSERT( !cursor.more() ); - } + BSONElementIterator cursor(&p, doc); + + ASSERT(cursor.more()); + BSONElementIterator::Context e = cursor.next(); + ASSERT_EQUALS(4, e.element().numberInt()); - // When multiple arrays are traversed implicitly in the same path, - // ElementIterator::Context::arrayOffset() should always refer to the current offset of the - // outermost array that is implicitly traversed. - TEST( Path, NestedArrayImplicitTraversal ) { - ElementPath p; - ASSERT( p.init( "a.b" ).isOK() ); - BSONObj doc = fromjson("{a: [{b: [2, 3]}, {b: [4, 5]}]}"); - BSONElementIterator cursor( &p, doc ); - - ASSERT( cursor.more() ); - ElementIterator::Context e = cursor.next(); - ASSERT_EQUALS( NumberInt, e.element().type() ); - ASSERT_EQUALS( 2, e.element().numberInt() ); - ASSERT_EQUALS( "0", e.arrayOffset().fieldNameStringData() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( NumberInt, e.element().type() ); - ASSERT_EQUALS( 3, e.element().numberInt() ); - ASSERT_EQUALS( "0", e.arrayOffset().fieldNameStringData() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( Array, e.element().type() ); - ASSERT_EQUALS( BSON( "0" << 2 << "1" << 3 ), e.element().Obj() ); - ASSERT_EQUALS( "0", e.arrayOffset().fieldNameStringData() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( NumberInt, e.element().type() ); - ASSERT_EQUALS( 4, e.element().numberInt() ); - ASSERT_EQUALS( "1", e.arrayOffset().fieldNameStringData() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( NumberInt, e.element().type() ); - ASSERT_EQUALS( 5, e.element().numberInt() ); - ASSERT_EQUALS( "1", e.arrayOffset().fieldNameStringData() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( Array, e.element().type() ); - ASSERT_EQUALS( BSON( "0" << 4 << "1" << 5 ), e.element().Obj() ); - ASSERT_EQUALS( "1", e.arrayOffset().fieldNameStringData() ); - - ASSERT( !cursor.more() ); - } - // SERVER-14886: when an array is being traversed explictly at the same time that a nested array - // is being traversed implicitly, ElementIterator::Context::arrayOffset() should return the - // current offset of the array being implicitly traversed. - TEST( Path, ArrayOffsetWithImplicitAndExplicitTraversal ) { - ElementPath p; - ASSERT( p.init( "a.0.b" ).isOK() ); - BSONObj doc = fromjson("{a: [{b: [2, 3]}, {b: [4, 5]}]}"); - BSONElementIterator cursor( &p, doc ); - - ASSERT( cursor.more() ); - ElementIterator::Context e = cursor.next(); - ASSERT_EQUALS( EOO, e.element().type() ); - ASSERT_EQUALS( "0", e.arrayOffset().fieldNameStringData() ); // First elt of outer array. - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( NumberInt, e.element().type() ); - ASSERT_EQUALS( 2, e.element().numberInt() ); - ASSERT_EQUALS( "0", e.arrayOffset().fieldNameStringData() ); // First elt of inner array. - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( NumberInt, e.element().type() ); - ASSERT_EQUALS( 3, e.element().numberInt() ); - ASSERT_EQUALS( "1", e.arrayOffset().fieldNameStringData() ); // Second elt of inner array. - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( Array, e.element().type() ); - ASSERT_EQUALS( BSON( "0" << 2 << "1" << 3 ), e.element().Obj() ); - ASSERT( e.arrayOffset().eoo() ); - - ASSERT( cursor.more() ); - e = cursor.next(); - ASSERT_EQUALS( EOO, e.element().type() ); - ASSERT_EQUALS( "1", e.arrayOffset().fieldNameStringData() ); // Second elt of outer array. - - ASSERT( !cursor.more() ); + ASSERT(!cursor.more()); +} + +// SERVER-15899: test iteration using a path that generates no elements, but traverses a long +// array containing subdocuments with nested arrays. +TEST(Path, NonMatchingLongArrayOfSubdocumentsWithNestedArrays) { + ElementPath p; + ASSERT(p.init("a.b.x").isOK()); + + // Build the document {a: [{b: []}, {b: []}, {b: []}, ...]}. + BSONObj subdoc = BSON("b" << BSONArray()); + BSONArrayBuilder builder; + for (int i = 0; i < 100 * 1000; ++i) { + builder.append(subdoc); } + BSONObj doc = BSON("a" << builder.arr()); + + BSONElementIterator cursor(&p, doc); - TEST( SimpleArrayElementIterator, SimpleNoArrayLast1 ) { - BSONObj obj = BSON( "a" << BSON_ARRAY( 5 << BSON( "x" << 6 ) << BSON_ARRAY( 7 << 9 ) << 11 ) ); - SimpleArrayElementIterator i( obj["a"], false ); + // The path "a.b.x" matches no elements. + ASSERT(!cursor.more()); +} - ASSERT( i.more() ); - ElementIterator::Context e = i.next(); - ASSERT_EQUALS( 5, e.element().numberInt() ); +// When multiple arrays are traversed implicitly in the same path, +// ElementIterator::Context::arrayOffset() should always refer to the current offset of the +// outermost array that is implicitly traversed. +TEST(Path, NestedArrayImplicitTraversal) { + ElementPath p; + ASSERT(p.init("a.b").isOK()); + BSONObj doc = fromjson("{a: [{b: [2, 3]}, {b: [4, 5]}]}"); + BSONElementIterator cursor(&p, doc); + + ASSERT(cursor.more()); + ElementIterator::Context e = cursor.next(); + ASSERT_EQUALS(NumberInt, e.element().type()); + ASSERT_EQUALS(2, e.element().numberInt()); + ASSERT_EQUALS("0", e.arrayOffset().fieldNameStringData()); + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(NumberInt, e.element().type()); + ASSERT_EQUALS(3, e.element().numberInt()); + ASSERT_EQUALS("0", e.arrayOffset().fieldNameStringData()); + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(Array, e.element().type()); + ASSERT_EQUALS(BSON("0" << 2 << "1" << 3), e.element().Obj()); + ASSERT_EQUALS("0", e.arrayOffset().fieldNameStringData()); + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(NumberInt, e.element().type()); + ASSERT_EQUALS(4, e.element().numberInt()); + ASSERT_EQUALS("1", e.arrayOffset().fieldNameStringData()); + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(NumberInt, e.element().type()); + ASSERT_EQUALS(5, e.element().numberInt()); + ASSERT_EQUALS("1", e.arrayOffset().fieldNameStringData()); + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(Array, e.element().type()); + ASSERT_EQUALS(BSON("0" << 4 << "1" << 5), e.element().Obj()); + ASSERT_EQUALS("1", e.arrayOffset().fieldNameStringData()); + + ASSERT(!cursor.more()); +} - ASSERT( i.more() ); - e = i.next(); - ASSERT_EQUALS( 6, e.element().Obj()["x"].numberInt() ); +// SERVER-14886: when an array is being traversed explictly at the same time that a nested array +// is being traversed implicitly, ElementIterator::Context::arrayOffset() should return the +// current offset of the array being implicitly traversed. +TEST(Path, ArrayOffsetWithImplicitAndExplicitTraversal) { + ElementPath p; + ASSERT(p.init("a.0.b").isOK()); + BSONObj doc = fromjson("{a: [{b: [2, 3]}, {b: [4, 5]}]}"); + BSONElementIterator cursor(&p, doc); + + ASSERT(cursor.more()); + ElementIterator::Context e = cursor.next(); + ASSERT_EQUALS(EOO, e.element().type()); + ASSERT_EQUALS("0", e.arrayOffset().fieldNameStringData()); // First elt of outer array. + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(NumberInt, e.element().type()); + ASSERT_EQUALS(2, e.element().numberInt()); + ASSERT_EQUALS("0", e.arrayOffset().fieldNameStringData()); // First elt of inner array. + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(NumberInt, e.element().type()); + ASSERT_EQUALS(3, e.element().numberInt()); + ASSERT_EQUALS("1", e.arrayOffset().fieldNameStringData()); // Second elt of inner array. + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(Array, e.element().type()); + ASSERT_EQUALS(BSON("0" << 2 << "1" << 3), e.element().Obj()); + ASSERT(e.arrayOffset().eoo()); + + ASSERT(cursor.more()); + e = cursor.next(); + ASSERT_EQUALS(EOO, e.element().type()); + ASSERT_EQUALS("1", e.arrayOffset().fieldNameStringData()); // Second elt of outer array. + + ASSERT(!cursor.more()); +} - ASSERT( i.more() ); - e = i.next(); - ASSERT_EQUALS( 7, e.element().Obj().firstElement().numberInt() ); +TEST(SimpleArrayElementIterator, SimpleNoArrayLast1) { + BSONObj obj = BSON("a" << BSON_ARRAY(5 << BSON("x" << 6) << BSON_ARRAY(7 << 9) << 11)); + SimpleArrayElementIterator i(obj["a"], false); - ASSERT( i.more() ); - e = i.next(); - ASSERT_EQUALS( 11, e.element().numberInt() ); + ASSERT(i.more()); + ElementIterator::Context e = i.next(); + ASSERT_EQUALS(5, e.element().numberInt()); - ASSERT( !i.more() ); - } + ASSERT(i.more()); + e = i.next(); + ASSERT_EQUALS(6, e.element().Obj()["x"].numberInt()); + + ASSERT(i.more()); + e = i.next(); + ASSERT_EQUALS(7, e.element().Obj().firstElement().numberInt()); - TEST( SimpleArrayElementIterator, SimpleArrayLast1 ) { - BSONObj obj = BSON( "a" << BSON_ARRAY( 5 << BSON( "x" << 6 ) << BSON_ARRAY( 7 << 9 ) << 11 ) ); - SimpleArrayElementIterator i( obj["a"], true ); + ASSERT(i.more()); + e = i.next(); + ASSERT_EQUALS(11, e.element().numberInt()); - ASSERT( i.more() ); - ElementIterator::Context e = i.next(); - ASSERT_EQUALS( 5, e.element().numberInt() ); + ASSERT(!i.more()); +} - ASSERT( i.more() ); - e = i.next(); - ASSERT_EQUALS( 6, e.element().Obj()["x"].numberInt() ); +TEST(SimpleArrayElementIterator, SimpleArrayLast1) { + BSONObj obj = BSON("a" << BSON_ARRAY(5 << BSON("x" << 6) << BSON_ARRAY(7 << 9) << 11)); + SimpleArrayElementIterator i(obj["a"], true); - ASSERT( i.more() ); - e = i.next(); - ASSERT_EQUALS( 7, e.element().Obj().firstElement().numberInt() ); + ASSERT(i.more()); + ElementIterator::Context e = i.next(); + ASSERT_EQUALS(5, e.element().numberInt()); - ASSERT( i.more() ); - e = i.next(); - ASSERT_EQUALS( 11, e.element().numberInt() ); + ASSERT(i.more()); + e = i.next(); + ASSERT_EQUALS(6, e.element().Obj()["x"].numberInt()); - ASSERT( i.more() ); - e = i.next(); - ASSERT_EQUALS( Array, e.element().type() ); + ASSERT(i.more()); + e = i.next(); + ASSERT_EQUALS(7, e.element().Obj().firstElement().numberInt()); - ASSERT( !i.more() ); - } + ASSERT(i.more()); + e = i.next(); + ASSERT_EQUALS(11, e.element().numberInt()); - TEST( SingleElementElementIterator, Simple1 ) { - BSONObj obj = BSON( "x" << 3 << "y" << 5 ); - SingleElementElementIterator i( obj["y"] ); + ASSERT(i.more()); + e = i.next(); + ASSERT_EQUALS(Array, e.element().type()); - ASSERT( i.more() ); - ElementIterator::Context e = i.next(); - ASSERT_EQUALS( 5, e.element().numberInt() ); + ASSERT(!i.more()); +} - ASSERT( !i.more() ); +TEST(SingleElementElementIterator, Simple1) { + BSONObj obj = BSON("x" << 3 << "y" << 5); + SingleElementElementIterator i(obj["y"]); - } + ASSERT(i.more()); + ElementIterator::Context e = i.next(); + ASSERT_EQUALS(5, e.element().numberInt()); + ASSERT(!i.more()); +} } |