diff --git a/tests/unit/suites/libraries/cms/component/router/rules/JComponentRouterRulesMenuTest.php b/tests/unit/suites/libraries/cms/component/router/rules/JComponentRouterRulesMenuTest.php index 77d250a91fb24..19c654eaf5a81 100644 --- a/tests/unit/suites/libraries/cms/component/router/rules/JComponentRouterRulesMenuTest.php +++ b/tests/unit/suites/libraries/cms/component/router/rules/JComponentRouterRulesMenuTest.php @@ -40,6 +40,10 @@ protected function setUp() { parent::setUp(); + // Getting categories relies on the user access which relies on the session. + $this->saveFactoryState(); + JFactory::$session = $this->getMockSession(); + $app = $this->getMockCmsApp(); JFactory::$application = $app; $router = new JComponentRouterViewInspector($app, $app->getMenu()); @@ -64,6 +68,21 @@ protected function setUp() $this->object = new JComponentRouterRulesMenuInspector($router); } + /** + * Overrides the parent tearDown method. + * + * @return void + * + * @see \PHPUnit\Framework\TestCase::tearDown() + * @since __DEPLOY_VERSION__ + */ + protected function tearDown() + { + $this->restoreFactoryState(); + + parent::tearDown(); + } + /** * Gets the data set to be loaded into the database during setup * diff --git a/tests/unit/suites/libraries/cms/component/router/rules/JComponentRouterRulesStandardTest.php b/tests/unit/suites/libraries/cms/component/router/rules/JComponentRouterRulesStandardTest.php new file mode 100644 index 0000000000000..1655657487521 --- /dev/null +++ b/tests/unit/suites/libraries/cms/component/router/rules/JComponentRouterRulesStandardTest.php @@ -0,0 +1,296 @@ +<?php +/** + * @package Joomla.UnitTest + * @subpackage Component + * + * @copyright Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE + */ + +require_once __DIR__ . '/../stubs/ComContentRouter.php'; +require_once __DIR__ . '/stubs/MockJComponentRouterRulesMenuMenuObject.php'; + +/** + * Test class for JComponentRouterRulesStandard. + * + * @package Joomla.UnitTest + * @subpackage Component + * @since __DEPLOY_VERSION__ + */ +class JComponentRouterRulesStandardTest extends TestCaseDatabase { + + /** + * Object under test + * + * @var JComponentRouterRulesStandard + * @since __DEPLOY_VERSION__ + */ + protected $object; + + /** + * Gets the data set to be loaded into the database during setup + * + * @return PHPUnit_Extensions_Database_DataSet_CsvDataSet + * + * @since __DEPLOY_VERSION__ + */ + protected function getDataSet() + { + $dataSet = new PHPUnit_Extensions_Database_DataSet_CsvDataSet(',', "'", '\\'); + + $dataSet->addTable('jos_categories', JPATH_TEST_DATABASE . '/jos_categories.csv'); + $dataSet->addTable('jos_content', JPATH_TEST_DATABASE . '/jos_content.csv'); + $dataSet->addTable('jos_extensions', JPATH_TEST_DATABASE . '/jos_extensions.csv'); + $dataSet->addTable('jos_menu', JPATH_TEST_DATABASE . '/jos_menu.csv'); + + return $dataSet; + } + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + protected function setUp() + { + parent::setUp(); + $noIds = true; + + // The menu object relies on a session so mock it. + $this->saveFactoryState(); + JFactory::$session = $this->getMockSession(); + + $app = $this->getMockCmsApp(); + JFactory::$application = $app; + + $router = new ContentRouterStandardRuleOnly($app, new JMenuSite(array('app' => $app, 'language' => self::getMockLanguage())), $noIds); + $categories = new JComponentRouterViewconfiguration('categories'); + $categories->setKey('id'); + $router->registerView($categories); + $category = new JComponentRouterViewconfiguration('category'); + $category->setKey('id')->setParent($categories)->setNestable()->addLayout('blog'); + $router->registerView($category); + $article = new JComponentRouterViewconfiguration('article'); + $article->setKey('id')->setParent($category, 'catid'); + $router->registerView($article); + $archive = new JComponentRouterViewconfiguration('archive'); + $router->registerView($archive); + $featured = new JComponentRouterViewconfiguration('featured'); + $router->registerView($featured); + $form = new JComponentRouterViewconfiguration('form'); + $router->registerView($form); + + $this->object = new JComponentRouterRulesStandard($router); + } + + /** + * Overrides the parent tearDown method. + * + * @return void + * + * @see \PHPUnit\Framework\TestCase::tearDown() + * @since __DEPLOY_VERSION__ + */ + protected function tearDown() + { + $this->restoreFactoryState(); + + parent::tearDown(); + } + + /** + * Tests the __construct() method + * + * @return void + * + * @covers JComponentRouterRulesStandard::__construct + * @since __DEPLOY_VERSION__ + */ + public function testConstruct() + { + $this->assertInstanceOf('JComponentRouterRulesStandard', $this->object); + $this->assertInstanceOf('JComponentRouterView', TestReflection::getValue($this->object, 'router')); + } + + /** + * Provides the data to test the build method. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + public function dataTestBuild() + { + return array( + array( + array( + 'option' => 'com_content', + 'view' => 'article', + 'catid' => 19, + 'id' => 8, + 'Itemid' => 260 + ), + array( + 'option' => 'com_content', + 'Itemid' => 260 + ), + array( + 0 => 'beginners' + ), + 'Error building a URL for an article with a parent category menu item' + ), + array( + array( + 'option' => 'com_content', + 'view' => 'article', + 'catid' => 73, + 'id' => 11, + 'Itemid' => 272 + ), + array( + 'option' => 'com_content', + 'Itemid' => 272 + ), + array( + 0 => 'park-site', + 1 => 'photo-gallery', + 2 => 'scenery', + 3 => 'cradle-mountain' + ), + 'Error building a URL for an article with multiple levels to it\'s category menu item' + ), + array( + array( + 'option' => 'com_content', + 'view' => 'category', + 'id' => 19, + 'Itemid' => 260 + ), + array( + 'option' => 'com_content', + 'Itemid' => 260 + ), + array( + ), + 'Error building a URL for category that has a menu item' + ), + array( + array( + 'option' => 'com_content', + 'view' => 'form', + 'Itemid' => 263 + ), + // TODO: I think this might be a bug? I think view should be unset whatever the status of the layout + array( + 'option' => 'com_content', + 'view' => 'form', + 'Itemid' => 263 + ), + array( + ), + 'Error building a URL for a menu item that doesn\'t have a key' + ), + array( + array( + 'option' => 'com_content', + 'id' => 19, + 'Itemid' => 260 + ), + array( + 'option' => 'com_content', + 'id' => 19, + 'Itemid' => 260 + ), + array( + ), + 'URL without a view specified cannot build' + ), + ); + } + + /** + * Tests the build() method + * + * @return void + * + * @covers JComponentRouterRulesStandard::build + * @dataProvider dataTestBuild + * @since __DEPLOY_VERSION__ + */ + public function testBuild($query, $expectedQuery, $expectedSegments, $error) + { + $actualSegments = array(); + $this->object->build($query, $actualSegments); + $this->assertEquals($expectedSegments, $actualSegments, $error); + $this->assertEquals($expectedQuery, $query, $error); + } + + /** + * Provides the data to test the build method. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + public function dataTestParse() + { + return array( + array( + array( + 0 => 'beginners' + ), + array( + 'option' => 'com_content', + 'view' => 'article', + 'catid' => 19, + 'id' => 8 + ), + 260, + 'Error parsing a URL for an article with a parent category menu item' + ), + array( + array( + 0 => 'park-site', + 1 => 'photo-gallery', + 2 => 'scenery', + 3 => 'cradle-mountain' + ), + array( + 'option' => 'com_content', + 'view' => 'article', + 'catid' => 73, + 'id' => 11 + ), + 272, + 'Error parsing a URL for an article with a parent category menu item' + ), + ); + } + + /** + * Tests the build() method + * + * @return void + * + * @covers JComponentRouterRulesStandard::parse + * @dataProvider dataTestParse + * @since __DEPLOY_VERSION__ + */ + public function testParse($segments, $expectedVars, $activeMenu, $error) + { + $vars = array(); + + // Set the router ID effectively mimicking JComponentRouterRulesMenu + /** @var ContentRouterStandardRuleOnly $router */ + $router = TestReflection::getValue($this->object, 'router'); + $router->menu->setActive($activeMenu); + TestReflection::setValue($this->object, 'router', $router); + + $this->object->parse($segments, $vars); + $this->assertEquals($expectedVars, $vars, $error . ' invalid vars'); + $this->assertEquals(array(), $segments, $error . ' invalid segments'); + } +} diff --git a/tests/unit/suites/libraries/cms/component/router/stubs/ComContentRouter.php b/tests/unit/suites/libraries/cms/component/router/stubs/ComContentRouter.php new file mode 100644 index 0000000000000..06464a5e2ce04 --- /dev/null +++ b/tests/unit/suites/libraries/cms/component/router/stubs/ComContentRouter.php @@ -0,0 +1,216 @@ +<?php +/** + * @package Joomla.UnitTest + * @subpackage Component + * + * @copyright Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +defined('_JEXEC') or die; + +/** + * Routing class of com_content, with the following changes: + * 1. The no id's object is a constructor parameter + * 2. The router only has the JComponentRouterRulesStandard rule attached + * + * @since __DEPLOY_VERSION__ + */ +class ContentRouterStandardRuleOnly extends JComponentRouterView +{ + protected $noIDs = false; + protected $name = 'content'; + + /** + * Content Component router constructor + * + * @param JApplicationCms $app The application object + * @param JMenu $menu The menu object to work with + * @param boolean $noIds Should ID's be present in the URL or not? + * + * @since __DEPLOY_VERSION__ + */ + public function __construct($app = null, $menu = null, $noIds) + { + $this->noIDs = $noIds; + $categories = new JComponentRouterViewconfiguration('categories'); + $categories->setKey('id'); + $this->registerView($categories); + $category = new JComponentRouterViewconfiguration('category'); + $category->setKey('id')->setParent($categories, 'catid')->setNestable()->addLayout('blog'); + $this->registerView($category); + $article = new JComponentRouterViewconfiguration('article'); + $article->setKey('id')->setParent($category, 'catid'); + $this->registerView($article); + $this->registerView(new JComponentRouterViewconfiguration('archive')); + $this->registerView(new JComponentRouterViewconfiguration('featured')); + $this->registerView(new JComponentRouterViewconfiguration('form')); + + parent::__construct($app, $menu); + + $this->attachRule(new JComponentRouterRulesStandard($this)); + } + + /** + * Method to get the segment(s) for a category + * + * @param string $id ID of the category to retrieve the segments for + * @param array $query The request that is built right now + * + * @return array|string The segments of this item + * + * @since __DEPLOY_VERSION__ + */ + public function getCategorySegment($id, $query) + { + $category = JCategories::getInstance($this->getName())->get($id); + + if ($category) + { + $path = array_reverse($category->getPath(), true); + $path[0] = '1:root'; + + if ($this->noIDs) + { + foreach ($path as &$segment) + { + list($id, $segment) = explode(':', $segment, 2); + } + } + + return $path; + } + + return array(); + } + + /** + * Method to get the segment(s) for a category + * + * @param string $id ID of the category to retrieve the segments for + * @param array $query The request that is built right now + * + * @return array|string The segments of this item + * + * @since __DEPLOY_VERSION__ + */ + public function getCategoriesSegment($id, $query) + { + return $this->getCategorySegment($id, $query); + } + + /** + * Method to get the segment(s) for an article + * + * @param string $id ID of the article to retrieve the segments for + * @param array $query The request that is built right now + * + * @return array|string The segments of this item + * + * @since __DEPLOY_VERSION__ + */ + public function getArticleSegment($id, $query) + { + if (!strpos($id, ':')) + { + $db = JFactory::getDbo(); + $dbquery = $db->getQuery(true); + $dbquery->select($dbquery->qn('alias')) + ->from($dbquery->qn('#__content')) + ->where('id = ' . $dbquery->q($id)); + $db->setQuery($dbquery); + + $id .= ':' . $db->loadResult(); + } + + if ($this->noIDs) + { + list($void, $segment) = explode(':', $id, 2); + + return array($void => $segment); + } + + return array((int) $id => $id); + } + + /** + * Method to get the id for a category + * + * @param string $segment Segment to retrieve the ID for + * @param array $query The request that is parsed right now + * + * @return mixed The id of this item or false + * + * @since __DEPLOY_VERSION__ + */ + public function getCategoryId($segment, $query) + { + if (isset($query['id'])) + { + $category = JCategories::getInstance($this->getName())->get($query['id']); + + foreach ($category->getChildren() as $child) + { + if ($this->noIDs) + { + if ($child->alias == $segment) + { + return $child->id; + } + } + else + { + if ($child->id == (int) $segment) + { + return $child->id; + } + } + } + } + + return false; + } + + /** + * Method to get the segment(s) for a category + * + * @param string $segment Segment to retrieve the ID for + * @param array $query The request that is parsed right now + * + * @return mixed The id of this item or false + * + * @since __DEPLOY_VERSION__ + */ + public function getCategoriesId($segment, $query) + { + return $this->getCategoryId($segment, $query); + } + + /** + * Method to get the segment(s) for an article + * + * @param string $segment Segment of the article to retrieve the ID for + * @param array $query The request that is parsed right now + * + * @return mixed The id of this item or false + * + * @since __DEPLOY_VERSION__ + */ + public function getArticleId($segment, $query) + { + if ($this->noIDs) + { + $db = JFactory::getDbo(); + $dbquery = $db->getQuery(true); + $dbquery->select($dbquery->qn('id')) + ->from($dbquery->qn('#__content')) + ->where('alias = ' . $dbquery->q($segment)) + ->where('catid = ' . $dbquery->q($query['id'])); + $db->setQuery($dbquery); + + return (int) $db->loadResult(); + } + + return (int) $segment; + } +}