From fd43b1694f1382a3a47f5dc546ebe3d39fcd6e7d Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Mon, 20 Jan 2020 14:14:49 +0100 Subject: Implement short patterns (patterns starting with ~) Also make pattern detector in cacheset and private's list accept such patterns. We probably should just try to parse and see if it is a (start of a) pattern. --- test/libapt/pattern_test.cc | 66 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'test/libapt/pattern_test.cc') diff --git a/test/libapt/pattern_test.cc b/test/libapt/pattern_test.cc index de2fbceb9..492a29eac 100644 --- a/test/libapt/pattern_test.cc +++ b/test/libapt/pattern_test.cc @@ -93,3 +93,69 @@ TEST(TreeParserTest, ParseWithManyArgsWithSpacesWithTrailingComma) EXPECT_EQ(patternNode->term, "?hello"); EXPECT_EQ(2u, patternNode->arguments.size()); } + +// Helper +static bool samePattern(const std::unique_ptr &a, const std::unique_ptr &b) +{ + auto pa = dynamic_cast(a.get()); + auto pb = dynamic_cast(b.get()); + + if (pa && pb) + { + if (pa->term != pb->term || pa->haveArgumentList != pb->haveArgumentList || pa->arguments.size() != pb->arguments.size()) + return false; + + for (size_t i = 0; i < pa->arguments.size(); i++) + { + if (!samePattern(pa->arguments[i], pb->arguments[i])) + return false; + } + return true; + } + + auto wa = dynamic_cast(a.get()); + auto wb = dynamic_cast(b.get()); + if (wa && wb) + return wa->word == wb->word && wa->quoted == wb->quoted; + + return false; +} + +#define EXPECT_PATTERN_EQ(shrt, lng) \ + EXPECT_TRUE(samePattern(PatternTreeParser(shrt).parseTop(), PatternTreeParser(lng).parseTop())) +#define EXPECT_PATTERN_EQ_ATOMIC(shrt, lng) \ + EXPECT_TRUE(PatternTreeParser(shrt).parseTop()); \ + caught = false; \ + try \ + { \ + PatternTreeParser(shrt "XXX").parseTop(); \ + } \ + catch (PatternTreeParser::Error & e) \ + { \ + caught = true; \ + }; \ + EXPECT_TRUE(caught) << shrt "XXX should have thrown an exception"; \ + EXPECT_PATTERN_EQ(shrt, lng) + +TEST(TreeParserTest, ParseShortPattern) +{ + bool caught; + EXPECT_PATTERN_EQ("~ramd64", "?architecture(amd64)"); + EXPECT_PATTERN_EQ("~AanArchive", "?archive(anArchive)"); + EXPECT_PATTERN_EQ_ATOMIC("~M", "?automatic"); + EXPECT_PATTERN_EQ_ATOMIC("~b", "?broken"); + EXPECT_PATTERN_EQ_ATOMIC("~c", "?config-files"); + EXPECT_PATTERN_EQ_ATOMIC("~E", "?essential"); + EXPECT_PATTERN_EQ_ATOMIC("~F", "?false"); + EXPECT_PATTERN_EQ_ATOMIC("~g", "?garbage"); + EXPECT_PATTERN_EQ_ATOMIC("~i", "?installed"); + EXPECT_PATTERN_EQ("~napt", "?name(apt)"); + EXPECT_PATTERN_EQ_ATOMIC("~o", "?obsolete"); + EXPECT_PATTERN_EQ("~Obar", "?origin(bar)"); + EXPECT_PATTERN_EQ("~sfoo", "?section(foo)"); + EXPECT_PATTERN_EQ("~esourcename", "?source-package(sourcename)"); + EXPECT_PATTERN_EQ_ATOMIC("~T", "?true"); + EXPECT_PATTERN_EQ_ATOMIC("~U", "?upgradable"); + EXPECT_PATTERN_EQ("~Vverstr", "?version(verstr)"); + EXPECT_PATTERN_EQ_ATOMIC("~v", "?virtual"); +} -- cgit v1.2.3 From 8d4967d3a187dd66cf14b070a9db63f8ea21b21f Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 28 Jan 2020 21:46:10 +0100 Subject: patterns: Implement unary ! --- test/libapt/pattern_test.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'test/libapt/pattern_test.cc') diff --git a/test/libapt/pattern_test.cc b/test/libapt/pattern_test.cc index 492a29eac..39959cd31 100644 --- a/test/libapt/pattern_test.cc +++ b/test/libapt/pattern_test.cc @@ -158,4 +158,5 @@ TEST(TreeParserTest, ParseShortPattern) EXPECT_PATTERN_EQ_ATOMIC("~U", "?upgradable"); EXPECT_PATTERN_EQ("~Vverstr", "?version(verstr)"); EXPECT_PATTERN_EQ_ATOMIC("~v", "?virtual"); + EXPECT_PATTERN_EQ("!foo", "?not(foo)"); } -- cgit v1.2.3 From ebe5f39bfbb64921d5d31e0a6e49287356a5e6e2 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 28 Jan 2020 23:06:08 +0100 Subject: patterns: Allow bare words only in arguments This changes the syntax from approximately expr = unary unary = '!'? primary primary = pattern | short-pattern | word | quoted-word pattern = '?' name [ '(' expr [',' expr]* ')' ] short-pattern = ~ name | ~name expr to: primary = pattern | short-pattern argument = word | quoted-word | expr pattern = '?' name [ '(' argument [',' argument]* ')' ] short-pattern = ~ name | ~name argument --- test/libapt/pattern_test.cc | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'test/libapt/pattern_test.cc') diff --git a/test/libapt/pattern_test.cc b/test/libapt/pattern_test.cc index 39959cd31..7fc6a1f8f 100644 --- a/test/libapt/pattern_test.cc +++ b/test/libapt/pattern_test.cc @@ -16,19 +16,25 @@ using namespace APT::Internal; TEST(TreeParserTest, ParseWord) { - auto node = PatternTreeParser("word").parseTop(); - auto wordNode = dynamic_cast(node.get()); + auto node = PatternTreeParser("?word(word)").parseTop(); + auto patternNode = dynamic_cast(node.get()); + + ASSERT_EQ(patternNode->arguments.size(), 1u); + auto wordNode = dynamic_cast(patternNode->arguments[0].get()); - EXPECT_EQ(node.get(), wordNode); + EXPECT_EQ(patternNode->arguments[0].get(), wordNode); EXPECT_EQ(wordNode->word, "word"); } TEST(TreeParserTest, ParseQuotedWord) { - auto node = PatternTreeParser("\"a word\"").parseTop(); - auto wordNode = dynamic_cast(node.get()); + auto node = PatternTreeParser("?word(\"a word\")").parseTop(); + auto patternNode = dynamic_cast(node.get()); + + ASSERT_EQ(patternNode->arguments.size(), 1u); + auto wordNode = dynamic_cast(patternNode->arguments[0].get()); - EXPECT_EQ(node.get(), wordNode); + EXPECT_EQ(patternNode->arguments[0].get(), wordNode); EXPECT_EQ(wordNode->word, "a word"); } @@ -158,5 +164,16 @@ TEST(TreeParserTest, ParseShortPattern) EXPECT_PATTERN_EQ_ATOMIC("~U", "?upgradable"); EXPECT_PATTERN_EQ("~Vverstr", "?version(verstr)"); EXPECT_PATTERN_EQ_ATOMIC("~v", "?virtual"); - EXPECT_PATTERN_EQ("!foo", "?not(foo)"); + EXPECT_PATTERN_EQ("!?foo", "?not(?foo)"); + + caught = false; + try + { + PatternTreeParser("!x").parseTop(); + } + catch (PatternTreeParser::Error &e) + { + caught = true; + }; + EXPECT_TRUE(caught) << "!X should have thrown an exception"; } -- cgit v1.2.3 From 250119362e44599aad7e75462fa4298ad1ab1ad9 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 28 Jan 2020 22:38:46 +0100 Subject: patterns: Parse sequence of patterns as ?and --- test/libapt/pattern_test.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test/libapt/pattern_test.cc') diff --git a/test/libapt/pattern_test.cc b/test/libapt/pattern_test.cc index 7fc6a1f8f..00d356d47 100644 --- a/test/libapt/pattern_test.cc +++ b/test/libapt/pattern_test.cc @@ -176,4 +176,12 @@ TEST(TreeParserTest, ParseShortPattern) caught = true; }; EXPECT_TRUE(caught) << "!X should have thrown an exception"; + + EXPECT_PATTERN_EQ("?a?b", "?and(?a, ?b)"); + EXPECT_PATTERN_EQ("~T~F", "?and(?true, ?false)"); + EXPECT_PATTERN_EQ("~T ~F", "?and(?true, ?false)"); + EXPECT_PATTERN_EQ("~T !~F", "?and(?true, ?not(?false))"); + EXPECT_PATTERN_EQ("!~F ~T", "?and(?not(?false), ?true)"); + EXPECT_PATTERN_EQ("!~F~T", "?and(?not(?false), ?true)"); + } -- cgit v1.2.3 From d6f38436a229dc4421e77b58bf42d07bdb28b808 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 1 Feb 2020 17:12:35 +0100 Subject: Implement | as or --- test/libapt/pattern_test.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'test/libapt/pattern_test.cc') diff --git a/test/libapt/pattern_test.cc b/test/libapt/pattern_test.cc index 00d356d47..d8d962758 100644 --- a/test/libapt/pattern_test.cc +++ b/test/libapt/pattern_test.cc @@ -184,4 +184,7 @@ TEST(TreeParserTest, ParseShortPattern) EXPECT_PATTERN_EQ("!~F ~T", "?and(?not(?false), ?true)"); EXPECT_PATTERN_EQ("!~F~T", "?and(?not(?false), ?true)"); + EXPECT_PATTERN_EQ("!~F~T | ~T", "?or(?and(?not(?false), ?true), ?true)"); + EXPECT_PATTERN_EQ("~ramd64|~rall", "?or(?architecture(amd64), ?architecture(all))"); + } -- cgit v1.2.3 From 8886ea163032fb8bf64211a94c5dc252a4572a9c Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 1 Feb 2020 17:21:40 +0100 Subject: patterns: Implement parsing of (...) groups --- test/libapt/pattern_test.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test/libapt/pattern_test.cc') diff --git a/test/libapt/pattern_test.cc b/test/libapt/pattern_test.cc index d8d962758..ca77959e3 100644 --- a/test/libapt/pattern_test.cc +++ b/test/libapt/pattern_test.cc @@ -187,4 +187,8 @@ TEST(TreeParserTest, ParseShortPattern) EXPECT_PATTERN_EQ("!~F~T | ~T", "?or(?and(?not(?false), ?true), ?true)"); EXPECT_PATTERN_EQ("~ramd64|~rall", "?or(?architecture(amd64), ?architecture(all))"); + EXPECT_PATTERN_EQ("(?A|?B)?C", "?and(?or(?A, ?B), ?C)"); + EXPECT_PATTERN_EQ("?A|?B?C", "?or(?A, ?and(?B, ?C))"); + EXPECT_PATTERN_EQ("?A|(?B?C)", "?or(?A, ?and(?B, ?C))"); + EXPECT_PATTERN_EQ("(?B?C)|?A", "?or(?and(?B, ?C), ?A)"); } -- cgit v1.2.3 From 11a40ab11f72f85e905bdba4d3274870fbcaeaee Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 1 Feb 2020 17:33:08 +0100 Subject: Correctly stop parsing short form arguments on space, also on ? we have to stop parsing on space so that things like ~ramd64 | ~rall work correctly. aptitude does not stop parsing on ?, but we'll do as it gets very confusing otherwise if you write stuff like ~ramd64?name(foo), and it resolves to ?and(?architecture(amd64?name), (foo))... --- test/libapt/pattern_test.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test/libapt/pattern_test.cc') diff --git a/test/libapt/pattern_test.cc b/test/libapt/pattern_test.cc index ca77959e3..84d09351c 100644 --- a/test/libapt/pattern_test.cc +++ b/test/libapt/pattern_test.cc @@ -186,6 +186,8 @@ TEST(TreeParserTest, ParseShortPattern) EXPECT_PATTERN_EQ("!~F~T | ~T", "?or(?and(?not(?false), ?true), ?true)"); EXPECT_PATTERN_EQ("~ramd64|~rall", "?or(?architecture(amd64), ?architecture(all))"); + EXPECT_PATTERN_EQ("~ramd64 | ~rall", "?or(?architecture(amd64), ?architecture(all))"); + EXPECT_PATTERN_EQ("~ramd64?name(foo)", "?and(?architecture(amd64), ?name(foo))"); EXPECT_PATTERN_EQ("(?A|?B)?C", "?and(?or(?A, ?B), ?C)"); EXPECT_PATTERN_EQ("?A|?B?C", "?or(?A, ?and(?B, ?C))"); -- cgit v1.2.3 From 404771d0ec11f26a0b631018719e2918a049455b Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Mon, 3 Feb 2020 12:15:07 +0100 Subject: patterns: test for empty terms, reject them --- test/libapt/pattern_test.cc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'test/libapt/pattern_test.cc') diff --git a/test/libapt/pattern_test.cc b/test/libapt/pattern_test.cc index 84d09351c..bfcaf2093 100644 --- a/test/libapt/pattern_test.cc +++ b/test/libapt/pattern_test.cc @@ -14,6 +14,32 @@ using namespace APT::Internal; +#define EXPECT_EXCEPTION(exp, exc, msg) \ + caught = false; \ + try \ + { \ + exp; \ + } \ + catch (exc & e) \ + { \ + caught = true; \ + EXPECT_TRUE(e.message.find(msg) != std::string::npos) << msg << " not in " << e.message; \ + }; \ + EXPECT_TRUE(caught) << #exp "should have thrown an exception" + +TEST(TreeParserTest, ParseInvalid) +{ + bool caught = false; + + // Not a valid pattern: Reject + EXPECT_EXCEPTION(PatternTreeParser("?").parse(), PatternTreeParser::Error, "Pattern must have a term"); + EXPECT_EXCEPTION(PatternTreeParser("?AB?").parse(), PatternTreeParser::Error, "Pattern must have a term"); + EXPECT_EXCEPTION(PatternTreeParser("~").parse(), PatternTreeParser::Error, "Unknown short pattern"); + + // Not a pattern at all: Report nullptr + EXPECT_EQ(PatternTreeParser("A?").parse(), nullptr); +} + TEST(TreeParserTest, ParseWord) { auto node = PatternTreeParser("?word(word)").parseTop(); -- cgit v1.2.3