Skip to content

Commit

Permalink
feat: add checks in the Either constructor
Browse files Browse the repository at this point in the history
- add static method to instantiate the Either class
- more tests
  • Loading branch information
iliaamiri committed Oct 28, 2024
1 parent b9f8d07 commit be1c2d0
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/Either.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,21 @@ public function __construct(
public mixed $result,
public ?Throwable $error = null
) {
if ($result instanceof Throwable) {
throw new InvalidArgumentException('Result cannot be a Throwable.');
}
if ($result === null && $error === null) {
throw new InvalidArgumentException('Either result or error must be set.');
}

parent::__construct(new ArrayIterator([$error, $result]));
}

public static function create(mixed $result, ?Throwable $error = null): self
{
return new self($result, $error);
}

public function getIterator(): Traversable
{
return new ArrayIterator([$this->error, $this->result]);
Expand Down
96 changes: 96 additions & 0 deletions tests/Unit/EitherTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

use MightFail\Either;

test('class must exist', function () {
expect(class_exists(Either::class))->toBeTrue();
});

test('should extend the IteratorIterator class', function () {
$either = new Either('foo');

expect($either)->toBeInstanceOf(IteratorIterator::class);
});

test('should implement the ArrayAccess interface', function () {
$either = new Either('foo');

expect($either)->toBeInstanceOf(ArrayAccess::class);
});

test('should have a result property', function () {
$either = new Either('foo');

expect($either->result)->toBe('foo');
});

test('should have an error property', function () {
$either = new Either(null, new Exception('foo'));

expect($either->error)->toBeInstanceOf(Exception::class);
});

test('should throw an error if result is an exception', function () {
expect(fn () => new Either(new Exception('foo')))->toThrow(InvalidArgumentException::class, 'Result cannot be a Throwable.');
});

test('should throw an error if both result and error are null', function () {
expect(fn () => new Either(null, null))->toThrow(InvalidArgumentException::class, 'Either result or error must be set.');
});

test('should have the correct methods', function () {
expect(method_exists(Either::class, 'getIterator'))->toBeTrue()
->and(method_exists(Either::class, 'offsetSet'))->toBeTrue()
->and(method_exists(Either::class, 'offsetExists'))->toBeTrue()
->and(method_exists(Either::class, 'offsetUnset'))->toBeTrue()
->and(method_exists(Either::class, 'offsetGet'))->toBeTrue()
->and(method_exists(Either::class, 'create'))->toBeTrue();
});

test('can be instantiated with new', function () {
$either = new Either('foo');

expect($either)->toBeInstanceOf(Either::class)
->and($either->result)->toBe('foo')
->and($either->error)->toBeNull();

[$error, $result] = $either;

expect($error)->toBeNull()
->and($result)->toBe('foo');

$either = new Either(null, new Exception('foo'));

expect($either)->toBeInstanceOf(Either::class)
->and($either->result)->toBeNull()
->and($either->error)->toBeInstanceOf(Exception::class);

[$error, $result] = $either;

expect($error)->toBeInstanceOf(Exception::class)
->and($result)->toBeNull();
});

test('can be instantiated with from', function () {
$either = Either::create('foo');

expect($either)->toBeInstanceOf(Either::class)
->and($either->result)->toBe('foo')
->and($either->error)->toBeNull();

[$error, $result] = $either;

expect($error)->toBeNull()
->and($result)->toBe('foo');

$either = Either::create(null, new Exception('foo'));

expect($either)->toBeInstanceOf(Either::class)
->and($either->result)->toBeNull()
->and($either->error)->toBeInstanceOf(Exception::class);

[$error, $result] = $either;

expect($error)->toBeInstanceOf(Exception::class)
->and($result)->toBeNull();
});
44 changes: 44 additions & 0 deletions tests/Unit/FailTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

use MightFail\Either;
use MightFail\Fail;
use MightFail\Might;

test('class must exist and have a static from method', function () {
expect(class_exists(Fail::class))->toBeTrue()
->and(method_exists(Fail::class, 'from'))->toBeTrue();
});

test('creates a Fail instance', function () {
$might = Fail::from(new Exception('foo'));

expect($might)->toBeInstanceOf(Fail::class);
});

test('extends from the Either class', function () {
$might = Fail::from(new Exception('foo'));

expect($might)->toBeInstanceOf(Either::class)
->and($might)->toBeInstanceOf(Fail::class)
->and($might)->not->toBeInstanceOf(Might::class);
});

test('has Either properties', function () {
$might = Fail::from(new Exception('foo'));

expect($might->result)->toBeNull()
->and($might->error)->toBeInstanceOf(Exception::class);

[$error, $result] = $might;

expect($error)->toBeInstanceOf(Exception::class)
->and($result)->toBeNull();
});

test('can instantiate with new', function () {
$might = new Fail(new Exception('foo'));

expect($might)->toBeInstanceOf(Fail::class)
->and($might->result)->toBeNull()
->and($might->error)->toBeInstanceOf(Exception::class);
});
44 changes: 44 additions & 0 deletions tests/Unit/MightTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

use MightFail\Either;
use MightFail\Fail;
use MightFail\Might;

test('class must exist and have a static from method', function () {
expect(class_exists(Might::class))->toBeTrue()
->and(method_exists(Might::class, 'from'))->toBeTrue();
});

test('creates a Might instance', function () {
$might = Might::from('foo');

expect($might)->toBeInstanceOf(Might::class);
});

test('extends from the Either class', function () {
$might = Might::from('foo');

expect($might)->toBeInstanceOf(Either::class)
->and($might)->toBeInstanceOf(Might::class)
->and($might)->not->toBeInstanceOf(Fail::class);
});

test('has Either properties', function () {
$might = Might::from('foo');

expect($might->result)->toBe('foo')
->and($might->error)->toBeNull();

[$error, $result] = $might;

expect($error)->toBeNull()
->and($result)->toBe('foo');
});

test('can instantiate with new', function () {
$might = new Might('foo');

expect($might)->toBeInstanceOf(Might::class)
->and($might->result)->toBe('foo')
->and($might->error)->toBeNull();
});

0 comments on commit be1c2d0

Please sign in to comment.