'Taylor', 'age' => 25]; $fluent = new Fluent($array); $refl = new ReflectionObject($fluent); $attributes = $refl->getProperty('attributes'); $this->assertEquals($array, $attributes->getValue($fluent)); $this->assertEquals($array, $fluent->getAttributes()); } public function testAttributesAreSetByConstructorGivenstdClass() { $array = ['name' => 'Taylor', 'age' => 25]; $fluent = new Fluent((object) $array); $refl = new ReflectionObject($fluent); $attributes = $refl->getProperty('attributes'); $this->assertEquals($array, $attributes->getValue($fluent)); $this->assertEquals($array, $fluent->getAttributes()); } public function testAttributesAreSetByConstructorGivenArrayIterator() { $array = ['name' => 'Taylor', 'age' => 25]; $fluent = new Fluent(new FluentArrayIteratorStub($array)); $refl = new ReflectionObject($fluent); $attributes = $refl->getProperty('attributes'); $this->assertEquals($array, $attributes->getValue($fluent)); $this->assertEquals($array, $fluent->getAttributes()); } public function testGetMethodReturnsAttribute() { $fluent = new Fluent(['name' => 'Taylor']); $this->assertSame('Taylor', $fluent->get('name')); $this->assertSame('Default', $fluent->get('foo', 'Default')); $this->assertSame('Taylor', $fluent->name); $this->assertNull($fluent->foo); } public function testSetMethodSetsAttribute() { $fluent = new Fluent; $fluent->set('name', 'Taylor'); $fluent->set('developer', true); $fluent->set('posts', 25); $fluent->set('computer.color', 'silver'); $this->assertSame('Taylor', $fluent->name); $this->assertTrue($fluent->developer); $this->assertSame(25, $fluent->posts); $this->assertSame(['color' => 'silver'], $fluent->computer); } public function testArrayAccessToAttributes() { $fluent = new Fluent(['attributes' => '1']); $this->assertTrue(isset($fluent['attributes'])); $this->assertEquals(1, $fluent['attributes']); $fluent->attributes(); $this->assertTrue($fluent['attributes']); } public function testMagicMethodsCanBeUsedToSetAttributes() { $fluent = new Fluent; $fluent->name = 'Taylor'; $fluent->developer(); $fluent->age(25); $this->assertSame('Taylor', $fluent->name); $this->assertTrue($fluent->developer); $this->assertEquals(25, $fluent->age); $this->assertInstanceOf(Fluent::class, $fluent->programmer()); } public function testIssetMagicMethod() { $array = ['name' => 'Taylor', 'age' => 25]; $fluent = new Fluent($array); $this->assertTrue(isset($fluent->name)); unset($fluent->name); $this->assertFalse(isset($fluent->name)); } public function testToArrayReturnsAttribute() { $array = ['name' => 'Taylor', 'age' => 25]; $fluent = new Fluent($array); $this->assertEquals($array, $fluent->toArray()); } public function testToJsonEncodesTheToArrayResult() { $fluent = $this->getMockBuilder(Fluent::class)->onlyMethods(['toArray'])->getMock(); $fluent->expects($this->once())->method('toArray')->willReturn(['foo']); $results = $fluent->toJson(); $this->assertJsonStringEqualsJsonString(json_encode(['foo']), $results); } public function testToPrettyJson() { $fluent = $this->getMockBuilder(Fluent::class)->onlyMethods(['toArray'])->getMock(); $fluent->expects($this->exactly(2))->method('toArray')->willReturn(['foo' => 'bar', 'bar' => 'foo']); $results = $fluent->toPrettyJson(); $expected = $fluent->toJson(JSON_PRETTY_PRINT); $this->assertJsonStringEqualsJsonString($expected, $results); $this->assertSame($expected, $results); $this->assertStringContainsString("\n", $results); $this->assertStringContainsString(' ', $results); } public function testScope() { $fluent = new Fluent(['user' => ['name' => 'taylor']]); $this->assertEquals(['taylor'], $fluent->scope('user.name')->toArray()); $this->assertEquals(['dayle'], $fluent->scope('user.age', 'dayle')->toArray()); $fluent = new Fluent(['products' => ['forge', 'vapour', 'spark']]); $this->assertEquals(['forge', 'vapour', 'spark'], $fluent->scope('products')->toArray()); $this->assertEquals(['foo', 'bar'], $fluent->scope('missing', ['foo', 'bar'])->toArray()); $fluent = new Fluent(['authors' => ['taylor' => ['products' => ['forge', 'vapour', 'spark']]]]); $this->assertEquals(['forge', 'vapour', 'spark'], $fluent->scope('authors.taylor.products')->toArray()); } public function testToCollection() { $fluent = new Fluent(['forge', 'vapour', 'spark']); $this->assertEquals(['forge', 'vapour', 'spark'], $fluent->collect()->all()); $fluent = new Fluent(['authors' => ['taylor' => ['products' => ['forge', 'vapour', 'spark']]]]); $this->assertEquals(['forge', 'vapour', 'spark'], $fluent->collect('authors.taylor.products')->all()); } public function testStringMethod() { $fluent = new Fluent([ 'int' => 123, 'int_str' => '456', 'float' => 123.456, 'float_str' => '123.456', 'float_zero' => 0.000, 'float_str_zero' => '0.000', 'str' => 'abc', 'empty_str' => '', 'null' => null, ]); $this->assertTrue($fluent->string('int') instanceof Stringable); $this->assertTrue($fluent->string('unknown_key') instanceof Stringable); $this->assertSame('123', $fluent->string('int')->value()); $this->assertSame('456', $fluent->string('int_str')->value()); $this->assertSame('123.456', $fluent->string('float')->value()); $this->assertSame('123.456', $fluent->string('float_str')->value()); $this->assertSame('0', $fluent->string('float_zero')->value()); $this->assertSame('0.000', $fluent->string('float_str_zero')->value()); $this->assertSame('', $fluent->string('empty_str')->value()); $this->assertSame('', $fluent->string('null')->value()); $this->assertSame('', $fluent->string('unknown_key')->value()); } public function testBooleanMethod() { $fluent = new Fluent(['with_trashed' => 'false', 'download' => true, 'checked' => 1, 'unchecked' => '0', 'with_on' => 'on', 'with_yes' => 'yes']); $this->assertTrue($fluent->boolean('checked')); $this->assertTrue($fluent->boolean('download')); $this->assertFalse($fluent->boolean('unchecked')); $this->assertFalse($fluent->boolean('with_trashed')); $this->assertFalse($fluent->boolean('some_undefined_key')); $this->assertTrue($fluent->boolean('with_on')); $this->assertTrue($fluent->boolean('with_yes')); } public function testIntegerMethod() { $fluent = new Fluent([ 'int' => '123', 'raw_int' => 456, 'zero_padded' => '078', 'space_padded' => ' 901', 'nan' => 'nan', 'mixed' => '1ab', 'underscore_notation' => '2_000', 'null' => null, ]); $this->assertSame(123, $fluent->integer('int')); $this->assertSame(456, $fluent->integer('raw_int')); $this->assertSame(78, $fluent->integer('zero_padded')); $this->assertSame(901, $fluent->integer('space_padded')); $this->assertSame(0, $fluent->integer('nan')); $this->assertSame(1, $fluent->integer('mixed')); $this->assertSame(2, $fluent->integer('underscore_notation')); $this->assertSame(123456, $fluent->integer('unknown_key', 123456)); $this->assertSame(0, $fluent->integer('null')); $this->assertSame(0, $fluent->integer('null', 123456)); } public function testFloatMethod() { $fluent = new Fluent([ 'float' => '1.23', 'raw_float' => 45.6, 'decimal_only' => '.6', 'zero_padded' => '0.78', 'space_padded' => ' 90.1', 'nan' => 'nan', 'mixed' => '1.ab', 'scientific_notation' => '1e3', 'null' => null, ]); $this->assertSame(1.23, $fluent->float('float')); $this->assertSame(45.6, $fluent->float('raw_float')); $this->assertSame(.6, $fluent->float('decimal_only')); $this->assertSame(0.78, $fluent->float('zero_padded')); $this->assertSame(90.1, $fluent->float('space_padded')); $this->assertSame(0.0, $fluent->float('nan')); $this->assertSame(1.0, $fluent->float('mixed')); $this->assertSame(1e3, $fluent->float('scientific_notation')); $this->assertSame(123.456, $fluent->float('unknown_key', 123.456)); $this->assertSame(0.0, $fluent->float('null')); $this->assertSame(0.0, $fluent->float('null', 123.456)); } public function testArrayMethod() { $fluent = new Fluent(['users' => [1, 2, 3]]); $this->assertIsArray($fluent->array('users')); $this->assertEquals([1, 2, 3], $fluent->array('users')); $this->assertEquals(['users' => [1, 2, 3]], $fluent->array()); $fluent = new Fluent(['text-payload']); $this->assertEquals(['text-payload'], $fluent->array()); $fluent = new Fluent(['email' => 'test@example.com']); $this->assertEquals(['test@example.com'], $fluent->array('email')); $fluent = new Fluent([]); $this->assertIsArray($fluent->array()); $this->assertEmpty($fluent->array()); $fluent = new Fluent(['users' => [1, 2, 3], 'roles' => [4, 5, 6], 'foo' => ['bar', 'baz'], 'email' => 'test@example.com']); $this->assertEmpty($fluent->array(['developers'])); $this->assertNotEmpty($fluent->array(['roles'])); $this->assertEquals(['roles' => [4, 5, 6]], $fluent->array(['roles'])); $this->assertEquals(['users' => [1, 2, 3], 'email' => 'test@example.com'], $fluent->array(['users', 'email'])); $this->assertEquals(['roles' => [4, 5, 6], 'foo' => ['bar', 'baz']], $fluent->array(['roles', 'foo'])); $this->assertEquals(['users' => [1, 2, 3], 'roles' => [4, 5, 6], 'foo' => ['bar', 'baz'], 'email' => 'test@example.com'], $fluent->array()); } public function testCollectMethod() { $fluent = new Fluent(['users' => [1, 2, 3]]); $this->assertInstanceOf(Collection::class, $fluent->collect('users')); $this->assertTrue($fluent->collect('developers')->isEmpty()); $this->assertEquals([1, 2, 3], $fluent->collect('users')->all()); $this->assertEquals(['users' => [1, 2, 3]], $fluent->collect()->all()); $fluent = new Fluent(['text-payload']); $this->assertEquals(['text-payload'], $fluent->collect()->all()); $fluent = new Fluent(['email' => 'test@example.com']); $this->assertEquals(['test@example.com'], $fluent->collect('email')->all()); $fluent = new Fluent([]); $this->assertInstanceOf(Collection::class, $fluent->collect()); $this->assertTrue($fluent->collect()->isEmpty()); $fluent = new Fluent(['users' => [1, 2, 3], 'roles' => [4, 5, 6], 'foo' => ['bar', 'baz'], 'email' => 'test@example.com']); $this->assertInstanceOf(Collection::class, $fluent->collect(['users'])); $this->assertTrue($fluent->collect(['developers'])->isEmpty()); $this->assertTrue($fluent->collect(['roles'])->isNotEmpty()); $this->assertEquals(['roles' => [4, 5, 6]], $fluent->collect(['roles'])->all()); $this->assertEquals(['users' => [1, 2, 3], 'email' => 'test@example.com'], $fluent->collect(['users', 'email'])->all()); $this->assertEquals(collect(['roles' => [4, 5, 6], 'foo' => ['bar', 'baz']]), $fluent->collect(['roles', 'foo'])); $this->assertEquals(['users' => [1, 2, 3], 'roles' => [4, 5, 6], 'foo' => ['bar', 'baz'], 'email' => 'test@example.com'], $fluent->collect()->all()); } public function testDateMethod() { $fluent = new Fluent([ 'as_null' => null, 'as_invalid' => 'invalid', 'as_datetime' => '20-01-01 16:30:25', 'as_format' => '1577896225', 'as_timezone' => '20-01-01 13:30:25', 'as_date' => '2020-01-01', 'as_time' => '16:30:25', ]); $current = Carbon::create(2020, 1, 1, 16, 30, 25); $this->assertNull($fluent->date('as_null')); $this->assertNull($fluent->date('doesnt_exists')); $this->assertEquals($current, $fluent->date('as_datetime')); $this->assertEquals($current->format('Y-m-d H:i:s P'), $fluent->date('as_format', 'U')->format('Y-m-d H:i:s P')); $this->assertEquals($current, $fluent->date('as_timezone', null, 'America/Santiago')); $this->assertTrue($fluent->date('as_date')->isSameDay($current)); $this->assertTrue($fluent->date('as_time')->isSameSecond('16:30:25')); } public function testDateMethodExceptionWhenValueInvalid() { $this->expectException(InvalidArgumentException::class); $fluent = new Fluent([ 'date' => 'invalid', ]); $fluent->date('date'); } public function testDateMethodExceptionWhenFormatInvalid() { $this->expectException(InvalidArgumentException::class); $fluent = new Fluent([ 'date' => '20-01-01 16:30:25', ]); $fluent->date('date', 'invalid_format'); } public function testEnumMethod() { $fluent = new Fluent([ 'valid_enum_value' => 'A', 'invalid_enum_value' => 'invalid', 'empty_value_request' => '', 'string' => [ 'a' => '1', 'b' => '2', 'doesnt_exist' => '-1024', ], 'int' => [ 'a' => 1, 'b' => 2, 'doesnt_exist' => 1024, ], ]); $this->assertNull($fluent->enum('doesnt_exist', TestEnum::class)); $this->assertEquals(TestStringBackedEnum::A, $fluent->enum('valid_enum_value', TestStringBackedEnum::class)); $this->assertNull($fluent->enum('invalid_enum_value', TestStringBackedEnum::class)); $this->assertNull($fluent->enum('empty_value_request', TestStringBackedEnum::class)); $this->assertNull($fluent->enum('valid_enum_value', TestEnum::class)); $this->assertEquals(TestBackedEnum::A, $fluent->enum('string.a', TestBackedEnum::class)); $this->assertEquals(TestBackedEnum::B, $fluent->enum('string.b', TestBackedEnum::class)); $this->assertNull($fluent->enum('string.doesnt_exist', TestBackedEnum::class)); $this->assertEquals(TestBackedEnum::A, $fluent->enum('int.a', TestBackedEnum::class)); $this->assertEquals(TestBackedEnum::B, $fluent->enum('int.b', TestBackedEnum::class)); $this->assertNull($fluent->enum('int.doesnt_exist', TestBackedEnum::class)); } public function testEnumsMethod() { $fluent = new Fluent([ 'valid_enum_values' => ['A', 'B'], 'invalid_enum_values' => ['invalid', 'invalid'], 'empty_value_request' => [], 'string' => [ 'a' => ['1', '2'], 'b' => '2', 'doesnt_exist' => '-1024', ], 'int' => [ 'a' => [1, 2], 'b' => 2, 'doesnt_exist' => 1024, ], ]); $this->assertEmpty($fluent->enums('doesnt_exist', TestEnum::class)); $this->assertEquals([TestStringBackedEnum::A, TestStringBackedEnum::B], $fluent->enums('valid_enum_values', TestStringBackedEnum::class)); $this->assertEmpty($fluent->enums('invalid_enum_value', TestStringBackedEnum::class)); $this->assertEmpty($fluent->enums('empty_value_request', TestStringBackedEnum::class)); $this->assertEmpty($fluent->enums('valid_enum_value', TestEnum::class)); $this->assertEquals([TestBackedEnum::A, TestBackedEnum::B], $fluent->enums('string.a', TestBackedEnum::class)); $this->assertEquals([TestBackedEnum::B], $fluent->enums('string.b', TestBackedEnum::class)); $this->assertEmpty($fluent->enums('string.doesnt_exist', TestBackedEnum::class)); $this->assertEquals([TestBackedEnum::A, TestBackedEnum::B], $fluent->enums('int.a', TestBackedEnum::class)); $this->assertEquals([TestBackedEnum::B], $fluent->enums('int.b', TestBackedEnum::class)); $this->assertEmpty($fluent->enums('int.doesnt_exist', TestBackedEnum::class)); } public function testFill() { $fluent = new Fluent(['name' => 'John Doe']); $fluent->fill([ 'email' => 'john.doe@example.com', 'age' => 30, ]); $this->assertEquals([ 'name' => 'John Doe', 'email' => 'john.doe@example.com', 'age' => 30, ], $fluent->getAttributes()); } public function testMacroable() { Fluent::macro('foo', function () { return $this->fill([ 'foo' => 'bar', 'baz' => 'zal', ]); }); $fluent = new Fluent([ 'bee' => 'ser', ]); $this->assertSame([ 'bee' => 'ser', 'foo' => 'bar', 'baz' => 'zal', ], $fluent->foo()->all()); } public function testFluentIsIterable() { $fluent = new Fluent([ 'name' => 'Taylor', 'role' => 'admin', ]); $result = []; foreach ($fluent as $key => $value) { $result[$key] = $value; } $this->assertSame([ 'name' => 'Taylor', 'role' => 'admin', ], $result); } public function testFluentIsEmpty() { $fluent = new Fluent; $this->assertTrue($fluent->isEmpty()); $this->assertFalse($fluent->isNotEmpty()); } public function testFluentIsNotEmpty() { $fluent = new Fluent([ 'name' => 'Taylor', 'role' => 'admin', ]); $this->assertTrue($fluent->isNotEmpty()); $this->assertFalse($fluent->isEmpty()); } } class FluentArrayIteratorStub implements IteratorAggregate { protected $items = []; public function __construct(array $items = []) { $this->items = $items; } public function getIterator(): ArrayIterator { return new ArrayIterator($this->items); } }