<?php
/**
 * SeekQuarry/Yioop --
 * Open Source Pure PHP Search Engine, Crawler, and Indexer
 *
 * Copyright (C) 2009 - 2026  Chris Pollett chris@pollett.org
 *
 * LICENSE:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see
 * <https://www.gnu.org/licenses/>.
 *
 * END LICENSE
 *
 * @author Chris Pollett chris@pollett.org
 * @license https://www.gnu.org/licenses/ GPL3
 * @link https://www.seekquarry.com/
 * @copyright 2009 - 2026
 * @package seek_quarry\tests
 */
namespace seekquarry\yioop\tests;

use seekquarry\yioop\configs as C;
use seekquarry\yioop\controllers\StaticController;
use seekquarry\yioop\library\UnitTest;

/**
 * Checks how the static controller picks the group whose wiki pages it
 * serves. A domain an admin routes to a landing group is served through
 * this controller, and the router hands it that group's id on the
 * ROUTE_GROUP_ID server variable; with no route, or a malformed one, the
 * world-readable Public group must be served instead. These cases pin
 * that resolution down so a stray or forged value cannot select an
 * arbitrary group.
 *
 * @author Chris Pollett
 */
class StaticControllerTest extends UnitTest
{
    /**
     * The controller whose group resolver is under test.
     * @var StaticController
     */
    public $controller;
    /**
     * Builds a controller for each test case without running its
     * constructor, since the group resolver only reads the request's
     * server variables and needs none of the controller's normal set-up.
     */
    public function setUp()
    {
        $reflection = new \ReflectionClass(StaticController::class);
        $this->controller = $reflection->newInstanceWithoutConstructor();
    }
    /**
     * Clears the routed-group server variable so one case does not leak
     * into the next.
     */
    public function tearDown()
    {
        unset($_SERVER['ROUTE_GROUP_ID']);
    }
    /**
     * With no routed group set, the Public group is served, the
     * historical behavior for the site's own static pages.
     */
    public function defaultsToPublicGroupTestCase()
    {
        unset($_SERVER['ROUTE_GROUP_ID']);
        $this->assertEqual($this->controller->staticGroupId(),
            C\PUBLIC_GROUP_ID,
            "no route serves the Public group");
    }
    /**
     * A positive routed group id is served as an integer, so a domain
     * pointed at a custom landing group reads that group's pages.
     */
    public function usesPositiveRoutedGroupTestCase()
    {
        $_SERVER['ROUTE_GROUP_ID'] = "7";
        $this->assertEqual($this->controller->staticGroupId(), 7,
            "a positive route selects that group");
        $this->assertTrue(
            $this->controller->staticGroupId() === 7,
            "the routed id comes back as an integer");
    }
    /**
     * A zero or negative routed group id is treated as no route and
     * falls back to the Public group.
     */
    public function rejectsNonPositiveRoutedGroupTestCase()
    {
        $_SERVER['ROUTE_GROUP_ID'] = "0";
        $this->assertEqual($this->controller->staticGroupId(),
            C\PUBLIC_GROUP_ID,
            "a zero route falls back to the Public group");
        $_SERVER['ROUTE_GROUP_ID'] = "-5";
        $this->assertEqual($this->controller->staticGroupId(),
            C\PUBLIC_GROUP_ID,
            "a negative route falls back to the Public group");
    }
    /**
     * A non-numeric routed group id cannot select a group and falls back
     * to the Public group.
     */
    public function rejectsNonNumericRoutedGroupTestCase()
    {
        $_SERVER['ROUTE_GROUP_ID'] = "not_a_number";
        $this->assertEqual($this->controller->staticGroupId(),
            C\PUBLIC_GROUP_ID,
            "a non-numeric route falls back to the Public group");
    }
    /**
     * On a routed group a baked group-controller self link written with
     * clean urls is rewritten to its static p/ url, keeping the page
     * name.
     */
    public function rewritesCleanUrlSelfLinkTestCase()
    {
        $_SERVER['ROUTE_GROUP_ID'] = "100";
        $html = '<a href="http://localhost/[{controller}]/100?a=wiki' .
            '&amp;[{token}]&amp;page_name=bob">BOB</a>';
        $out = $this->controller->rewriteRoutedGroupLinks($html);
        $this->assertTrue(
            strpos($out, 'href="' . C\SHORT_BASE_URL . 'p/bob"') !== false,
            "clean-url self link becomes the static p/ url");
        $this->assertTrue(strpos($out, '[{token}]') === false,
            "the token placeholder is gone from the rewritten link");
    }
    /**
     * The rewrite keys on the page_name query the read url ends with, so
     * a self link written as a query string, not clean urls, is rewritten
     * the same way.
     */
    public function rewritesQueryStringSelfLinkTestCase()
    {
        $_SERVER['ROUTE_GROUP_ID'] = "100";
        $html = '<a href="/src/?c=[{controller}]&amp;a=wiki&amp;' .
            'group_id=100&amp;[{token}]&amp;page_name=bob">BOB</a>';
        $out = $this->controller->rewriteRoutedGroupLinks($html);
        $this->assertTrue(
            strpos($out, 'href="' . C\SHORT_BASE_URL . 'p/bob"') !== false,
            "query-string self link becomes the static p/ url");
    }
    /**
     * A page served for the Public group keeps its links untouched, since
     * the Public group already carries controller-agnostic links.
     */
    public function leavesPublicGroupLinksUnchangedTestCase()
    {
        unset($_SERVER['ROUTE_GROUP_ID']);
        $html = '<a href="[{controller_and_page}]bob">BOB</a>';
        $this->assertEqual(
            $this->controller->rewriteRoutedGroupLinks($html), $html,
            "a Public page's links are returned unchanged");
    }
}
