common-test.c++ (13780B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #include "common.h" 23 #include "../string.h" 24 #include <kj/compat/gtest.h> 25 26 namespace kj { 27 namespace parse { 28 namespace { 29 30 typedef IteratorInput<char, const char*> Input; 31 32 TEST(CommonParsers, AnyParser) { 33 StringPtr text = "foo"; 34 Input input(text.begin(), text.end()); 35 constexpr auto parser = any; 36 37 Maybe<char> result = parser(input); 38 KJ_IF_MAYBE(c, result) { 39 EXPECT_EQ('f', *c); 40 } else { 41 ADD_FAILURE() << "Expected 'c', got null."; 42 } 43 EXPECT_FALSE(input.atEnd()); 44 45 result = parser(input); 46 KJ_IF_MAYBE(c, result) { 47 EXPECT_EQ('o', *c); 48 } else { 49 ADD_FAILURE() << "Expected 'o', got null."; 50 } 51 EXPECT_FALSE(input.atEnd()); 52 53 result = parser(input); 54 KJ_IF_MAYBE(c, result) { 55 EXPECT_EQ('o', *c); 56 } else { 57 ADD_FAILURE() << "Expected 'o', got null."; 58 } 59 EXPECT_TRUE(input.atEnd()); 60 61 result = parser(input); 62 EXPECT_TRUE(result == nullptr); 63 EXPECT_TRUE(input.atEnd()); 64 } 65 66 TEST(CommonParsers, ExactElementParser) { 67 StringPtr text = "foo"; 68 Input input(text.begin(), text.end()); 69 70 Maybe<Tuple<>> result = exactly('f')(input); 71 EXPECT_TRUE(result != nullptr); 72 EXPECT_FALSE(input.atEnd()); 73 74 result = exactly('o')(input); 75 EXPECT_TRUE(result != nullptr); 76 EXPECT_FALSE(input.atEnd()); 77 78 result = exactly('x')(input); 79 EXPECT_TRUE(result == nullptr); 80 EXPECT_FALSE(input.atEnd()); 81 82 auto parser = exactly('o'); 83 ParserRef<Input, Tuple<>> wrapped = ref<Input>(parser); 84 result = wrapped(input); 85 EXPECT_TRUE(result != nullptr); 86 EXPECT_TRUE(input.atEnd()); 87 } 88 89 TEST(CommonParsers, ExactlyConstParser) { 90 StringPtr text = "foo"; 91 Input input(text.begin(), text.end()); 92 93 Maybe<Tuple<>> result = exactlyConst<char, 'f'>()(input); 94 EXPECT_TRUE(result != nullptr); 95 EXPECT_FALSE(input.atEnd()); 96 97 result = exactlyConst<char, 'o'>()(input); 98 EXPECT_TRUE(result != nullptr); 99 EXPECT_FALSE(input.atEnd()); 100 101 result = exactlyConst<char, 'x'>()(input); 102 EXPECT_TRUE(result == nullptr); 103 EXPECT_FALSE(input.atEnd()); 104 105 auto parser = exactlyConst<char, 'o'>(); 106 ParserRef<Input, Tuple<>> wrapped = ref<Input>(parser); 107 result = wrapped(input); 108 EXPECT_TRUE(result != nullptr); 109 EXPECT_TRUE(input.atEnd()); 110 } 111 112 TEST(CommonParsers, ConstResultParser) { 113 auto parser = constResult(exactly('o'), 123); 114 115 StringPtr text = "o"; 116 Input input(text.begin(), text.end()); 117 Maybe<int> result = parser(input); 118 KJ_IF_MAYBE(i, result) { 119 EXPECT_EQ(123, *i); 120 } else { 121 ADD_FAILURE() << "Expected 123, got null."; 122 } 123 EXPECT_TRUE(input.atEnd()); 124 } 125 126 TEST(CommonParsers, DiscardParser) { 127 auto parser = discard(any); 128 129 StringPtr text = "o"; 130 Input input(text.begin(), text.end()); 131 Maybe<Tuple<>> result = parser(input); 132 EXPECT_TRUE(result != nullptr); 133 EXPECT_TRUE(input.atEnd()); 134 } 135 136 TEST(CommonParsers, SequenceParser) { 137 StringPtr text = "foo"; 138 139 { 140 Input input(text.begin(), text.end()); 141 Maybe<Tuple<>> result = sequence(exactly('f'), exactly('o'), exactly('o'))(input); 142 EXPECT_TRUE(result != nullptr); 143 EXPECT_TRUE(input.atEnd()); 144 } 145 146 { 147 Input input(text.begin(), text.end()); 148 Maybe<Tuple<>> result = sequence(exactly('f'), exactly('o'))(input); 149 EXPECT_TRUE(result != nullptr); 150 EXPECT_FALSE(input.atEnd()); 151 } 152 153 { 154 Input input(text.begin(), text.end()); 155 Maybe<Tuple<>> result = sequence(exactly('x'), exactly('o'), exactly('o'))(input); 156 EXPECT_TRUE(result == nullptr); 157 EXPECT_FALSE(input.atEnd()); 158 } 159 160 { 161 Input input(text.begin(), text.end()); 162 Maybe<Tuple<>> result = 163 sequence(sequence(exactly('f'), exactly('o')), exactly('o'))(input); 164 EXPECT_TRUE(result != nullptr); 165 EXPECT_TRUE(input.atEnd()); 166 } 167 168 { 169 Input input(text.begin(), text.end()); 170 Maybe<Tuple<>> result = 171 sequence(sequence(exactly('f')), exactly('o'), exactly('o'))(input); 172 EXPECT_TRUE(result != nullptr); 173 EXPECT_TRUE(input.atEnd()); 174 } 175 176 { 177 Input input(text.begin(), text.end()); 178 Maybe<int> result = sequence(transform(exactly('f'), [](){return 123;}), 179 exactly('o'), exactly('o'))(input); 180 KJ_IF_MAYBE(i, result) { 181 EXPECT_EQ(123, *i); 182 } else { 183 ADD_FAILURE() << "Expected 123, got null."; 184 } 185 EXPECT_TRUE(input.atEnd()); 186 } 187 } 188 189 TEST(CommonParsers, ManyParserCountOnly) { 190 StringPtr text = "foooob"; 191 192 auto parser = sequence(exactly('f'), many(exactly('o'))); 193 194 { 195 Input input(text.begin(), text.begin() + 3); 196 Maybe<int> result = parser(input); 197 KJ_IF_MAYBE(i, result) { 198 EXPECT_EQ(2, *i); 199 } else { 200 ADD_FAILURE() << "Expected 2, got null."; 201 } 202 EXPECT_TRUE(input.atEnd()); 203 } 204 205 { 206 Input input(text.begin(), text.begin() + 5); 207 Maybe<int> result = parser(input); 208 KJ_IF_MAYBE(i, result) { 209 EXPECT_EQ(4, *i); 210 } else { 211 ADD_FAILURE() << "Expected 4, got null."; 212 } 213 EXPECT_TRUE(input.atEnd()); 214 } 215 216 { 217 Input input(text.begin(), text.end()); 218 Maybe<int> result = parser(input); 219 KJ_IF_MAYBE(i, result) { 220 EXPECT_EQ(4, *i); 221 } else { 222 ADD_FAILURE() << "Expected 4, got null."; 223 } 224 EXPECT_FALSE(input.atEnd()); 225 } 226 } 227 228 TEST(CommonParsers, TimesParser) { 229 StringPtr text = "foobar"; 230 231 auto parser = sequence(exactly('f'), times(any, 4)); 232 233 { 234 Input input(text.begin(), text.begin() + 4); 235 Maybe<Array<char>> result = parser(input); 236 EXPECT_TRUE(result == nullptr); 237 EXPECT_TRUE(input.atEnd()); 238 } 239 240 { 241 Input input(text.begin(), text.begin() + 5); 242 Maybe<Array<char>> result = parser(input); 243 KJ_IF_MAYBE(s, result) { 244 EXPECT_EQ("ooba", heapString(*s)); 245 } else { 246 ADD_FAILURE() << "Expected string, got null."; 247 } 248 EXPECT_TRUE(input.atEnd()); 249 } 250 251 { 252 Input input(text.begin(), text.end()); 253 Maybe<Array<char>> result = parser(input); 254 KJ_IF_MAYBE(s, result) { 255 EXPECT_EQ("ooba", heapString(*s)); 256 } else { 257 ADD_FAILURE() << "Expected string, got null."; 258 } 259 EXPECT_FALSE(input.atEnd()); 260 } 261 } 262 263 TEST(CommonParsers, TimesParserCountOnly) { 264 StringPtr text = "foooob"; 265 266 auto parser = sequence(exactly('f'), times(exactly('o'), 4)); 267 268 { 269 Input input(text.begin(), text.begin() + 4); 270 Maybe<Tuple<>> result = parser(input); 271 EXPECT_TRUE(result == nullptr); 272 EXPECT_TRUE(input.atEnd()); 273 } 274 275 { 276 Input input(text.begin(), text.begin() + 5); 277 Maybe<Tuple<>> result = parser(input); 278 EXPECT_TRUE(result != nullptr); 279 EXPECT_TRUE(input.atEnd()); 280 } 281 282 { 283 Input input(text.begin(), text.end()); 284 Maybe<Tuple<>> result = parser(input); 285 EXPECT_TRUE(result != nullptr); 286 EXPECT_FALSE(input.atEnd()); 287 } 288 289 text = "fooob"; 290 291 { 292 Input input(text.begin(), text.end()); 293 Maybe<Tuple<>> result = parser(input); 294 EXPECT_TRUE(result == nullptr); 295 EXPECT_FALSE(input.atEnd()); 296 } 297 } 298 299 TEST(CommonParsers, ManyParserSubResult) { 300 StringPtr text = "foooob"; 301 302 auto parser = many(any); 303 304 { 305 Input input(text.begin(), text.end()); 306 Maybe<Array<char>> result = parser(input); 307 KJ_IF_MAYBE(chars, result) { 308 EXPECT_EQ(text, heapString(*chars)); 309 } else { 310 ADD_FAILURE() << "Expected char array, got null."; 311 } 312 EXPECT_TRUE(input.atEnd()); 313 } 314 } 315 316 TEST(CommonParsers, OptionalParser) { 317 auto parser = sequence( 318 transform(exactly('b'), []() -> uint { return 123; }), 319 optional(transform(exactly('a'), []() -> uint { return 456; })), 320 transform(exactly('r'), []() -> uint { return 789; })); 321 322 { 323 StringPtr text = "bar"; 324 Input input(text.begin(), text.end()); 325 Maybe<Tuple<uint, Maybe<uint>, uint>> result = parser(input); 326 KJ_IF_MAYBE(value, result) { 327 EXPECT_EQ(123u, get<0>(*value)); 328 KJ_IF_MAYBE(value2, get<1>(*value)) { 329 EXPECT_EQ(456u, *value2); 330 } else { 331 ADD_FAILURE() << "Expected 456, got null."; 332 } 333 EXPECT_EQ(789u, get<2>(*value)); 334 } else { 335 ADD_FAILURE() << "Expected result tuple, got null."; 336 } 337 EXPECT_TRUE(input.atEnd()); 338 } 339 340 { 341 StringPtr text = "br"; 342 Input input(text.begin(), text.end()); 343 Maybe<Tuple<uint, Maybe<uint>, uint>> result = parser(input); 344 KJ_IF_MAYBE(value, result) { 345 EXPECT_EQ(123u, get<0>(*value)); 346 EXPECT_TRUE(get<1>(*value) == nullptr); 347 EXPECT_EQ(789u, get<2>(*value)); 348 } else { 349 ADD_FAILURE() << "Expected result tuple, got null."; 350 } 351 EXPECT_TRUE(input.atEnd()); 352 } 353 354 { 355 StringPtr text = "bzr"; 356 Input input(text.begin(), text.end()); 357 Maybe<Tuple<uint, Maybe<uint>, uint>> result = parser(input); 358 EXPECT_TRUE(result == nullptr); 359 } 360 } 361 362 TEST(CommonParsers, OneOfParser) { 363 auto parser = oneOf( 364 transform(sequence(exactly('f'), exactly('o'), exactly('o')), 365 []() -> StringPtr { return "foo"; }), 366 transform(sequence(exactly('b'), exactly('a'), exactly('r')), 367 []() -> StringPtr { return "bar"; })); 368 369 { 370 StringPtr text = "foo"; 371 Input input(text.begin(), text.end()); 372 Maybe<StringPtr> result = parser(input); 373 KJ_IF_MAYBE(s, result) { 374 EXPECT_EQ("foo", *s); 375 } else { 376 ADD_FAILURE() << "Expected 'foo', got null."; 377 } 378 EXPECT_TRUE(input.atEnd()); 379 } 380 381 { 382 StringPtr text = "bar"; 383 Input input(text.begin(), text.end()); 384 Maybe<StringPtr> result = parser(input); 385 KJ_IF_MAYBE(s, result) { 386 EXPECT_EQ("bar", *s); 387 } else { 388 ADD_FAILURE() << "Expected 'bar', got null."; 389 } 390 EXPECT_TRUE(input.atEnd()); 391 } 392 } 393 394 TEST(CommonParsers, TransformParser) { 395 StringPtr text = "foo"; 396 397 auto parser = transformWithLocation( 398 sequence(exactly('f'), exactly('o'), exactly('o')), 399 [](Span<const char*> location) -> int { 400 EXPECT_EQ("foo", StringPtr(location.begin(), location.end())); 401 return 123; 402 }); 403 404 { 405 Input input(text.begin(), text.end()); 406 Maybe<int> result = parser(input); 407 KJ_IF_MAYBE(i, result) { 408 EXPECT_EQ(123, *i); 409 } else { 410 ADD_FAILURE() << "Expected 123, got null."; 411 } 412 EXPECT_TRUE(input.atEnd()); 413 } 414 } 415 416 TEST(CommonParsers, TransformOrRejectParser) { 417 auto parser = transformOrReject(many(any), 418 [](Array<char> chars) -> Maybe<int> { 419 if (heapString(chars) == "foo") { 420 return 123; 421 } else { 422 return nullptr; 423 } 424 }); 425 426 { 427 StringPtr text = "foo"; 428 Input input(text.begin(), text.end()); 429 Maybe<int> result = parser(input); 430 KJ_IF_MAYBE(i, result) { 431 EXPECT_EQ(123, *i); 432 } else { 433 ADD_FAILURE() << "Expected 123, got null."; 434 } 435 EXPECT_TRUE(input.atEnd()); 436 } 437 438 { 439 StringPtr text = "bar"; 440 Input input(text.begin(), text.end()); 441 Maybe<int> result = parser(input); 442 EXPECT_TRUE(result == nullptr); 443 EXPECT_TRUE(input.atEnd()); 444 } 445 } 446 447 TEST(CommonParsers, References) { 448 struct TransformFunc { 449 int value; 450 451 TransformFunc(int value): value(value) {} 452 453 int operator()() const { return value; } 454 }; 455 456 // Don't use auto for the parsers here in order to verify that the templates are properly choosing 457 // whether to use references or copies. 458 459 Transform_<Exactly_<char>, TransformFunc> parser1 = 460 transform(exactly('f'), TransformFunc(12)); 461 462 auto otherParser = exactly('o'); 463 Transform_<Exactly_<char>&, TransformFunc> parser2 = 464 transform(otherParser, TransformFunc(34)); 465 466 auto otherParser2 = exactly('b'); 467 Transform_<Exactly_<char>, TransformFunc> parser3 = 468 transform(mv(otherParser2), TransformFunc(56)); 469 470 StringPtr text = "foob"; 471 auto parser = transform( 472 sequence(parser1, parser2, exactly('o'), parser3), 473 [](int i, int j, int k) { return i + j + k; }); 474 475 { 476 Input input(text.begin(), text.end()); 477 Maybe<int> result = parser(input); 478 KJ_IF_MAYBE(i, result) { 479 EXPECT_EQ(12 + 34 + 56, *i); 480 } else { 481 ADD_FAILURE() << "Expected 12 + 34 + 56, got null."; 482 } 483 EXPECT_TRUE(input.atEnd()); 484 } 485 } 486 487 TEST(CommonParsers, NotLookingAt) { 488 auto parser = notLookingAt(exactly('a')); 489 490 { 491 StringPtr text = "a"; 492 Input input(text.begin(), text.end()); 493 EXPECT_TRUE(parser(input) == nullptr); 494 EXPECT_FALSE(input.atEnd()); 495 } 496 497 { 498 StringPtr text = "b"; 499 Input input(text.begin(), text.end()); 500 EXPECT_TRUE(parser(input) != nullptr); 501 EXPECT_FALSE(input.atEnd()); 502 } 503 } 504 505 TEST(CommonParsers, EndOfInput) { 506 auto parser = endOfInput; 507 508 { 509 StringPtr text = "a"; 510 Input input(text.begin(), text.end()); 511 EXPECT_TRUE(parser(input) == nullptr); 512 EXPECT_TRUE(parser(input) == nullptr); 513 input.next(); 514 EXPECT_FALSE(parser(input) == nullptr); 515 } 516 } 517 518 } // namespace 519 } // namespace parse 520 } // namespace kj