1111import pytest
1212
1313from docx .opc .oxml import CT_Relationships
14+ from docx .opc .package import Part
1415from docx .opc .packuri import PackURI
1516from docx .opc .rel import _Relationship , Relationships
1617
17- from ..unitutil .mock import call , class_mock , Mock , patch , PropertyMock
18+ from ..unitutil .mock import (
19+ call , class_mock , instance_mock , Mock , patch , PropertyMock
20+ )
1821
1922
2023class Describe_Relationship (object ):
@@ -56,21 +59,6 @@ def it_should_have_relative_ref_for_internal_rel(self):
5659
5760class DescribeRelationships (object ):
5861
59- def it_has_a_len (self ):
60- rels = Relationships (None )
61- assert len (rels ) == 0
62-
63- def it_has_dict_style_lookup_of_rel_by_rId (self ):
64- rel = Mock (name = 'rel' , rId = 'foobar' )
65- rels = Relationships (None )
66- rels ['foobar' ] = rel
67- assert rels ['foobar' ] == rel
68-
69- def it_should_raise_on_failed_lookup_by_rId (self ):
70- rels = Relationships (None )
71- with pytest .raises (KeyError ):
72- rels ['barfoo' ]
73-
7462 def it_can_add_a_relationship (self , _Relationship_ ):
7563 baseURI , rId , reltype , target , external = (
7664 'baseURI' , 'rId9' , 'reltype' , 'target' , False
@@ -91,13 +79,43 @@ def it_can_add_an_external_relationship(self, add_ext_rel_fixture_):
9179 assert rel .target_ref == url
9280 assert rel .reltype == reltype
9381
94- def it_should_return_an_existing_one_if_it_matches (
82+ def it_can_find_a_relationship_by_rId (self ):
83+ rel = Mock (name = 'rel' , rId = 'foobar' )
84+ rels = Relationships (None )
85+ rels ['foobar' ] = rel
86+ assert rels ['foobar' ] == rel
87+
88+ def it_can_find_or_add_a_relationship (
89+ self , rels_with_matching_rel_ , rels_with_missing_rel_ ):
90+
91+ rels , reltype , part , matching_rel = rels_with_matching_rel_
92+ assert rels .get_or_add (reltype , part ) == matching_rel
93+
94+ rels , reltype , part , new_rel = rels_with_missing_rel_
95+ assert rels .get_or_add (reltype , part ) == new_rel
96+
97+ def it_can_find_or_add_an_external_relationship (
9598 self , add_matching_ext_rel_fixture_ ):
9699 rels , reltype , url , rId = add_matching_ext_rel_fixture_
97100 _rId = rels .get_or_add_ext_rel (reltype , url )
98101 assert _rId == rId
99102 assert len (rels ) == 1
100103
104+ def it_can_find_a_related_part_by_rId (self , rels_with_known_target_part ):
105+ rels , rId , known_target_part = rels_with_known_target_part
106+ part = rels .related_parts [rId ]
107+ assert part is known_target_part
108+
109+ def it_raises_on_related_part_not_found (self , rels ):
110+ with pytest .raises (KeyError ):
111+ rels .related_parts ['rId666' ]
112+
113+ def it_can_find_a_related_part_by_reltype (
114+ self , rels_with_target_known_by_reltype ):
115+ rels , reltype , known_target_part = rels_with_target_known_by_reltype
116+ part = rels .part_with_reltype (reltype )
117+ assert part is known_target_part
118+
101119 def it_can_compose_rels_xml (self , rels , rels_elm ):
102120 # exercise ---------------------
103121 rels .xml
@@ -115,6 +133,11 @@ def it_can_compose_rels_xml(self, rels, rels_elm):
115133 any_order = True
116134 )
117135
136+ def it_knows_the_next_available_rId_to_help (self , rels_with_rId_gap ):
137+ rels , expected_next_rId = rels_with_rId_gap
138+ next_rId = rels ._next_rId
139+ assert next_rId == expected_next_rId
140+
118141 # fixtures ---------------------------------------------
119142
120143 @pytest .fixture
@@ -129,10 +152,22 @@ def add_matching_ext_rel_fixture_(self, request, reltype, url):
129152 rels .add_relationship (reltype , url , rId , is_external = True )
130153 return rels , reltype , url , rId
131154
155+ # fixture components -----------------------------------
156+
157+ @pytest .fixture
158+ def _baseURI (self ):
159+ return '/baseURI'
160+
132161 @pytest .fixture
133162 def _Relationship_ (self , request ):
134163 return class_mock (request , 'docx.opc.rel._Relationship' )
135164
165+ @pytest .fixture
166+ def _rel_with_target_known_by_reltype (
167+ self , _rId , reltype , _target_part , _baseURI ):
168+ rel = _Relationship (_rId , reltype , _target_part , _baseURI )
169+ return rel , reltype , _target_part
170+
136171 @pytest .fixture
137172 def rels (self ):
138173 """
@@ -168,10 +203,82 @@ def rels_elm(self, request):
168203 request .addfinalizer (patch_ .stop )
169204 return rels_elm
170205
206+ @pytest .fixture
207+ def _rel_with_known_target_part (
208+ self , _rId , reltype , _target_part , _baseURI ):
209+ rel = _Relationship (_rId , reltype , _target_part , _baseURI )
210+ return rel , _rId , _target_part
211+
212+ @pytest .fixture
213+ def rels_with_known_target_part (self , rels , _rel_with_known_target_part ):
214+ rel , rId , target_part = _rel_with_known_target_part
215+ rels .add_relationship (None , target_part , rId )
216+ return rels , rId , target_part
217+
218+ @pytest .fixture
219+ def rels_with_matching_rel_ (self , request , rels ):
220+ matching_reltype_ = instance_mock (
221+ request , str , name = 'matching_reltype_'
222+ )
223+ matching_part_ = instance_mock (
224+ request , Part , name = 'matching_part_'
225+ )
226+ matching_rel_ = instance_mock (
227+ request , _Relationship , name = 'matching_rel_' ,
228+ reltype = matching_reltype_ , target_part = matching_part_ ,
229+ is_external = False
230+ )
231+ rels [1 ] = matching_rel_
232+ return rels , matching_reltype_ , matching_part_ , matching_rel_
233+
234+ @pytest .fixture
235+ def rels_with_missing_rel_ (self , request , rels , _Relationship_ ):
236+ missing_reltype_ = instance_mock (
237+ request , str , name = 'missing_reltype_'
238+ )
239+ missing_part_ = instance_mock (
240+ request , Part , name = 'missing_part_'
241+ )
242+ new_rel_ = instance_mock (
243+ request , _Relationship , name = 'new_rel_' ,
244+ reltype = missing_reltype_ , target_part = missing_part_ ,
245+ is_external = False
246+ )
247+ _Relationship_ .return_value = new_rel_
248+ return rels , missing_reltype_ , missing_part_ , new_rel_
249+
250+ @pytest .fixture
251+ def rels_with_rId_gap (self , request ):
252+ rels = Relationships (None )
253+ rel_with_rId1 = instance_mock (
254+ request , _Relationship , name = 'rel_with_rId1' , rId = 'rId1'
255+ )
256+ rel_with_rId3 = instance_mock (
257+ request , _Relationship , name = 'rel_with_rId3' , rId = 'rId3'
258+ )
259+ rels ['rId1' ] = rel_with_rId1
260+ rels ['rId3' ] = rel_with_rId3
261+ return rels , 'rId2'
262+
263+ @pytest .fixture
264+ def rels_with_target_known_by_reltype (
265+ self , rels , _rel_with_target_known_by_reltype ):
266+ rel , reltype , target_part = _rel_with_target_known_by_reltype
267+ rels [1 ] = rel
268+ return rels , reltype , target_part
269+
171270 @pytest .fixture
172271 def reltype (self ):
173272 return 'http://rel/type'
174273
274+ @pytest .fixture
275+ def _rId (self ):
276+ return 'rId6'
277+
278+ @pytest .fixture
279+ def _target_part (self , request ):
280+ return instance_mock (request , Part )
281+
175282 @pytest .fixture
176283 def url (self ):
177284 return 'https://github.com/scanny/python-docx'
0 commit comments