<?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
 * @filesource
 */
namespace seekquarry\yioop\tests;

use seekquarry\yioop\library\JavascriptUnitTest;
use seekquarry\yioop\library\WikiParser;

/**
 * Checks that the Javascript wiki parser in scripts/help.js renders wiki
 * inputs to the same html the server-side WikiParser produces. The two
 * parsers are a port of one another and are meant to agree character for
 * character, so the server parser renders each input to get the html the
 * Javascript parser is expected to match. There are two groups of cases:
 * the code block cases Chris reported, where a multi-line code example used
 * to leak its close code tag and a code block wrapping a pre tag used to
 * break on its line breaks, and a broader group covering headings,
 * emphasis, links, lists, tables, and other everyday markup. In a browser
 * each group shows a pass or fail table; from the command line the
 * JavascriptUnitTest runner replays the same check under node.
 *
 * @author Chris Pollett
 */
class WikiParserJavascriptTest extends JavascriptUnitTest
{
    /**
     * Checks the code and pre block cases Chris reported plus the plain
     * inline code and pre cases they grew out of.
     *
     * @return string html and Javascript that checks each case in a
     *      browser or, from the command line, under node
     */
    public function codeBlockTestCase()
    {
        $inputs = [
            ["inline code", "see <code>foo</code> here\n"],
            ["pre block", "<pre>x</pre>\n"],
            ["user agent code block",
                "<code>\n Mozilla/5.0 (compatible; NAME_FROM_THIS_FIELD; " .
                "YOUR_SITES_URL/bot)\n</code>\n"],
            ["code around pre on one line",
                "<code><pre>lalala</pre></code>\n"],
            ["code around pre on many lines",
                "<code>\n<pre>\nlalala\n</pre>\n</code>\n"],
            ["text after a pre close", "<pre>foo</pre> and more\n"],
        ];
        return $this->renderCases("wikiParserCodeBlock",
            "codeBlockTestCase", $inputs);
    }
    /**
     * Checks a broad set of everyday wiki markup so the port is exercised
     * beyond the code block cases.
     *
     * @return string html and Javascript that checks each case in a
     *      browser or, from the command line, under node
     */
    public function parseCorpusTestCase()
    {
        $inputs = [
            ["heading", "== Sub =="],
            ["italic", "''i''"],
            ["bold", "'''b'''"],
            ["internal link", "[[Page|text]]"],
            ["external link", "[[http://x/|e]]"],
            ["nested list", "* a\n** b\n"],
            ["ordered list", "# one\n# two\n"],
            ["definition list", "; term : def\n"],
            ["table", "{|\n! H\n|-\n| c\n|}\n"],
            ["nowiki", "<nowiki><b>x</b></nowiki>\n"],
            ["indent", ": in\n"],
            ["horizontal rule", "----\n"],
            ["multibyte", "café ⚙\n"],
        ];
        return $this->renderCases("wikiParserCorpus",
            "parseCorpusTestCase", $inputs);
    }
    /**
     * Renders the server parser output for each input and builds the html
     * and Javascript block that, in a browser or under node, renders each
     * input again with the Javascript parser and reports whether it matches
     * the server output. Each input is a name paired with a wiki source.
     *
     * @param string $container_id id of the div the result table is added
     *      under
     * @param string $test_name name shown for this group of cases
     * @param array $inputs list of name and wiki source pairs to check
     * @return string the html and Javascript block for this group of cases
     */
    private function renderCases($container_id, $test_name, $inputs)
    {
        $parser = new WikiParser("/b/");
        $cases = [];
        foreach ($inputs as $input) {
            $cases[] = ["name" => $input[0], "source" => $input[1],
                "expected" => $parser->parse($input[1], false, false, 0)];
        }
        $wiki_cases = json_encode($cases);
        ob_start();
        ?>
        <div id="<?= $container_id ?>">
        </div>
        <script src="../scripts/basic.js" ></script>
        <script src="../scripts/help.js" ></script>
        <script src="../scripts/javascript_unit_test.js" ></script>
        <script>
        var wiki_cases = <?= $wiki_cases ?>;
        var results = [];
        for (let index = 0; index < wiki_cases.length; index++) {
            let parser = new WikiParser("/b/", false);
            let rendered = parser.parse(wiki_cases[index].source, false);
            results.push({ name: wiki_cases[index].name,
                pass: rendered === wiki_cases[index].expected });
        }
        reportUnitTestResults("<?= $container_id ?>", "<?= $test_name ?>",
            results);
        </script>
        <?php
        $out_data = ob_get_contents();
        ob_end_clean();
        return $out_data;
    }
}
