@@ -88,6 +88,41 @@ def it_calculates_its_child_extents_to_help(self, child_exts_fixture):
8888 x , y , cx , cy = xSp ._child_extents
8989 assert (x , y , cx , cy ) == expected_values
9090
91+ def it_returns_zero_for_max_shape_id_on_an_empty_spTree (self ):
92+ spTree = element ("p:spTree" )
93+ assert spTree .max_shape_id == 0
94+
95+ def it_finds_the_max_id_among_shape_descendants (self ):
96+ spTree = element (
97+ "p:spTree/(p:nvGrpSpPr/p:cNvPr{id=1,name=root}"
98+ ",p:sp/p:nvSpPr/p:cNvPr{id=2,name=a}"
99+ ",p:sp/p:nvSpPr/p:cNvPr{id=42,name=b}"
100+ ",p:sp/p:nvSpPr/p:cNvPr{id=7,name=c})"
101+ )
102+ assert spTree .max_shape_id == 42
103+
104+ def but_it_ignores_sibling_ids_outside_the_shape_tree (self ):
105+ # ---Regression for the slide-master shape-id-overflow bug surfaced by
106+ # SlideMaster.add_text_watermark: `<p:sldLayoutIdLst>` lives as a
107+ # sibling of `<p:cSld>` on a slide master and uses sentinel ids
108+ # starting at 2147483649. A whole-document xpath would pull those
109+ # values in and push the next shape id past `xs:int`, which
110+ # PowerPoint quarantines on open ("Repair" path).
111+ sldMaster = element (
112+ "p:sldMaster/(p:cSld/p:spTree/(p:nvGrpSpPr/p:cNvPr{id=1,name=root}"
113+ ",p:sp/p:nvSpPr/p:cNvPr{id=2,name=title})"
114+ ",p:sldLayoutIdLst/(p:sldLayoutId{id=2147483649,r:id=rId1}"
115+ ",p:sldLayoutId{id=2147483650,r:id=rId2}))"
116+ )
117+ spTree = sldMaster .find (
118+ "{http://schemas.openxmlformats.org/presentationml/2006/main}cSld/"
119+ "{http://schemas.openxmlformats.org/presentationml/2006/main}spTree"
120+ )
121+ # ---scoped to spTree descendants; 2147483649 etc. are NOT counted---
122+ assert spTree .max_shape_id == 2
123+ # ---and `_next_shape_id` (max + 1) stays in the safe shape-id range---
124+ assert spTree .max_shape_id + 1 == 3
125+
91126 # fixtures ---------------------------------------------
92127
93128 @pytest .fixture
0 commit comments