Merge #16887: Abstract out some of the descriptor Span-parsing helpers

bb36372b8f test: add unit tests for Span-parsing helpers (Sebastian Falbesoner)
5e69aeec3f Add documenting comments to spanparsing.h (Pieter Wuille)
230d43fdbc Abstract out some of the descriptor Span-parsing helpers (Pieter Wuille)

Pull request description:

  As suggested here: https://github.com/bitcoin/bitcoin/pull/16800#issuecomment-531605482.

  This moves the Span parsing functions out of the descriptor module, making them more easily usable for other parsers (in particular, in preparation for miniscript parsing).

ACKs for top commit:
  MarcoFalke:
    ACK bb36372b8f

Tree-SHA512: b5c5c11a9bc3f0a1c2c4cfa22755654ecfb8d4b69da0dc1fb9f04e1556dc0f6ffd87ad153600963279ac465d587d7971b53d240ced802d12693682411ac73deb
This commit is contained in:
MarcoFalke
2019-10-10 12:32:57 -04:00
5 changed files with 252 additions and 57 deletions

View File

@@ -12,6 +12,7 @@
#include <util/strencodings.h>
#include <util/string.h>
#include <util/time.h>
#include <util/spanparsing.h>
#include <stdint.h>
#include <thread>
@@ -1572,4 +1573,127 @@ BOOST_AUTO_TEST_CASE(test_Capitalize)
BOOST_CHECK_EQUAL(Capitalize("\x00\xfe\xff"), "\x00\xfe\xff");
}
static std::string SpanToStr(Span<const char>& span)
{
return std::string(span.begin(), span.end());
}
BOOST_AUTO_TEST_CASE(test_spanparsing)
{
using namespace spanparsing;
std::string input;
Span<const char> sp;
bool success;
// Const(...): parse a constant, update span to skip it if successful
input = "MilkToastHoney";
sp = MakeSpan(input);
success = Const("", sp); // empty
BOOST_CHECK(success);
BOOST_CHECK_EQUAL(SpanToStr(sp), "MilkToastHoney");
success = Const("Milk", sp);
BOOST_CHECK(success);
BOOST_CHECK_EQUAL(SpanToStr(sp), "ToastHoney");
success = Const("Bread", sp);
BOOST_CHECK(!success);
success = Const("Toast", sp);
BOOST_CHECK(success);
BOOST_CHECK_EQUAL(SpanToStr(sp), "Honey");
success = Const("Honeybadger", sp);
BOOST_CHECK(!success);
success = Const("Honey", sp);
BOOST_CHECK(success);
BOOST_CHECK_EQUAL(SpanToStr(sp), "");
// Func(...): parse a function call, update span to argument if successful
input = "Foo(Bar(xy,z()))";
sp = MakeSpan(input);
success = Func("FooBar", sp);
BOOST_CHECK(!success);
success = Func("Foo(", sp);
BOOST_CHECK(!success);
success = Func("Foo", sp);
BOOST_CHECK(success);
BOOST_CHECK_EQUAL(SpanToStr(sp), "Bar(xy,z())");
success = Func("Bar", sp);
BOOST_CHECK(success);
BOOST_CHECK_EQUAL(SpanToStr(sp), "xy,z()");
success = Func("xy", sp);
BOOST_CHECK(!success);
// Expr(...): return expression that span begins with, update span to skip it
Span<const char> result;
input = "(n*(n-1))/2";
sp = MakeSpan(input);
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "(n*(n-1))/2");
BOOST_CHECK_EQUAL(SpanToStr(sp), "");
input = "foo,bar";
sp = MakeSpan(input);
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "foo");
BOOST_CHECK_EQUAL(SpanToStr(sp), ",bar");
input = "(aaaaa,bbbbb()),c";
sp = MakeSpan(input);
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "(aaaaa,bbbbb())");
BOOST_CHECK_EQUAL(SpanToStr(sp), ",c");
input = "xyz)foo";
sp = MakeSpan(input);
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "xyz");
BOOST_CHECK_EQUAL(SpanToStr(sp), ")foo");
input = "((a),(b),(c)),xxx";
sp = MakeSpan(input);
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "((a),(b),(c))");
BOOST_CHECK_EQUAL(SpanToStr(sp), ",xxx");
// Split(...): split a string on every instance of sep, return vector
std::vector<Span<const char>> results;
input = "xxx";
results = Split(MakeSpan(input), 'x');
BOOST_CHECK_EQUAL(results.size(), 4);
BOOST_CHECK_EQUAL(SpanToStr(results[0]), "");
BOOST_CHECK_EQUAL(SpanToStr(results[1]), "");
BOOST_CHECK_EQUAL(SpanToStr(results[2]), "");
BOOST_CHECK_EQUAL(SpanToStr(results[3]), "");
input = "one#two#three";
results = Split(MakeSpan(input), '-');
BOOST_CHECK_EQUAL(results.size(), 1);
BOOST_CHECK_EQUAL(SpanToStr(results[0]), "one#two#three");
input = "one#two#three";
results = Split(MakeSpan(input), '#');
BOOST_CHECK_EQUAL(results.size(), 3);
BOOST_CHECK_EQUAL(SpanToStr(results[0]), "one");
BOOST_CHECK_EQUAL(SpanToStr(results[1]), "two");
BOOST_CHECK_EQUAL(SpanToStr(results[2]), "three");
input = "*foo*bar*";
results = Split(MakeSpan(input), '*');
BOOST_CHECK_EQUAL(results.size(), 4);
BOOST_CHECK_EQUAL(SpanToStr(results[0]), "");
BOOST_CHECK_EQUAL(SpanToStr(results[1]), "foo");
BOOST_CHECK_EQUAL(SpanToStr(results[2]), "bar");
BOOST_CHECK_EQUAL(SpanToStr(results[3]), "");
}
BOOST_AUTO_TEST_SUITE_END()