1 // expression_geo_test.cpp
2
3
4 /**
5 * Copyright (C) 2018-present MongoDB, Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the Server Side Public License, version 1,
9 * as published by MongoDB, Inc.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * Server Side Public License for more details.
15 *
16 * You should have received a copy of the Server Side Public License
17 * along with this program. If not, see
18 * <http://www.mongodb.com/licensing/server-side-public-license>.
19 *
20 * As a special exception, the copyright holders give permission to link the
21 * code of portions of this program with the OpenSSL library under certain
22 * conditions as described in each individual source file and distribute
23 * linked combinations including the program with the OpenSSL library. You
24 * must comply with the Server Side Public License in all respects for
25 * all of the code used other than as permitted herein. If you modify file(s)
26 * with this exception, you may extend this exception to your version of the
27 * file(s), but you are not obligated to do so. If you do not wish to do so,
28 * delete this exception statement from your version. If you delete this
29 * exception statement from all source files in the program, then also delete
30 * it in the license file.
31 */
32
33 /** Unit tests for MatchExpression operator implementations in match_operators.{h,cpp}. */
34
35 #include "mongo/unittest/unittest.h"
36
37 #include "mongo/db/jsobj.h"
38 #include "mongo/db/json.h"
39 #include "mongo/db/matcher/expression.h"
40 #include "mongo/db/matcher/expression_geo.h"
41 #include "mongo/stdx/memory.h"
42
43 namespace mongo {
44
TEST(ExpressionGeoTest,Geo1)45 TEST(ExpressionGeoTest, Geo1) {
46 BSONObj query = fromjson("{loc:{$within:{$box:[{x: 4, y:4},[6,6]]}}}");
47
48 std::unique_ptr<GeoExpression> gq(new GeoExpression);
49 ASSERT_OK(gq->parseFrom(query["loc"].Obj()));
50
51 GeoMatchExpression ge;
52 ASSERT(ge.init("a", gq.release(), query).isOK());
53
54 ASSERT(!ge.matchesBSON(fromjson("{a: [3,4]}")));
55 ASSERT(ge.matchesBSON(fromjson("{a: [4,4]}")));
56 ASSERT(ge.matchesBSON(fromjson("{a: [5,5]}")));
57 ASSERT(ge.matchesBSON(fromjson("{a: [5,5.1]}")));
58 ASSERT(ge.matchesBSON(fromjson("{a: {x: 5, y:5.1}}")));
59 }
60
TEST(ExpressionGeoTest,GeoNear1)61 TEST(ExpressionGeoTest, GeoNear1) {
62 BSONObj query = fromjson(
63 "{loc:{$near:{$maxDistance:100, "
64 "$geometry:{type:\"Point\", coordinates:[0,0]}}}}");
65 std::unique_ptr<GeoNearExpression> nq(new GeoNearExpression);
66 ASSERT_OK(nq->parseFrom(query["loc"].Obj()));
67
68 GeoNearMatchExpression gne;
69 ASSERT(gne.init("a", nq.release(), query).isOK());
70
71 // We can't match the data but we can make sure it was parsed OK.
72 ASSERT_EQUALS(gne.getData().centroid->crs, SPHERE);
73 ASSERT_EQUALS(gne.getData().minDistance, 0);
74 ASSERT_EQUALS(gne.getData().maxDistance, 100);
75 }
76
makeGeoMatchExpression(const BSONObj & locQuery)77 std::unique_ptr<GeoMatchExpression> makeGeoMatchExpression(const BSONObj& locQuery) {
78 std::unique_ptr<GeoExpression> gq(new GeoExpression);
79 ASSERT_OK(gq->parseFrom(locQuery));
80
81 std::unique_ptr<GeoMatchExpression> ge = stdx::make_unique<GeoMatchExpression>();
82 ASSERT_OK(ge->init("a", gq.release(), locQuery));
83
84 return ge;
85 }
86
makeGeoNearMatchExpression(const BSONObj & locQuery)87 std::unique_ptr<GeoNearMatchExpression> makeGeoNearMatchExpression(const BSONObj& locQuery) {
88 std::unique_ptr<GeoNearExpression> nq(new GeoNearExpression);
89 ASSERT_OK(nq->parseFrom(locQuery));
90
91 std::unique_ptr<GeoNearMatchExpression> gne = stdx::make_unique<GeoNearMatchExpression>();
92 ASSERT_OK(gne->init("a", nq.release(), locQuery));
93
94 return gne;
95 }
96
97
98 /**
99 * A bunch of cases in which a geo expression is equivalent() to both itself or to another
100 * expression.
101 */
TEST(ExpressionGeoTest,GeoEquivalent)102 TEST(ExpressionGeoTest, GeoEquivalent) {
103 {
104 BSONObj query = fromjson("{$within: {$box: [{x: 4, y: 4}, [6, 6]]}}");
105 std::unique_ptr<GeoMatchExpression> ge(makeGeoMatchExpression(query));
106 ASSERT(ge->equivalent(ge.get()));
107 }
108 {
109 BSONObj query = fromjson(
110 "{$within: {$geometry: {type: 'Polygon',"
111 "coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]}}}");
112 std::unique_ptr<GeoMatchExpression> ge(makeGeoMatchExpression(query));
113 ASSERT(ge->equivalent(ge.get()));
114 }
115 {
116 BSONObj query1 = fromjson(
117 "{$within: {$geometry: {type: 'Polygon',"
118 "coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]}}}"),
119 query2 = fromjson(
120 "{$within: {$geometry: {type: 'Polygon',"
121 "coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]}}}");
122 std::unique_ptr<GeoMatchExpression> ge1(makeGeoMatchExpression(query1)),
123 ge2(makeGeoMatchExpression(query2));
124 ASSERT(ge1->equivalent(ge2.get()));
125 }
126 }
127
128 /**
129 * A bunch of cases in which a *geoNear* expression is equivalent both to itself or to
130 * another expression.
131 */
TEST(ExpressionGeoTest,GeoNearEquivalent)132 TEST(ExpressionGeoTest, GeoNearEquivalent) {
133 {
134 BSONObj query = fromjson(
135 "{$near: {$maxDistance: 100, "
136 "$geometry: {type: 'Point', coordinates: [0, 0]}}}");
137 std::unique_ptr<GeoNearMatchExpression> gne(makeGeoNearMatchExpression(query));
138 ASSERT(gne->equivalent(gne.get()));
139 }
140 {
141 BSONObj query = fromjson(
142 "{$near: {$minDistance: 10, $maxDistance: 100,"
143 "$geometry: {type: 'Point', coordinates: [0, 0]}}}");
144 std::unique_ptr<GeoNearMatchExpression> gne(makeGeoNearMatchExpression(query));
145 ASSERT(gne->equivalent(gne.get()));
146 }
147 {
148 BSONObj query1 = fromjson(
149 "{$near: {$maxDistance: 100, "
150 "$geometry: {type: 'Point', coordinates: [1, 0]}}}"),
151 query2 = fromjson(
152 "{$near: {$maxDistance: 100, "
153 "$geometry: {type: 'Point', coordinates: [1, 0]}}}");
154 std::unique_ptr<GeoNearMatchExpression> gne1(makeGeoNearMatchExpression(query1)),
155 gne2(makeGeoNearMatchExpression(query2));
156 ASSERT(gne1->equivalent(gne2.get()));
157 }
158 }
159
160 /**
161 * A geo expression being not equivalent to another expression.
162 */
TEST(ExpressionGeoTest,GeoNotEquivalent)163 TEST(ExpressionGeoTest, GeoNotEquivalent) {
164 BSONObj query1 = fromjson(
165 "{$within: {$geometry: {type: 'Polygon',"
166 "coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]}}}"),
167 query2 = fromjson(
168 "{$within: {$geometry: {type: 'Polygon',"
169 "coordinates: [[[0, 0], [3, 6], [6, 2], [0, 0]]]}}}");
170 std::unique_ptr<GeoMatchExpression> ge1(makeGeoMatchExpression(query1)),
171 ge2(makeGeoMatchExpression(query2));
172 ASSERT(!ge1->equivalent(ge2.get()));
173 }
174
175 /**
176 * A *geoNear* expression being not equivalent to another expression.
177 */
TEST(ExpressionGeoTest,GeoNearNotEquivalent)178 TEST(ExpressionGeoTest, GeoNearNotEquivalent) {
179 BSONObj query1 = fromjson(
180 "{$near: {$maxDistance: 100, "
181 "$geometry: {type: 'Point', coordinates: [0, 0]}}}"),
182 query2 = fromjson(
183 "{$near: {$maxDistance: 100, "
184 "$geometry: {type: 'Point', coordinates: [1, 0]}}}");
185 std::unique_ptr<GeoNearMatchExpression> gne1(makeGeoNearMatchExpression(query1)),
186 gne2(makeGeoNearMatchExpression(query2));
187 ASSERT(!gne1->equivalent(gne2.get()));
188 }
189 }
190