Skip to content

Commit

Permalink
Merge pull request #16 from slope-it/add-create-from-format
Browse files Browse the repository at this point in the history
  • Loading branch information
asprega committed May 29, 2022
2 parents 58945d3 + cd1a38c commit d278f9f
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 11 deletions.
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ Note that, as this is not a tool intended for production, it should be required

- date()
- date_create()
- date_create_from_format()
- date_create_immutable()
- date_create_immutable_from_format()
- getdate()
- gettimeofday()
- gmdate()
Expand All @@ -49,17 +51,12 @@ Note that, as this is not a tool intended for production, it should be required
- time()
- unixtojd()
- DateTime::__construct
- DateTime::createFromFormat
- DateTimeImmutable::__construct
- DateTimeImmutable::createFromFormat
- $_SERVER['REQUEST_TIME']
- $_SERVER['REQUEST_TIME_FLOAT']

## Functions/methods with missing mocks (HELP NEEDED!)

- date_create_from_format()
- date_create_immutable_from_format()
- DateTime::createFromFormat
- DateTimeImmutable::createFromFormat

## Usage

### 1. Stateful API
Expand Down
36 changes: 36 additions & 0 deletions src/ClockMock.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ private static function activateMocksIfNeeded(): void

uopz_set_return('date', self::mock_date(), true);
uopz_set_return('date_create', self::mock_date_create(), true);
uopz_set_return('date_create_from_format', self::mock_date_create_from_format(), true);
uopz_set_return('date_create_immutable', self::mock_date_create_immutable(), true);
uopz_set_return('date_create_immutable_from_format', self::mock_date_create_immutable_from_format(), true);
uopz_set_return('getdate', self::mock_getdate(), true);
uopz_set_return('gettimeofday', self::mock_gettimeofday(), true);
uopz_set_return('gmdate', self::mock_gmdate(), true);
Expand All @@ -131,7 +133,9 @@ private static function activateMocksIfNeeded(): void
}

uopz_set_mock(\DateTime::class, DateTimeMock::class);
uopz_set_return(\DateTime::class, 'createFromFormat', self::mock_date_create_from_format(), true);
uopz_set_mock(\DateTimeImmutable::class, DateTimeImmutableMock::class);
uopz_set_return(\DateTimeImmutable::class, 'createFromFormat', self::mock_date_create_immutable_from_format(), true);

self::$areMocksActive = true;
}
Expand All @@ -156,6 +160,25 @@ private static function mock_date_create(): callable
return fn (?string $datetime = 'now', ?DateTimeZone $timezone = null) => new \DateTime($datetime, $timezone);
}

/**
* @see https://www.php.net/manual/en/function.date-create-from-format.php
*/
private static function mock_date_create_from_format(): callable
{
return function ($format, $datetime, DateTimeZone $timezone = null) {
$dateTimeObject = \DateTime::createFromFormat($format, $datetime, $timezone);

$parsedDate = date_parse($datetime);

return $dateTimeObject->setTime(
$parsedDate['hour'] === false ? idate('H') : $parsedDate['hour'],
$parsedDate['minute'] === false ? idate('i') : $parsedDate['minute'],
$parsedDate['second'] === false ? idate('s') : $parsedDate['second'],
$parsedDate['fraction'] === false ? (int) date('u') : $parsedDate['fraction'],
);
};
}

/**
* @see https://www.php.net/manual/en/function.date-create-immutable.php
*/
Expand All @@ -165,6 +188,19 @@ private static function mock_date_create_immutable(): callable
=> new \DateTimeImmutable($datetime, $timezone);
}

/**
* @see https://www.php.net/manual/en/function.date-create-immutable-from-format.php
*/
public static function mock_date_create_immutable_from_format(): callable
{
return function ($format, $datetime, DateTimeZone $timezone = null) {
// Create an immutable instance starting from the mutable mock, so we don't have to replicate mocking logic.
$mutableDateTime = date_create_from_format($format, $datetime, $timezone);

return new \DateTimeImmutable($mutableDateTime->format('Y-m-d\TH:i:s.uT'), $timezone);
};
}

