Skip to content

Instantly share code, notes, and snippets.

@weverson83
Created July 17, 2017 18:10
Show Gist options
  • Save weverson83/262142b9d745c4aed535c52d09f09409 to your computer and use it in GitHub Desktop.
Save weverson83/262142b9d745c4aed535c52d09f09409 to your computer and use it in GitHub Desktop.
Category Tree - PHPUnit Test Case
<?php
class CategoryTreeTest extends PHPUnit_Framework_TestCase
{
/**
* @return array
*/
public function getCategories(){
$root = [
'id' => 'root',
'parent' => null,
'children' => [],
];
$books = [
'id' => 'books',
'parent' => 'root',
'children' => [],
];
$movies = [
'id' => 'movies',
'parent' => 'root',
'children' => [],
];
$fantasy = [
'id' => 'fantasy',
'parent' => 'books',
'children' => [],
];
$tolkien = [
'id' => 'tolkien',
'parent' => 'fantasy',
'children' => [],
];
$root['children'] = [&$books, &$movies];
$books['children'] = [&$fantasy];
$fantasy['children'] = [&$tolkien];
return $root;
}
/**
* @return array
*/
public function getProductsAssignments()
{
return [
'B001' => ['movies', 'fantasy'],
'D8' => ['tolkien', 'root'],
'H12' => ['books', 'tolkien', 'root', 'movies', 'fantasy'],
'RX20' => [],
];
}
/**
* @param string $categoryId
* @param array $currentCategory
* @return array | false
*/
public function getCategoryById($categoryId, $currentCategory = null)
{
if (!$currentCategory) {
$currentCategory = $this->getCategories();
}
if ($currentCategory['id'] == $categoryId) {
return $currentCategory;
}
$result = array_reduce($currentCategory['children'], function ($result, $child) use ($categoryId) {
$category = $this->getCategoryById($categoryId, $child);
if ($category) {
$result = $category;
}
return $result;
}, false);
return $result;
}
/**
* @param $productId
* @return array
*/
protected function getProductCategories($productId)
{
$assignments = $this->getProductsAssignments();
if (!array_key_exists($productId, $assignments)) {
return [];
}
return array_reduce($assignments[$productId], function ($result, $categoryId) {
$currentCategory = $this->getCategoryById($categoryId);
if ($currentCategory !== false) {
$result[] = $currentCategory;
}
return $result;
}, []);
}
/**
* @param $productId
* @return array
*/
public function getPaths($productId)
{
$paths = array_reduce($this->getProductCategories($productId), function ($result, $category) {
do {
$path[] = $category['id'];
}
while ($category = $this->getCategoryById($category['parent']));
if (count($path) > 1) {
$result[] = array_reverse($path);
}
return $result;
}, []);
if (!count($paths)) {
return ['EMPTY'];
}
$paths = $this->transformIntoString($this->removeDuplicatedTrees($paths));
usort($paths, function ($pathA, $pathB) {
return strcmp($pathA, $pathB);
});
return $paths;
}
/**
* @param $paths
* @return mixed
*/
protected function transformIntoString($paths)
{
return array_reduce($paths, function ($result, $path) {
$result[] = implode(';', $path);
return $result;
}, []);
}
/**
* @param $paths
* @return array
*/
protected function removeDuplicatedTrees($paths)
{
for ($i = 0; $i < count($paths); $i++) {
for ($j = count($paths) - 1; $j > $i; $j--) {
if (count(array_intersect($paths[$i], $paths[$j])) > 1) {
$paths[$i] = $paths[$i] + $paths[$j];
unset($paths[$j]);
}
}
}
return $paths;
}
public function testGetCategoryById()
{
$root = $this->getCategories();
$this->assertEquals($root, $this->getCategoryById('root'));
$this->assertEquals($root['children'][0], $this->getCategoryById('books'));
$this->assertEquals($root['children'][1], $this->getCategoryById('movies'));
$this->assertEquals($root['children'][0]['children'][0], $this->getCategoryById('fantasy'));
$this->assertEquals($root['children'][0]['children'][0]['children'][0], $this->getCategoryById('tolkien'));
}
public function testPathIsEmptyWhenNoProductIdIsSpecified()
{
$this->assertEquals(['EMPTY'], $this->getPaths(''));
}
public function testPathIsEmptyWhenInvalidProductIdIsSpecified()
{
$this->assertEquals(['EMPTY'], $this->getPaths('XXXXXXXX'));
}
public function testPathIsEmptyWhenProductCategoryIsRoot()
{
$this->assertEquals(['EMPTY'], $this->getPaths('RX20'));
}
public function testPathsReturnsInAlphabeticalOrder()
{
$this->assertEquals(
[
'root;books;fantasy',
'root;movies',
], $this->getPaths('B001'));
}
public function testGetPathsOnFourthLevel()
{
$this->assertEquals(['root;books;fantasy;tolkien'], $this->getPaths('D8'));
}
public function testOnlyTheLongestPathIsReturnedWhenProductHas2CategoriesIntTeSameTree()
{
$this->assertEquals(['root;books;fantasy;tolkien', 'root;movies'], $this->getPaths('H12'));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment