Skip to content

Commit b972a92

Browse files
allow runtime dynamic type assertions
1 parent a0012b8 commit b972a92

File tree

2 files changed

+56
-18
lines changed

2 files changed

+56
-18
lines changed

src/ObjectId.php

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,19 @@ private static function generator(): Generator
3434

3535
/**
3636
* Constructor.
37+
* @throws Invalid
3738
*/
38-
public function __construct(?string $rawData = null)
39+
public function __construct($rawData = null)
3940
{
40-
if ($rawData !== null) {
41-
if (strlen($rawData) !== 12) {
42-
throw new Invalid("Raw data must be 12 bytes for ObjectId.");
43-
}
44-
$this->rawData = $rawData;
45-
} else {
41+
if ($rawData === null) {
4642
$this->rawData = self::generator()->nextObjectId();
43+
return;
4744
}
45+
if (!is_string($rawData))
46+
throw new Invalid("Raw data must be a string.");
47+
if (strlen($rawData) !== 12)
48+
throw new Invalid("Raw data must be 12 bytes for ObjectId.");
49+
$this->rawData = $rawData;
4850
}
4951

5052
/**
@@ -54,8 +56,10 @@ public function __construct(?string $rawData = null)
5456
* @return ObjectId
5557
* @throws Invalid if $rawData is not 12 bytes.
5658
*/
57-
public static function fromBinary(string $data): ObjectId
59+
public static function fromBinary($data): ObjectId
5860
{
61+
if (!is_string($data))
62+
throw new Invalid("The input must be a string.");
5963
return new self($data);
6064
}
6165

@@ -66,11 +70,12 @@ public static function fromBinary(string $data): ObjectId
6670
* @return ObjectId
6771
* @throws Invalid If the provided string is invalid.
6872
*/
69-
public static function fromString(string $string): ObjectId
73+
public static function fromString($string): ObjectId
7074
{
71-
if (!self::legal($string)) {
72-
throw new Invalid("'$string' is an invalid ObjectId.");
73-
}
75+
if (!is_string($string))
76+
throw new Invalid("The input must be a string.");
77+
if (!self::legal($string))
78+
throw new Invalid("'$string' is not a 24-character hex string.");
7479
return self::fromBinary(hex2bin($string));
7580
}
7681

@@ -82,9 +87,14 @@ public static function fromString(string $string): ObjectId
8287
* @return ObjectId The new object id.
8388
* @throws Invalid
8489
*/
85-
public static function fromTime(int|DateTime $time, bool $unique = true): ObjectId
90+
public static function fromTime($time, bool $unique = true): ObjectId
8691
{
87-
$timestamp = $time instanceof DateTime ? $time->getTimestamp() : (int)$time;
92+
if ($time instanceof DateTime)
93+
$timestamp = $time->getTimestamp();
94+
elseif (is_integer($time))
95+
$timestamp = $time;
96+
else
97+
throw new Invalid("The input must be a time.");
8898

8999
if ($unique) {
90100
$data = self::generator()->nextObjectId($timestamp);

tests/Unit/ObjectIdTest.php

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
Invalid::class,
2626
);
2727
}
28+
foreach ([null, 1] as $specimen) {
29+
expect(fn() => ObjectId::fromBinary($specimen))->toThrow(
30+
Invalid::class,
31+
);
32+
}
2833
});
2934

3035
it('creates an ObjectId from string', function () {
@@ -35,10 +40,12 @@
3540
expect($objectId->toBinary())->toBe($rawId);
3641
});
3742

38-
it('throws Invalid exception in fromString for a non-hex string', function () {
39-
expect(fn() => ObjectId::fromString('ダメ'))->toThrow(
40-
Invalid::class,
41-
);
43+
it('throws Invalid exception in fromString for an invalid string', function () {
44+
foreach ([null, 1, 'ダメ'] as $specimen) {
45+
expect(fn() => ObjectId::fromString($specimen))->toThrow(
46+
Invalid::class,
47+
);
48+
}
4249
});
4350

4451
it('throws Invalid exception in fromString when the length is no good', function () {
@@ -65,6 +72,27 @@
6572
expect(substr($objectId->toString(), -16))->toBe(str_repeat('00', 8));
6673
});
6774

75+
it('throws Invalid exception in fromTime for an invalid value', function () {
76+
foreach ([null, 'ダメ'] as $specimen) {
77+
expect(fn() => ObjectId::fromTime($specimen))->toThrow(
78+
Invalid::class,
79+
);
80+
}
81+
});
82+
83+
it('should allow timestamps to wrap over', function () {
84+
foreach ([
85+
[Carbon::createFromTimestamp(0x100000000), 0],
86+
[Carbon::createFromTimestamp(-1), 0xffffffff],
87+
[0x100000000, 0],
88+
[-1, 0xffffffff],
89+
] as [$time, $expected]) {
90+
$objectId = ObjectId::fromTime($time);
91+
$embeddedTime = new Carbon($objectId->toTime());
92+
expect($embeddedTime->getTimestamp())->toBe($expected);
93+
}
94+
});
95+
6896
it('returns the 24-char hex string via __toString()', function () {
6997
$objectId = ObjectId::fromString(str_repeat('00', 12));
7098
expect((string)$objectId)->toBe(str_repeat('00', 12));

0 commit comments

Comments
 (0)