Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions .dagger/src/CalendR.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,39 @@ public function test(
#[DefaultPath('.')] Directory $source,
string $phpVersion = '8.4',
string $dependencyVersion = 'highest',
): string {
return $this
?string $coverallsRepoToken = null,
?string $ciName = null,
?string $ciJobId = null,
?string $ciBranch = null,
): string
{
$container = $this
->build($source, $phpVersion, $dependencyVersion)
->withExec(['php', './vendor/bin/phpunit', '--coverage-text'])
->withFile('/tmp/coveralls-linux.tar.gz', dag()->http('https://coveralls.io/coveralls-linux.tar.gz'))
->withExec(['tar', '-xvzf', '/tmp/coveralls-linux.tar.gz', '-C', '/usr/local/bin']);


$exec = ['php', './vendor/bin/phpunit', '--coverage-text'];
if ($coverallsRepoToken) {
$exec[] = '--coverage-clover=build/logs/clover.xml';

$container = $container->withEnvVariable('COVERALLS_REPO_TOKEN', $coverallsRepoToken);
}

if ($ciName && $ciJobId && $ciBranch) {
$container = $container
->withEnvVariable('CI_NAME', $ciName)
->withEnvVariable('CI_JOB_ID', $ciJobId)
->withEnvVariable('CI_BRANCH', $ciBranch);
}

$container = $container->withExec($exec);

if ($coverallsRepoToken) {
$container = $container->withExec(['coveralls', 'report']);
}

return $container
->stdout();
}

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
with:
version: "latest"
verb: call
args: test --source=. --php-version=${{ matrix.php-versions }} --dependency-version=${{ matrix.dependencies-versions }}
args: test --source=. --php-version=${{ matrix.php-versions }} --dependency-version=${{ matrix.dependencies-versions }} --coveralls-repo-token=${{ secrets.COVERALLS_REPO_TOKEN }} --ci-name=gha --ci-job-id=${{ github.run_id }} --ci-branch=${{ github.ref }}
cloud-token: ${{ secrets.DAGGER_CLOUD_TOKEN }}

mutation:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
CalendR provides a clean, immutable, and iterable API to manipulate time periods (Years, Months, Weeks, Days...) and manage associated events.

