<?php
/**
 * @copyright (c) Kufer Software GmbH, Loisachstrasse 4, D-84453 Mühldorf
 */

/**
 * Generated by PHPUnit_SkeletonGenerator on 2019-02-27 at 15:07:59.
 */
class ArrayOperationsTest extends \PHPUnit\Framework\TestCase
{
  /**
   * @var ArrayOperations
   */
  protected $object;

  /**
   * Sets up the fixture, for example, opens a network connection.
   * This method is called before a test is executed.
   */
  protected function setUp(): void
  {
    $this->object = new ArrayOperations();
  }

  /**
   * Tears down the fixture, for example, closes a network connection.
   * This method is called after a test is executed.
   */
  protected function tearDown(): void
  {
  }

  /**
   * @covers ArrayOperations::any
   * @test
   */
  public function any_leeresArray_False()
  {
    $this->assertFalse($this->object->any(array(), function($e) {return true;}));
  }

  /**
   * @covers ArrayOperations::any
   * @test
   */
  public function any_keinElementPasst_False()
  {
    $istGerade = function($e) {return $e % 2 == 0;};
    $this->assertFalse($this->object->any(array(1, 3, 5), $istGerade));

    $istA = function($e) {return $e == 'a' || $e == 'A'; };
    $this->assertFalse($this->object->any(array('B', 'C'), $istA));
  }

  /**
   * @covers ArrayOperations::any
   * @test
   */
  public function any_einOderMehrereElementePassen_True()
  {
    $istGerade = function($e) {return $e % 2 == 0;};
    $this->assertTrue($this->object->any(array(1, 4, 5), $istGerade));

    $istA = function($e) {return $e == 'a' || $e == 'A'; };
    $this->assertTrue($this->object->any(array('a', 'A'), $istA));
  }

  /**
   * @covers ArrayOperations::all
   * @test
   */
  public function all_leeresArray_False()
  {
    $this->assertFalse($this->object->all(array(), function($e) {return true;}));
  }

  /**
   * @covers ArrayOperations::all
   * @test
   */
  public function all_nichtAlleElementePassen_False()
  {
    $istGerade = function($e) {return $e % 2 == 0;};
    $this->assertFalse($this->object->all(array(2, 3, 4), $istGerade));

    $istA = function($e) {return $e == 'a' || $e == 'A'; };
    $this->assertFalse($this->object->all(array('B', 'A'), $istA));
  }

  /**
   * @covers ArrayOperations::all
   * @test
   */
  public function all_alleElementePassen_True()
  {
    $istGerade = function($e) {return $e % 2 == 0;};
    $this->assertTrue($this->object->all(array(2, 4, 6), $istGerade));

    $istA = function($e) {return $e == 'a' || $e == 'A'; };
    $this->assertTrue($this->object->all(array('a', 'A'), $istA));
  }

  /**
   * @covers ArrayOperations::flatten
   * @test
   */
  public function flatten_leeresArray_leeresArray()
  {
    $this->assertEquals(array(), $this->object->flatten(array()));
  }

  /**
   * @covers ArrayOperations::flatten
   * @test
   */
  public function flatten_eindimensionalesArray_gleichesArray()
  {
    $this->assertEquals(array('1'), $this->object->flatten(array('1')));
    $this->assertEquals(array(1, 2, 3, 4, 5), $this->object->flatten(array(1, 2, 3, 4, 5)));
    $this->assertEquals(array(5, 4, 3, 2, 1), $this->object->flatten(array(5, 4, 3, 2, 1)));
  }

  /**
   * @covers ArrayOperations::flatten
   * @test
   */
  public function flatten_mehrdimensionalesArray_eindimensionalesArray()
  {
    $this->assertEquals(array(1, 2, 3, 4, 5, 6), $this->object->flatten(array(1, 2, 3, array(4, 5, 6))));
    $this->assertEquals(array(1, 2, 3, 4, 5, 6), $this->object->flatten(array(array(1, 2, 3), 4, 5, 6)));
    $this->assertEquals(array(1, 2, 3, 4, 5, 6), $this->object->flatten(array(1, 2, array(3, 4, 5), 6)));

    $this->assertEquals(array(1, 2, 3, 4, 5, 6), $this->object->flatten(array(1, 2, array(array(3, array(4)), 5), 6)));
  }

