diff --git a/src/Meritoo/Common/Collection/Collection.php b/src/Meritoo/Common/Collection/Collection.php new file mode 100644 index 0000000..7618640 --- /dev/null +++ b/src/Meritoo/Common/Collection/Collection.php @@ -0,0 +1,284 @@ + + * @copyright Meritoo.pl + */ +class Collection implements Countable, ArrayAccess, IteratorAggregate +{ + /** + * The elements of collection + * + * @var array + */ + private $elements; + + /** + * Class constructor + * + * @param array $elements (optional) The elements of collection + */ + public function __construct(array $elements = []) + { + $this->elements = $elements; + } + + /** + * {@inheritdoc} + * Required by interface Countable + */ + public function count() + { + return count($this->elements); + } + + /** + * {@inheritdoc} + * Required by interface ArrayAccess + */ + public function offsetExists($offset) + { + return $this->exists($offset); + } + + /** + * {@inheritdoc} + * Required by interface ArrayAccess + */ + public function offsetGet($offset) + { + if ($this->exists($offset)) { + return $this->elements[$offset]; + } + + return null; + } + + /** + * {@inheritdoc} + * Required by interface ArrayAccess + */ + public function offsetSet($offset, $value) + { + $this->elements[$offset] = $value; + } + + /** + * {@inheritdoc} + * Required by interface ArrayAccess + */ + public function offsetUnset($offset) + { + if ($this->exists($offset)) { + unset($this->elements[$offset]); + } + } + + /** + * {@inheritdoc} + * Required by interface IteratorAggregate + */ + public function getIterator() + { + return new ArrayIterator($this->elements); + } + + /** + * Adds given element (at the end of collection) + * + * @param mixed $element The element to add + * @param mixed $index (optional) Index / key of the element + * @return $this + */ + public function add($element, $index = null) + { + if ($index === null) { + $this->elements[] = $element; + } else { + $this->elements[$index] = $element; + } + + return $this; + } + + /** + * Adds given elements (at the end of collection) + * + * @param array|Collection $elements The elements to add + * @param bool|false $useIndexes (optional) If is set to true, indexes of given elements will be used in + * this collection. Otherwise - not. + * @return $this + */ + public function addMultiple($elements, $useIndexes = false) + { + if (!empty($elements)) { + foreach ($elements as $index => $element) { + if (!$useIndexes) { + $index = null; + } + + $this->add($element, $index); + } + } + + return $this; + } + + /** + * Prepends given element (adds given element at the beginning of collection) + * + * @param mixed $element The element to prepend + * @return $this + */ + public function prepend($element) + { + array_unshift($this->elements, $element); + + return $this; + } + + /** + * Removes given element + * + * @param mixed $element The element to remove + * @return $this + */ + public function remove($element) + { + if ($this->count() > 0) { + foreach ($this->elements as $index => $existing) { + if ($element === $existing) { + unset($this->elements[$index]); + break; + } + } + } + + return $this; + } + + /** + * Returns information if collection is empty + * + * @return bool + */ + public function isEmpty() + { + return empty($this->elements); + } + + /** + * Returns information if given element is first in the collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function isFirst($element) + { + return reset($this->elements) === $element; + } + + /** + * Returns information if given element is last in the collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function isLast($element) + { + return end($this->elements) === $element; + } + + /** + * Returns information if the collection has given element, iow. if given element exists in the collection + * + * @param mixed $element The element to verify + * @return bool + */ + public function has($element) + { + $index = Arrays::getIndexOf($this->elements, $element); + + return $index !== null && $index !== false; + } + + /** + * Returns previous element for given element + * + * @param mixed $element The element to verify + * @return mixed|null + */ + public function getPrevious($element) + { + return Arrays::getPreviousElement($this->elements, $element); + } + + /** + * Returns next element for given element + * + * @param mixed $element The element to verify + * @return mixed|null + */ + public function getNext($element) + { + return Arrays::getNextElement($this->elements, $element); + } + + /** + * Returns the first element in the collection + * + * @return mixed + */ + public function getFirst() + { + return Arrays::getFirstElement($this->elements); + } + + /** + * Returns the last element in the collection + * + * @return mixed + */ + public function getLast() + { + return Arrays::getLastElement($this->elements); + } + + /** + * Returns an array representation of the collection + * + * @return array + */ + public function toArray() + { + return $this->elements; + } + + /** + * Returns information if element with given index/key exists + * + * @param string|int $index The index/key of element + * @return bool + */ + private function exists($index) + { + return isset($this->elements[$index]) || array_key_exists($index, $this->elements); + } +} diff --git a/tests/Meritoo/Common/Tests/Collection/CollectionTest.php b/tests/Meritoo/Common/Tests/Collection/CollectionTest.php new file mode 100644 index 0000000..f8d85c6 --- /dev/null +++ b/tests/Meritoo/Common/Tests/Collection/CollectionTest.php @@ -0,0 +1,334 @@ + + * @copyright Meritoo.pl + */ +class CollectionTest extends PHPUnit_Framework_TestCase +{ + /** + * An empty collection + * + * @var Collection + */ + private $emptyCollection; + + /** + * Simple collection + * + * @var Collection + */ + private $simpleCollection; + + /** + * Elements of simple collection + * + * @var array + */ + private $simpleElements; + + public function testEmptyCollection() + { + static::assertEquals(0, $this->emptyCollection->count()); + static::assertCount(0, $this->emptyCollection); + static::assertEmpty($this->emptyCollection); + + static::assertTrue($this->emptyCollection->isEmpty()); + static::assertEquals([], $this->emptyCollection->toArray()); + static::assertEmpty($this->emptyCollection->toArray()); + + static::assertNull($this->emptyCollection->getFirst()); + static::assertNull($this->emptyCollection->getLast()); + static::assertNull($this->emptyCollection[1]); + static::assertNull($this->emptyCollection['abc']); + } + + public function testNotEmptyCollection() + { + static::assertEquals(4, $this->simpleCollection->count()); + static::assertCount(4, $this->simpleCollection); + static::assertNotEmpty($this->simpleCollection); + + static::assertFalse($this->simpleCollection->isEmpty()); + static::assertEquals($this->simpleElements, $this->simpleCollection->toArray()); + static::assertNotEmpty($this->simpleCollection->toArray()); + + static::assertEquals('lorem', $this->simpleCollection->getFirst()); + static::assertEquals('sit', $this->simpleCollection->getLast()); + static::assertEquals('dolor', $this->simpleCollection[123]); + } + + public function testCount() + { + static::assertEquals(0, $this->emptyCollection->count()); + static::assertEquals(4, $this->simpleCollection->count()); + } + + public function testOffsetExists() + { + static::assertFalse(isset($this->emptyCollection['abc'])); + static::assertFalse(isset($this->simpleCollection['abc'])); + + static::assertTrue(isset($this->simpleCollection[0])); + static::assertTrue(isset($this->simpleCollection[345])); + } + + public function testOffsetGet() + { + static::assertNull($this->emptyCollection['abc']); + static::assertNull($this->simpleCollection['abc']); + + static::assertEquals('lorem', $this->simpleCollection[0]); + static::assertEquals('sit', $this->simpleCollection[345]); + } + + public function testOffsetSet() + { + $this->emptyCollection['test1'] = 1234; + $this->simpleCollection['test2'] = 5678; + + static::assertTrue($this->emptyCollection->has(1234)); + static::assertEquals(1234, $this->emptyCollection['test1']); + + static::assertTrue($this->simpleCollection->has(5678)); + static::assertEquals(5678, $this->simpleCollection['test2']); + } + + public function testOffsetUnset() + { + unset($this->simpleCollection[0]); + + static::assertFalse($this->simpleCollection->has('lorem')); + static::assertEquals('ipsum', $this->simpleCollection[1]); + static::assertEquals(3, $this->simpleCollection->count()); + + unset($this->simpleCollection[123]); + + static::assertFalse($this->simpleCollection->has('dolor')); + static::assertEquals('ipsum', $this->simpleCollection[1]); + static::assertEquals(2, $this->simpleCollection->count()); + } + + public function testGetIterator() + { + static::assertInstanceOf(ArrayIterator::class, $this->simpleCollection->getIterator()); + } + + public function testAdd() + { + $this->emptyCollection->add('test1'); + + static::assertTrue($this->emptyCollection->has('test1')); + static::assertEquals(1, $this->emptyCollection->count()); + static::assertEquals('test1', $this->emptyCollection[0]); + } + + public function testAddWithIndex() + { + $this->emptyCollection->add('test2', 1234); + + static::assertTrue($this->emptyCollection->has('test2')); + static::assertEquals(1, $this->emptyCollection->count()); + static::assertEquals('test2', $this->emptyCollection[1234]); + } + + public function testAddMultipleUsingEmptyArray() + { + $this->emptyCollection->addMultiple([]); + + static::assertEquals(0, $this->emptyCollection->count()); + static::assertTrue($this->emptyCollection->isEmpty()); + } + + public function testAddMultiple() + { + $elements = [ + 'test1', + 'test2', + 1234 => 'test3', + 5678 => 'test4', + ]; + + $this->emptyCollection->addMultiple($elements); + + static::assertFalse($this->emptyCollection->isEmpty()); + static::assertEquals(4, $this->emptyCollection->count()); + + static::assertEquals('test1', $this->emptyCollection[0]); + static::assertEquals('test2', $this->emptyCollection[1]); + static::assertEquals('test3', $this->emptyCollection[2]); + static::assertEquals('test4', $this->emptyCollection[3]); + } + + public function testAddMultipleUsingIndexes() + { + $elements = [ + 'test1', + 'test2', + 1234 => 'test3', + 5678 => 'test4', + ]; + + $this->emptyCollection->addMultiple($elements, true); + + static::assertFalse($this->emptyCollection->isEmpty()); + static::assertEquals(4, $this->emptyCollection->count()); + + static::assertEquals('test1', $this->emptyCollection[0]); + static::assertEquals('test2', $this->emptyCollection[1]); + static::assertEquals('test3', $this->emptyCollection[1234]); + static::assertEquals('test4', $this->emptyCollection[5678]); + } + + public function testPrepend() + { + $this->emptyCollection->prepend('lorem-ipsum'); + + static::assertFalse($this->emptyCollection->isEmpty()); + static::assertEquals(1, $this->emptyCollection->count()); + static::assertEquals('lorem-ipsum', $this->emptyCollection[0]); + + $this->simpleCollection->prepend('lorem-ipsum'); + + static::assertFalse($this->simpleCollection->isEmpty()); + static::assertEquals(5, $this->simpleCollection->count()); + static::assertEquals('lorem-ipsum', $this->simpleCollection[0]); + } + + public function testRemoveNotExistingElement() + { + $this->emptyCollection->remove('abc'); + + static::assertTrue($this->emptyCollection->isEmpty()); + static::assertEquals(0, $this->emptyCollection->count()); + + $this->simpleCollection->remove('abc'); + + static::assertFalse($this->simpleCollection->isEmpty()); + static::assertEquals(4, $this->simpleCollection->count()); + } + + public function testRemove() + { + static::assertFalse($this->simpleCollection->isEmpty()); + static::assertEquals(4, $this->simpleCollection->count()); + static::assertEquals('ipsum', $this->simpleCollection[1]); + + $this->simpleCollection->remove('ipsum'); + + static::assertFalse($this->simpleCollection->isEmpty()); + static::assertEquals(3, $this->simpleCollection->count()); + static::assertNull($this->simpleCollection[1]); + } + + public function testIsEmpty() + { + static::assertTrue($this->emptyCollection->isEmpty()); + static::assertFalse($this->simpleCollection->isEmpty()); + } + + public function testIsFirst() + { + static::assertFalse($this->emptyCollection->isFirst('abc')); + static::assertFalse($this->simpleCollection->isFirst('abc')); + static::assertFalse($this->simpleCollection->isFirst('dolor')); + static::assertTrue($this->simpleCollection->isFirst('lorem')); + } + + public function testIsLast() + { + static::assertFalse($this->emptyCollection->isLast('abc')); + static::assertFalse($this->simpleCollection->isLast('abc')); + static::assertFalse($this->simpleCollection->isLast('dolor')); + static::assertTrue($this->simpleCollection->isLast('sit')); + } + + public function testHas() + { + static::assertFalse($this->emptyCollection->has('abc')); + static::assertFalse($this->simpleCollection->has('abc')); + static::assertTrue($this->simpleCollection->has('lorem')); + static::assertTrue($this->simpleCollection->has('dolor')); + } + + public function testGetPrevious() + { + static::assertNull($this->emptyCollection->getPrevious('abc')); + static::assertNull($this->simpleCollection->getPrevious('abc')); + static::assertNull($this->simpleCollection->getPrevious('lorem')); + + static::assertEquals('lorem', $this->simpleCollection->getPrevious('ipsum')); + static::assertEquals('dolor', $this->simpleCollection->getPrevious('sit')); + } + + public function testGetNext() + { + static::assertNull($this->emptyCollection->getNext('abc')); + static::assertNull($this->simpleCollection->getNext('abc')); + static::assertNull($this->simpleCollection->getNext('sit')); + + static::assertEquals('dolor', $this->simpleCollection->getNext('ipsum')); + static::assertEquals('sit', $this->simpleCollection->getNext('dolor')); + } + + public function testGetFirst() + { + static::assertNull($this->emptyCollection->getFirst()); + static::assertEquals('lorem', $this->simpleCollection->getFirst()); + } + + public function testGetLast() + { + static::assertNull($this->emptyCollection->getLast()); + static::assertEquals('sit', $this->simpleCollection->getLast()); + } + + public function testToArray() + { + static::assertEquals([], $this->emptyCollection->toArray()); + static::assertEquals($this->simpleElements, $this->simpleCollection->toArray()); + } + + public function testExistsVisibilityAndArguments() + { + $reflection = new ReflectionClass(Collection::class); + $method = $reflection->getMethod('exists'); + + self::assertTrue($method->isPrivate()); + self::assertEquals(1, $method->getNumberOfParameters()); + self::assertEquals(1, $method->getNumberOfRequiredParameters()); + } + + /** + * {@inheritdoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->simpleElements = [ + 'lorem', + 'ipsum', + 123 => 'dolor', + 345 => 'sit', + ]; + + $this->emptyCollection = new Collection(); + $this->simpleCollection = new Collection($this->simpleElements); + } +} diff --git a/tests/Meritoo/Common/Tests/Utilities/DatePeriodTest.php b/tests/Meritoo/Common/Tests/Utilities/DatePeriodTest.php index 9fb0b4c..ec15cd4 100644 --- a/tests/Meritoo/Common/Tests/Utilities/DatePeriodTest.php +++ b/tests/Meritoo/Common/Tests/Utilities/DatePeriodTest.php @@ -12,6 +12,7 @@ use DateTime; use Generator; use Meritoo\Common\Utilities\DatePeriod; use Meritoo\Common\Utilities\TestCase; +use ReflectionClass; /** * Tests of date's period @@ -21,6 +22,16 @@ use Meritoo\Common\Utilities\TestCase; */ class DatePeriodTest extends TestCase { + public function testConstructorVisibilityAndArguments() + { + $reflection = new ReflectionClass(DatePeriod::class); + $constructor = $reflection->getConstructor(); + + self::assertTrue($constructor->isPublic()); + self::assertEquals(2, $constructor->getNumberOfParameters()); + self::assertEquals(0, $constructor->getNumberOfRequiredParameters()); + } + /** * @param DateTime $startDate (optional) Start date of period * @param DateTime $endDate (optional) End date of period