149 lines
4.4 KiB
PHP
149 lines
4.4 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\Dashboard\Stats;
|
|
|
|
use App\Dashboard\Stats\ArticlesPerFeed;
|
|
use App\Dashboard\Stats\Breakdown;
|
|
use App\Models\Article;
|
|
use App\Models\Feed;
|
|
use App\Support\DateRange;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Carbon;
|
|
use Tests\TestCase;
|
|
|
|
class ArticlesPerFeedTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private function range(): DateRange
|
|
{
|
|
return new DateRange(
|
|
Carbon::parse('2026-07-01 00:00:00'),
|
|
Carbon::parse('2026-07-31 23:59:59'),
|
|
);
|
|
}
|
|
|
|
public function test_it_counts_articles_per_feed_within_the_range(): void
|
|
{
|
|
$busy = Feed::factory()->create(['name' => 'Busy Feed']);
|
|
$quiet = Feed::factory()->create(['name' => 'Quiet Feed']);
|
|
|
|
Article::factory()->count(3)->create([
|
|
'feed_id' => $busy->id,
|
|
'created_at' => Carbon::parse('2026-07-10 12:00:00'),
|
|
]);
|
|
Article::factory()->create([
|
|
'feed_id' => $quiet->id,
|
|
'created_at' => Carbon::parse('2026-07-11 12:00:00'),
|
|
]);
|
|
|
|
$rows = (new ArticlesPerFeed)->for($this->range())->rows;
|
|
|
|
$this->assertSame(['Busy Feed' => 3, 'Quiet Feed' => 1], $this->pluck($rows));
|
|
}
|
|
|
|
public function test_it_reports_zero_for_a_feed_with_no_articles_in_the_range(): void
|
|
{
|
|
Feed::factory()->create(['name' => 'Silent Feed']);
|
|
|
|
$rows = (new ArticlesPerFeed)->for($this->range())->rows;
|
|
|
|
$this->assertSame(['Silent Feed' => 0], $this->pluck($rows));
|
|
}
|
|
|
|
public function test_it_excludes_articles_outside_the_range(): void
|
|
{
|
|
$feed = Feed::factory()->create(['name' => 'Feed']);
|
|
|
|
Article::factory()->create([
|
|
'feed_id' => $feed->id,
|
|
'created_at' => Carbon::parse('2026-06-30 23:59:59'),
|
|
]);
|
|
Article::factory()->create([
|
|
'feed_id' => $feed->id,
|
|
'created_at' => Carbon::parse('2026-08-01 00:00:00'),
|
|
]);
|
|
|
|
$rows = (new ArticlesPerFeed)->for($this->range())->rows;
|
|
|
|
$this->assertSame(['Feed' => 0], $this->pluck($rows));
|
|
}
|
|
|
|
public function test_it_orders_feeds_by_count_descending(): void
|
|
{
|
|
$low = Feed::factory()->create(['name' => 'Low']);
|
|
$high = Feed::factory()->create(['name' => 'High']);
|
|
|
|
Article::factory()->create([
|
|
'feed_id' => $low->id,
|
|
'created_at' => Carbon::parse('2026-07-10 12:00:00'),
|
|
]);
|
|
Article::factory()->count(5)->create([
|
|
'feed_id' => $high->id,
|
|
'created_at' => Carbon::parse('2026-07-10 12:00:00'),
|
|
]);
|
|
|
|
$rows = (new ArticlesPerFeed)->for($this->range())->rows;
|
|
|
|
$this->assertSame(['High', 'Low'], array_map(fn ($row) => $row->label, $rows));
|
|
}
|
|
|
|
public function test_it_breaks_ties_alphabetically(): void
|
|
{
|
|
foreach (['Zulu', 'Alpha', 'Mike'] as $name) {
|
|
$feed = Feed::factory()->create(['name' => $name]);
|
|
|
|
Article::factory()->create([
|
|
'feed_id' => $feed->id,
|
|
'created_at' => Carbon::parse('2026-07-10 12:00:00'),
|
|
]);
|
|
}
|
|
|
|
$rows = (new ArticlesPerFeed)->for($this->range())->rows;
|
|
|
|
$this->assertSame(['Alpha', 'Mike', 'Zulu'], array_map(fn ($row) => $row->label, $rows));
|
|
}
|
|
|
|
public function test_it_reports_the_range_total(): void
|
|
{
|
|
$feed = Feed::factory()->create();
|
|
|
|
Article::factory()->count(4)->create([
|
|
'feed_id' => $feed->id,
|
|
'created_at' => Carbon::parse('2026-07-10 12:00:00'),
|
|
]);
|
|
|
|
$this->assertSame(4, (new ArticlesPerFeed)->for($this->range())->total());
|
|
}
|
|
|
|
public function test_it_reports_a_zero_total_with_no_feeds(): void
|
|
{
|
|
$result = (new ArticlesPerFeed)->for($this->range());
|
|
|
|
$this->assertSame(0, $result->total());
|
|
$this->assertSame([], $result->rows);
|
|
}
|
|
|
|
public function test_it_exposes_a_stable_key_and_label(): void
|
|
{
|
|
$stat = new ArticlesPerFeed;
|
|
|
|
$this->assertSame('articles-per-feed', $stat->key());
|
|
$this->assertSame('Articles per Feed', $stat->label());
|
|
}
|
|
|
|
/**
|
|
* @param array<int, Breakdown> $rows
|
|
* @return array<string, int>
|
|
*/
|
|
private function pluck(array $rows): array
|
|
{
|
|
$out = [];
|
|
|
|
foreach ($rows as $row) {
|
|
$out[$row->label] = $row->count;
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
}
|