<commit_before><?php

/**
 * @covers Dash\Dash
 */
class DashTest extends PHPUnit_Framework_TestCase
{
	public function testReadmeExamples()
	{
		/*
			Dash vs. array_*()
		 */

		$people = [
			['name' => 'John', 'gender' => 'male',   'age' => 12],
			['name' => 'Jane', 'gender' => 'female', 'age' => 34],
			['name' => 'Pete', 'gender' => 'male',   'age' => 23],
			['name' => 'Mary', 'gender' => 'female', 'age' => 42],
			['name' => 'Mark', 'gender' => 'male',   'age' => 19],
		];

		$avgMaleAge = Dash\chain($people)
			->filter(['gender', 'male'])
			->map('age')
			->average()
			->value();
		$this->assertSame(18, $avgMaleAge);

		if (function_exists('array_column')) {  // array_column() requires PHP 5.5+
			$males = array_filter($people, function ($person) {
				return $person['gender'] === 'male';
			});
			$avgMaleAge = array_sum(array_column($males, 'age')) / count($males);
			$this->assertSame(18, $avgMaleAge);
		}

		/*
			Ad-hoc operation
		 */

		$result = Dash\chain(['one' => 1, 'two' => 2, 'three' => 3])
			->filter('Dash\isOdd')
			->thru(function($input) {
				return array_change_key_case($input, CASE_UPPER);
			})
			->keys()
			->value();
		$this->assertSame(['ONE', 'THREE'], $result);

		/*
			Data types
		 */

		$this->assertSame(
			[4, 8],
			Dash\chain([1, 2, 3, 4])
				->filter('Dash\isEven')
				->map(function ($value) {
					return $value * 2;
				})
				->value()
		);

		$this->assertSame(
			'a, c',
			Dash\chain((object) ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4])
				->filter('Dash\isOdd')
				->keys()
				->join(', ')
				->value()
		);