  /**
   * @covers ArrayOperations::flattenPreserveKeys
   * @test
   */
  public function flattenPreserveKeys_leeresArray_leeresArray()
  {
    $this->assertEquals(array(), $this->object->flattenPreserveKeys(array()));
  }

  /**
   * @covers ArrayOperations::flattenPreserveKeys
   * @test
   */
  public function flattenPreserveKeys_eindimensionalesArray_gleichesArray()
  {
    $this->assertEquals(array('a' => '1'), $this->object->flattenPreserveKeys(array('a' => '1')));
    $this->assertEquals(array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5), $this->object->flattenPreserveKeys(array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5)));
    $this->assertEquals(array(0 => 5, 1 => 4, 2 => 3, 3 => 2, 4 => 1), $this->object->flattenPreserveKeys(array(5, 4, 3, 2, 1)));
  }

  /**
   * @covers ArrayOperations::flattenPreserveKeys
   * @test
   */
  public function flattenPreserveKeys_mehrdimensionalesArray_eindimensionalesArray()
  {
    $this->assertEquals(array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6), $this->object->flattenPreserveKeys(array('a' => 1, 'b' => 2, 'c' => 3, 'x1' => array('d' => 4, 'e' => 5, 'f' => 6))));
    $this->assertEquals(array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6), $this->object->flattenPreserveKeys(array('x1' => array('a' => 1, 'b' => 2, 'c' => 3), 'd' => 4, 'e' => 5, 'f' => 6)));
    $this->assertEquals(array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6), $this->object->flattenPreserveKeys(array('a' => 1, 'b' => 2, 'x1' => array('c' => 3, 'd' => 4, 'e' => 5), 'f' => 6)));

    $this->assertEquals(array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6), $this->object->flattenPreserveKeys(array('a' => 1, 'b' => 2, 'x1' => array('x2' => array('c' => 3, 'x3' => array('d' => 4)), 'e' => 5), 'f' => 6)));
  }

  /**
   * @covers ArrayOperations::flattenPreserveKeys
   * @test
   */
  public function flattenPreserveKeys_mehrfacheKeys_letztereWirdGenommen()
  {
    $this->assertEquals(array('a' => 4, 'b' => 5, 'c' => 3), $this->object->flattenPreserveKeys(array('a' => 1, 'b' => 2, 'c' => 3, 'x1' => array('a' => 4, 'b' => 5))));
    $this->assertEquals(array('a' => 4, 'b' => 5, 'c' => 3), $this->object->flattenPreserveKeys(array('x1' => array('a' => 1, 'b' => 2, 'c' => 3), 'a' => 4, 'b' => 5)));
  }

  /**
   * @covers ArrayOperations::mapRecursive
   * @test
   */
  public function mapRecursive_leeresArray_leeresArray()
  {
    $this->assertEquals(array(), $this->object->mapRecursive('abs', array()));
  }

  /**
   * @covers ArrayOperations::mapRecursive
   * @test
   */
  public function mapRecursive_eindimensinalesArray_wieArrayMap()
  {
    $this->assertEquals(array(1, 2, 3), $this->object->mapRecursive('abs', array(-1, 2, -3)));
    $this->assertEquals(array('abc', 'abc', 'abc'), $this->object->mapRecursive('strtolower', array('abc', 'ABC', 'aBc')));
  }

  /**
   * @covers ArrayOperations::mapRecursive
   * @test
   */
  public function mapRecursive_mehrdimensionalesArray_arbeiteRecursive()
  {
    $this->assertEquals(array(1, 2, array(3)), $this->object->mapRecursive('abs', array(-1, 2, array(-3))));
    $this->assertEquals(array('abc', array('abc'), 'abc'), $this->object->mapRecursive('strtolower', array('abc', array('ABC'), 'aBc')));

    $this->assertEquals(array('a' => 1, 'b' => 2, 'x1' => array('c' => 3)), $this->object->mapRecursive('abs', array('a' => -1, 'b' => 2, 'x1' => array('c' => -3))));

    $this->assertEquals(array(1, array(2, array(3))), $this->object->mapRecursive('abs', array(-1, array(2, array(-3)))));
  }

  /**
   * @covers ArrayOperations::find
   * @test
   */
  public function find_leeresArray_ReturnNull()
  {
    $this->assertNull($this->object->find(function($e) {return true;}, array()));
  }

  /**
   * @covers ArrayOperations::find
   * @test
   */
  public function find_noElementFound_ReturnNull()
  {
    $this->assertNull($this->object->find(function($e) {return false;}, array(1, 2, 3)));
    $this->assertNull($this->object->find(function($e) {return $e > 5;}, array(1, 2, 3)));
    $this->assertNull($this->object->find(function($e) {return strlen($e) > 3;}, array('abc', 'd', 'ef')));
  }

  /**
   * @covers ArrayOperations::find
   * @test
   */
  public function find_oneElementFound_ReturnKey()
  {
    $this->assertEquals($this->object->find(function($e) {return $e == 1;}, array(1, 2, 3)), 0);
    $this->assertEquals($this->object->find(function($e) {return $e > 5;}, array(1, 6, 3)), 1);
    $this->assertEquals($this->object->find(function($e) {return strlen($e) > 3;}, array('null' => 'abc', 'eins' => 'deg', 'zwei' => 'efasdf')), 'zwei');
  }

  /**
   * @covers ArrayOperations::find
   * @test
   */
  public function find_moreElementsFound_ReturnKeyOfFirstFoundElement()
  {
    $this->assertEquals($this->object->find(function($e) {return true;}, array(1, 2, 3)), 0);
    $this->assertEquals($this->object->find(function($e) {return $e > 5;}, array(1, 6, 8)), 1);
    $this->assertEquals($this->object->find(function($e) {return strlen($e) > 3;}, array('null' => 'abc', 'eins' => 'degsdfafdsf', 'zwei' => 'efasdf')), 'eins');
  }

  /**
   * @covers ArrayOptions::replace
   * @test
   */
  public function replace_leeresArray_ReturnLeeresArray()
  {
    $this->assertEquals($this->object->replace(array(), 'A', 'B'), array());
  }

  /**
   * @covers ArrayOptions::replace
   * @test
   */
  public function replace_oneElement_ReturnReplacedElementInArray()
  {
    $this->assertEquals($this->object->replace(array('A'), 'A', 'B'), array('B'));
  }

  /**
   * @covers ArrayOptions::replace
   * @test
   */
  public function replace_oneElementNoMatch_ReturnIdentity()
  {
    $this->assertEquals($this->object->replace(array('A'), 'B', 'C'), array('A'));
  }

  /**
   * @covers ArrayOptions::replace
   * @test
   */
  public function replace_moreElementsOneMatch_ReturnReplacedElementInArray()
  {
    $this->assertEquals($this->object->replace(str_split('hello'), 'e', 'a'), str_split('hallo'));
    $this->assertEquals($this->object->replace(array(1, 2, 3, 4), 4, 1), array(1, 2, 3, 1));
    $this->assertEquals($this->object->replace(array(1, 2, 3, 4), 1, 4), array(4, 2, 3, 4));
  }

  /**
   * @covers ArrayOptions::replace
   * @test
   */
  public function replace_moreElementsMoreMatch_ReturnReplacedElementsInArray()
  {
    $this->assertEquals($this->object->replace(str_split('abcccd'), 'c', 'd'), str_split('abdddd'));
    $this->assertEquals($this->object->replace(array(4, 1, 2, 3, 4), 4, 1), array(1, 1, 2, 3, 1));
    $this->assertEquals($this->object->replace(array(1, 1, 1), 1, 2), array(2, 2, 2));
  }

  /**
   * @covers ArrayOptions::replace
   * @test
   */
  public function replace_preserveKeys_ReturnReplacedValuesNotKeysArray()
  {
    $this->assertEquals(
      $this->object->replace(array('0' => 'nan', '1' => 'eins', '2' => 'zwei'), 'nan', 'null'),
      array('0' => 'null', '1' => 'eins', '2' => 'zwei')
    );
    $this->assertEquals(
      $this->object->replace(array('nan' => 'nan', 'eins' => 'eins', 'zwei' => 'zwei'), 'nan', 'null'),
      array('nan' => 'null', 'eins' => 'eins', 'zwei' => 'zwei')
    );
  }

  /**
   * @covers ArrayOperations::firstValue
   * @test
   */
  public function firstValue_NoValue_ReturnsFalse()
  {
    $this->assertFalse($this->object->firstValue(array()));
  }

  /**
   * @covers ArrayOperations::firstValue
   * @test
   */
  public function firstValue_OneValue_ReturnsValue()
  {
    $this->assertEquals(100, $this->object->firstValue(array(100)));
  }

  /**
   * @covers ArrayOperations::firstValue
   * @test
   */
  public function firstValue_MoreValue_ReturnsFirstValue()
  {
    $this->assertEquals(100, $this->object->firstValue(array(100, 23, 1, 1000)));
  }

  /**
   * @covers ArrayOperations::firstValue
   * @test
   */
  public function firstValue_InternerPointerVerschoben_ReturnsFirstValue()
  {
    $a = array(100, 23, 1, 1000);
    // Eine frühere Implementierung von firstValue hat nur funktioniert, wenn der interne Pointer
    // des Arrays auf das erste Element zeigte.
    next($a);
    $this->assertEquals(100, $this->object->firstValue($a));
  }

  /**
   * @covers ArrayOperations::lastValue
   * @test
   */
  public function lastValue_NoValue_ReturnsFalse()
  {
    $this->assertFalse($this->object->lastValue(array()));
  }

  /**
   * @covers ArrayOperations::lastValue
   * @test
   */
  public function lastValue_OneValue_ReturnsValue()
  {
    $this->assertEquals(100, $this->object->lastValue(array(100)));
  }

  /**
   * @covers ArrayOperations::lastValue
   * @test
   */
  public function lastValue_MoreValue_ReturnsLastValue()
  {
    $this->assertEquals(1000, $this->object->lastValue(array(100, 23, 1, 1000)));
  }

  /**
   * @covers ArrayOperations::setMultidimKeys
   * @test
   */
  public function setMultidimKeys_NoKeys_Throws()
  {
    $this->expectException(InvalidArgumentException::class);
    $array = array('key1', 'wertalt1');
    $this->object->setMultidimKeys($array, array(), 'wertneu');
  }

  /**
   * @covers ArrayOperations::setMultidimKeys
   * @test
   */
  public function setMultidimKeys_OneExistingKey_DoNothing()
  {
    $array = array('key1' => 'wertalt1', 'key2' => 'wertalt2');
    $this->object->setMultidimKeys($array, array('key1'));
    $this->assertEquals('wertalt1', $array['key1']);

    $this->assertEquals('wertalt2', $array['key2']);
  }

  /**
   * @covers ArrayOperations::setMultidimKeys
   * @test
   */
  public function setMultidimKeys_OneNonExistingKey_InsertKey()
  {
    $array = array('key2' => 'wertalt2');
    $this->object->setMultidimKeys($array, array('key1'));
    $this->assertTrue(isset($array['key1']));
    $this->assertEquals(array(), $array['key1']);

    $this->assertEquals('wertalt2', $array['key2']);
  }

  /**
   * @covers ArrayOperations::setMultidimKeys
   * @test
   */
  public function setMultidimKeys_MultipleExistingKeys_DoNothing()
  {
    $array = array('key1' => array(
      'key2' => array(
          'key3' => 'wertalt'
      )
    ));
    $this->object->setMultidimKeys($array, array('key1', 'key2', 'key3'));
    $this->assertEquals('wertalt', $array['key1']['key2']['key3']);
  }

  /**
   * @covers ArrayOperations::setMultidimKeys
   * @test
   */
  public function setMultidimKeys_MultipleNonExistingKeys_InsertNonExistingKeys()
  {
    $array = array('key1' => array(
      'key2' => array(
          'key3' => 'wertalt'
      )
    ));
    $this->object->setMultidimKeys($array, array('key1', 'key2Nicht', 'key3'));
    $this->assertTrue(isset($array['key1']['key2Nicht']['key3']));
    $this->assertEquals(array(), $array['key1']['key2Nicht']['key3']);

    $this->assertEquals('wertalt', $array['key1']['key2']['key3']);
  }

  /**
   * @covers ArrayOperations::filterPreserveKeys
   * @test
   */
  public function filterPreserveKeys_LeeresArray_GibLeeresArrayZurueck()
  {
    $leeresArray = array();
    $praedikat = function($element) {
      return true;
    };

    $arrayGefiltert = $this->object->filterPreserveKeys($leeresArray, $praedikat);

    $this->assertEquals(array(), $arrayGefiltert);
  }

  /**
   * @covers ArrayOperations::filterPreserveKeys
   * @test
   */
  public function filterPreserveKeys_PraedikatImmerFalse_GibLeeresArrayZurueck()
  {
    $array = array(1, 2, 3, 4);
    $praedikatImmerFalse = function($element) {
      return false;
    };

    $arrayGefiltert = $this->object->filterPreserveKeys($array, $praedikatImmerFalse);

    $this->assertEquals(array(), $arrayGefiltert);
  }

  /**
   * @covers ArrayOperations::filterPreserveKeys
   * @test
   */
  public function filterPreserveKeys_PraedikatImmerTrue_GibArrayUnveraendertZurueck()
  {
    $array = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4);
    $praedikatImmerTrue = function($element) {
      return true;
    };

    $arrayGefiltert = $this->object->filterPreserveKeys($array, $praedikatImmerTrue);

    $this->assertEquals(array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4), $arrayGefiltert);
  }

  /**
   * @covers ArrayOperations::filterPreserveKeys
   * @test
   */
  public function filterPreserveKeys_NumerischeKeys_BehaletKeysBei()
  {
    $array = array(0 => 0, 1 => 1, 2 => 2, 3 => 3, 6 => 6, 7 => 7);
    $gerade = function($element) {
      return ($element % 2) == 0;
    };

    $arrayGefiltert = $this->object->filterPreserveKeys($array, $gerade);

    $this->assertEquals(array(0 => 0, 2 => 2, 6 => 6), $arrayGefiltert);
  }

  /**
   * @covers ArrayOperations::filterPreserveKeys
   * @test
   */
  public function filterPreserveKeys_StringKeys_BehaletKeysBei()
  {
    $array = array('a' => 0, 'b' => 1, 'c' => 2, 'd' => 3, 'g' => 6, 'h' => 7);
    $gerade = function($element) {
      return ($element % 2) == 0;
    };

    $arrayGefiltert = $this->object->filterPreserveKeys($array, $gerade);

    $this->assertEquals(array('a' => 0, 'c' => 2, 'g' => 6), $arrayGefiltert);
  }

  /**
   * @covers ArrayOperations::filterReassignKeys
   * @test
   */
  public function filterReassignKeys_LeeresArray_GibLeeresArrayZurueck()
  {
    $leeresArray = array();
    $praedikat = function($element) {
      return true;
    };

    $arrayGefiltert = $this->object->filterReassignKeys($leeresArray, $praedikat);

    $this->assertEquals(array(), $arrayGefiltert);
  }

  /**
   * @covers ArrayOperations::filterReassignKeys
   * @test
   */
  public function filterReassignKeys_PraedikatImmerFalse_GibLeeresArrayZurueck()
  {
    $array = array(1, 2, 3, 4);
    $praedikatImmerFalse = function($element) {
      return false;
    };

    $arrayGefiltert = $this->object->filterReassignKeys($array, $praedikatImmerFalse);

    $this->assertEquals(array(), $arrayGefiltert);
  }

  /**
   * @covers ArrayOperations::filterReassignKeys
   * @test
   */
  public function filterReassignKeys_PraedikatImmerTrue_GibArrayMitNummerischenKeysZurueck()
  {
    $array = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4);
    $praedikatImmerTrue = function($element) {
      return true;
    };

    $arrayGefiltert = $this->object->filterReassignKeys($array, $praedikatImmerTrue);

    $this->assertEquals(array(0 => 1, 1 => 2, 2 => 3, 3 => 4), $arrayGefiltert);
  }

  /**
   * @covers ArrayOperations::filterReassignKeys
   * @test
   */
  public function filterReassignKeys_NumerischeKeys_FuelleLueckenInKeys()
  {
    $array = array(0 => 0, 1 => 1, 2 => 2, 3 => 3, 6 => 6, 7 => 7);
    $gerade = function($element) {
      return ($element % 2) == 0;
    };

    $arrayGefiltert = $this->object->filterReassignKeys($array, $gerade);

    $this->assertEquals(array(0 => 0, 1 => 2, 2 => 6), $arrayGefiltert);
  }

  /**
   * @covers ArrayOperations::filterReassignKeys
   * @test
   */
  public function filterReassignKeys_StringKeys_SetzeNumerischeKeys()
  {
    $array = array('a' => 0, 'b' => 1, 'c' => 2, 'd' => 3, 'g' => 6, 'h' => 7);
    $gerade = function($element) {
      return ($element % 2) == 0;
    };

    $arrayGefiltert = $this->object->filterReassignKeys($array, $gerade);

    $this->assertEquals(array(0 => 0, 1 => 2, 2 => 6), $arrayGefiltert);
  }

  /**
   * @covers \ArrayOperations::xrange
   * @test
   */
  public function xrange_range_equals()
  {
    $this->assertEquals(\range(0, 0), \iterator_to_array($this->object->xrange(0, 0)));
    $this->assertEquals(\range(0, 16), \iterator_to_array($this->object->xrange(0, 16)));
    $this->assertEquals(\range(0, 16, 2), \iterator_to_array($this->object->xrange(0, 16, 2)));
    $this->assertEquals(\range(0, 16, 5), \iterator_to_array($this->object->xrange(0, 16, 5)));
    $this->assertEquals(\range(1, 0), \iterator_to_array($this->object->xrange(1, 0)));
    $this->assertEquals(\range(12, 0), \iterator_to_array($this->object->xrange(12, 0)));
  }

  /**
   * @covers \ArrayOperations::uniqueByKey
   * @test
   */
  public function uniqueByKey_empty_empty()
  {
    $this->assertEquals(array(), $this->object->uniqueByKey(array(), 'id'));
  }

  /**
   * @covers \ArrayOperations::uniqueByKey
   * @test
   */
  public function uniqueByKey_unique_unique()
  {
    $fnCreate = function($i) {
      $obj = new class() {
        public $key;
        public $name;
      };
      $obj->key = $i;
      $obj->name = 'name' . $i;

      return $obj;
    };

    $this->assertEquals(array($fnCreate(0)), $this->object->uniqueByKey(array($fnCreate(0)), 'key'));
    $this->assertEquals(array($fnCreate(1)), $this->object->uniqueByKey(array($fnCreate(1)), 'key'));
    $this->assertEquals(array($fnCreate(0), $fnCreate(1)), $this->object->uniqueByKey(array($fnCreate(0), $fnCreate(1)), 'key'));
  }

  /**
   * @covers \ArrayOperations::uniqueByKey
   * @test
   */
  public function uniqueByKey_notunique_unique()
  {
    $fnCreate = function($i) {
      $obj = new class() {
        public $key;
        public $name;
      };
      $obj->key = $i;
      $obj->name = 'name' . $i;

      return $obj;
    };

    $this->assertEquals(array($fnCreate(0)), $this->object->uniqueByKey(array($fnCreate(0), $fnCreate(0)), 'key'));
    $this->assertEquals(array($fnCreate(0)), $this->object->uniqueByKey(array($fnCreate(0), $fnCreate(0), $fnCreate(0)), 'key'));
    $this->assertEquals(array($fnCreate(1)), $this->object->uniqueByKey(array($fnCreate(1), $fnCreate(1)), 'key'));
    $this->assertEquals(array($fnCreate(0), $fnCreate(1)), $this->object->uniqueByKey(array($fnCreate(0), $fnCreate(1)), 'key'));
    $this->assertEquals(array($fnCreate(0), $fnCreate(1)), $this->object->uniqueByKey(array($fnCreate(0), $fnCreate(1)), 'key'));
    $this->assertEquals(array($fnCreate(1), $fnCreate(0)), $this->object->uniqueByKey(array($fnCreate(1), $fnCreate(0), $fnCreate(1)), 'key'));
    $this->assertEquals(array($fnCreate(1), $fnCreate(0)), $this->object->uniqueByKey(array($fnCreate(1), $fnCreate(0), $fnCreate(1), $fnCreate(1)), 'key'));
  }

  /**
   * @covers \ArrayOperations::reduceWithIntermediateResults
   * @test
   */
  public function reduceWithIntermediateResults_emptyArray_ArrayContainsOnlyInitial()
  {
    $add = function($a, $b) {
      return $a + $b;
    };

    $initial = 123;

    $this->assertEquals(array($initial), $this->object->reduceWithIntermediateResults(array(), $add, $initial));
  }

  /**
   * @covers \ArrayOperations::reduceWithIntermediateResults
   * @test
   */
  public function reduceWithIntermediateResults_ArrayHasOneElement_ArrayContainsInitialAndOneIntermediateResult()
  {
    $add = function($a, $b) {
      return $a + $b;
    };

    $initial = 111;

    $this->assertEquals(array(111, 333), $this->object->reduceWithIntermediateResults(array(222), $add, $initial));
  }

  /**
   * @covers \ArrayOperations::reduceWithIntermediateResults
   * @test
   */
  public function reduceWithIntermediateResults_ArrayHasManyElements_ArrayContainsInitialAndAllIntermediateResults()
  {
    $add = function($a, $b) {
      return $a + $b;
    };

    $initial = 0;

    $this->assertEquals(array(0, 1, 3, 6, 10), $this->object->reduceWithIntermediateResults(array(1, 2, 3, 4), $add, $initial));
  }

  /**
   * @covers \ArrayOperations::reduceWithIntermediateResults
   * @test
   */
  public function reduceWithIntermediateResults_WorkingWithStrings_ArrayOfStrings()
  {
    $concat = function($a, $b) {
      return $a . $b;
    };

    $initial = '';

    $this->assertEquals(array('', 'a', 'ab', 'abc', 'abcd'), $this->object->reduceWithIntermediateResults(array('a', 'b', 'c', 'd'), $concat, $initial));
  }

  /**
   * @covers \ArrayOperations::reduceWithIntermediateResults
   * @test
   */
  public function reduceWithIntermediateResultsIntermediateResultsHaveDiffrentTypes_Array()
  {
    $addLengthOfString = function($intermediateResult, $string) {
      return $intermediateResult + strlen($string);
    };

    $initial = 0;

    $this->assertEquals(array(0, 4, 9), $this->object->reduceWithIntermediateResults(array('vier', 'fuenf'), $addLengthOfString, $initial));
  }

  /**
   * @covers \ArrayOperations::mapUniqueAttribute
   * @test
   */
  public function mapUniqueAttribut_empty_empty()
  {
    $this->assertEquals(array(), $this->object->mapUniqueAttribute(array(), 'attr'));
  }

  /**
   * @covers \ArrayOperations::mapUniqueAttribute
   * @test
   */
  public function mapUniqueAttribute_unique_unique()
  {
    $ary = array_map(static function($i) {
      $result = new class() extends Datamodul {
        public $idx;
      };
      $result->idx = $i;

      return $result;
    }, range(1, 10));

    $this->assertEquals(range(1, 10), $this->object->mapUniqueAttribute($ary, 'idx'));
  }

  /**
   * @covers \ArrayOperations::mapUniqueAttribute
   * @test
   */
  public function mapUniqueAttribute_unique_notUnique()
  {
    $ary = array_map(static function($i) {
      $result = new class() extends Datamodul {
        public $idx;
      };
      $result->idx = $i;

      return $result;
    }, range(1, 10));
    array_push($ary, ...$ary);
    array_push($ary, ...$ary);

    $this->assertEquals(range(1, 10), $this->object->mapUniqueAttribute($ary, 'idx'));
  }
}
