[lldb][NFCI] Add unittests for ObjCLanguage::MethodName
authorAlex Langford <alangford@apple.com>
Thu, 4 May 2023 00:41:58 +0000 (17:41 -0700)
committerAlex Langford <alangford@apple.com>
Thu, 4 May 2023 20:50:57 +0000 (13:50 -0700)
I have a patch to refactor this class and I'd like a unittest in place
to make sure I don't break anything.

Differential Revision: https://reviews.llvm.org/D149804

lldb/unittests/Language/CMakeLists.txt
lldb/unittests/Language/ObjC/CMakeLists.txt [new file with mode: 0644]
lldb/unittests/Language/ObjC/ObjCLanguageTest.cpp [new file with mode: 0644]

index 3cca831956ab676f1251a9827d445f46245ac8df..6f173568c76e69fde0013270facfe4695710f9a5 100644 (file)
@@ -1,3 +1,4 @@
 add_subdirectory(CPlusPlus)
 add_subdirectory(CLanguages)
 add_subdirectory(Highlighting)
+add_subdirectory(ObjC)
diff --git a/lldb/unittests/Language/ObjC/CMakeLists.txt b/lldb/unittests/Language/ObjC/CMakeLists.txt
new file mode 100644 (file)
index 0000000..82cc847
--- /dev/null
@@ -0,0 +1,6 @@
+add_lldb_unittest(LanguageObjCTests
+  ObjCLanguageTest.cpp
+
+  LINK_LIBS
+    lldbPluginObjCLanguage
+)
diff --git a/lldb/unittests/Language/ObjC/ObjCLanguageTest.cpp b/lldb/unittests/Language/ObjC/ObjCLanguageTest.cpp
new file mode 100644 (file)
index 0000000..e9cb5d1
--- /dev/null
@@ -0,0 +1,114 @@
+//===-- ObjCLanguageTest.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "Plugins/Language/ObjC/ObjCLanguage.h"
+#include "lldb/lldb-enumerations.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <optional>
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb_private;
+
+TEST(ObjCLanguage, MethodNameParsing) {
+  struct TestCase {
+    llvm::StringRef input;
+    llvm::StringRef full_name_sans_category;
+    llvm::StringRef class_name;
+    llvm::StringRef class_name_with_category;
+    llvm::StringRef category;
+    llvm::StringRef selector;
+  };
+
+  TestCase strict_cases[] = {
+      {"-[MyClass mySelector:]", "", "MyClass", "MyClass", "", "mySelector:"},
+      {"+[MyClass mySelector:]", "", "MyClass", "MyClass", "", "mySelector:"},
+      {"-[MyClass(my_category) mySelector:]", "-[MyClass mySelector:]",
+       "MyClass", "MyClass(my_category)", "my_category", "mySelector:"},
+      {"+[MyClass(my_category) mySelector:]", "+[MyClass mySelector:]",
+       "MyClass", "MyClass(my_category)", "my_category", "mySelector:"},
+  };
+
+  TestCase lax_cases[] = {
+      {"[MyClass mySelector:]", "", "MyClass", "MyClass", "", "mySelector:"},
+      {"[MyClass(my_category) mySelector:]", "[MyClass mySelector:]", "MyClass",
+       "MyClass(my_category)", "my_category", "mySelector:"},
+  };
+
+  // First, be strict
+  for (const auto &test : strict_cases) {
+    ObjCLanguage::MethodName method(test.input, /*strict = */ true);
+    EXPECT_TRUE(method.IsValid(/*strict = */ true));
+    EXPECT_EQ(
+        test.full_name_sans_category,
+        method.GetFullNameWithoutCategory(/*empty_if_no_category = */ true)
+            .GetStringRef());
+    EXPECT_EQ(test.class_name, method.GetClassName().GetStringRef());
+    EXPECT_EQ(test.class_name_with_category,
+              method.GetClassNameWithCategory().GetStringRef());
+    EXPECT_EQ(test.category, method.GetCategory().GetStringRef());
+    EXPECT_EQ(test.selector, method.GetSelector().GetStringRef());
+  }
+
+  // We should make sure strict parsing does not accept lax cases
+  for (const auto &test : lax_cases) {
+    ObjCLanguage::MethodName method(test.input, /*strict = */ true);
+    EXPECT_FALSE(method.IsValid(/*strict = */ true));
+  }
+
+  // All strict cases should work when not lax
+  for (const auto &test : strict_cases) {
+    ObjCLanguage::MethodName method(test.input, /*strict = */ false);
+    EXPECT_TRUE(method.IsValid(/*strict = */ false));
+    EXPECT_EQ(
+        test.full_name_sans_category,
+        method.GetFullNameWithoutCategory(/*empty_if_no_category = */ true)
+            .GetStringRef());
+    EXPECT_EQ(test.class_name, method.GetClassName().GetStringRef());
+    EXPECT_EQ(test.class_name_with_category,
+              method.GetClassNameWithCategory().GetStringRef());
+    EXPECT_EQ(test.category, method.GetCategory().GetStringRef());
+    EXPECT_EQ(test.selector, method.GetSelector().GetStringRef());
+  }
+
+  // Make sure non-strict parsing works
+  for (const auto &test : lax_cases) {
+    ObjCLanguage::MethodName method(test.input, /*strict = */ false);
+    EXPECT_TRUE(method.IsValid(/*strict = */ false));
+    EXPECT_EQ(
+        test.full_name_sans_category,
+        method.GetFullNameWithoutCategory(/*empty_if_no_category = */ true)
+            .GetStringRef());
+    EXPECT_EQ(test.class_name, method.GetClassName().GetStringRef());
+    EXPECT_EQ(test.class_name_with_category,
+              method.GetClassNameWithCategory().GetStringRef());
+    EXPECT_EQ(test.category, method.GetCategory().GetStringRef());
+    EXPECT_EQ(test.selector, method.GetSelector().GetStringRef());
+  }
+}
+
+TEST(CPlusPlusLanguage, InvalidMethodNameParsing) {
+  // Tests that we correctly reject malformed function names
+
+  llvm::StringRef test_cases[] = {"+[Uh oh!",
+                                  "-[Definitely not...",
+                                  "[Nice try ] :)",
+                                  "+MaybeIfYouSquintYourEyes]",
+                                  "?[Tricky]",
+                                  "+[]",
+                                  "-[]",
+                                  "[]"};
+
+  for (const auto &name : test_cases) {
+    ObjCLanguage::MethodName strict_method(name, /*strict = */ true);
+    EXPECT_FALSE(strict_method.IsValid(true));
+
+    ObjCLanguage::MethodName lax_method(name, /*strict = */ false);
+    EXPECT_FALSE(lax_method.IsValid(true));
+  }
+}