		$this->assertSame(
			5,
			Dash\chain(new ArrayObject(['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4]))
				->pick(['b', 'c'])
				->values()
				->sum()
				->value()
		);

		$iterator = new \FilesystemIterator(__DIR__, \FilesystemIterator::SKIP_DOTS);
		$filenames = Dash\chain($iterator)
			->reject(function ($fileinfo) {
				return $fileinfo->isDir();
			})
			->map(function ($fileinfo) {
				return pathinfo($fileinfo)['filename'];
			})
			->value();

		$this->assertGreaterThan(10, count($filenames));

		/*
			Custom operation
		 */

		Dash\Dash::setCustom('keyCase', function ($input, $case = CASE_LOWER) {
			return array_change_key_case($input, $case);
		});

		$result = Dash\chain(['one' => 1, 'two' => 2, 'three' => 3])
			->filter('Dash\isOdd')
			->keyCase(CASE_UPPER)
			->keys()
			->value();

		Dash\Dash::unsetCustom('keyCase');
		$this->assertSame(['ONE', 'THREE'], $result);
	}

	public function testExamples()
	{
		$this->assertSame(
			[2, 4, 6],
			Dash\Dash::map([1, 2, 3], function ($n) { return $n * 2; })
		);

		$result = Dash\Dash::chain([1, 2, 3])
			->filter(function ($n) { return $n < 3; })
			->map(function ($n) { return $n * 2; })
			->value();
		$this->assertSame([2, 4], $result);
	}

	public function testCurryExamples()
	{
		// @codingStandardsIgnoreLine
		function DashTest_listThree($a, $b, $c)
		{
			return "$a, $b, and $c";
		}

		$listThree = Dash\curry('DashTest_listThree');
		$listTwo = $listThree('first');
		$this->assertSame('first, second, and third', $listTwo('second', 'third'));

		$filtered = Dash\Dash::chain(['a' => 3, 'b' => '3', 'c' => 3, 'd' => 3.0])
			->filter(Dash\Curry\identical(3))
			->value();

		$this->assertSame(['a' => 3, 'c' => 3], $filtered);

		$containsTruthy = Dash\Curry\contains(true, 'Dash\equal');
		$this->assertTrue($containsTruthy([0, 1, 0]));

		$containsTrue = Dash\Curry\contains(true, 'Dash\identical');
		$this->assertFalse($containsTrue([0, 1, 0]));
	}

	/*
		addGlobalAlias()
		------------------------------------------------------------
	 */

	public function testAddGlobalAliasWithDefault()
	{
		Dash\Dash::addGlobalAlias();
		$chain = __([1, 2, 3]);

		$this->assertInstanceOf('Dash\Dash', $chain);
		$this->assertSame([1, 2, 3], $chain->value());

		$chain->map(function ($n) { return $n * 2; });
		$this->assertSame([2, 4, 6], $chain->value());
	}

	public function testAddGlobalAliasWithCustom()
	{
		Dash\Dash::addGlobalAlias('DashTest_dash');
		$chain = DashTest_dash([1, 2, 3]);

		$this->assertInstanceOf('Dash\Dash', $chain);
		$this->assertSame([1, 2, 3], $chain->value());

		$chain->map(function ($n) { return $n * 2; });
		$this->assertSame([2, 4, 6], $chain->value());
	}

	/**
	 * @expectedException RuntimeException
	 */
	public function testAddGlobalAliasWithExisting()
	{
		$name = 'DashTest_dash' . intval(microtime(true));
		eval("function $name() {}");

		Dash\Dash::addGlobalAlias($name);
	}

	/*
		chain()
		------------------------------------------------------------
	 */

	public function testChain()
	{
		$chain = Dash\Dash::chain([1, 2, 3]);
		$this->assertSame([1, 2, 3], $chain->value());
	}

	public function testChainWithArray()
	{
		$chain = Dash\Dash::chain([1, 2, 3])
			->filter(function ($n) { return $n < 3; })
			->map(function ($n) { return $n * 2; });

		$this->assertSame([2, 4], $chain->value());
	}

	public function testChainWithObject()
	{
		$chain = Dash\Dash::chain((object) ['a' => 1, 'b' => 2, 'c' => 3])
			->pick(['b', 'c'])
			->toObject();

		$this->assertEquals((object) ['b' => 2, 'c' => 3], $chain->value());
	}

	public function testChainWithDefault()
	{
		$chain = Dash\Dash::chain()
			->filter(function ($n) { return $n < 3; })
			->map(function ($n) { return $n * 2; });

		try {
			$chain->value();
			$this->assertTrue(false, 'This should never be called');
		}
		catch (Exception $e) {
			$this->assertTrue(true);
		}

		$chain->with([1, 2, 3]);
		$this->assertSame([2, 4], $chain->value());
	}

	public function testChainReuse()
	{
		$chain = Dash\Dash::chain([1, 2, 3])->map(function ($n) { return $n * 2; });
		$this->assertSame([2, 4, 6], $chain->value());

		$chain->with([4, 5, 6]);
		$this->assertSame([8, 10, 12], $chain->value());
	}

	/*
		setCustom(), unsetCustom()
		------------------------------------------------------------
	 */

	public function testCustomOperation()
	{
		/*
			setCustom()
		 */

		Dash\Dash::setCustom('triple', function ($value) {
			return $value * 3;
		});

		$this->assertSame(12, Dash\Dash::triple(4));

		/*
			unsetCustom()
		 */

		Dash\Dash::unsetCustom('triple');

		try {
			Dash\Dash::triple(2);
			$this->assertTrue(false, 'This should never be called');
		}
		catch (Exception $e) {
			$this->assertTrue(true);
		}
	}

	/**
	 * @expectedException Exception
	 * @codingStandardsIgnoreLine
	 * @expectedExceptionMessage Cannot create a custom method named 'map'; Dash\map() already exists and cannot be overridden
	 */
	public function testCustomOperationWithExisting()
	{
		Dash\Dash::setCustom('map', function ($n) {});
	}

	public function testCustomOperationForNumbersStandalone()
	{
		Dash\Dash::setCustom('triple', function ($value) {
			return $value * 3;
		});

		$this->assertSame(12, Dash\Dash::triple(4));

		Dash\Dash::unsetCustom('triple');
	}

	public function testCustomOperationForNumbersChained()
	{
		Dash\Dash::setCustom('double', function ($value) {
			return $value * 2;
		});

		$this->assertSame(8, Dash\Dash::chain(4)->double()->value());

		Dash\Dash::unsetCustom('double');
	}

	public function testCustomOperationForIterablesStandalone()
	{
		Dash\Dash::setCustom('addEach', function ($iterable, $add) {
			return Dash\Dash::map($iterable, function ($n) use ($add) { return $n + $add; });
		});

		$this->assertSame(
			[4, 5, 6],
			Dash\Dash::addEach([1, 2, 3], 3)
		);

		Dash\Dash::unsetCustom('addEach');
	}

	public function testCustomOperationForIterablesChained()
	{
		Dash\Dash::setCustom('addEach', function ($iterable, $add) {
			return Dash\Dash::map($iterable, function ($n) use ($add) { return $n + $add; });
		});

		$this->assertSame(
			[4, 5, 6],
			Dash\Dash::chain([1, 2, 3])->addEach(3)->value()
		);

		Dash\Dash::unsetCustom('addEach');
	}

	public function testCustomOperationLookup()
	{
		Dash\Dash::setCustom('double', function ($value) {
			return $value * 2;
		});

		$this->assertSame(
			[2, 4, 6],
			Dash\Dash::chain([1, 2, 3])->map('Dash\Dash::double')->value()
		);

		Dash\Dash::unsetCustom('double');
	}

	/*
		Standalone operations
		------------------------------------------------------------
	 */<commit_msg>Add missing test case to cover Dash::getCustom()<commit_after><?php

/**
 * @covers Dash\Dash
 */
class DashTest extends PHPUnit_Framework_TestCase
{
	public function testReadmeExamples()
	{
		/*
			Dash vs. array_*()
		 */

		$people = [
			['name' => 'John', 'gender' => 'male',   'age' => 12],
			['name' => 'Jane', 'gender' => 'female', 'age' => 34],
			['name' => 'Pete', 'gender' => 'male',   'age' => 23],
			['name' => 'Mary', 'gender' => 'female', 'age' => 42],
			['name' => 'Mark', 'gender' => 'male',   'age' => 19],
		];

		$avgMaleAge = Dash\chain($people)
			->filter(['gender', 'male'])
			->map('age')
			->average()
			->value();
		$this->assertSame(18, $avgMaleAge);

		if (function_exists('array_column')) {  // array_column() requires PHP 5.5+
			$males = array_filter($people, function ($person) {
				return $person['gender'] === 'male';
			});
			$avgMaleAge = array_sum(array_column($males, 'age')) / count($males);
			$this->assertSame(18, $avgMaleAge);
		}

		/*
			Ad-hoc operation
		 */

		$result = Dash\chain(['one' => 1, 'two' => 2, 'three' => 3])
			->filter('Dash\isOdd')
			->thru(function($input) {
				return array_change_key_case($input, CASE_UPPER);
			})
			->keys()
			->value();
		$this->assertSame(['ONE', 'THREE'], $result);

		/*
			Data types
		 */

		$this->assertSame(
			[4, 8],
			Dash\chain([1, 2, 3, 4])
				->filter('Dash\isEven')
				->map(function ($value) {
					return $value * 2;
				})
				->value()
		);

		$this->assertSame(
			'a, c',
			Dash\chain((object) ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4])
				->filter('Dash\isOdd')
				->keys()
				->join(', ')
				->value()
		);

		$this->assertSame(
			5,
			Dash\chain(new ArrayObject(['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4]))
				->pick(['b', 'c'])
				->values()
				->sum()
				->value()
		);

		$iterator = new \FilesystemIterator(__DIR__, \FilesystemIterator::SKIP_DOTS);
		$filenames = Dash\chain($iterator)
			->reject(function ($fileinfo) {
				return $fileinfo->isDir();
			})
			->map(function ($fileinfo) {
				return pathinfo($fileinfo)['filename'];
			})
			->value();

		$this->assertGreaterThan(10, count($filenames));

		/*
			Custom operation
		 */

		Dash\Dash::setCustom('keyCase', function ($input, $case = CASE_LOWER) {
			return array_change_key_case($input, $case);
		});

		$result = Dash\chain(['one' => 1, 'two' => 2, 'three' => 3])
			->filter('Dash\isOdd')
			->keyCase(CASE_UPPER)
			->keys()
			->value();

		Dash\Dash::unsetCustom('keyCase');
		$this->assertSame(['ONE', 'THREE'], $result);
	}

	public function testExamples()
	{
		$this->assertSame(
			[2, 4, 6],
			Dash\Dash::map([1, 2, 3], function ($n) { return $n * 2; })
		);

		$result = Dash\Dash::chain([1, 2, 3])
			->filter(function ($n) { return $n < 3; })
			->map(function ($n) { return $n * 2; })
			->value();
		$this->assertSame([2, 4], $result);
	}

	public function testCurryExamples()
	{
		// @codingStandardsIgnoreLine
		function DashTest_listThree($a, $b, $c)
		{
			return "$a, $b, and $c";
		}

		$listThree = Dash\curry('DashTest_listThree');
		$listTwo = $listThree('first');
		$this->assertSame('first, second, and third', $listTwo('second', 'third'));

		$filtered = Dash\Dash::chain(['a' => 3, 'b' => '3', 'c' => 3, 'd' => 3.0])
			->filter(Dash\Curry\identical(3))
			->value();

		$this->assertSame(['a' => 3, 'c' => 3], $filtered);

		$containsTruthy = Dash\Curry\contains(true, 'Dash\equal');
		$this->assertTrue($containsTruthy([0, 1, 0]));

		$containsTrue = Dash\Curry\contains(true, 'Dash\identical');
		$this->assertFalse($containsTrue([0, 1, 0]));
	}

	/*
		addGlobalAlias()
		------------------------------------------------------------
	 */

	public function testAddGlobalAliasWithDefault()
	{
		Dash\Dash::addGlobalAlias();
		$chain = __([1, 2, 3]);

		$this->assertInstanceOf('Dash\Dash', $chain);
		$this->assertSame([1, 2, 3], $chain->value());

		$chain->map(function ($n) { return $n * 2; });
		$this->assertSame([2, 4, 6], $chain->value());
	}

	public function testAddGlobalAliasWithCustom()
	{
		Dash\Dash::addGlobalAlias('DashTest_dash');
		$chain = DashTest_dash([1, 2, 3]);

		$this->assertInstanceOf('Dash\Dash', $chain);
		$this->assertSame([1, 2, 3], $chain->value());

		$chain->map(function ($n) { return $n * 2; });
		$this->assertSame([2, 4, 6], $chain->value());
	}

	/**
	 * @expectedException RuntimeException
	 */
	public function testAddGlobalAliasWithExisting()
	{
		$name = 'DashTest_dash' . intval(microtime(true));
		eval("function $name() {}");

		Dash\Dash::addGlobalAlias($name);
	}

	/*
		chain()
		------------------------------------------------------------
	 */

	public function testChain()
	{
		$chain = Dash\Dash::chain([1, 2, 3]);
		$this->assertSame([1, 2, 3], $chain->value());
	}

	public function testChainWithArray()
	{
		$chain = Dash\Dash::chain([1, 2, 3])
			->filter(function ($n) { return $n < 3; })
			->map(function ($n) { return $n * 2; });

		$this->assertSame([2, 4], $chain->value());
	}

	public function testChainWithObject()
	{
		$chain = Dash\Dash::chain((object) ['a' => 1, 'b' => 2, 'c' => 3])
			->pick(['b', 'c'])
			->toObject();

		$this->assertEquals((object) ['b' => 2, 'c' => 3], $chain->value());
	}

	public function testChainWithDefault()
	{
		$chain = Dash\Dash::chain()
			->filter(function ($n) { return $n < 3; })
			->map(function ($n) { return $n * 2; });

		try {
			$chain->value();
			$this->assertTrue(false, 'This should never be called');
		}
		catch (Exception $e) {
			$this->assertTrue(true);
		}

		$chain->with([1, 2, 3]);
		$this->assertSame([2, 4], $chain->value());
	}

	public function testChainReuse()
	{
		$chain = Dash\Dash::chain([1, 2, 3])->map(function ($n) { return $n * 2; });
		$this->assertSame([2, 4, 6], $chain->value());

		$chain->with([4, 5, 6]);
		$this->assertSame([8, 10, 12], $chain->value());
	}

	/*
		setCustom(), unsetCustom()
		------------------------------------------------------------
	 */

	public function testCustomOperation()
	{
		/*
			setCustom()
		 */

		Dash\Dash::setCustom('triple', function ($value) {
			return $value * 3;
		});

		$this->assertSame(12, Dash\Dash::triple(4));

		/*
			unsetCustom()
		 */

		Dash\Dash::unsetCustom('triple');

		try {
			Dash\Dash::triple(2);
			$this->assertTrue(false, 'This should never be called');
		}
		catch (Exception $e) {
			$this->assertTrue(true);
		}
	}

	/**
	 * @expectedException Exception
	 * @codingStandardsIgnoreLine
	 * @expectedExceptionMessage Cannot create a custom method named 'map'; Dash\map() already exists and cannot be overridden
	 */
	public function testCustomOperationWithExisting()
	{
		Dash\Dash::setCustom('map', function ($n) {});
	}

	public function testCustomOperationForNumbersStandalone()
	{
		Dash\Dash::setCustom('triple', function ($value) {
			return $value * 3;
		});

		$this->assertSame(12, Dash\Dash::triple(4));

		Dash\Dash::unsetCustom('triple');
	}

	public function testCustomOperationForNumbersChained()
	{
		Dash\Dash::setCustom('double', function ($value) {
			return $value * 2;
		});

		$this->assertSame(8, Dash\Dash::chain(4)->double()->value());

		Dash\Dash::unsetCustom('double');
	}

	public function testCustomOperationForIterablesStandalone()
	{
		Dash\Dash::setCustom('addEach', function ($iterable, $add) {
			return Dash\Dash::map($iterable, function ($n) use ($add) { return $n + $add; });
		});

		$this->assertSame(
			[4, 5, 6],
			Dash\Dash::addEach([1, 2, 3], 3)
		);

		Dash\Dash::unsetCustom('addEach');
	}

	public function testCustomOperationForIterablesChained()
	{
		Dash\Dash::setCustom('addEach', function ($iterable, $add) {
			return Dash\Dash::map($iterable, function ($n) use ($add) { return $n + $add; });
		});

		$this->assertSame(
			[4, 5, 6],
			Dash\Dash::chain([1, 2, 3])->addEach(3)->value()
		);

		Dash\Dash::unsetCustom('addEach');
	}

	public function testCustomOperationLookup()
	{
		Dash\Dash::setCustom('double', function ($value) {
			return $value * 2;
		});

		$this->assertSame(
			[2, 4, 6],
			Dash\Dash::chain([1, 2, 3])->map(Dash\Dash::getCustom('double'))->value()
		);

		$this->assertSame(
			[2, 4, 6],
			Dash\Dash::chain([1, 2, 3])->map('Dash\Dash::double')->value()
		);

		Dash\Dash::unsetCustom('double');
	}

	/*
		Standalone operations
		------------------------------------------------------------
	 */
{'fraction_non_alphanumeric': 0.25198424719781887, 'fraction_numerical': 0.019872765828536806, 'mean_word_length': 3.2420971472629145, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 278, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3993305', 'n_tokens_mistral': 7148, 'n_tokens_neox': 6013, 'n_words': 1165}