-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libclang/python] Improve test coverage #109846
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Achieve 100% test coverage on classes Cursor, Diagnostic, Type
@llvm/pr-subscribers-clang Author: Jannick Kremer (DeinAlptraum) ChangesAchieve 100% test coverage on classes Cursor, Diagnostic, Type. Full diff: https://github.com/llvm/llvm-project/pull/109846.diff 3 Files Affected:
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py
index 7476947bde2ea6..77d8ca415708f8 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -14,6 +14,7 @@
from clang.cindex import TranslationUnit
from clang.cindex import TypeKind
from clang.cindex import BinaryOperator
+from clang.cindex import StorageClass
from .util import get_cursor
from .util import get_cursors
from .util import get_tu
@@ -279,6 +280,90 @@ def test_is_default_method(self):
self.assertTrue(xc.is_default_method())
self.assertFalse(yc.is_default_method())
+ def test_is_deleted_method(self):
+ source = "class X { X() = delete; }; class Y { Y(); };"
+ tu = get_tu(source, lang="cpp")
+
+ xs = get_cursors(tu, "X")
+ ys = get_cursors(tu, "Y")
+
+ self.assertEqual(len(xs), 2)
+ self.assertEqual(len(ys), 2)
+
+ xc = xs[1]
+ yc = ys[1]
+
+ self.assertTrue(xc.is_deleted_method())
+ self.assertFalse(yc.is_deleted_method())
+
+ def test_is_copy_assignment_operator_method(self):
+ source_with_copy_assignment_operators = """
+ struct Foo {
+ // Those are copy-assignment operators
+ bool operator=(const Foo&);
+ bool operator=(Foo&);
+ Foo operator=(Foo);
+ bool operator=(volatile Foo&);
+ bool operator=(const volatile Foo&);
+
+ // Positive-check that the recognition works for templated classes too
+ template <typename T>
+ class Bar {
+ bool operator=(const Bar&);
+ Bar operator=(const Bar);
+ bool operator=(Bar<T>&);
+ bool operator=(volatile Bar&);
+ bool operator=(const volatile Bar<T>&);
+ };
+ """
+ source_without_copy_assignment_operators = """
+ struct Foo {
+ // Those are not copy-assignment operators
+ template<typename T>
+ bool operator=(const T&);
+ bool operator=(const bool&);
+ bool operator=(char&);
+ bool operator=(volatile unsigned int&);
+ bool operator=(const volatile unsigned char&);
+ bool operator=(int);
+ bool operator=(Foo&&);
+ };
+ """
+ tu_with_copy_assignment_operators = get_tu(
+ source_with_copy_assignment_operators, lang="cpp"
+ )
+ tu_without_copy_assignment_operators = get_tu(
+ source_without_copy_assignment_operators, lang="cpp"
+ )
+
+ copy_assignment_operators_cursors = get_cursors(
+ tu_with_copy_assignment_operators, "operator="
+ )
+ non_copy_assignment_operators_cursors = get_cursors(
+ tu_without_copy_assignment_operators, "operator="
+ )
+
+ self.assertEqual(len(copy_assignment_operators_cursors), 10)
+ self.assertTrue(len(non_copy_assignment_operators_cursors), 9)
+
+ self.assertTrue(
+ all(
+ [
+ cursor.is_copy_assignment_operator_method()
+ for cursor in copy_assignment_operators_cursors
+ ]
+ )
+ )
+
+ self.assertFalse(
+ any(
+ [
+ cursor.is_copy_assignment_operator_method()
+ for cursor in non_copy_assignment_operators_cursors
+ ]
+ )
+ )
+
def test_is_move_assignment_operator_method(self):
"""Ensure Cursor.is_move_assignment_operator_method works."""
source_with_move_assignment_operators = """
@@ -482,6 +567,41 @@ def test_is_scoped_enum(self):
self.assertFalse(regular_enum.is_scoped_enum())
self.assertTrue(scoped_enum.is_scoped_enum())
+ def test_get_definition(self):
+ """Ensure Cursor.get_definition works."""
+ tu = get_tu(
+ """
+class A {
+ constexpr static int f(){return 3;}
+};
+struct B {
+ int b = A::f();
+};
+""",
+ lang="cpp",
+ )
+ curs = get_cursors(tu, "f")
+ self.assertEqual(len(curs), 4)
+ self.assertEqual(curs[0].kind, CursorKind.CXX_METHOD)
+ self.assertEqual(curs[1].get_definition(), curs[0])
+ self.assertEqual(curs[2].get_definition(), curs[0])
+ self.assertEqual(curs[3].get_definition(), curs[0])
+
+ def test_get_usr(self):
+ """Ensure Cursor.get_usr works."""
+ tu = get_tu(
+ """
+int add(int, int);
+int add(int a, int b) { return a + b; }
+int add(float a, float b) { return a + b; }
+""",
+ lang="cpp",
+ )
+ curs = get_cursors(tu, "add")
+ self.assertEqual(len(curs), 3)
+ self.assertEqual(curs[0].get_usr(), curs[1].get_usr())
+ self.assertNotEqual(curs[0].get_usr(), curs[2].get_usr())
+
def test_underlying_type(self):
tu = get_tu("typedef int foo;")
typedef = get_cursor(tu, "foo")
@@ -570,6 +690,23 @@ def test_enum_values_cpp(self):
self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(ham.enum_value, 0x10000000000)
+ def test_enum_values_unsigned(self):
+ tu = get_tu("enum TEST : unsigned char { SPAM=0, HAM = 200};", lang="cpp")
+ enum = get_cursor(tu, "TEST")
+ self.assertIsNotNone(enum)
+
+ self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
+
+ enum_constants = list(enum.get_children())
+ self.assertEqual(len(enum_constants), 2)
+
+ spam, ham = enum_constants
+
+ self.assertEqual(spam.kind, CursorKind.ENUM_CONSTANT_DECL)
+ self.assertEqual(spam.enum_value, 0)
+ self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
+ self.assertEqual(ham.enum_value, 200)
+
def test_annotation_attribute(self):
tu = get_tu(
'int foo (void) __attribute__ ((annotate("here be annotation attribute")));'
@@ -625,6 +762,25 @@ def test_result_type_objc_method_decl(self):
self.assertEqual(cursor.kind, CursorKind.OBJC_INSTANCE_METHOD_DECL)
self.assertEqual(result_type.kind, TypeKind.VOID)
+ def test_storage_class(self):
+ tu = get_tu(
+ """
+extern int ex;
+register int reg;
+int count(int a, int b){
+ static int counter = 0;
+ return 0;
+}
+""",
+ lang="cpp",
+ )
+ cursor = get_cursor(tu, "ex")
+ self.assertEqual(cursor.storage_class, StorageClass.EXTERN)
+ cursor = get_cursor(tu, "counter")
+ self.assertEqual(cursor.storage_class, StorageClass.STATIC)
+ cursor = get_cursor(tu, "reg")
+ self.assertEqual(cursor.storage_class, StorageClass.REGISTER)
+
def test_availability(self):
tu = get_tu("class A { A(A const&) = delete; };", lang="cpp")
@@ -681,6 +837,23 @@ def test_get_token_cursor(self):
r_cursor = t_cursor.referenced # should not raise an exception
self.assertEqual(r_cursor.kind, CursorKind.CLASS_DECL)
+ def test_get_field_offsetof(self):
+ tu = get_tu(
+ "struct myStruct {int a; char b; char c; short d; char e;};", lang="cpp"
+ )
+ c1 = get_cursor(tu, "myStruct")
+ c2 = get_cursor(tu, "a")
+ c3 = get_cursor(tu, "b")
+ c4 = get_cursor(tu, "c")
+ c5 = get_cursor(tu, "d")
+ c6 = get_cursor(tu, "e")
+ self.assertEqual(c1.get_field_offsetof(), -1)
+ self.assertEqual(c2.get_field_offsetof(), 0)
+ self.assertEqual(c3.get_field_offsetof(), 32)
+ self.assertEqual(c4.get_field_offsetof(), 40)
+ self.assertEqual(c5.get_field_offsetof(), 48)
+ self.assertEqual(c6.get_field_offsetof(), 64)
+
def test_get_arguments(self):
tu = get_tu("void foo(int i, int j);")
foo = get_cursor(tu, "foo")
@@ -799,3 +972,13 @@ def test_binop(self):
for op, typ in operators.items():
c = get_cursor(tu, op)
assert c.binary_operator == typ
+
+ def test_from_result_null(self):
+ tu = get_tu("int a = 1+2;", lang="cpp")
+ op = next(next(tu.cursor.get_children()).get_children())
+ self.assertEqual(op.kind, CursorKind.BINARY_OPERATOR)
+ self.assertEqual(op.get_definition(), None)
+
+ def test_from_cursor_result_null(self):
+ tu = get_tu("")
+ self.assertEqual(tu.cursor.semantic_parent, None)
diff --git a/clang/bindings/python/tests/cindex/test_diagnostics.py b/clang/bindings/python/tests/cindex/test_diagnostics.py
index 57c41baaa25419..041083d12c7f16 100644
--- a/clang/bindings/python/tests/cindex/test_diagnostics.py
+++ b/clang/bindings/python/tests/cindex/test_diagnostics.py
@@ -46,6 +46,8 @@ def test_diagnostic_fixit(self):
self.assertEqual(tu.diagnostics[0].location.column, 26)
self.assertRegex(tu.diagnostics[0].spelling, "use of GNU old-style.*")
self.assertEqual(len(tu.diagnostics[0].fixits), 1)
+ with self.assertRaises(IndexError):
+ tu.diagnostics[0].fixits[1]
self.assertEqual(tu.diagnostics[0].fixits[0].range.start.line, 1)
self.assertEqual(tu.diagnostics[0].fixits[0].range.start.column, 26)
self.assertEqual(tu.diagnostics[0].fixits[0].range.end.line, 1)
@@ -97,6 +99,8 @@ def test_diagnostic_children(self):
children = d.children
self.assertEqual(len(children), 1)
+ with self.assertRaises(IndexError):
+ children[1]
self.assertEqual(children[0].severity, Diagnostic.Note)
self.assertRegex(children[0].spelling, ".*declared here")
self.assertEqual(children[0].location.line, 1)
@@ -111,3 +115,16 @@ def test_diagnostic_string_repr(self):
repr(d),
"<Diagnostic severity 3, location <SourceLocation file 't.c', line 1, column 26>, spelling \"expected ';' after struct\">",
)
+
+ def test_diagnostic_string_format(self):
+ tu = get_tu("struct MissingSemicolon{}")
+ self.assertEqual(len(tu.diagnostics), 1)
+ d = tu.diagnostics[0]
+
+ self.assertEqual(str(d), "t.c:1:26: error: expected ';' after struct")
+ self.assertEqual(
+ d.format(0b111111),
+ "t.c:1:26: error: expected ';' after struct [3, Parse Issue]",
+ )
+ with self.assertRaises(ValueError):
+ d.format(0b1000000)
diff --git a/clang/bindings/python/tests/cindex/test_type.py b/clang/bindings/python/tests/cindex/test_type.py
index 1dd8db0e3e814c..c8769c121cad8c 100644
--- a/clang/bindings/python/tests/cindex/test_type.py
+++ b/clang/bindings/python/tests/cindex/test_type.py
@@ -10,7 +10,9 @@
from clang.cindex import CursorKind
from clang.cindex import TranslationUnit
from clang.cindex import TypeKind
+from clang.cindex import RefQualifierKind
from .util import get_cursor
+from .util import get_cursors
from .util import get_tu
@@ -308,10 +310,10 @@ def test_element_type(self):
def test_invalid_element_type(self):
"""Ensure Type.element_type raises if type doesn't have elements."""
tu = get_tu("int i;")
- i = get_cursor(tu, "i")
- self.assertIsNotNone(i)
- with self.assertRaises(Exception):
- i.element_type
+ ty = get_cursor(tu, "i").type
+ with self.assertRaises(Exception) as ctx:
+ ty.element_type
+ self.assertEqual(str(ctx.exception), "Element type not available on this type.")
def test_element_count(self):
"""Ensure Type.element_count works."""
@@ -357,6 +359,50 @@ def test_is_restrict_qualified(self):
self.assertTrue(i.type.is_restrict_qualified())
self.assertFalse(j.type.is_restrict_qualified())
+ def test_get_result(self):
+ tu = get_tu("void foo(); int bar(char, short);")
+ foo = get_cursor(tu, "foo")
+ bar = get_cursor(tu, "bar")
+ self.assertEqual(foo.type.get_result().spelling, "void")
+ self.assertEqual(bar.type.get_result().spelling, "int")
+
+ def test_get_class_type(self):
+ tu = get_tu(
+ """
+class myClass
+{
+ char *myAttr;
+};
+
+char *myClass::*pMyAttr = &myClass::myAttr;
+""",
+ lang="cpp",
+ )
+ cur = get_cursor(tu, "pMyAttr")
+ self.assertEqual(cur.type.get_class_type().spelling, "myClass")
+
+ def test_get_named_type(self):
+ tu = get_tu("using char_alias = char; char_alias xyz;", lang="cpp")
+ cur = get_cursor(tu, "xyz")
+ self.assertEqual(cur.type.kind, TypeKind.ELABORATED)
+ self.assertEqual(cur.type.get_named_type().spelling, "char_alias")
+
+ def test_get_ref_qualifier(self):
+ tu = get_tu(
+ """
+class A
+{
+ const int& getAttr() const &;
+ int getAttr() const &&;
+};
+""",
+ lang="cpp",
+ )
+ getters = get_cursors(tu, "getAttr")
+ self.assertEqual(len(getters), 2)
+ self.assertEqual(getters[0].type.get_ref_qualifier(), RefQualifierKind.LVALUE)
+ self.assertEqual(getters[1].type.get_ref_qualifier(), RefQualifierKind.RVALUE)
+
def test_record_layout(self):
"""Ensure Cursor.type.get_size, Cursor.type.get_align and
Cursor.type.get_offset works."""
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to admit I can't assess the completeness of those tests, but they are certainly welcome. Thank you!
Achieve 100% test coverage on classes Cursor, Diagnostic, Type.
This mistake was introduced in #109846
This mistake was introduced in llvm#109846
This mistake was introduced in llvm#109846
Achieve 100% test coverage on classes Cursor, Diagnostic, Type.