Last active
August 31, 2017 16:39
-
-
Save thepsion5/0659dadc1b4bed197dbec096b49cbccb to your computer and use it in GitHub Desktop.
Example Permutation Generation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
trait GeneratesPermutationsTrait | |
{ | |
/** | |
* Generates an array with N unique combinations of inputs and a unique output, where N is equal to 2^count($params) | |
* For example, generatePermutations([], 'Param 1', 'Param 2') would return something similar to: | |
* [ | |
* [ | |
* 'inputs' => ['Param 1v1', 'Param 2v1'], | |
* 'output' => 'Param 1v1 Param 2v1' | |
* ], | |
* [ | |
* 'inputs' => ['Param 1v1', 'Param 2v2'], | |
* 'output' => 'Param 1v1 Param 2v2' | |
* ], | |
* [ | |
* 'inputs' => ['Param 1v2', 'Param 2v1'], | |
* 'output' => 'Param 1v2 Param 2v1' | |
* ], | |
* [ | |
* 'inputs' => ['Param 1v2', 'Param 2v2'], | |
* 'output' => 'Param 1v2 Param 2v2' | |
* ] | |
* ] | |
* | |
* @param array $permutationTypes Associative array of permutation variable types. Supports "string", "bool", and "array" | |
* @param array ...$params One or more parameters used to generate permutations | |
* @return array[] Nested array of permutations, each with an 'inputs' key and an 'output' key | |
*/ | |
protected function generatePermutations(array $permutationTypes, ...$params) | |
{ | |
$permutations = []; | |
$parsedTypes = []; | |
foreach($params as $param) { | |
$parsedTypes[$param] = isset($permutationTypes[$param]) ? $permutationTypes[$param] : 'string'; | |
} | |
$totalPermutations = 2**count($params); | |
for($permutationIndex = 1; $permutationIndex <= $totalPermutations; $permutationIndex++) { | |
$thisPermutation = [ | |
'inputs' => [], | |
'output' => '' | |
]; | |
foreach($params as $paramIndex => $param) { | |
$iteration = ( ( (int) ($permutationIndex / (2**$paramIndex) ) ) % 2) + 1; | |
$thisPermutation['inputs'][] = $this->generatePermutationInputForType($param, $parsedTypes[$param], $iteration); | |
} | |
$thisPermutation['output'] = array_reduce($thisPermutation['inputs'], function($carry, $item) { | |
return $carry . var_export($item, true); | |
}, ''); | |
$permutations[] = $thisPermutation; | |
} | |
return $permutations; | |
} | |
/** | |
* Returns an input based on the supplied parameter name, parameter type, and iteration # | |
* | |
* @param string $param The parameter name | |
* @param string $type The parameter type - supports "array", "bool", and "string" | |
* @param int $iteration | |
* @return array|bool|string | |
*/ | |
private function generatePermutationInputForType($param, $type, $iteration) | |
{ | |
switch($type) { | |
case 'array': | |
return ["$param v$iteration"]; | |
case 'bool': | |
return ($iteration % 2) === 0; | |
case 'string': | |
default: | |
return "$param v$iteration"; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class SomeCacheDecoratorTest extends \PHPUnit\Framework\TestCase | |
{ | |
use GeneratesPermutationsTrait; | |
/* snip - omitted non-relevant code */ | |
/** @test */ | |
public function caches_get_results_get_something_calls() | |
{ | |
//returns 2^(# of params) arrays with an 'inputs' column and an 'output' column | |
$permutations = $this->generatePermutations([], 'Param 1', 'Param 2', 'Param 3'); | |
$mockResults = array_column($permutations, 'output'); | |
//setup expected method calls on the mock | |
foreach($permutations as $permutation) { | |
$this->mockRepo->shouldReceive('getSomething') | |
->with(...$permutation['inputs']) | |
->once() | |
->andReturn($permutation['output']); | |
} | |
$actualResults = []; | |
$cachedResults = []; | |
foreach($permutations as $permutation) { | |
//should call the underlying repository class (in this case, the mock) | |
$actualResults[] = $this->cacheDecorator()->getSomething(...$permutation['inputs']); | |
//should return the cached response without calling the underlying class | |
$cachedResults[] = $this->cacheDecorator()->getSomething(...$permutation['inputs']); | |
} | |
//assert the decorator properly returns the results of the underlying call the first time | |
$this->assertEquals($mockResults, $actualResults); | |
//assert the decorator properly returns the cached results the second time | |
$this->assertEquals($mockResults, $cachedResults); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment