// expression_geo_test.cpp /** * Copyright (C) 2013 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ /** Unit tests for MatchExpression operator implementations in match_operators.{h,cpp}. */ #include "mongo/unittest/unittest.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_geo.h" #include "mongo/db/matcher/matcher.h" #include "mongo/stdx/memory.h" namespace mongo { TEST(ExpressionGeoTest, Geo1) { BSONObj query = fromjson("{loc:{$within:{$box:[{x: 4, y:4},[6,6]]}}}"); std::unique_ptr gq(new GeoExpression); ASSERT_OK(gq->parseFrom(query["loc"].Obj())); GeoMatchExpression ge; ASSERT(ge.init("a", gq.release(), query).isOK()); ASSERT(!ge.matchesBSON(fromjson("{a: [3,4]}"))); ASSERT(ge.matchesBSON(fromjson("{a: [4,4]}"))); ASSERT(ge.matchesBSON(fromjson("{a: [5,5]}"))); ASSERT(ge.matchesBSON(fromjson("{a: [5,5.1]}"))); ASSERT(ge.matchesBSON(fromjson("{a: {x: 5, y:5.1}}"))); } TEST(ExpressionGeoTest, GeoNear1) { BSONObj query = fromjson( "{loc:{$near:{$maxDistance:100, " "$geometry:{type:\"Point\", coordinates:[0,0]}}}}"); std::unique_ptr nq(new GeoNearExpression); ASSERT_OK(nq->parseFrom(query["loc"].Obj())); GeoNearMatchExpression gne; ASSERT(gne.init("a", nq.release(), query).isOK()); // We can't match the data but we can make sure it was parsed OK. ASSERT_EQUALS(gne.getData().centroid->crs, SPHERE); ASSERT_EQUALS(gne.getData().minDistance, 0); ASSERT_EQUALS(gne.getData().maxDistance, 100); } std::unique_ptr makeGeoMatchExpression(const BSONObj& locQuery) { std::unique_ptr gq(new GeoExpression); ASSERT_OK(gq->parseFrom(locQuery)); std::unique_ptr ge = stdx::make_unique(); ASSERT_OK(ge->init("a", gq.release(), locQuery)); return ge; } std::unique_ptr makeGeoNearMatchExpression(const BSONObj& locQuery) { std::unique_ptr nq(new GeoNearExpression); ASSERT_OK(nq->parseFrom(locQuery)); std::unique_ptr gne = stdx::make_unique(); ASSERT_OK(gne->init("a", nq.release(), locQuery)); return gne; } /** * A bunch of cases in which a geo expression is equivalent() to both itself or to another * expression. */ TEST(ExpressionGeoTest, GeoEquivalent) { { BSONObj query = fromjson("{$within: {$box: [{x: 4, y: 4}, [6, 6]]}}"); std::unique_ptr ge(makeGeoMatchExpression(query)); ASSERT(ge->equivalent(ge.get())); } { BSONObj query = fromjson( "{$within: {$geometry: {type: 'Polygon'," "coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]}}}"); std::unique_ptr ge(makeGeoMatchExpression(query)); ASSERT(ge->equivalent(ge.get())); } { BSONObj query1 = fromjson( "{$within: {$geometry: {type: 'Polygon'," "coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]}}}"), query2 = fromjson( "{$within: {$geometry: {type: 'Polygon'," "coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]}}}"); std::unique_ptr ge1(makeGeoMatchExpression(query1)), ge2(makeGeoMatchExpression(query2)); ASSERT(ge1->equivalent(ge2.get())); } } /** * A bunch of cases in which a *geoNear* expression is equivalent both to itself or to * another expression. */ TEST(ExpressionGeoTest, GeoNearEquivalent) { { BSONObj query = fromjson( "{$near: {$maxDistance: 100, " "$geometry: {type: 'Point', coordinates: [0, 0]}}}"); std::unique_ptr gne(makeGeoNearMatchExpression(query)); ASSERT(gne->equivalent(gne.get())); } { BSONObj query = fromjson( "{$near: {$minDistance: 10, $maxDistance: 100," "$geometry: {type: 'Point', coordinates: [0, 0]}}}"); std::unique_ptr gne(makeGeoNearMatchExpression(query)); ASSERT(gne->equivalent(gne.get())); } { BSONObj query1 = fromjson( "{$near: {$maxDistance: 100, " "$geometry: {type: 'Point', coordinates: [1, 0]}}}"), query2 = fromjson( "{$near: {$maxDistance: 100, " "$geometry: {type: 'Point', coordinates: [1, 0]}}}"); std::unique_ptr gne1(makeGeoNearMatchExpression(query1)), gne2(makeGeoNearMatchExpression(query2)); ASSERT(gne1->equivalent(gne2.get())); } } /** * A geo expression being not equivalent to another expression. */ TEST(ExpressionGeoTest, GeoNotEquivalent) { BSONObj query1 = fromjson( "{$within: {$geometry: {type: 'Polygon'," "coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]}}}"), query2 = fromjson( "{$within: {$geometry: {type: 'Polygon'," "coordinates: [[[0, 0], [3, 6], [6, 2], [0, 0]]]}}}"); std::unique_ptr ge1(makeGeoMatchExpression(query1)), ge2(makeGeoMatchExpression(query2)); ASSERT(!ge1->equivalent(ge2.get())); } /** * A *geoNear* expression being not equivalent to another expression. */ TEST(ExpressionGeoTest, GeoNearNotEquivalent) { BSONObj query1 = fromjson( "{$near: {$maxDistance: 100, " "$geometry: {type: 'Point', coordinates: [0, 0]}}}"), query2 = fromjson( "{$near: {$maxDistance: 100, " "$geometry: {type: 'Point', coordinates: [1, 0]}}}"); std::unique_ptr gne1(makeGeoNearMatchExpression(query1)), gne2(makeGeoNearMatchExpression(query2)); ASSERT(!gne1->equivalent(gne2.get())); } }