11import fake_module
22import pytest
3+ import types
34
45from citation_compass import (
56 cite_function ,
@@ -31,13 +32,44 @@ def example_function_x(x):
3132 return x
3233
3334
35+ class _FakeTestingClass :
36+ """A fake class for testing."""
37+
38+ def __init__ (self , data = 1 ):
39+ self .data = data
40+
41+ @classmethod
42+ @cite_function
43+ def fake_class_classmethod (cls ):
44+ """A fake classmethod for testing."""
45+ return cls (data = 1 )
46+
47+ @staticmethod
48+ @cite_function
49+ def fake_class_staticmethod ():
50+ """A fake staticmethod for testing."""
51+ return 0
52+
53+ @cite_function
54+ def fake_class_normal_method (self ):
55+ """A fake normal class method for testing."""
56+ return self .data
57+
58+ def uncited_method (self ):
59+ """A method that is not cited."""
60+ return self .data
61+
62+
3463def test_citations_all ():
3564 """Check that all the citations are registered."""
3665 known_citations = [
3766 # The functions defined in this file.
3867 "test_citation.example_function_1: function_citation_1" ,
3968 "test_citation.example_function_2: function_citation_2" ,
4069 "test_citation.example_function_x: function_citation_x" ,
70+ "test_citation._FakeTestingClass.fake_class_classmethod: A fake classmethod for testing." ,
71+ "test_citation._FakeTestingClass.fake_class_staticmethod: A fake staticmethod for testing." ,
72+ "test_citation._FakeTestingClass.fake_class_normal_method: A fake normal class method for testing." ,
4173 # The items defined in fake_module.
4274 "fake_module: CitationCompass, 2025." ,
4375 "fake_module.FakeClass.fake_method: A fake class method for testing." ,
@@ -60,8 +92,8 @@ def test_citations_all():
6092 obj = fake_module .FakeCitedClass ()
6193 assert isinstance (obj , fake_module .FakeCitedClass )
6294
63- # A citation with no docstring, but a label.
64- @cite_function ("function_citation_3" )
95+ # A citation with no docstring, but a manual label.
96+ @cite_function (label = "function_citation_3" )
6597 def example_function_3 ():
6698 return 3
6799
@@ -238,6 +270,50 @@ def test_find_in_citations():
238270 assert len (find_in_citations ("FakeCitedClass" , True )) == 1
239271
240272
273+ def test_functions_in_class ():
274+ """Test that we correctly handle methods in a class including static and class methods."""
275+ obj = _FakeTestingClass (data = 5 )
276+
277+ # Nothing is used.
278+ assert len (find_in_citations ("fake_class_normal_method" , True )) == 0
279+ assert len (find_in_citations ("fake_class_staticmethod" , True )) == 0
280+ assert len (find_in_citations ("fake_class_classmethod" , True )) == 0
281+
282+ # All the functions are usable.
283+ assert obj .fake_class_normal_method () == 5
284+ assert obj .fake_class_staticmethod () == 0
285+
286+ obj2 = obj .fake_class_classmethod ()
287+ assert isinstance (obj2 , _FakeTestingClass )
288+ assert obj2 .data == 1
289+
290+ # Everything is now cited.
291+ assert len (find_in_citations ("fake_class_normal_method" , True )) == 1
292+ assert len (find_in_citations ("fake_class_staticmethod" , True )) == 1
293+ assert len (find_in_citations ("fake_class_classmethod" , True )) == 1
294+
295+ # We preserve the types of each method when called from the class. The class method
296+ # static method should be those types.
297+ assert isinstance (_FakeTestingClass .__dict__ ["fake_class_normal_method" ], types .FunctionType )
298+ assert isinstance (_FakeTestingClass .__dict__ ["fake_class_staticmethod" ], staticmethod )
299+ assert isinstance (_FakeTestingClass .__dict__ ["fake_class_classmethod" ], classmethod )
300+
301+ # Check the types when accessing an instance.
302+ assert isinstance (obj .fake_class_normal_method , types .MethodType )
303+ assert isinstance (obj .fake_class_staticmethod , types .FunctionType )
304+ assert isinstance (obj .fake_class_classmethod , types .MethodType )
305+
306+ # We preserve the names of the methods.
307+ assert obj .fake_class_classmethod .__name__ == "fake_class_classmethod"
308+ assert obj .fake_class_staticmethod .__name__ == "fake_class_staticmethod"
309+ assert obj .fake_class_normal_method .__name__ == "fake_class_normal_method"
310+
311+ # We preserve the docstring of the methods.
312+ assert obj .fake_class_classmethod .__doc__ == "A fake classmethod for testing."
313+ assert obj .fake_class_staticmethod .__doc__ == "A fake staticmethod for testing."
314+ assert obj .fake_class_normal_method .__doc__ == "A fake normal class method for testing."
315+
316+
241317def test_citation_context ():
242318 """Test the CitationContext class."""
243319 reset_used_citations ()
0 commit comments