@@ -36,6 +36,16 @@ class FakeManager(base.RESTManager):
3636_path = "/tests"
3737
3838
39+ class FakeParent :
40+ id = 42
41+
42+
43+ class FakeManagerWithParent (base .RESTManager ):
44+ _path = "/tests/{test_id}/cases"
45+ _obj_cls = FakeObject
46+ _from_parent_attrs = {"test_id" :"id" }
47+
48+
3949@pytest .fixture
4050def fake_gitlab ():
4151return FakeGitlab ()
@@ -46,6 +56,21 @@ def fake_manager(fake_gitlab):
4656return FakeManager (fake_gitlab )
4757
4858
59+ @pytest .fixture
60+ def fake_manager_with_parent (fake_gitlab ):
61+ return FakeManagerWithParent (fake_gitlab ,parent = FakeParent )
62+
63+
64+ @pytest .fixture
65+ def fake_object (fake_manager ):
66+ return FakeObject (fake_manager , {"attr1" :"foo" ,"alist" : [1 ,2 ,3 ]})
67+
68+
69+ @pytest .fixture
70+ def fake_object_with_parent (fake_manager_with_parent ):
71+ return FakeObject (fake_manager_with_parent , {"attr1" :"foo" ,"alist" : [1 ,2 ,3 ]})
72+
73+
4974class TestRESTManager :
5075def test_computed_path_simple (self ):
5176class MGR (base .RESTManager ):
@@ -306,3 +331,75 @@ def test_repr(self, fake_manager):
306331
307332FakeObject ._id_attr = None
308333assert repr (obj )== "<FakeObject>"
334+
335+ def test_attributes_get (self ,fake_object ):
336+ assert fake_object .attr1 == "foo"
337+ result = fake_object .attributes
338+ assert result == {"attr1" :"foo" ,"alist" : [1 ,2 ,3 ]}
339+
340+ def test_attributes_shows_updates (self ,fake_object ):
341+ # Updated attribute value is reflected in `attributes`
342+ fake_object .attr1 = "hello"
343+ assert fake_object .attributes == {"attr1" :"hello" ,"alist" : [1 ,2 ,3 ]}
344+ assert fake_object .attr1 == "hello"
345+ # New attribute is in `attributes`
346+ fake_object .new_attrib = "spam"
347+ assert fake_object .attributes == {
348+ "attr1" :"hello" ,
349+ "new_attrib" :"spam" ,
350+ "alist" : [1 ,2 ,3 ],
351+ }
352+
353+ def test_attributes_is_copy (self ,fake_object ):
354+ # Modifying the dictionary does not cause modifications to the object
355+ result = fake_object .attributes
356+ result ["alist" ].append (10 )
357+ assert result == {"attr1" :"foo" ,"alist" : [1 ,2 ,3 ,10 ]}
358+ assert fake_object .attributes == {"attr1" :"foo" ,"alist" : [1 ,2 ,3 ]}
359+
360+ def test_attributes_has_parent_attrs (self ,fake_object_with_parent ):
361+ assert fake_object_with_parent .attr1 == "foo"
362+ result = fake_object_with_parent .attributes
363+ assert result == {"attr1" :"foo" ,"alist" : [1 ,2 ,3 ],"test_id" :"42" }
364+
365+ def test_asdict (self ,fake_object ):
366+ assert fake_object .attr1 == "foo"
367+ result = fake_object .asdict ()
368+ assert result == {"attr1" :"foo" ,"alist" : [1 ,2 ,3 ]}
369+
370+ def test_asdict_no_parent_attrs (self ,fake_object_with_parent ):
371+ assert fake_object_with_parent .attr1 == "foo"
372+ result = fake_object_with_parent .asdict ()
373+ assert result == {"attr1" :"foo" ,"alist" : [1 ,2 ,3 ]}
374+ assert "test_id" not in fake_object_with_parent .asdict ()
375+ assert "test_id" not in fake_object_with_parent .asdict (with_parent_attrs = False )
376+ assert "test_id" in fake_object_with_parent .asdict (with_parent_attrs = True )
377+
378+ def test_asdict_modify_dict_does_not_change_object (self ,fake_object ):
379+ result = fake_object .asdict ()
380+ # Demonstrate modifying the dictionary does not modify the object
381+ result ["attr1" ]= "testing"
382+ result ["alist" ].append (4 )
383+ assert result == {"attr1" :"testing" ,"alist" : [1 ,2 ,3 ,4 ]}
384+ assert fake_object .attr1 == "foo"
385+ assert fake_object .alist == [1 ,2 ,3 ]
386+
387+ def test_asdict_modify_dict_does_not_change_object2 (self ,fake_object ):
388+ # Modify attribute and then ensure modifying a list in the returned dict won't
389+ # modify the list in the object.
390+ fake_object .attr1 = [9 ,7 ,8 ]
391+ assert fake_object .asdict ()== {
392+ "attr1" : [9 ,7 ,8 ],
393+ "alist" : [1 ,2 ,3 ],
394+ }
395+ result = fake_object .asdict ()
396+ result ["attr1" ].append (1 )
397+ assert fake_object .asdict ()== {
398+ "attr1" : [9 ,7 ,8 ],
399+ "alist" : [1 ,2 ,3 ],
400+ }
401+
402+ def test_asdict_modify_object (self ,fake_object ):
403+ # asdict() returns the updated value
404+ fake_object .attr1 = "spam"
405+ assert fake_object .asdict ()== {"attr1" :"spam" ,"alist" : [1 ,2 ,3 ]}