Skip to content

Commit be1c2d0

Browse files
committed
feat: add checks in the Either constructor
- add static method to instantiate the Either class - more tests
1 parent b9f8d07 commit be1c2d0

4 files changed

Lines changed: 196 additions & 0 deletions

File tree

src/Either.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,21 @@ public function __construct(
1515
public mixed $result,
1616
public ?Throwable $error = null
1717
) {
18+
if ($result instanceof Throwable) {
19+
throw new InvalidArgumentException('Result cannot be a Throwable.');
20+
}
21+
if ($result === null && $error === null) {
22+
throw new InvalidArgumentException('Either result or error must be set.');
23+
}
24+
1825
parent::__construct(new ArrayIterator([$error, $result]));
1926
}
2027

28+
public static function create(mixed $result, ?Throwable $error = null): self
29+
{
30+
return new self($result, $error);
31+
}
32+
2133
public function getIterator(): Traversable
2234
{
2335
return new ArrayIterator([$this->error, $this->result]);

tests/Unit/EitherTest.php

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
use MightFail\Either;
4+
5+
test('class must exist', function () {
6+
expect(class_exists(Either::class))->toBeTrue();
7+
});
8+
9+
test('should extend the IteratorIterator class', function () {
10+
$either = new Either('foo');
11+
12+
expect($either)->toBeInstanceOf(IteratorIterator::class);
13+
});
14+
15+
test('should implement the ArrayAccess interface', function () {
16+
$either = new Either('foo');
17+
18+
expect($either)->toBeInstanceOf(ArrayAccess::class);
19+
});
20+
21+
test('should have a result property', function () {
22+
$either = new Either('foo');
23+
24+
expect($either->result)->toBe('foo');
25+
});
26+
27+
test('should have an error property', function () {
28+
$either = new Either(null, new Exception('foo'));
29+
30+
expect($either->error)->toBeInstanceOf(Exception::class);
31+
});
32+
33+
test('should throw an error if result is an exception', function () {
34+
expect(fn () => new Either(new Exception('foo')))->toThrow(InvalidArgumentException::class, 'Result cannot be a Throwable.');
35+
});
36+
37+
test('should throw an error if both result and error are null', function () {
38+
expect(fn () => new Either(null, null))->toThrow(InvalidArgumentException::class, 'Either result or error must be set.');
39+
});
40+
41+
test('should have the correct methods', function () {
42+
expect(method_exists(Either::class, 'getIterator'))->toBeTrue()
43+
->and(method_exists(Either::class, 'offsetSet'))->toBeTrue()
44+
->and(method_exists(Either::class, 'offsetExists'))->toBeTrue()
45+
->and(method_exists(Either::class, 'offsetUnset'))->toBeTrue()
46+
->and(method_exists(Either::class, 'offsetGet'))->toBeTrue()
47+
->and(method_exists(Either::class, 'create'))->toBeTrue();
48+
});
49+
50+
test('can be instantiated with new', function () {
51+
$either = new Either('foo');
52+
53+
expect($either)->toBeInstanceOf(Either::class)
54+
->and($either->result)->toBe('foo')
55+
->and($either->error)->toBeNull();
56+
57+
[$error, $result] = $either;
58+
59+
expect($error)->toBeNull()
60+
->and($result)->toBe('foo');
61+
62+
$either = new Either(null, new Exception('foo'));
63+
64+
expect($either)->toBeInstanceOf(Either::class)
65+
->and($either->result)->toBeNull()
66+
->and($either->error)->toBeInstanceOf(Exception::class);
67+
68+
[$error, $result] = $either;
69+
70+
expect($error)->toBeInstanceOf(Exception::class)
71+
->and($result)->toBeNull();
72+
});
73+
74+
test('can be instantiated with from', function () {
75+
$either = Either::create('foo');
76+
77+
expect($either)->toBeInstanceOf(Either::class)
78+
->and($either->result)->toBe('foo')
79+
->and($either->error)->toBeNull();
80+
81+
[$error, $result] = $either;
82+
83+
expect($error)->toBeNull()
84+
->and($result)->toBe('foo');
85+
86+
$either = Either::create(null, new Exception('foo'));
87+
88+
expect($either)->toBeInstanceOf(Either::class)
89+
->and($either->result)->toBeNull()
90+
->and($either->error)->toBeInstanceOf(Exception::class);
91+
92+
[$error, $result] = $either;
93+
94+
expect($error)->toBeInstanceOf(Exception::class)
95+
->and($result)->toBeNull();
96+
});

tests/Unit/FailTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
use MightFail\Either;
4+
use MightFail\Fail;
5+
use MightFail\Might;
6+
7+
test('class must exist and have a static from method', function () {
8+
expect(class_exists(Fail::class))->toBeTrue()
9+
->and(method_exists(Fail::class, 'from'))->toBeTrue();
10+
});
11+
12+
test('creates a Fail instance', function () {
13+
$might = Fail::from(new Exception('foo'));
14+
15+
expect($might)->toBeInstanceOf(Fail::class);
16+
});
17+
18+
test('extends from the Either class', function () {
19+
$might = Fail::from(new Exception('foo'));
20+
21+
expect($might)->toBeInstanceOf(Either::class)
22+
->and($might)->toBeInstanceOf(Fail::class)
23+
->and($might)->not->toBeInstanceOf(Might::class);
24+
});
25+
26+
test('has Either properties', function () {
27+
$might = Fail::from(new Exception('foo'));
28+
29+
expect($might->result)->toBeNull()
30+
->and($might->error)->toBeInstanceOf(Exception::class);
31+
32+
[$error, $result] = $might;
33+
34+
expect($error)->toBeInstanceOf(Exception::class)
35+
->and($result)->toBeNull();
36+
});
37+
38+
test('can instantiate with new', function () {
39+
$might = new Fail(new Exception('foo'));
40+
41+
expect($might)->toBeInstanceOf(Fail::class)
42+
->and($might->result)->toBeNull()
43+
->and($might->error)->toBeInstanceOf(Exception::class);
44+
});

tests/Unit/MightTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
use MightFail\Either;
4+
use MightFail\Fail;
5+
use MightFail\Might;
6+
7+
test('class must exist and have a static from method', function () {
8+
expect(class_exists(Might::class))->toBeTrue()
9+
->and(method_exists(Might::class, 'from'))->toBeTrue();
10+
});
11+
12+
test('creates a Might instance', function () {
13+
$might = Might::from('foo');
14+
15+
expect($might)->toBeInstanceOf(Might::class);
16+
});
17+
18+
test('extends from the Either class', function () {
19+
$might = Might::from('foo');
20+
21+
expect($might)->toBeInstanceOf(Either::class)
22+
->and($might)->toBeInstanceOf(Might::class)
23+
->and($might)->not->toBeInstanceOf(Fail::class);
24+
});
25+
26+
test('has Either properties', function () {
27+
$might = Might::from('foo');
28+
29+
expect($might->result)->toBe('foo')
30+
->and($might->error)->toBeNull();
31+
32+
[$error, $result] = $might;
33+
34+
expect($error)->toBeNull()
35+
->and($result)->toBe('foo');
36+
});
37+
38+
test('can instantiate with new', function () {
39+
$might = new Might('foo');
40+
41+
expect($might)->toBeInstanceOf(Might::class)
42+
->and($might->result)->toBe('foo')
43+
->and($might->error)->toBeNull();
44+
});

0 commit comments

Comments
 (0)