xref: /6.6.0/subjson/tests/t_match.cc (revision 9f2dfe6a)
1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3*     Copyright 2015 Couchbase, Inc
4*
5*   Licensed under the Apache License, Version 2.0 (the "License");
6*   you may not use this file except in compliance with the License.
7*   You may obtain a copy of the License at
8*
9*       http://www.apache.org/licenses/LICENSE-2.0
10*
11*   Unless required by applicable law or agreed to in writing, software
12*   distributed under the License is distributed on an "AS IS" BASIS,
13*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*   See the License for the specific language governing permissions and
15*   limitations under the License.
16*/
17#include "subdoc-tests-common.h"
18
19using std::string;
20using std::cerr;
21using std::endl;
22using Subdoc::Path;
23using Subdoc::Match;
24using Subdoc::Util;
25
26#define JQ(s) "\"" s "\""
27
28class MatchTests : public ::testing::Test {
29protected:
30    static const std::string json;
31    static jsonsl_t jsn;
32    Path pth;
33    Match m;
34
35    static void SetUpTestCase() { jsn = Match::jsn_alloc(); }
36    static void TearDownTestCase() { Match::jsn_free(jsn); }
37    virtual void SetUp() { m.clear(); }
38};
39
40jsonsl_t MatchTests::jsn = NULL;
41const std::string MatchTests::json = "{"
42        JQ("key1") ":" JQ("val1") ","
43        JQ("subdict") ":{" JQ("subkey1") ":" JQ("subval1") "},"
44        JQ("sublist") ":[" JQ("elem1") "," JQ("elem2") "," JQ("elem3") "],"
45        JQ("nested_list") ":[  [" JQ("nested1") ",2,3,4,5,6,7,8,9,0]  ],"
46        JQ("empty_list") ":[],"
47        JQ("numbers") ":[1,2,3,4,5,6,7,8,9,0]" ","
48        JQ("empty") ":{}" ","
49        JQ("U\\u002DEscape") ":null"
50       "}";
51
52TEST_F(MatchTests, testToplevelDict)
53{
54    pth.parse("key1");
55    m.exec_match(json, pth, jsn);
56    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
57    ASSERT_EQ(JSONSL_ERROR_SUCCESS, m.status);
58    ASSERT_EQ("\"val1\"", Util::match_match(m));
59    ASSERT_EQ("\"key1\"", Util::match_key(m));
60}
61
62TEST_F(MatchTests, testNestedDict)
63{
64    pth.parse("subdict.subkey1");
65    m.exec_match(json, pth, jsn);
66    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
67    ASSERT_EQ(JSONSL_ERROR_SUCCESS, m.status);
68    ASSERT_EQ("\"subval1\"", Util::match_match(m));
69    ASSERT_EQ("\"subkey1\"", Util::match_key(m));
70}
71
72TEST_F(MatchTests, testArrayIndex)
73{
74    pth.parse("sublist[1]");
75    m.exec_match(json, pth, jsn);
76    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
77    ASSERT_EQ(JSONSL_ERROR_SUCCESS, m.status);
78    ASSERT_EQ("\"elem2\"", Util::match_match(m));
79    ASSERT_FALSE(m.has_key());
80}
81
82TEST_F(MatchTests, testMismatchArrayAsDict)
83{
84    pth.parse("key1[9]");
85    m.exec_match(json, pth, jsn);
86    ASSERT_EQ(JSONSL_MATCH_TYPE_MISMATCH, m.matchres);
87}
88
89TEST_F(MatchTests, testMismatchDictAsArray)
90{
91    pth.parse("subdict[0]");
92    m.exec_match(json, pth, jsn);
93    ASSERT_EQ(JSONSL_MATCH_TYPE_MISMATCH, m.matchres);
94}
95
96TEST_F(MatchTests, testMatchContainerValue)
97{
98    pth.parse("numbers");
99    m.exec_match(json, pth, jsn);
100    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
101    ASSERT_EQ("[1,2,3,4,5,6,7,8,9,0]", Util::match_match(m));
102}
103
104TEST_F(MatchTests, testFinalComponentNotFound)
105{
106    pth.parse("empty.field");
107    m.exec_match(json, pth, jsn);
108    ASSERT_NE(0, m.immediate_parent_found);
109    ASSERT_EQ(2, m.match_level);
110    ASSERT_EQ("{}", Util::match_parent(m));
111}
112
113TEST_F(MatchTests, testOOBArrayIndex)
114{
115    pth.parse("sublist[4]");
116    m.exec_match(json, pth, jsn);
117    ASSERT_NE(0, m.immediate_parent_found);
118    ASSERT_EQ(2, m.match_level);
119    ASSERT_EQ("[\"elem1\",\"elem2\",\"elem3\"]", Util::match_parent(m));
120}
121
122TEST_F(MatchTests, testAllComponentsNotFound)
123{
124    pth.parse("non.existent.path");
125    m.exec_match(json, pth, jsn);
126    ASSERT_EQ(0, m.immediate_parent_found);
127    ASSERT_EQ(1, m.match_level);
128    ASSERT_EQ(json, Util::match_parent(m));
129}
130
131TEST_F(MatchTests, testSingletonComponentNotFound)
132{
133    pth.parse("toplevel");
134    m.exec_match(json, pth, jsn);
135    ASSERT_EQ(1, m.match_level);
136    ASSERT_NE(0, m.immediate_parent_found);
137    ASSERT_EQ(json, Util::match_parent(m));
138}
139
140TEST_F(MatchTests, testUescape)
141{
142    // See if we can find the 'u-escape' here.
143    m.clear();
144    pth.parse("U-Escape");
145    m.exec_match(json, pth, jsn);
146    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
147    ASSERT_EQ("\"U\\u002DEscape\"", m.loc_key.to_string());
148}
149
150TEST_F(MatchTests, testGetLastElement)
151{
152    pth.parse("sublist");
153    m.get_last = 1;
154    m.exec_match(json, pth, jsn);
155
156    // Ensure the last element actually matches..
157    ASSERT_EQ(3, m.match_level);
158    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
159    ASSERT_EQ(JSONSL_T_STRING, m.type);
160    ASSERT_EQ("\"elem3\"", Util::match_match(m));
161    ASSERT_EQ(2, m.position);
162    ASSERT_EQ(2, m.num_siblings);
163
164    m.clear();
165    pth.parse("nested_list");
166    m.get_last = 1;
167    m.exec_match(json, pth, jsn);
168    ASSERT_EQ(3, m.match_level);
169    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
170    ASSERT_EQ(JSONSL_T_LIST, m.type);
171
172    ASSERT_EQ("[" JQ("nested1") ",2,3,4,5,6,7,8,9,0]", Util::match_match(m));
173    ASSERT_EQ(10, m.num_children);
174    ASSERT_EQ(0, m.num_siblings);
175}
176
177TEST_F(MatchTests, testGetNumSiblings)
178{
179    pth.parse("nested_list[0][0]");
180    // By default, siblings are not extracted
181    ASSERT_EQ(Match::GET_MATCH_ONLY, m.extra_options);
182    m.exec_match(json, pth, jsn);
183    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
184    ASSERT_EQ(JSONSL_T_STRING, m.type); // String
185    ASSERT_EQ(0, m.num_siblings);
186
187    m.clear();
188    ASSERT_EQ(Match::GET_MATCH_ONLY, m.extra_options);
189    m.extra_options = Match::GET_FOLLOWING_SIBLINGS;
190    m.exec_match(json, pth, jsn);
191    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
192    ASSERT_TRUE(m.num_siblings > 0);
193    ASSERT_FALSE(m.is_only());
194    ASSERT_TRUE(m.is_first());
195}
196
197// It's important that we test this at the Match level as well, even though
198// tests are already present at the 'Operation' and 'Path' level.
199TEST_F(MatchTests, testNegativeIndex)
200{
201    pth.parse("sublist[-1]");
202    m.exec_match(json, pth, jsn);
203    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
204    ASSERT_EQ(JSONSL_T_STRING, m.type);
205    ASSERT_EQ(2, m.num_siblings);
206    ASSERT_EQ(3, m.match_level);
207    ASSERT_EQ("\"elem3\"", Util::match_match(m));
208
209    // Multiple nested elements..
210    pth.parse("nested_list[-1][-1]");
211    m.exec_match(json, pth, jsn);
212    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
213    ASSERT_EQ(JSONSL_T_SPECIAL, m.type);
214    ASSERT_EQ("0", Util::match_match(m));
215    ASSERT_EQ(4, m.match_level);
216}
217
218TEST_F(MatchTests, testMatchUnique)
219{
220    pth.parse("empty_list");
221    m.ensure_unique.assign("key", 3);
222    m.exec_match(json, pth, jsn);
223    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
224    ASSERT_EQ(JSONSL_T_LIST, m.type);
225    ASSERT_EQ(2, m.match_level);
226    ASSERT_FALSE(m.unique_item_found);
227    ASSERT_EQ("[]", Util::match_match(m));
228
229    // Test with non-empty path, item found
230    m.clear();
231    pth.parse("numbers");
232    m.ensure_unique.assign("1", 1);
233    m.exec_match(json, pth, jsn);
234    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
235    ASSERT_TRUE(m.unique_item_found);
236
237    // test with non-empty path, item not found
238    m.clear();
239    pth.parse("numbers");
240    m.ensure_unique.assign("42", 2);
241    m.exec_match(json, pth, jsn);
242    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
243    ASSERT_FALSE(m.unique_item_found);
244    ASSERT_NE(0, m.num_children);
245    ASSERT_EQ("[1,2,3,4,5,6,7,8,9,0]", Util::match_match(m));
246
247    // Test with path mismatch:
248    m.clear();
249    pth.parse("empty");
250    m.ensure_unique.assign("foo", 3);
251    m.exec_match(json, pth, jsn);
252    ASSERT_EQ(JSONSL_MATCH_TYPE_MISMATCH, m.matchres);
253
254    // Test with negative index, not found
255    m.clear();
256    pth.parse("nested_list[-1]");
257    m.ensure_unique.assign("foo", 3);
258    m.exec_match(json, pth, jsn);
259    ASSERT_EQ(JSONSL_MATCH_COMPLETE, m.matchres);
260    ASSERT_FALSE(m.unique_item_found);
261    ASSERT_NE(0, m.num_children);
262}
263