render([]); $this->assertStringStartsWith('render([]); $this->assertStringEndsWith('', $svg); } #[Test] public function it_includes_role_img_attribute_for_accessibility(): void { $svg = (new SvgRenderer())->render([]); $this->assertStringContainsString('role="img"', $svg); } #[Test] public function it_includes_aria_label_attribute_for_accessibility(): void { $svg = (new SvgRenderer())->render([]); $this->assertStringContainsString('aria-label="Contribution graph"', $svg); } #[Test] #[DataProvider('theme_background_provider')] public function it_applies_background_color_for_theme(string $theme, string $expectedColor): void { $svg = (new SvgRenderer())->render([], $theme); $this->assertStringContainsString($expectedColor, $svg); } public static function theme_background_provider(): iterable { yield 'dark theme' => ['dark', '#0d1117']; yield 'light theme' => ['light', '#ffffff']; yield 'unknown theme' => ['unknown', '#0d1117']; } #[Test] public function it_shows_zero_contributions_when_no_data_is_provided(): void { $svg = (new SvgRenderer())->render([]); $this->assertStringContainsString('0 contributions in the last year', $svg); } #[Test] public function it_displays_formatted_total_contribution_count(): void { $today = (new \DateTimeImmutable('today'))->format('Y-m-d'); $svg = (new SvgRenderer())->render([$today => 1234]); $this->assertStringContainsString('1,234 contributions in the last year', $svg); } #[Test] public function it_renders_all_53_week_columns(): void { $svg = (new SvgRenderer())->render([]); // MARGIN_X(28) + col_52 * STEP(13) = 704 $this->assertStringContainsString('x="704"', $svg); } #[Test] #[DataProvider('day_of_week_label_provider')] public function it_renders_day_of_week_label(string $label): void { $svg = (new SvgRenderer())->render([]); $this->assertStringContainsString('>' . $label . '<', $svg); } public static function day_of_week_label_provider(): iterable { yield 'Monday' => ['Mon']; yield 'Wednesday' => ['Wed']; yield 'Friday' => ['Fri']; } #[Test] public function it_renders_a_less_label_in_the_legend(): void { $svg = (new SvgRenderer())->render([]); $this->assertStringContainsString('>Less<', $svg); } #[Test] public function it_renders_a_more_label_in_the_legend(): void { $svg = (new SvgRenderer())->render([]); $this->assertStringContainsString('>More<', $svg); } #[Test] public function it_sums_contributions_from_multiple_dates(): void { $today = (new \DateTimeImmutable('today'))->format('Y-m-d'); $yesterday = (new \DateTimeImmutable('yesterday'))->format('Y-m-d'); $svg = (new SvgRenderer())->render([$today => 3, $yesterday => 7]); $this->assertStringContainsString('10 contributions in the last year', $svg); } }