| // Copyright 2019 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "src/developer/debug/zxdb/expr/identifier_glob.h" | |
| #include <lib/syslog/cpp/macros.h> | |
| #include <gtest/gtest.h> | |
| #include "src/developer/debug/zxdb/expr/expr_parser.h" | |
| namespace zxdb { | |
| namespace { | |
| using Score = std::optional<int>; | |
| // Parses the given idetifier and asserts success. Used for constant input in this test. | |
| ParsedIdentifier Parse(const std::string& s) { | |
| ParsedIdentifier result; | |
| Err err = ExprParser::ParseIdentifier(s, &result); | |
| FX_CHECK(!err.has_error()) << err.msg(); | |
| return result; | |
| } | |
| } // namespace | |
| TEST(IdentifierGlob, Exact) { | |
| IdentifierGlob myclass; | |
| ASSERT_FALSE(myclass.Init("MyClass").has_error()); | |
| // Exact match. | |
| EXPECT_EQ(Score(0), myclass.Matches(Parse("MyClass"))); | |
| // The identifier parser will trim whitespace. | |
| EXPECT_EQ(Score(0), myclass.Matches(Parse("MyClass "))); | |
| EXPECT_EQ(Score(0), myclass.Matches(Parse(" MyClass"))); | |
| // Non-matches. | |
| EXPECT_EQ(std::nullopt, myclass.Matches(Parse("MyClassA"))); | |
| EXPECT_EQ(std::nullopt, myclass.Matches(Parse("MyClas"))); | |
| EXPECT_EQ(std::nullopt, myclass.Matches(Parse("myclass"))); | |
| EXPECT_EQ(std::nullopt, myclass.Matches(Parse("MyClass<>"))); | |
| // Global qualification in either direction doesn't matter. | |
| IdentifierGlob global_myclass; | |
| ASSERT_FALSE(global_myclass.Init("::MyClass").has_error()); | |
| EXPECT_EQ(Score(0), global_myclass.Matches(Parse("::MyClass"))); | |
| EXPECT_EQ(Score(0), global_myclass.Matches(Parse("MyClass"))); | |
| } | |
| TEST(IdentifierGlob, EmptyTemplates) { | |
| IdentifierGlob no_star; | |
| ASSERT_FALSE(no_star.Init("MyClass<>").has_error()); | |
| // Template existance must match. | |
| EXPECT_EQ(Score(0), no_star.Matches(Parse("MyClass<>"))); // Technically invalid C++. | |
| EXPECT_EQ(std::nullopt, no_star.Matches(Parse("MyClass"))); | |
| } | |
| TEST(IdentifierGlob, OneTemplate) { | |
| IdentifierGlob one_star; | |
| ASSERT_FALSE(one_star.Init("MyClass<*>").has_error()); | |
| // "*" won't match no template params. | |
| EXPECT_EQ(std::nullopt, one_star.Matches(Parse("MyClass<>"))); | |
| // String globs will match this, but our identifier one won't. | |
| EXPECT_EQ(std::nullopt, one_star.Matches(Parse("MyClass<int>::Something<int>"))); | |
| // Will eat multiple params. | |
| EXPECT_EQ(Score(1), one_star.Matches(Parse("MyClass<int>"))); | |
| EXPECT_EQ(Score(2), one_star.Matches(Parse("MyClass<int, int>"))); | |
| EXPECT_EQ(Score(3), one_star.Matches(Parse("MyClass<int,int,double>"))); | |
| } | |
| TEST(IdentifierGlob, TwoTemplate) { | |
| IdentifierGlob one_star; | |
| ASSERT_FALSE(one_star.Init("MyClass<*,*>").has_error()); | |
| // Won't match fewer template params. | |
| EXPECT_EQ(std::nullopt, one_star.Matches(Parse("MyClass<>"))); | |
| EXPECT_EQ(std::nullopt, one_star.Matches(Parse("MyClass<int>"))); | |
| EXPECT_EQ(std::nullopt, one_star.Matches(Parse("MyClass<Something<Foo>>"))); | |
| EXPECT_EQ(Score(1), one_star.Matches(Parse("MyClass<int, Something<Foo>>"))); | |
| EXPECT_EQ(Score(2), one_star.Matches(Parse("MyClass<int,int,double>"))); | |
| } | |
| TEST(IdentifierGlob, LiteralTemplate) { | |
| IdentifierGlob one_lit; | |
| ASSERT_FALSE(one_lit.Init("MyClass<int>").has_error()); | |
| EXPECT_EQ(std::nullopt, one_lit.Matches(Parse("MyClass<>"))); | |
| EXPECT_EQ(std::nullopt, one_lit.Matches(Parse("MyClass<float>"))); | |
| EXPECT_EQ(std::nullopt, one_lit.Matches(Parse("MyClass<int, int>"))); | |
| EXPECT_EQ(std::nullopt, one_lit.Matches(Parse("MyClass<int*>"))); | |
| EXPECT_EQ(Score(0), one_lit.Matches(Parse("MyClass<int>"))); | |
| // * not by itself is a literal (in this case, a pointer). | |
| IdentifierGlob lit_ptr; | |
| ASSERT_FALSE(lit_ptr.Init("MyClass<int*>").has_error()); | |
| EXPECT_EQ(std::nullopt, lit_ptr.Matches(Parse("MyClass<int>"))); | |
| EXPECT_EQ(Score(0), lit_ptr.Matches(Parse("MyClass<int* >"))); | |
| IdentifierGlob two_lit; | |
| ASSERT_FALSE(two_lit.Init("MyClass<int, float>").has_error()); | |
| EXPECT_EQ(std::nullopt, two_lit.Matches(Parse("MyClass<int, int>"))); | |
| EXPECT_EQ(Score(0), two_lit.Matches(Parse("MyClass <int,float >"))); | |
| } | |
| TEST(IdentifierGlob, StarLiteralTemplate) { | |
| IdentifierGlob star_lit; | |
| ASSERT_FALSE(star_lit.Init("MyClass<*, int>").has_error()); | |
| EXPECT_EQ(std::nullopt, star_lit.Matches(Parse("MyClass<int>"))); | |
| EXPECT_EQ(Score(1), star_lit.Matches(Parse("MyClass<double,int>"))); | |
| // "*" not greedy unless last. | |
| EXPECT_EQ(std::nullopt, star_lit.Matches(Parse("MyClass<double, double, int>"))); | |
| EXPECT_EQ(std::nullopt, star_lit.Matches(Parse("MyClass<double, int, double>"))); | |
| } | |
| TEST(IdentifierGlob, LiteralStarTemplate) { | |
| IdentifierGlob lit_star; | |
| ASSERT_FALSE(lit_star.Init("MyClass<int,*>").has_error()); | |
| EXPECT_EQ(std::nullopt, lit_star.Matches(Parse("MyClass<int>"))); | |
| EXPECT_EQ(Score(1), lit_star.Matches(Parse("MyClass<int,int>"))); | |
| EXPECT_EQ(Score(2), lit_star.Matches(Parse("MyClass<int,double,float>"))); | |
| } | |
| } // namespace zxdb |