<?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\configs as C;
use seekquarry\yioop\library\UnitTest;
use seekquarry\yioop\library\WikiParser;
/**
* Checks that the body written for a front page is read back as the page
* it was meant to be, in whichever markup the group reads.
*
* A group may be set to wiki markup or to markdown, and a heading and a
* link to a page are spelt differently in the two. A body written in the
* wrong one shows its own markup to a reader: a group set to markdown was
* given a wiki heading and drew the equals signs rather than a heading.
* These cases parse what is written with the parser the group would use
* and look for the heading or the link that should have come out, so the
* two spellings cannot drift apart again.
*
* @author Chris Pollett
*/
class FrontPageBodyTest extends UnitTest
{
/**
* Sets up nothing; every case builds the little markup it needs.
*/
public function setUp()
{
}
/**
* Tears down nothing; no case leaves anything behind.
*/
public function tearDown()
{
}
/**
* Parses a piece of markup the way a group set to one engine would.
*
* @param string $markup the markup to read
* @param int $render_engine which markup to read it as
* @return string the html that comes out
*/
public function readAs($markup, $render_engine)
{
$parser = new WikiParser("", false);
return $parser->parse($markup, false, false, $render_engine);
}
/**
* A place left empty names itself as a heading, and it has to be a
* heading in the markup the group reads rather than the other one.
*/
public function undefinedPlaceIsAHeadingInEitherMarkupTestCase()
{
$classes = "front-page-lead front-page-undefined";
$wiki = "{{class=\"" . $classes . "\"\n=Lead Page Undefined=\n}}";
$markdown = "{{class=\"" . $classes .
"\"\n# Lead Page Undefined\n}}";
$from_wiki = $this->readAs($wiki, C\MEDIAWIKI_ENGINE);
$from_markdown = $this->readAs($markdown, C\MARKDOWN_ENGINE);
$this->assertTrue(strpos($from_wiki, "<h1") !== false,
"a wiki heading read as wiki gives a heading");
$this->assertTrue(strpos($from_markdown, "<h1") !== false,
"a markdown heading read as markdown gives a heading");
$this->assertTrue(strpos($from_markdown, "#") === false,
"the markdown heading leaves no hash for a reader to see");
}
/**
* The spelling of the other markup is shown to a reader rather than
* drawn, which is the fault these cases stand guard over.
*/
public function wrongMarkupShowsItselfToAReaderTestCase()
{
$classes = "front-page-lead front-page-undefined";
$wiki_in_markdown = $this->readAs("{{class=\"" . $classes .
"\"\n=Lead Page Undefined=\n}}", C\MARKDOWN_ENGINE);
$this->assertTrue(strpos($wiki_in_markdown, "<h1") === false,
"a wiki heading read as markdown gives no heading");
$this->assertTrue(
strpos($wiki_in_markdown, "=Lead Page Undefined=") !== false,
"a wiki heading read as markdown shows its equals signs");
}
/**
* A place holding one article is a link to that page, and a page name
* with a space in it has to survive being made into one.
*/
public function articlePlaceIsALinkInEitherMarkupTestCase()
{
$named = "Some Page";
$wiki = "{{class=\"front-page-lead\"\n[[" . $named . "]]\n}}";
$markdown = "{{class=\"front-page-lead\"\n[" . $named . "](" .
rawurlencode($named) . ")\n}}";
$from_wiki = $this->readAs($wiki, C\MEDIAWIKI_ENGINE);
$from_markdown = $this->readAs($markdown, C\MARKDOWN_ENGINE);
$this->assertTrue(strpos($from_wiki, "<a href=") !== false,
"a wiki link read as wiki gives a link");
$this->assertTrue(strpos($from_markdown, "<a href=") !== false,
"a markdown link read as markdown gives a link");
$this->assertTrue(strpos($from_markdown, "title=") === false,
"the space in the page name is not read as a link title");
$this->assertTrue(strpos($from_markdown, ">Some Page<") !== false,
"the reader sees the page's own name");
}
/**
* A same-unit mark lets the meaning beside a term hold a list and a
* paragraph rather than only what fits on one line, and the mark
* itself is never shown to a reader.
*/
public function sameUnitHoldsWholeBlocksTestCase()
{
$said = ";'''Voting''': {{same-unit Whether members may vote.\n" .
"* '''No Voting''' - posts carry no vote.\n" .
"* '''Vote Up''' - a member may vote up only. }}\n";
$out = $this->readAs($said, C\MEDIAWIKI_ENGINE);
$this->assertEqual(1, substr_count($out, "<dt>"),
"the run gives one term");
$this->assertEqual(1, substr_count($out, "<dd>"),
"the run gives one meaning");
$this->assertTrue(strpos($out, "<ul>") !== false,
"the meaning holds a list");
$this->assertTrue(strpos($out, "same-unit") === false,
"the mark itself is not shown to a reader");
}
/**
* Without the mark, a meaning is only what fits on its own line, which
* is the behavior everything already written depends on.
*/
public function withoutTheMarkAMeaningIsOneLineTestCase()
{
$said = ";Term: just the one line\n* a list of its own\n";
$out = $this->readAs($said, C\MEDIAWIKI_ENGINE);
$this->assertTrue(strpos($out, "<dd>") !== false,
"the term still gives a meaning");
$this->assertTrue(strpos($out, "<dd><ul>") === false,
"the list after it is not swallowed into the meaning");
}
/**
* The mark standing on its own, with no enclosing thing to be the
* content of, holds what is inside it where it stands rather than
* being shown to a reader as markup.
*/
public function sameUnitStandingAloneIsReadTestCase()
{
$alone = "{{same-unit Several lines held together. }}\n";
foreach ([C\MEDIAWIKI_ENGINE, C\MARKDOWN_ENGINE] as $engine) {
$out = $this->readAs($alone, $engine);
$this->assertTrue(strpos($out, "same-unit Several") === false,
"the mark is not shown to a reader");
$this->assertTrue(
strpos($out, "Several lines held together.") !== false,
"what the mark holds is read where it stood");
}
}
/**
* The mark works wherever a piece of the page reads a line at a time,
* not only beside a term, so a writer need not learn where it may be
* used.
*/
public function sameUnitWorksInEveryLineAtATimePlaceTestCase()
{
$held = "{{same-unit A line.\n* one }}";
$places = ["a list item" => "* " . $held . "\n",
"a table cell" => "{|\n|-\n| " . $held . "\n|}\n",
"an indent" => ": " . $held . "\n",
"on its own" => $held . "\n"];
foreach ($places as $where => $text) {
$out = $this->readAs($text, C\MEDIAWIKI_ENGINE);
$this->assertTrue(strpos($out, "same-unit A") === false,
"the mark is not shown in " . $where);
$this->assertTrue(strpos($out, "<li>one</li>") !== false,
"what the mark holds is read in " . $where);
}
}
/**
* The mark may come after words of the writer's own on the same line,
* as when a list item names what it is about and then holds the rest.
*/
public function sameUnitMayFollowWordsOnItsLineTestCase()
{
$said = "##'''Do this.''' {{same-unit How to do it.\n" .
"* first\n* second }}\n";
$out = $this->readAs($said, C\MEDIAWIKI_ENGINE);
$this->assertTrue(strpos($out, "same-unit How") === false,
"the mark is not shown to a reader");
$this->assertTrue(strpos($out, "<b>Do this.</b>") !== false,
"the writer's own words are kept");
$this->assertTrue(strpos($out, "<li>first</li>") !== false,
"what the mark holds is read");
$this->assertTrue(strpos($out, "<ol>") !== false,
"the numbered item is still a numbered item");
}
/**
* Markdown writes a definition list with the term on its own line and
* the meaning beneath it after a colon, and a meaning may open a
* same-unit mark just as a wiki one may.
*/
public function markdownDefinitionListTakesASameUnitTestCase()
{
$said = "**Voting**\n: {{same-unit Whether members may vote.\n" .
"- **No Voting** - posts carry no vote. }}\n\n" .
"**Feed**\n: The group's posts themselves.\n";
$out = $this->readAs($said, C\MARKDOWN_ENGINE);
$this->assertEqual(2, substr_count($out, "<dt>"),
"both terms give a term");
$this->assertEqual(2, substr_count($out, "<dd>"),
"both terms give a meaning");
$this->assertTrue(strpos($out, "<ul>") !== false,
"the marked meaning holds a list");
$this->assertTrue(strpos($out, "same-unit") === false,
"the mark itself is not shown to a reader");
$this->assertTrue(strpos($out, "<dd>The group") !== false,
"the plain meaning is still just its line");
}
/**
* A line opening with a colon under no term is not a definition, so
* ordinary markdown that happens to start that way is left alone.
*/
public function markdownWithoutATermIsNotADefinitionTestCase()
{
$out = $this->readAs("just a paragraph\n\nand another\n",
C\MARKDOWN_ENGINE);
$this->assertTrue(strpos($out, "<dl>") === false,
"plain paragraphs give no definition list");
}
/**
* What wraps a place in its classes, and what asks a category for its
* articles, are read the same by both, so neither needs a spelling of
* its own.
*/
public function wrapperAndCategoryListReadTheSameTestCase()
{
$wrapper = "{{class=\"front-page-lead\"\nsome words\n}}";
foreach ([C\MEDIAWIKI_ENGINE, C\MARKDOWN_ENGINE] as $engine) {
$out = $this->readAs($wrapper, $engine);
$this->assertTrue(
strpos($out, "class=\"front-page-lead\"") !== false,
"the wrapper gives its classes whichever markup is read");
}
$asked = "{{category-list|Sports|front-page-below}}";
foreach ([C\MEDIAWIKI_ENGINE, C\MARKDOWN_ENGINE] as $engine) {
$out = $this->readAs($asked, $engine);
$this->assertTrue(
strpos($out, "[{category-list|Sports|") !== false,
"the category ask survives whichever markup is read");
}
}
}