Skip to content

Commit 4e7d222

Browse files
committed
fix: ensure getAverageInterval and getMedianInterval do not mutate intervals state
1 parent 6fb4c8d commit 4e7d222

File tree

2 files changed

+62
-9
lines changed

2 files changed

+62
-9
lines changed

src/FeedIo/Reader/Result/UpdateStats.php

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,23 +133,24 @@ public function getMaxInterval(): int
133133
*/
134134
public function getAverageInterval(): int
135135
{
136-
sort($this->intervals);
136+
$intervals = $this->intervals;
137+
sort($intervals);
137138

138-
$count = count($this->intervals);
139+
$count = count($intervals);
139140
if ($count === 0) {
140141
return 0;
141142
}
142143

143144
// some feeds could have very old historic
144145
// articles so eliminate them with statistic
145-
$q1 = $this->intervals[(int) floor($count * 0.25)];
146-
$q3 = $this->intervals[(int) floor($count * 0.75)];
146+
$q1 = $intervals[(int) floor($count * 0.25)];
147+
$q3 = $intervals[(int) floor($count * 0.75)];
147148
$iqr = $q3 - $q1;
148149

149150
$lower_bound = $q1 - 1.5 * $iqr;
150151
$upper_bound = $q3 + 1.5 * $iqr;
151152

152-
$result = array_filter($this->intervals, function($value) use ($lower_bound, $upper_bound) {
153+
$result = array_filter($intervals, function($value) use ($lower_bound, $upper_bound) {
153154
return $value >= $lower_bound && $value <= $upper_bound;
154155
});
155156

@@ -163,19 +164,20 @@ public function getAverageInterval(): int
163164
*/
164165
public function getMedianInterval(): int
165166
{
166-
sort($this->intervals);
167+
$intervals = $this->intervals;
168+
sort($intervals);
167169

168-
$count = count($this->intervals);
170+
$count = count($intervals);
169171
if ($count === 0) {
170172
return 0;
171173
}
172174

173175
$num = (int) floor($count / 2);
174176

175177
if ($count % 2 === 0) {
176-
return intval(floor(($this->intervals[$num - 1] + $this->intervals[$num]) / 2));
178+
return intval(floor(($intervals[$num - 1] + $intervals[$num]) / 2));
177179
} else {
178-
return $this->intervals[$num];
180+
return $intervals[$num];
179181
}
180182
}
181183

tests/FeedIo/Reader/Result/UpdateStatsTest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,57 @@ public function testAverageIntervalWhenAllValuesFiltered()
426426
$this->assertGreaterThanOrEqual(0, $average);
427427
}
428428

429+
/**
430+
* Test that getAverageInterval and getMedianInterval don't mutate $this->intervals
431+
* This ensures calling these methods doesn't have side effects on other methods
432+
*/
433+
public function testIntervalMethodsDoNotMutateState()
434+
{
435+
$feed = new Feed();
436+
$feed->setLastModified(new \DateTime('-1 day'));
437+
438+
$dates = [
439+
'-5 days',
440+
'-1 day',
441+
'-3 days',
442+
'-2 days',
443+
'-4 days',
444+
];
445+
446+
foreach ($dates as $date) {
447+
$item = new Feed\Item();
448+
$item->setLastModified(new \DateTime($date));
449+
$feed->add($item);
450+
}
451+
452+
$stats = new UpdateStats($feed);
453+
454+
// Get the original intervals (should be in chronological order based on how they're computed)
455+
$originalIntervals = $stats->getIntervals();
456+
457+
// Call methods that need to sort the intervals
458+
$average = $stats->getAverageInterval();
459+
$median = $stats->getMedianInterval();
460+
461+
// Get intervals again - they should still be in the original order
462+
$intervalsAfter = $stats->getIntervals();
463+
464+
$this->assertEquals($originalIntervals, $intervalsAfter,
465+
'Calling getAverageInterval() and getMedianInterval() should not mutate the intervals array');
466+
467+
// Call again to verify no mutation on subsequent calls
468+
$average2 = $stats->getAverageInterval();
469+
$median2 = $stats->getMedianInterval();
470+
$intervalsAfter2 = $stats->getIntervals();
471+
472+
$this->assertEquals($originalIntervals, $intervalsAfter2,
473+
'Multiple calls to statistical methods should not mutate the intervals array');
474+
475+
// Results should be consistent
476+
$this->assertEquals($average, $average2);
477+
$this->assertEquals($median, $median2);
478+
}
479+
429480
private function getDates(): array
430481
{
431482
return [

0 commit comments

Comments
 (0)