blob: 6c7a8e68b49ce702b77bc7a2d78a28f15ceb0145 [file] [log] [blame]
Václav Kubernát4108e0d2018-10-29 13:32:22 +01001/*
2 * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
3 * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
4 *
5 * Written by Václav Kubernát <kubervac@fit.cvut.cz>
6 *
7*/
8
Václav Kubernát26b56082020-02-03 18:28:56 +01009#include "trompeloeil_doctest.hpp"
Václav Kubernát43908fb2020-01-02 19:05:51 +010010#include "datastoreaccess_mock.hpp"
Václav Kubernát4108e0d2018-10-29 13:32:22 +010011#include "parser.hpp"
Václav Kubernát1ed4aa32020-01-23 13:13:28 +010012#include "pretty_printers.hpp"
Václav Kubernát4108e0d2018-10-29 13:32:22 +010013#include "static_schema.hpp"
14
15TEST_CASE("path_completion")
16{
17 auto schema = std::make_shared<StaticSchema>();
18 schema->addModule("example");
19 schema->addModule("second");
Václav Kubernátefcac932020-01-10 15:26:32 +010020 schema->addContainer("/", "example:ano");
21 schema->addContainer("/", "example:anoda");
22 schema->addList("/example:ano", "example:listInCont", {"number"});
23 schema->addContainer("/", "second:amelie");
24 schema->addContainer("/", "example:bota");
25 schema->addContainer("/example:ano", "example:a2");
26 schema->addContainer("/example:bota", "example:b2");
27 schema->addContainer("/example:ano/example:a2", "example:a3");
28 schema->addContainer("/example:bota/example:b2", "example:b3");
29 schema->addList("/", "example:list", {"number"});
Václav Kubernát3a99f002020-03-31 02:27:41 +020030 schema->addLeaf("/example:list", "example:number", yang::Int32{});
Václav Kubernátefcac932020-01-10 15:26:32 +010031 schema->addContainer("/example:list", "example:contInList");
Václav Kubernát7707cae2020-01-16 12:04:53 +010032 schema->addList("/", "example:ovoce", {"name"});
Václav Kubernát3a99f002020-03-31 02:27:41 +020033 schema->addLeaf("/example:ovoce", "example:name", yang::String{});
Václav Kubernát7707cae2020-01-16 12:04:53 +010034 schema->addList("/", "example:ovocezelenina", {"name"});
Václav Kubernát3a99f002020-03-31 02:27:41 +020035 schema->addLeaf("/example:ovocezelenina", "example:name", yang::String{});
Václav Kubernátefcac932020-01-10 15:26:32 +010036 schema->addList("/", "example:twoKeyList", {"number", "name"});
Václav Kubernát3a99f002020-03-31 02:27:41 +020037 schema->addLeaf("/example:twoKeyList", "example:name", yang::String{});
38 schema->addLeaf("/example:twoKeyList", "example:number", yang::Int32{});
39 schema->addLeaf("/", "example:leafInt", yang::Int32{});
Václav Kubernátabf52802020-05-19 01:31:17 +020040 schema->addLeaf("/", "example:readonly", yang::Int32{}, yang::AccessType::ReadOnly);
Václav Kubernát743d9eb2020-05-18 13:42:36 +020041 schema->addLeafList("/", "example:addresses", yang::String{});
Václav Kubernáte7248b22020-06-26 15:38:59 +020042 schema->addRpc("/", "second:fire");
43 schema->addLeaf("/second:fire", "second:whom", yang::String{});
Václav Kubernát43908fb2020-01-02 19:05:51 +010044 auto mockDatastore = std::make_shared<MockDatastoreAccess>();
45
46 // The parser will use DataQuery for key value completion, but I'm not testing that here, so I don't return anything.
47 ALLOW_CALL(*mockDatastore, listInstances("/example:list"))
48 .RETURN(std::vector<ListInstance>{});
49 ALLOW_CALL(*mockDatastore, listInstances("/example:twoKeyList"))
50 .RETURN(std::vector<ListInstance>{});
51
52 // DataQuery gets the schema from DatastoreAccess once
53 auto expectation = NAMED_REQUIRE_CALL(*mockDatastore, schema())
54 .RETURN(schema);
55 auto dataQuery = std::make_shared<DataQuery>(*mockDatastore);
56 expectation.reset();
Václav Kubernát28cf3362020-06-29 17:52:51 +020057 Parser parser(schema, WritableOps::No, dataQuery);
Václav Kubernát4108e0d2018-10-29 13:32:22 +010058 std::string input;
59 std::ostringstream errorStream;
Václav Kubernát1ed4aa32020-01-23 13:13:28 +010060
61 std::set<std::string> expectedCompletions;
62 // GCC complains here with -Wmaybe-uninitialized if I don't assign
63 // something here. I suspect it's because of nested SECTIONs. -1 is an
64 // invalid value (as in, I'll never expect expectedContextLength to be -1),
65 // so let's go with that.
66 int expectedContextLength = -1;
Václav Kubernát4108e0d2018-10-29 13:32:22 +010067
Václav Kubernát329c6c32019-02-06 16:41:53 +010068 SECTION("node name completion")
Václav Kubernát4108e0d2018-10-29 13:32:22 +010069 {
Václav Kubernát329c6c32019-02-06 16:41:53 +010070 SECTION("ls ")
71 {
72 input = "ls ";
Václav Kubernáte7248b22020-06-26 15:38:59 +020073 expectedCompletions = {"example:addresses/", "example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list/", "example:ovoce/", "example:readonly ", "example:ovocezelenina/", "example:twoKeyList/", "second:amelie/", "second:fire/"};
Václav Kubernát1ed4aa32020-01-23 13:13:28 +010074 expectedContextLength = 0;
Václav Kubernát329c6c32019-02-06 16:41:53 +010075 }
76
77 SECTION("ls e")
78 {
79 input = "ls e";
Václav Kubernát743d9eb2020-05-18 13:42:36 +020080 expectedCompletions = {"example:addresses/", "example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list/", "example:ovoce/", "example:readonly ", "example:ovocezelenina/", "example:twoKeyList/"};
Václav Kubernát1ed4aa32020-01-23 13:13:28 +010081 expectedContextLength = 1;
Václav Kubernát329c6c32019-02-06 16:41:53 +010082 }
83
84 SECTION("ls example:ano")
85 {
86 input = "ls example:ano";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +010087 expectedCompletions = {"example:ano/", "example:anoda/"};
88 expectedContextLength = 11;
Václav Kubernát329c6c32019-02-06 16:41:53 +010089 }
90
Václav Kubernáte2d629f2020-04-28 11:01:54 +020091 SECTION("ls example:ano/a")
Václav Kubernát329c6c32019-02-06 16:41:53 +010092 {
Václav Kubernáte2d629f2020-04-28 11:01:54 +020093 input = "ls example:ano/a";
94 expectedCompletions = {"a2/"};
95 expectedContextLength = 1;
Václav Kubernát329c6c32019-02-06 16:41:53 +010096 }
97
98 SECTION("ls x")
99 {
100 input = "ls x";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100101 expectedCompletions = {};
102 expectedContextLength = 1;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100103 }
104
105 SECTION("ls /")
106 {
107 input = "ls /";
Václav Kubernáte7248b22020-06-26 15:38:59 +0200108 expectedCompletions = {"example:addresses/", "example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list/", "example:ovoce/", "example:readonly ", "example:ovocezelenina/", "example:twoKeyList/", "second:amelie/", "second:fire/"};
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100109 expectedContextLength = 0;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100110 }
111
112 SECTION("ls /e")
113 {
114 input = "ls /e";
Václav Kubernát743d9eb2020-05-18 13:42:36 +0200115 expectedCompletions = {"example:addresses/", "example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list/", "example:ovoce/", "example:readonly ", "example:ovocezelenina/", "example:twoKeyList/"};
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100116 expectedContextLength = 1;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100117 }
118
Václav Kubernáte69133a2019-11-01 19:01:34 +0100119 SECTION("ls example:bota")
120 {
121 input = "ls example:bota";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100122 expectedCompletions = {"example:bota/"};
123 expectedContextLength = 12;
Václav Kubernáte69133a2019-11-01 19:01:34 +0100124 }
125
126 SECTION("ls /example:bota")
127 {
128 input = "ls /example:bota";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100129 expectedCompletions = {"example:bota/"};
130 expectedContextLength = 12;
Václav Kubernáte69133a2019-11-01 19:01:34 +0100131 }
132
Václav Kubernát329c6c32019-02-06 16:41:53 +0100133 SECTION("ls /s")
134 {
135 input = "ls /s";
Václav Kubernáte7248b22020-06-26 15:38:59 +0200136 expectedCompletions = {"second:amelie/", "second:fire/"};
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100137 expectedContextLength = 1;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100138 }
139
Václav Kubernát743d9eb2020-05-18 13:42:36 +0200140 SECTION("ls /example:list")
141 {
142 input = "ls /example:list";
143 expectedCompletions = {"example:list/"};
144 expectedContextLength = 12;
145 }
146
Václav Kubernát26be33a2020-02-13 13:30:14 +0100147 SECTION("ls /example:list/")
148 {
149 input = "ls /example:list/";
Václav Kubernáte2d629f2020-04-28 11:01:54 +0200150 expectedCompletions = {"contInList/", "number "};
Václav Kubernát26be33a2020-02-13 13:30:14 +0100151 expectedContextLength = 0;
152 }
153
Václav Kubernát329c6c32019-02-06 16:41:53 +0100154 SECTION("ls /example:list[number=3]/")
155 {
156 input = "ls /example:list[number=3]/";
Václav Kubernáte2d629f2020-04-28 11:01:54 +0200157 expectedCompletions = {"contInList/", "number "};
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100158 expectedContextLength = 0;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100159 }
160
161 SECTION("ls /example:list[number=3]/c")
162 {
Václav Kubernáte2d629f2020-04-28 11:01:54 +0200163 input = "ls /example:list[number=3]/c";
164 expectedCompletions = {"contInList/"};
165 expectedContextLength = 1;
166 }
167
168 SECTION("ls /example:list[number=3]/n")
169 {
170 input = "ls /example:list[number=3]/n";
171 expectedCompletions = {"number "};
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100172 expectedContextLength = 1;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100173 }
174
175 SECTION("ls /example:list[number=3]/a")
176 {
177 input = "ls /example:list[number=3]/a";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100178 expectedCompletions = {};
179 expectedContextLength = 1;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100180 }
Václav Kubernát26be33a2020-02-13 13:30:14 +0100181
Václav Kubernáte2d629f2020-04-28 11:01:54 +0200182 SECTION("ls /example:list/contInList/")
Václav Kubernát26be33a2020-02-13 13:30:14 +0100183 {
Václav Kubernáte2d629f2020-04-28 11:01:54 +0200184 input = "ls /example:list/contInList/";
Václav Kubernát26be33a2020-02-13 13:30:14 +0100185 expectedCompletions = {};
186 expectedContextLength = 0;
187 }
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100188 }
189
Václav Kubernát7eb47152020-11-12 16:57:03 +0100190 SECTION("get completion")
191 {
192 SECTION("get /example:ano/l")
193 {
194 input = "get /example:ano/l";
195 expectedCompletions = {"listInCont"};
196 expectedContextLength = 1;
197 }
Václav Kubernát85ba7382020-11-18 18:11:18 +0100198
199 SECTION("get /example:list/")
200 {
201 input = "get /example:list/";
202 expectedCompletions = {};
203 // The expectedContextLength is 13, because the completion isn't actually generated after the slash.
204 expectedContextLength = 13;
205 }
Václav Kubernát7eb47152020-11-12 16:57:03 +0100206 }
207
Václav Kubernát3200b862020-12-03 02:34:55 +0100208 SECTION("describe completion")
209 {
210 SECTION("path with list at the end")
211 {
212 input = "describe /example:list/";
213 expectedCompletions = {"contInList/", "number "};
214 expectedContextLength = 0;
215 }
216 }
217
Václav Kubernát329c6c32019-02-06 16:41:53 +0100218 SECTION("list keys completion")
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100219 {
Václav Kubernát329c6c32019-02-06 16:41:53 +0100220 SECTION("cd example:lis")
221 {
222 input = "cd example:lis";
Václav Kubernátcb3af402020-02-12 16:49:17 +0100223 expectedCompletions = {"example:list"};
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100224 expectedContextLength = 11;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100225 }
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100226
Václav Kubernát51853b22019-04-16 21:53:44 +0200227 SECTION("set example:list")
228 {
229 input = "set example:list";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100230 expectedCompletions = {"example:list["};
231 expectedContextLength = 12;
Václav Kubernát4c325482019-04-11 17:51:55 +0200232 }
233
234 SECTION("cd example:list")
235 {
236 input = "cd example:list";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100237 expectedCompletions = {"example:list["};
238 expectedContextLength = 12;
Václav Kubernát51853b22019-04-16 21:53:44 +0200239 }
240
Václav Kubernát329c6c32019-02-06 16:41:53 +0100241 SECTION("cd example:list[")
242 {
243 input = "cd example:list[";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100244 expectedCompletions = {"number="};
245 expectedContextLength = 0;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100246 }
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100247
Václav Kubernát329c6c32019-02-06 16:41:53 +0100248 SECTION("cd example:list[numb")
249 {
250 input = "cd example:list[numb";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100251 expectedCompletions = {"number="};
252 expectedContextLength = 4;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100253 }
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100254
Václav Kubernát329c6c32019-02-06 16:41:53 +0100255 SECTION("cd example:list[number")
256 {
257 input = "cd example:list[number";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100258 expectedCompletions = {"number="};
259 expectedContextLength = 6;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100260 }
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100261
Václav Kubernát117f7b52020-01-23 16:10:55 +0100262 SECTION("cd example:list[number=")
263 {
264 input = "cd example:list[number=";
Václav Kubernát43908fb2020-01-02 19:05:51 +0100265 expectedCompletions = {};
266 expectedContextLength = 0;
Václav Kubernát117f7b52020-01-23 16:10:55 +0100267 }
268
Václav Kubernát329c6c32019-02-06 16:41:53 +0100269 SECTION("cd example:list[number=12")
270 {
271 input = "cd example:list[number=12";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100272 expectedCompletions = {"]/"};
273 expectedContextLength = 0;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100274 }
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100275
Václav Kubernát329c6c32019-02-06 16:41:53 +0100276 SECTION("cd example:list[number=12]")
277 {
278 input = "cd example:list[number=12]";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100279 expectedCompletions = {"]/"};
280 expectedContextLength = 1;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100281 }
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100282
Václav Kubernát329c6c32019-02-06 16:41:53 +0100283 SECTION("cd example:twoKeyList[")
284 {
285 input = "cd example:twoKeyList[";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100286 expectedCompletions = {"name=", "number="};
287 expectedContextLength = 0;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100288 }
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100289
Václav Kubernát4c325482019-04-11 17:51:55 +0200290 SECTION("cd example:twoKeyList[name=\"AHOJ\"")
291 {
292 input = "cd example:twoKeyList[name=\"AHOJ\"";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100293 expectedCompletions = {"]["};
294 expectedContextLength = 0;
Václav Kubernát4c325482019-04-11 17:51:55 +0200295 }
296
297 SECTION("cd example:twoKeyList[name=\"AHOJ\"]")
298 {
299 input = "cd example:twoKeyList[name=\"AHOJ\"]";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100300 expectedCompletions = {"]["};
301 expectedContextLength = 1;
Václav Kubernát4c325482019-04-11 17:51:55 +0200302 }
303
Václav Kubernát329c6c32019-02-06 16:41:53 +0100304 SECTION("cd example:twoKeyList[name=\"AHOJ\"][")
305 {
306 input = "cd example:twoKeyList[name=\"AHOJ\"][";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100307 expectedCompletions = {"number="};
308 expectedContextLength = 0;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100309 }
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100310
Václav Kubernát329c6c32019-02-06 16:41:53 +0100311 SECTION("cd example:twoKeyList[number=42][")
312 {
313 input = "cd example:twoKeyList[number=42][";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100314 expectedCompletions = {"name="};
315 expectedContextLength = 0;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100316 }
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100317
Václav Kubernát329c6c32019-02-06 16:41:53 +0100318 SECTION("cd example:twoKeyList[name=\"AHOJ\"][number=123")
319 {
320 input = "cd example:twoKeyList[name=\"AHOJ\"][number=123";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100321 expectedCompletions = {"]/"};
322 expectedContextLength = 0;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100323 }
324
325 SECTION("cd example:twoKeyList[name=\"AHOJ\"][number=123]")
326 {
327 input = "cd example:twoKeyList[name=\"AHOJ\"][number=123]";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100328 expectedCompletions = {"]/"};
329 expectedContextLength = 1;
Václav Kubernát329c6c32019-02-06 16:41:53 +0100330 }
Václav Kubernát4c325482019-04-11 17:51:55 +0200331
332 SECTION("cd example:ovoce")
333 {
334 input = "cd example:ovoce";
Václav Kubernátcb3af402020-02-12 16:49:17 +0100335 expectedCompletions = {"example:ovoce", "example:ovocezelenina"};
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100336 expectedContextLength = 13;
Václav Kubernát4c325482019-04-11 17:51:55 +0200337 }
Václav Kubernátcb3af402020-02-12 16:49:17 +0100338
339 SECTION("cd example:ovoceze")
340 {
341 input = "cd example:ovoceze";
342 expectedCompletions = {"example:ovocezelenina"};
343 expectedContextLength = 15;
344 }
345
346 SECTION("cd example:ovocezelenina")
347 {
348 input = "cd example:ovocezelenina";
349 expectedCompletions = {"example:ovocezelenina["};
350 expectedContextLength = 21;
351 }
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100352 }
353
Václav Kubernátabf52802020-05-19 01:31:17 +0200354 SECTION("no readonly data leafs in set")
355 {
356 input = "set example:read";
357 expectedContextLength = 12;
358 }
359
Václav Kubernát8028f942019-09-25 16:03:23 +0200360 SECTION("clear completions when no longer inputting path")
361 {
362 input = "set example:leafInt ";
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100363 expectedCompletions = {};
364 expectedContextLength = 0;
Václav Kubernát8028f942019-09-25 16:03:23 +0200365 }
366
Václav Kubernátaa4250a2020-07-22 00:02:23 +0200367 SECTION("rpc input nodes NOT completed for prepare command")
Václav Kubernáte7248b22020-06-26 15:38:59 +0200368 {
Václav Kubernátaa4250a2020-07-22 00:02:23 +0200369 input = "prepare example:fire/";
Václav Kubernáte7248b22020-06-26 15:38:59 +0200370 expectedCompletions = {};
371 expectedContextLength = 13;
372 }
373
374 SECTION("rpc input nodes completed for set command")
375 {
376 parser.changeNode({{}, {{module_{"second"}, rpcNode_{"fire"}}}});
377 input = "set ";
378 expectedCompletions = {"whom "};
379 expectedContextLength = 0;
380 }
381
382 SECTION("completion for other stuff while inside an rpc")
383 {
384 parser.changeNode({{}, {{module_{"second"}, rpcNode_{"fire"}}}});
385 input = "set ../";
386 expectedCompletions = {"example:addresses", "example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list", "example:ovoce", "example:ovocezelenina", "example:twoKeyList", "second:amelie/", "second:fire/"};
387 expectedContextLength = 0;
388 }
389
Václav Kubernát31029682020-10-29 08:23:04 +0100390 SECTION("rpc nodes not completed for the get command")
391 {
392 input = "get ";
393 expectedCompletions = {"example:addresses", "example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list", "example:ovoce", "example:ovocezelenina", "example:readonly ", "example:twoKeyList", "second:amelie/"};
394 expectedContextLength = 0;
395 }
396
Václav Kubernát0d47e5e2020-11-17 12:27:05 +0100397 SECTION("leafs not completed for cd")
398 {
399 input = "cd ";
400 expectedCompletions = {"example:addresses", "example:ano/", "example:anoda/", "example:bota/","example:list", "example:ovoce", "example:ovocezelenina", "example:twoKeyList", "second:amelie/"};
401 expectedContextLength = 0;
402 }
403
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100404 REQUIRE(parser.completeCommand(input, errorStream) == (Completions{expectedCompletions, expectedContextLength}));
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100405}