[![CI Status](https://github.com/yohang/CalendR/actions/workflows/ci.yml/badge.svg)](https://github.com/yohang/CalendR/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/yohang/CalendR/badge.svg?branch=master)](https://coveralls.io/github/yohang/CalendR?branch=main)
[![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fyohang%2FCalendR%2Fmain)](https://dashboard.stryker-mutator.io/reports/github.com/yohang/CalendR/main)

## ✨ Features
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function load(array $configs, ContainerBuilder $container): void

$defaultFirstWeekday = $config['periods']['default_first_weekday'];
if (!($defaultFirstWeekday instanceof DayOfWeek)) {
$defaultFirstWeekday = DayOfWeek::from($defaultFirstWeekday);
$defaultFirstWeekday = DayOfWeek::from($defaultFirstWeekday); // @codeCoverageIgnore
}

$container
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ public function getConfigTreeBuilder(): TreeBuilder
->enumFqcn(DayOfWeek::class)
->defaultValue(DayOfWeek::MONDAY);
} else {
// @codeCoverageIgnoreStart
$enumNode
->values(array_map(fn (DayOfWeek $dayOfWeek) => $dayOfWeek->value, DayOfWeek::cases()))
->defaultValue(DayOfWeek::MONDAY->value)
->validate()
->ifNotInArray(array_map(static fn (DayOfWeek $d) => $d->value, DayOfWeek::cases()))
->thenInvalid('Day must be be between 0 (Sunday) and 6 (Saturday)')
->end();
// @codeCoverageIgnoreEnd
}

return $treeBuilder;
Expand Down
8 changes: 4 additions & 4 deletions src/Bridge/Symfony/Bundle/Resources/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use CalendR\Bridge\Twig\CalendRExtension;
use CalendR\Calendar;
use CalendR\Event\EventManager;
use CalendR\Period\PeriodPeriodFactory;
use CalendR\Period\PeriodFactory;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

use function Symfony\Component\DependencyInjection\Loader\Configurator\service;
Expand All @@ -16,12 +16,12 @@
->public();

$container->services()
->set(PeriodPeriodFactory::class)
->set(PeriodFactory::class)
->public();

$container->services()
->set(Calendar::class)
->arg('$factory', service(PeriodPeriodFactory::class))
->arg('$factory', service(PeriodFactory::class))
->arg('$eventManager', service(EventManager::class))
->public();

Expand All @@ -35,7 +35,7 @@
->public();

$container->services()
->alias('calendr.factory', PeriodPeriodFactory::class)
->alias('calendr.factory', PeriodFactory::class)
->public();

$container->services()
Expand Down
4 changes: 2 additions & 2 deletions src/Calendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
use CalendR\Period\Hour;
use CalendR\Period\Minute;
use CalendR\Period\Month;
use CalendR\Period\PeriodFactory;
use CalendR\Period\PeriodFactoryInterface;
use CalendR\Period\PeriodInterface;
use CalendR\Period\PeriodPeriodFactory;
use CalendR\Period\Second;
use CalendR\Period\Week;
use CalendR\Period\Year;
Expand All @@ -26,7 +26,7 @@
readonly class Calendar
{
public function __construct(
protected PeriodFactoryInterface $factory = new PeriodPeriodFactory(),
protected PeriodFactoryInterface $factory = new PeriodFactory(),
private EventManager $eventManager = new EventManager(),
) {
}
Expand Down
5 changes: 1 addition & 4 deletions src/Event/Collection/IndexedCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,7 @@ final class IndexedCollection implements CollectionInterface, \IteratorAggregate
*/
public function __construct(array $events = [], ?callable $callable = null)
{
$this->indexFunction = (static fn (\DateTimeInterface $dateTime): string => $dateTime->format('Y-m-d'));
if (\is_callable($callable)) {
$this->indexFunction = $callable;
}
$this->indexFunction = $callable ?? static fn (\DateTimeInterface $dateTime): string => $dateTime->format('Y-m-d');

foreach ($events as $event) {
$this->add($event);
Expand Down
4 changes: 2 additions & 2 deletions src/Period/Month.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function getDays(): array

/**
* Returns the first day of the first week of month.
* First day of week is configurable via {@link PeriodPeriodFactory}.
* First day of week is configurable via {@link PeriodFactory}.
*/
public function getFirstDayOfFirstWeek(): \DateTimeImmutable
{
Expand All @@ -51,7 +51,7 @@ public function getExtendedMonth(): PeriodInterface

/**
* Returns the last day of last week of month
* First day of week is configurable via {@link PeriodPeriodFactory}.
* First day of week is configurable via {@link PeriodFactory}.
*/
public function getLastDayOfLastWeek(): \DateTimeImmutable
{
Expand Down
2 changes: 1 addition & 1 deletion src/Period/PeriodAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public function getEnd(): \DateTimeImmutable
protected function getFactory(): PeriodFactoryInterface
{
if (null === $this->factory) {
$this->factory = new PeriodPeriodFactory();
$this->factory = new PeriodFactory();
}

return $this->factory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use CalendR\DayOfWeek;

final class PeriodPeriodFactory implements PeriodFactoryInterface
final class PeriodFactory implements PeriodFactoryInterface
{
public function __construct(
private DayOfWeek $firstWeekday = DayOfWeek::MONDAY,
Expand Down
2 changes: 1 addition & 1 deletion src/Period/Range.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function __construct(\DateTimeInterface $begin, \DateTimeInterface $end,
#[\Override]
public static function isValid(\DateTimeInterface $start): bool
{
return true;
throw new NotImplemented('Range period doesn\'t support isValid().');
}

#[\Override]
Expand Down
4 changes: 2 additions & 2 deletions tests/Bridge/Symfony/Functional/ServicesRegistrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use CalendR\Calendar;
use CalendR\Event\EventManager;
use CalendR\Period\PeriodPeriodFactory;
use CalendR\Period\PeriodFactory;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

final class ServicesRegistrationTest extends KernelTestCase
Expand All @@ -19,7 +19,7 @@ protected function tearDown(): void
public function testServicesAccessibles(): void
{
$this->assertInstanceOf(Calendar::class, self::getContainer()->get('calendr'));
$this->assertInstanceOf(PeriodPeriodFactory::class, self::getContainer()->get('calendr.factory'));
$this->assertInstanceOf(PeriodFactory::class, self::getContainer()->get('calendr.factory'));
$this->assertInstanceOf(EventManager::class, self::getContainer()->get('calendr.event_manager'));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;

final class BasicTest extends TestCase
final class ArrayCollectionTest extends TestCase
{
use ProphecyTrait;

Expand Down Expand Up @@ -104,4 +104,13 @@ public function testAll(): void
}
$this->assertCount(\count($this->collection), $this->collection->all());
}

public function testIterationIsIndexed(): void
{
$collection = new ArrayCollection(self::$events);
foreach ($collection as $index => $events) {
$this->assertIsInt($index);
$this->assertInstanceOf(Event::class, $events);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;

final class IndexedTest extends TestCase
final class IndexedCollectionTest extends TestCase
{
use ProphecyTrait;

Expand Down Expand Up @@ -103,4 +103,16 @@ public function testAll(): void
$this->assertSame(self::$events[$index], $event);
}
}

public function testIterationIsIndexed(): void
{
$indexFunction = function (\DateTimeInterface $dateTime): string {
return 'i-'.$dateTime->format('W');
};

$collection = new IndexedCollection(self::$events, $indexFunction);
foreach ($collection as $index => $events) {
$this->assertSame('i-19', $index);
}
}
}
17 changes: 17 additions & 0 deletions tests/Event/EventTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
namespace CalendR\Test\Event;

use CalendR\Event\Event;
use CalendR\Event\EventInterface;
use CalendR\Event\Exception\InvalidEvent;
use CalendR\Period\Day;
use CalendR\Period\Month;
use CalendR\Period\PeriodInterface;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -69,4 +71,19 @@ public static function provideDates(): iterable
yield ['begin' => '2025-11-29 00:00:00', 'end' => '2025-11-30 00:00:00', 'date' => new \DateTimeImmutable('2025-11-29 00:00:00'), 'expected' => true];
yield ['begin' => '2025-11-29 00:00:00', 'end' => '2025-11-30 00:00:00', 'date' => new \DateTimeImmutable('2025-11-30 00:00:00'), 'expected' => false];
}

#[DataProvider('providerForDuring')]
public function testIsDuring(EventInterface $event, PeriodInterface $period, bool $result): void
{
$this->assertSame($result, $event->isDuring($period));
}

public static function providerForDuring(): iterable
{
yield [new Event(new \DateTimeImmutable('2025-12-02 08:00'), new \DateTimeImmutable('2025-12-02 12:00')), new Day(new \DateTimeImmutable('2025-12-02')), true];
yield [new Event(new \DateTimeImmutable('2025-12-03'), new \DateTimeImmutable('2025-12-04')), new Month(new \DateTimeImmutable('2025-12-01')), true];
yield [new Event(new \DateTimeImmutable('2025-12-03'), new \DateTimeImmutable('2025-12-04')), new Month(new \DateTimeImmutable('2025-11-01')), false];
yield [new Event(new \DateTimeImmutable('2025-11-02'), new \DateTimeImmutable('2025-11-03')), new Day(new \DateTimeImmutable('2025-11-02')), false];
yield [new Event(new \DateTimeImmutable('2025-11-01'), new \DateTimeImmutable('2025-11-03')), new Month(new \DateTimeImmutable('2025-11-01')), true];
}
}
8 changes: 8 additions & 0 deletions tests/Event/Provider/AggregateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,12 @@ public function testGetEvents(): void

$this->assertSame([$event1, $event2], $this->object->getEvents($begin, $end));
}

public function testConstructorThrowsIfInvalidProvider(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Providers must implement CalendR\\Event\\ProviderInterface');

new AggregateProvider([new \stdClass()]);
}
}
4 changes: 2 additions & 2 deletions tests/Period/DayTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
use CalendR\Period\Day;
use CalendR\Period\Exception\NotADay;
use CalendR\Period\Hour;
use CalendR\Period\PeriodFactory;
use CalendR\Period\PeriodFactoryInterface;
use CalendR\Period\PeriodInterface;
use CalendR\Period\PeriodPeriodFactory;
use CalendR\Period\Range;
use CalendR\Period\Year;
use PHPUnit\Framework\Attributes\DataProvider;
Expand Down Expand Up @@ -178,7 +178,7 @@ public static function includesDataProvider(): \Iterator
public function testIteration(): void
{
$start = new \DateTimeImmutable('2012-01-15');
$day = new Day($start, new PeriodPeriodFactory());
$day = new Day($start, new PeriodFactory());

$i = 0;

Expand Down
6 changes: 3 additions & 3 deletions tests/Period/FactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use CalendR\Period\Hour;
use CalendR\Period\Minute;
use CalendR\Period\Month;
use CalendR\Period\PeriodPeriodFactory;
use CalendR\Period\PeriodFactory;
use CalendR\Period\Range;
use CalendR\Period\Second;
use CalendR\Period\Week;
Expand Down Expand Up @@ -103,8 +103,8 @@ public static function providerGetFirstMondayAndLastSunday(): \Iterator
yield [$factory->getMonth(2012, 12), '2012-11-26'];
}

protected function getDefaultOptionsFactory(): PeriodPeriodFactory
protected function getDefaultOptionsFactory(): PeriodFactory
{
return new PeriodPeriodFactory();
return new PeriodFactory();
}
}
4 changes: 2 additions & 2 deletions tests/Period/HourTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
use CalendR\Period\Exception\NotAnHour;
use CalendR\Period\Hour;
use CalendR\Period\Minute;
use CalendR\Period\PeriodFactory;
use CalendR\Period\PeriodFactoryInterface;
use CalendR\Period\PeriodInterface;
use CalendR\Period\PeriodPeriodFactory;
use CalendR\Period\Second;
use CalendR\Period\Year;
use PHPUnit\Framework\Attributes\DataProvider;
Expand Down Expand Up @@ -214,7 +214,7 @@ public static function includesDataProvider(): \Iterator
public function testIteration(): void
{
$start = new \DateTimeImmutable('2012-01-15 13:00');
$hour = new Hour($start, new PeriodPeriodFactory());
$hour = new Hour($start, new PeriodFactory());

$i = 0;
foreach ($hour as $minuteKey => $minute) {
Expand Down
4 changes: 2 additions & 2 deletions tests/Period/MinuteTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
use CalendR\Period\Exception\NotAMinute;
use CalendR\Period\Hour;
use CalendR\Period\Minute;
use CalendR\Period\PeriodFactory;
use CalendR\Period\PeriodFactoryInterface;
use CalendR\Period\PeriodInterface;
use CalendR\Period\PeriodPeriodFactory;
use CalendR\Period\Second;
use CalendR\Period\Year;
use PHPUnit\Framework\Attributes\DataProvider;
Expand Down Expand Up @@ -229,7 +229,7 @@ public static function providerIncludes(): \Iterator
public function testIteration(): void
{
$start = new \DateTimeImmutable('2012-01-15 15:47');
$minute = new Minute($start, new PeriodPeriodFactory());
$minute = new Minute($start, new PeriodFactory());

$i = 0;
foreach ($minute as $secondKey => $second) {
Expand Down
Loading