@@ -178,6 +178,138 @@ public function addRuleWithCompletePositionAddsRuleAndPreservesPosition(
178178 self ::assertSame (64 , $ ruleToAdd ->getColumnNumber (), 'column number not preserved ' );
179179 }
180180
181+ /**
182+ * @return array<string, array{0: non-empty-list<non-empty-string>, 1: int<0, max>}>
183+ */
184+ public static function provideInitialPropertyNamesAndSiblingIndex (): array
185+ {
186+ $ initialPropertyNamesSets = self ::providePropertyNamesToBeSetInitially ();
187+
188+ // Provide sets with each possible sibling index for the initially set `Rule`s.
189+ $ initialPropertyNamesAndSiblingIndexSets = [];
190+ foreach ($ initialPropertyNamesSets as $ setName => $ data ) {
191+ $ initialPropertyNames = $ data [0 ];
192+ for ($ siblingIndex = 0 ; $ siblingIndex < \count ($ initialPropertyNames ); ++$ siblingIndex ) {
193+ $ initialPropertyNamesAndSiblingIndexSets [$ setName . ', sibling index ' . $ siblingIndex ] =
194+ [$ initialPropertyNames , $ siblingIndex ];
195+ }
196+ }
197+
198+ return $ initialPropertyNamesAndSiblingIndexSets ;
199+ }
200+
201+ /**
202+ * @return DataProvider<string, array{0: non-empty-list<string>, 1: int<0, max>, 2: string}>
203+ */
204+ public static function provideInitialPropertyNamesAndSiblingIndexAndPropertyNameToAdd (): DataProvider
205+ {
206+ return DataProvider::cross (
207+ self ::provideInitialPropertyNamesAndSiblingIndex (),
208+ self ::providePropertyNameToAdd ()
209+ );
210+ }
211+
212+ /**
213+ * @test
214+ *
215+ * @param list<string> $initialPropertyNames
216+ * @param int<0, max> $siblingIndex
217+ *
218+ * @dataProvider provideInitialPropertyNamesAndSiblingIndexAndPropertyNameToAdd
219+ */
220+ public function addRuleWithSiblingInsertsRuleBeforeSibling (
221+ array $ initialPropertyNames ,
222+ int $ siblingIndex ,
223+ string $ propertyNameToAdd
224+ ): void {
225+ self ::markTestSkipped ('tofix: if property names don \'t match, sibling is ignored ' );
226+
227+ $ ruleToAdd = new Rule ($ propertyNameToAdd );
228+ $ this ->setRulesFromPropertyNames ($ initialPropertyNames );
229+ $ sibling = $ this ->subject ->getRules ()[$ siblingIndex ];
230+
231+ $ this ->subject ->addRule ($ ruleToAdd , $ sibling );
232+
233+ $ rules = $ this ->subject ->getRules ();
234+ $ siblingPosition = \array_search ($ sibling , $ rules , true );
235+ self ::assertIsInt ($ siblingPosition );
236+ self ::assertSame ($ siblingPosition - 1 , \array_search ($ ruleToAdd , $ rules , true ));
237+ }
238+
239+ /**
240+ * @test
241+ *
242+ * @param list<string> $initialPropertyNames
243+ * @param int<0, max> $siblingIndex
244+ *
245+ * @dataProvider provideInitialPropertyNamesAndSiblingIndexAndPropertyNameToAdd
246+ */
247+ public function addRuleWithSiblingSetsValidLineNumber (
248+ array $ initialPropertyNames ,
249+ int $ siblingIndex ,
250+ string $ propertyNameToAdd
251+ ): void {
252+ $ ruleToAdd = new Rule ($ propertyNameToAdd );
253+ $ this ->setRulesFromPropertyNames ($ initialPropertyNames );
254+ $ sibling = $ this ->subject ->getRules ()[$ siblingIndex ];
255+
256+ $ this ->subject ->addRule ($ ruleToAdd , $ sibling );
257+
258+ self ::assertIsInt ($ ruleToAdd ->getLineNumber (), 'line number not set ' );
259+ self ::assertGreaterThanOrEqual (1 , $ ruleToAdd ->getLineNumber (), 'line number not valid ' );
260+ }
261+
262+ /**
263+ * @test
264+ *
265+ * @param list<string> $initialPropertyNames
266+ * @param int<0, max> $siblingIndex
267+ *
268+ * @dataProvider provideInitialPropertyNamesAndSiblingIndexAndPropertyNameToAdd
269+ */
270+ public function addRuleWithSiblingSetsValidColumnNumber (
271+ array $ initialPropertyNames ,
272+ int $ siblingIndex ,
273+ string $ propertyNameToAdd
274+ ): void {
275+ self ::markTestSkipped ('tofix: sometimes a negative column number results ' );
276+
277+ $ ruleToAdd = new Rule ($ propertyNameToAdd );
278+ $ this ->setRulesFromPropertyNames ($ initialPropertyNames );
279+ $ sibling = $ this ->subject ->getRules ()[$ siblingIndex ];
280+
281+ $ this ->subject ->addRule ($ ruleToAdd , $ sibling );
282+
283+ self ::assertIsInt ($ ruleToAdd ->getColumnNumber (), 'column number not set ' );
284+ self ::assertGreaterThanOrEqual (0 , $ ruleToAdd ->getColumnNumber (), 'column number not valid ' );
285+ }
286+
287+ /**
288+ * @test
289+ *
290+ * @param list<string> $initialPropertyNames
291+ *
292+ * @dataProvider provideInitialPropertyNamesAndPropertyNameToAdd
293+ */
294+ public function addRuleWithSiblingNotInRuleSetAddsRuleAfterInitialRulesAndSetsValidLineAndColumnNumbers (
295+ array $ initialPropertyNames ,
296+ string $ propertyNameToAdd
297+ ): void {
298+ $ ruleToAdd = new Rule ($ propertyNameToAdd );
299+ $ this ->setRulesFromPropertyNames ($ initialPropertyNames );
300+
301+ // `display` is sometimes in `$initialPropertyNames` and sometimes the `$propertyNameToAdd`.
302+ // Choosing this for the bogus sibling allows testing all combinations of whether it is or isn't.
303+ $ this ->subject ->addRule ($ ruleToAdd , new Rule ('display ' ));
304+
305+ $ rules = $ this ->subject ->getRules ();
306+ self ::assertSame ($ ruleToAdd , \end ($ rules ));
307+ self ::assertIsInt ($ ruleToAdd ->getLineNumber (), 'line number not set ' );
308+ self ::assertGreaterThanOrEqual (1 , $ ruleToAdd ->getLineNumber (), 'line number not valid ' );
309+ self ::assertIsInt ($ ruleToAdd ->getColumnNumber (), 'column number not set ' );
310+ self ::assertGreaterThanOrEqual (0 , $ ruleToAdd ->getColumnNumber (), 'column number not valid ' );
311+ }
312+
181313 /**
182314 * @return array<string, array{0: list<string>, 1: string, 2: list<string>}>
183315 */
0 commit comments