/**
* @see https://www.php.net/manual/en/function.getdate.php
*/
Expand Down
6 changes: 3 additions & 3 deletions src/DateTimeMock/DateTimeImmutableMock.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ class DateTimeImmutableMock extends \DateTimeImmutable
{
public function __construct(?string $datetime = 'now', ?DateTimeZone $timezone = null)
{
// Just use the mutable version of the mock, so we don't have to replicate freezing logic.
$otherDateTime = new DateTimeMock($datetime, $timezone);
// Create an immutable instance starting from the mutable mock, so we don't have to replicate mocking logic.
$mutableDateTime = new DateTimeMock($datetime, $timezone);

parent::__construct($otherDateTime->format('Y-m-d\TH:i:s.uT'), $timezone);
parent::__construct($mutableDateTime->format('Y-m-d\TH:i:s.uT'), $timezone);
}
}
44 changes: 43 additions & 1 deletion tests/ClockMockTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,21 @@ public function test_DateTimeImmutable_constructor_with_relative_mocked_date_wit
public function test_DateTimeImmutable_constructor_with_timezone()
{
$dateWithTimezone = new \DateTimeImmutable('1986-06-05 14:41:32+02:00');

ClockMock::freeze($fakeNow = new \DateTimeImmutable('now'));

$this->assertEquals($dateWithTimezone, new \DateTimeImmutable('1986-06-05 14:41:32+02:00'));
}

public function test_DateTimeImmutable_createFromFormat()
{
ClockMock::freeze(new \DateTimeImmutable('1986-06-05 12:13:14'));

$dateTimeFromFormat = \DateTimeImmutable::createFromFormat('Y-m-d', '2022-05-28');

// Verification: when not provided with a time, createFromFormat should use current time.
$this->assertSame('2022-05-28 12:13:14', $dateTimeFromFormat->format('Y-m-d H:i:s'));
}

public function test_DateTime_constructor_with_absolute_mocked_date()
{
Expand Down Expand Up @@ -97,6 +107,16 @@ public function test_DateTime_constructor_with_relative_mocked_date_without_micr
$this->assertEquals($juneFifth1986, new \DateTime('1986-06-05'));
}

public function test_DateTime_createFromFormat()
{
ClockMock::freeze(new \DateTimeImmutable('1986-06-05 12:13:14'));

$dateTimeFromFormat = \DateTime::createFromFormat('Y-m-d', '2022-05-28');

// Verification: when not provided with a time, createFromFormat should use current time.
$this->assertSame('2022-05-28 12:13:14', $dateTimeFromFormat->format('Y-m-d H:i:s'));
}

public function test_date()
{
ClockMock::freeze(new \DateTime('1986-06-05'));
Expand All @@ -112,13 +132,35 @@ public function test_date_create()
$this->assertEquals($fakeNow, date_create());
}

public function test_date_create_from_format()
{
ClockMock::freeze(new \DateTimeImmutable('1986-06-05 12:13:14'));

$dateTimeFromFormat = date_create_from_format('Y-m-d', '2022-05-28');

// Verification: when not provided with a time, createFromFormat should use current time.
$this->assertInstanceOf(\DateTime::class, $dateTimeFromFormat);
$this->assertSame('2022-05-28 12:13:14', $dateTimeFromFormat->format('Y-m-d H:i:s'));
}

public function test_date_create_immutable()
{
ClockMock::freeze($fakeNow = new \DateTimeImmutable('1986-06-05'));

$this->assertEquals($fakeNow, date_create_immutable());
}

public function test_date_create_immutable_from_format()
{
ClockMock::freeze(new \DateTimeImmutable('1986-06-05 12:13:14'));

$dateTimeFromFormat = date_create_immutable_from_format('Y-m-d', '2022-05-28');

// Verification: when not provided with a time, createFromFormat should use current time.
$this->assertInstanceOf(\DateTimeImmutable::class, $dateTimeFromFormat);
$this->assertSame('2022-05-28 12:13:14', $dateTimeFromFormat->format('Y-m-d H:i:s'));
}

public function test_getdate()
{
ClockMock::freeze(new \DateTime('@518306400'));
Expand Down

0 comments on commit d278f9f

Please sign in to comment.