1 | //===-- ObjCLanguageTest.cpp ----------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | #include "Plugins/Language/ObjC/ObjCLanguage.h" |
9 | #include "lldb/lldb-enumerations.h" |
10 | #include "gmock/gmock.h" |
11 | #include "gtest/gtest.h" |
12 | #include <optional> |
13 | |
14 | #include "llvm/ADT/StringRef.h" |
15 | |
16 | using namespace lldb_private; |
17 | |
18 | TEST(ObjCLanguage, MethodNameParsing) { |
19 | struct TestCase { |
20 | llvm::StringRef input; |
21 | llvm::StringRef full_name_sans_category; |
22 | llvm::StringRef class_name; |
23 | llvm::StringRef class_name_with_category; |
24 | llvm::StringRef category; |
25 | llvm::StringRef selector; |
26 | }; |
27 | |
28 | TestCase strict_cases[] = { |
29 | {.input: "-[MyClass mySelector:]" , .full_name_sans_category: "" , .class_name: "MyClass" , .class_name_with_category: "MyClass" , .category: "" , .selector: "mySelector:" }, |
30 | {.input: "+[MyClass mySelector:]" , .full_name_sans_category: "" , .class_name: "MyClass" , .class_name_with_category: "MyClass" , .category: "" , .selector: "mySelector:" }, |
31 | {.input: "-[MyClass(my_category) mySelector:]" , .full_name_sans_category: "-[MyClass mySelector:]" , |
32 | .class_name: "MyClass" , .class_name_with_category: "MyClass(my_category)" , .category: "my_category" , .selector: "mySelector:" }, |
33 | {.input: "+[MyClass(my_category) mySelector:]" , .full_name_sans_category: "+[MyClass mySelector:]" , |
34 | .class_name: "MyClass" , .class_name_with_category: "MyClass(my_category)" , .category: "my_category" , .selector: "mySelector:" }, |
35 | }; |
36 | |
37 | TestCase lax_cases[] = { |
38 | {.input: "[MyClass mySelector:]" , .full_name_sans_category: "" , .class_name: "MyClass" , .class_name_with_category: "MyClass" , .category: "" , .selector: "mySelector:" }, |
39 | {.input: "[MyClass(my_category) mySelector:]" , .full_name_sans_category: "[MyClass mySelector:]" , .class_name: "MyClass" , |
40 | .class_name_with_category: "MyClass(my_category)" , .category: "my_category" , .selector: "mySelector:" }, |
41 | }; |
42 | |
43 | // First, be strict |
44 | for (const auto &test : strict_cases) { |
45 | std::optional<const ObjCLanguage::MethodName> method = |
46 | ObjCLanguage::MethodName::Create(name: test.input, /*strict = */ true); |
47 | EXPECT_TRUE(method.has_value()); |
48 | EXPECT_EQ(test.full_name_sans_category, |
49 | method->GetFullNameWithoutCategory()); |
50 | EXPECT_EQ(test.class_name, method->GetClassName()); |
51 | EXPECT_EQ(test.class_name_with_category, |
52 | method->GetClassNameWithCategory()); |
53 | EXPECT_EQ(test.category, method->GetCategory()); |
54 | EXPECT_EQ(test.selector, method->GetSelector()); |
55 | } |
56 | |
57 | // We should make sure strict parsing does not accept lax cases |
58 | for (const auto &test : lax_cases) { |
59 | std::optional<const ObjCLanguage::MethodName> method = |
60 | ObjCLanguage::MethodName::Create(name: test.input, /*strict = */ true); |
61 | EXPECT_FALSE(method.has_value()); |
62 | } |
63 | |
64 | // All strict cases should work when not lax |
65 | for (const auto &test : strict_cases) { |
66 | std::optional<const ObjCLanguage::MethodName> method = |
67 | ObjCLanguage::MethodName::Create(name: test.input, /*strict = */ false); |
68 | EXPECT_TRUE(method.has_value()); |
69 | EXPECT_EQ(test.full_name_sans_category, |
70 | method->GetFullNameWithoutCategory()); |
71 | EXPECT_EQ(test.class_name, method->GetClassName()); |
72 | EXPECT_EQ(test.class_name_with_category, |
73 | method->GetClassNameWithCategory()); |
74 | EXPECT_EQ(test.category, method->GetCategory()); |
75 | EXPECT_EQ(test.selector, method->GetSelector()); |
76 | } |
77 | |
78 | // Make sure non-strict parsing works |
79 | for (const auto &test : lax_cases) { |
80 | std::optional<const ObjCLanguage::MethodName> method = |
81 | ObjCLanguage::MethodName::Create(name: test.input, /*strict = */ false); |
82 | EXPECT_TRUE(method.has_value()); |
83 | EXPECT_EQ(test.full_name_sans_category, |
84 | method->GetFullNameWithoutCategory()); |
85 | EXPECT_EQ(test.class_name, method->GetClassName()); |
86 | EXPECT_EQ(test.class_name_with_category, |
87 | method->GetClassNameWithCategory()); |
88 | EXPECT_EQ(test.category, method->GetCategory()); |
89 | EXPECT_EQ(test.selector, method->GetSelector()); |
90 | } |
91 | } |
92 | |
93 | TEST(ObjCLanguage, InvalidMethodNameParsing) { |
94 | // Tests that we correctly reject malformed function names |
95 | |
96 | llvm::StringRef test_cases[] = {"+[Uh oh!" , |
97 | "-[Definitely not..." , |
98 | "[Nice try ] :)" , |
99 | "+MaybeIfYouSquintYourEyes]" , |
100 | "?[Tricky]" , |
101 | "+[]" , |
102 | "-[]" , |
103 | "[]" }; |
104 | |
105 | for (const auto &name : test_cases) { |
106 | std::optional<const ObjCLanguage::MethodName> strict_method = |
107 | ObjCLanguage::MethodName::Create(name, /*strict = */ false); |
108 | EXPECT_FALSE(strict_method.has_value()); |
109 | |
110 | std::optional<const ObjCLanguage::MethodName> lax_method = |
111 | ObjCLanguage::MethodName::Create(name, /*strict = */ false); |
112 | EXPECT_FALSE(lax_method.has_value()); |
113 | } |
114 | } |
115 | |