Update website

This commit is contained in:
Guilhem Lavaux 2024-11-19 08:02:04 +01:00
parent 4413528994
commit 1d90fbf296
6865 changed files with 1091082 additions and 0 deletions

View file

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST;
use Doctrine\RST\Builder;
use Exception;
use PHPUnit\Framework\TestCase;
use function file_get_contents;
use function shell_exec;
abstract class BaseBuilderTest extends TestCase
{
/** @var Builder */
protected $builder;
abstract protected function getFixturesDirectory(): string;
protected function setUp(): void
{
shell_exec('rm -rf ' . $this->targetFile());
$this->builder = new Builder();
$this->builder->getConfiguration()->setUseCachedMetas(false);
$this->configureBuilder($this->builder);
$this->builder->build($this->sourceFile(), $this->targetFile());
}
protected function configureBuilder(Builder $builder): void
{
}
protected function sourceFile(string $file = ''): string
{
return __DIR__ . '/' . $this->getFixturesDirectory() . '/input/' . $file;
}
protected function targetFile(string $file = ''): string
{
return __DIR__ . '/' . $this->getFixturesDirectory() . '/output/' . $file;
}
/** @throws Exception */
protected function getFileContents(string $path): string
{
$contents = file_get_contents($path);
if ($contents === false) {
throw new Exception('Could not load file.');
}
return $contents;
}
}

View file

@ -0,0 +1,412 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\Builder;
use Doctrine\RST\Builder;
use Doctrine\RST\Meta\MetaEntry;
use Doctrine\Tests\RST\BaseBuilderTest;
use Symfony\Component\DomCrawler\Crawler;
use function array_map;
use function array_unique;
use function array_values;
use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function is_dir;
use function iterator_to_array;
use function range;
use function sleep;
use function sprintf;
use function str_replace;
use function substr_count;
use function unserialize;
/**
* Unit testing for RST
*/
class BuilderTest extends BaseBuilderTest
{
public function testRecreate(): void
{
$builder = $this->builder->recreate();
self::assertSame($this->builder->getKernel(), $builder->getKernel());
self::assertSame($this->builder->getConfiguration(), $builder->getConfiguration());
}
/**
* Tests that the build produced the excepted documents
*/
public function testBuild(): void
{
self::assertTrue(is_dir($this->targetFile()));
self::assertTrue(file_exists($this->targetFile('index.html')));
self::assertTrue(file_exists($this->targetFile('introduction.html')));
self::assertTrue(file_exists($this->targetFile('subdirective.html')));
self::assertTrue(file_exists($this->targetFile('magic-link.html')));
self::assertTrue(file_exists($this->targetFile('subdir/test.html')));
self::assertTrue(file_exists($this->targetFile('subdir/file.html')));
}
public function testCachedMetas(): void
{
// check that metas were cached
self::assertTrue(file_exists($this->targetFile('metas.php')));
$cachedContents = (string) file_get_contents($this->targetFile('metas.php'));
/** @var MetaEntry[] $metaEntries */
$metaEntries = unserialize($cachedContents);
self::assertArrayHasKey('index', $metaEntries);
self::assertSame('Summary', $metaEntries['index']->getTitle());
// look at all the other documents this document depends
// on, like :doc: and :ref:
self::assertSame([
'index',
'toc-glob',
'subdir/index',
], array_values(array_unique($metaEntries['introduction']->getDepends())));
// assert the self-refs don't mess up dependencies
self::assertSame([
'subdir/index',
'index',
'subdir/file',
], array_values(array_unique($metaEntries['subdir/index']->getDepends())));
// update meta cache to see that it was used
// Summary is the main header in "index.rst"
// we reference it in link-to-index.rst
// it should cause link-to-index.rst to re-render with the new
// title as the link
file_put_contents(
$this->targetFile('metas.php'),
str_replace('Summary', 'Sumario', $cachedContents)
);
// also we need to trigger the link-to-index.rst as looking updated
sleep(1);
$contents = file_get_contents(__DIR__ . '/input/link-to-index.rst');
file_put_contents(
__DIR__ . '/input/link-to-index.rst',
$contents . ' '
);
// change it back
file_put_contents(
__DIR__ . '/input/link-to-index.rst',
$contents
);
// new builder, which will use cached metas
$builder = new Builder();
$builder->build($this->sourceFile(), $this->targetFile());
$contents = $this->getFileContents($this->targetFile('link-to-index.html'));
self::assertStringContainsString('Sumario', $contents);
}
/**
* Tests the ..url :: directive
*/
public function testUrl(): void
{
$contents = $this->getFileContents($this->targetFile('index.html'));
self::assertStringContainsString('"magic-link.html', $contents);
self::assertStringContainsString('Another page', $contents);
}
/**
* Tests the links
*/
public function testLinks(): void
{
$contents = $this->getFileContents($this->targetFile('subdir/test.html'));
self::assertStringContainsString('"../to/resource"', $contents);
self::assertStringContainsString('"http://absolute/"', $contents);
self::assertStringContainsString('"http://google.com"', $contents);
self::assertStringContainsString('"http://yahoo.com"', $contents);
self::assertSame(2, substr_count($contents, 'http://something.com'));
}
public function testAnchor(): void
{
$contents = $this->getFileContents($this->targetFile('subdir/test.html'));
self::assertStringContainsString('<p>This is a <a href="test.html#test-anchor">test anchor</a></p>', $contents);
self::assertStringContainsString('<a id="test-anchor"></a>', $contents);
}
/**
* Tests that the index toctree worked
*/
public function testToctree(): void
{
$contents = $this->getFileContents($this->targetFile('index.html'));
self::assertStringContainsString('"introduction.html', $contents);
self::assertStringContainsString('Introduction page', $contents);
self::assertStringContainsString('"subdirective.html', $contents);
self::assertStringContainsString('"subdir/test.html', $contents);
self::assertStringContainsString('"subdir/file.html', $contents);
}
public function testToctreeGlob(): void
{
$contents = $this->getFileContents($this->targetFile('toc-glob.html'));
// links to first <h1> tag of other pages must not contain a url fragment
self::assertStringContainsString('magic-link.html"', $contents);
self::assertStringContainsString('introduction.html"', $contents);
self::assertStringContainsString('subdirective.html"', $contents);
self::assertStringContainsString('subdir/file.html"', $contents);
// links to other <h1> tags should contain a url fragment
self::assertStringContainsString('index.html#another-h1', $contents);
// links to other headings contain a url fragment
self::assertStringContainsString('subdir/test.html#subdirectory', $contents);
self::assertStringContainsString('subdir/file.html#heading-2', $contents);
// link to <h1> inside the same page contains a url fragment
self::assertStringContainsString('toc-glob.html#toc-glob', $contents);
}
public function testToctreeGlobOrder(): void
{
$contents = $this->getFileContents($this->targetFile('toc-glob.html'));
// assert `index` is first since it is defined first in toc-glob.rst
self::assertStringContainsString('<div class="toc"><ul><li id="index-html" class="toc-item"><a href="index.html">Summary</a></li>', $contents);
// assert `index` is not included and duplicated by the glob
self::assertStringNotContainsString('</ul><li id="index-html" class="toc-item"><a href="index.html">Summary</a></li>', $contents);
// assert `introduction` is at the end after the glob since it is defined last in toc-glob.rst
self::assertStringContainsString('<a href="introduction.html">Introduction page</a></li></ul></div>', $contents);
// assert the glob part is alphabetical
$crawler = new Crawler($contents);
$expectedLinks = [
'index.html',
// a second "h1" (a rare thing) is included as a top-level headline
'index.html#another-h1',
// this is another.rst - it has a custom url
'magic-link.html',
'introduction.html',
'link-to-index.html',
// the subdir handling is actually different than Sphinx, which
// does not look into subdirs with a normal * glob
'subdir/file.html',
'subdir/test.html',
'subdir/toc.html',
'subdirective.html',
'toc-glob-reversed.html',
// only here because we explicitly include it, "self file" is normally ignored
'toc-glob.html#toc-glob',
// this is manually included again
'introduction.html',
];
$actualLinks = array_map(static function ($linkElement): string {
return $linkElement->attributes->getNamedItem('href')->nodeValue;
}, iterator_to_array($crawler->filter('.toc > ul > li > a')));
self::assertSame($expectedLinks, $actualLinks);
}
public function testToctreeGlobReversedOrder(): void
{
$contents = $this->getFileContents($this->targetFile('toc-glob-reversed.html'));
$crawler = new Crawler($contents);
// see previous test for why they are in this order (now reversed)
$expectedLinks = [
'introduction.html',
'toc-glob.html',
'subdirective.html',
'subdir/toc.html',
'subdir/test.html',
'subdir/file.html',
'link-to-index.html',
'introduction.html',
'magic-link.html',
'index.html',
// having the other h1 anchor AFTER index.html is what Sphinx does too
'index.html#another-h1',
];
$actualLinks = array_map(static function ($linkElement): string {
return $linkElement->attributes->getNamedItem('href')->nodeValue;
}, iterator_to_array($crawler->filter('.toc > ul > li > a')));
self::assertSame($expectedLinks, $actualLinks);
}
public function testToctreeInSubdirectory(): void
{
$contents = $this->getFileContents($this->targetFile('subdir/toc.html'));
self::assertStringContainsString('../introduction.html"', $contents);
self::assertStringContainsString('../subdirective.html"', $contents);
self::assertStringContainsString('../magic-link.html"', $contents);
self::assertStringContainsString('"test.html"', $contents);
self::assertStringContainsString('file.html"', $contents);
}
public function testAnchors(): void
{
$contents = $this->getFileContents($this->targetFile('index.html'));
self::assertStringContainsString('<a id="reference_anchor"></a>', $contents);
$contents = $this->getFileContents($this->targetFile('introduction.html'));
self::assertStringContainsString('<p>Reference to the <a href="index.html#reference_anchor">Summary Reference</a></p>', $contents);
}
/**
* Testing references to other documents
*/
public function testReferences(): void
{
$contents = $this->getFileContents($this->targetFile('introduction.html'));
self::assertStringContainsString('<a href="index.html#toc">Index, paragraph toc</a>', $contents);
self::assertStringContainsString('<a href="index.html">Index</a>', $contents);
self::assertStringContainsString('<a href="index.html">Summary</a>', $contents);
self::assertStringContainsString('<a href="index.html">Link index absolutely</a>', $contents);
self::assertStringContainsString('<a href="subdir/test.html#test_reference">Test Reference</a>', $contents);
self::assertStringContainsString('<a href="subdir/test.html#camelCaseReference">Camel Case Reference</a>', $contents);
$contents = $this->getFileContents($this->targetFile('subdir/test.html'));
self::assertStringContainsString('"../index.html"', $contents);
self::assertStringContainsString('<a href="test.html#subdir_same_doc_reference">the subdir same doc reference</a>', $contents);
self::assertStringContainsString('<a href="../index.html">Reference absolute to index</a>', $contents);
self::assertStringContainsString('<a href="file.html">Reference absolute to file</a>', $contents);
self::assertStringContainsString('<a href="file.html">Reference relative to file</a>', $contents);
$contents = $this->getFileContents($this->targetFile('index.html'));
self::assertStringContainsString('Link to <a href="index.html#same_doc_reference">the same doc reference</a>', $contents);
self::assertStringContainsString('Link to <a href="index.html#same_doc_reference_ticks">the same doc reference with ticks</a>', $contents);
self::assertStringContainsString('Link to <a href="subdir/test.html#subdirectory">Subdirectory</a>', $contents);
self::assertStringContainsString('Link to <a href="subdir/test.html#subdirectory">Subdirectory Test</a>', $contents);
self::assertStringContainsString('Link to <a href="subdir/test.html#subdirectory-child">Subdirectory Child', $contents);
self::assertStringContainsString('Link to <a href="subdir/test.html#subdirectory-child">Subdirectory Child Test</a>', $contents);
self::assertStringContainsString('Link to <a href="subdir/test.html#subdirectory-child-level-2">Subdirectory Child Level 2', $contents);
self::assertStringContainsString('Link to <a href="subdir/test.html#subdirectory-child-level-2">Subdirectory Child Level 2 Test</a>', $contents);
self::assertStringContainsString('Link to <a href="subdir/test.html#subdirectory-child-level-3">Subdirectory Child Level 3', $contents);
self::assertStringContainsString('Link to <a href="subdir/test.html#subdirectory-child-level-3">Subdirectory Child Level 3 Test</a>', $contents);
}
public function testSubdirReferences(): void
{
$contents = $this->getFileContents($this->targetFile('subdir/test.html'));
self::assertStringContainsString('<p>This is a <a href="test.html#test-anchor">test anchor</a></p>', $contents);
self::assertStringContainsString('<p>This is a <a href="test.html#test-subdir-anchor">test subdir reference with anchor</a></p>', $contents);
}
public function testFileInclude(): void
{
$contents = $this->getFileContents($this->targetFile('subdir/test.html'));
self::assertSame(2, substr_count($contents, 'This file is included'));
}
/**
* Testing wrapping sub directive
*/
public function testSubDirective(): void
{
$contents = $this->getFileContents($this->targetFile('subdirective.html'));
self::assertSame(2, substr_count($contents, '<div class="note">'));
self::assertSame(2, substr_count($contents, '<li>'));
self::assertStringContainsString('</div>', $contents);
self::assertSame(2, substr_count($contents, '</li>'));
self::assertSame(1, substr_count($contents, '<ul>'));
self::assertSame(1, substr_count($contents, '</ul>'));
self::assertStringContainsString('<p>This is a simple note!</p>', $contents);
self::assertStringContainsString('<h2>There is a title here</h2>', $contents);
}
public function testReferenceInDirective(): void
{
$contents = $this->getFileContents($this->targetFile('index.html'));
self::assertStringContainsString(
'<div class="note"><p><a href="introduction.html">Reference in directory</a></p>',
$contents
);
}
public function testTitleLinks(): void
{
$contents = $this->getFileContents($this->targetFile('magic-link.html'));
self::assertStringContainsString(
'<p>see <a href="magic-link.html#see-also">See also</a></p>',
$contents
);
self::assertStringContainsString(
'<p>see <a href="magic-link.html#another-page">Another page</a></p>',
$contents
);
self::assertStringContainsString(
'<p>see <a href="magic-link.html#test">test</a></p>',
$contents
);
self::assertStringContainsString(
'<p>see <a href="magic-link.html#title-with-ampersand">title with ampersand &amp;</a></p>',
$contents
);
self::assertStringContainsString(
'<p>see <a href="magic-link.html#a-title-with-ticks">A title with ticks</a></p>',
$contents
);
}
public function testHeadings(): void
{
$contents = $this->getFileContents($this->targetFile('subdir/file.html'));
foreach (range(1, 6) as $index) {
self::assertStringContainsString(
sprintf(
'<h%d>Heading %d</h%d>',
$index,
$index,
$index
),
$contents
);
}
}
public function testReferenceToTitleWith2CharactersLong(): void
{
$contents = $this->getFileContents($this->targetFile('subdir/test.html'));
self::assertStringContainsString(
'<a href="test.html#em">em</a>',
$contents
);
}
protected function getFixturesDirectory(): string
{
return 'Builder';
}
}

View file

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\Builder;
use Doctrine\RST\Builder\Copier;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Filesystem\Filesystem;
class CopierTest extends TestCase
{
/** @var Filesystem|MockObject */
private $filesystem;
/** @var Copier */
private $copier;
public function testDoCopy(): void
{
$this->filesystem->expects(self::once())
->method('copy')
->with('/source/from', '/target/to');
$this->copier->copy('from', 'to');
$this->copier->doCopy('/source', '/target');
}
public function testDoMkdir(): void
{
$this->filesystem->expects(self::once())
->method('mkdir')
->with('/target/directory');
$this->copier->mkdir('directory');
$this->copier->doMkdir('/target');
}
protected function setUp(): void
{
$this->filesystem = $this->createMock(Filesystem::class);
$this->copier = new Copier($this->filesystem);
}
}

View file

@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\Builder;
use Doctrine\RST\Builder\Documents;
use Doctrine\RST\Meta\MetaEntry;
use Doctrine\RST\Meta\Metas;
use Doctrine\RST\Nodes\DocumentNode;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Filesystem\Filesystem;
class DocumentsTest extends TestCase
{
/** @var Filesystem|MockObject */
private $filesystem;
/** @var Metas|MockObject */
private $metas;
/** @var Documents */
private $documents;
public function testGetAll(): void
{
$document1 = $this->createMock(DocumentNode::class);
$document2 = $this->createMock(DocumentNode::class);
$this->documents->addDocument('document1', $document1);
$this->documents->addDocument('document2', $document2);
$expected = [
'document1' => $document1,
'document2' => $document2,
];
self::assertSame($expected, $this->documents->getAll());
}
public function testHasDocument(): void
{
self::assertFalse($this->documents->hasDocument('document'));
$document = $this->createMock(DocumentNode::class);
$this->documents->addDocument('document', $document);
self::assertTrue($this->documents->hasDocument('document'));
}
public function testRender(): void
{
$document = $this->createMock(DocumentNode::class);
$this->documents->addDocument('document', $document);
$metaEntry = $this->createMock(MetaEntry::class);
$this->metas->expects(self::once())
->method('get')
->with('document')
->willReturn($metaEntry);
$metaEntry->expects(self::once())
->method('getUrl')
->willReturn('url');
$this->filesystem->expects(self::once())
->method('mkdir')
->with('/target', 0755);
$document->expects(self::once())
->method('renderDocument')
->willReturn('rendered document');
$this->filesystem->expects(self::once())
->method('dumpFile')
->with('/target/url', 'rendered document');
$this->documents->render('/target');
}
protected function setUp(): void
{
$this->filesystem = $this->createMock(Filesystem::class);
$this->metas = $this->createMock(Metas::class);
$this->documents = new Documents(
$this->filesystem,
$this->metas
);
}
}

View file

@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\Builder;
use Doctrine\RST\Builder\Documents;
use Doctrine\RST\Builder\ParseQueue;
use Doctrine\RST\Builder\ParseQueueProcessor;
use Doctrine\RST\ErrorManager;
use Doctrine\RST\Kernel;
use Doctrine\RST\Meta\Metas;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use function sys_get_temp_dir;
use function touch;
class ParseQueueProcessorTest extends TestCase
{
/** @var Kernel|MockObject */
private $kernel;
/** @var ErrorManager|MockObject */
private $errorManager;
/** @var Metas|MockObject */
private $metas;
/** @var Documents|MockObject */
private $documents;
/** @var string */
private $directory;
/** @var string */
private $targetDirectory;
/** @var string */
private $fileExtension;
/** @var ParseQueueProcessor */
private $parseQueueProcessor;
public function testProcess(): void
{
touch($this->directory . '/file.rst');
$parseQueue = new ParseQueue();
$parseQueue->addFile('file', true);
$this->documents->expects(self::once())
->method('addDocument')
->with('file');
$this->kernel->expects(self::once())
->method('postParse');
$this->metas->expects(self::once())
->method('set');
$this->parseQueueProcessor->process($parseQueue);
}
protected function setUp(): void
{
$this->kernel = $this->createMock(Kernel::class);
$this->errorManager = $this->createMock(ErrorManager::class);
$this->metas = $this->createMock(Metas::class);
$this->documents = $this->createMock(Documents::class);
$this->directory = sys_get_temp_dir();
$this->targetDirectory = '/target';
$this->fileExtension = 'rst';
$this->parseQueueProcessor = new ParseQueueProcessor(
$this->kernel,
$this->errorManager,
$this->metas,
$this->documents,
$this->directory,
$this->targetDirectory,
$this->fileExtension
);
}
}

View file

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\Builder;
use Doctrine\RST\Builder\ParseQueue;
use PHPUnit\Framework\TestCase;
class ParseQueueTest extends TestCase
{
public function testAddingFiles(): void
{
$parseQueue = new ParseQueue();
$parseQueue->addFile('file_needs_parsing1', true);
$parseQueue->addFile('file_no_parsing1', false);
self::assertTrue($parseQueue->isFileKnownToParseQueue('file_needs_parsing1'));
self::assertTrue($parseQueue->isFileKnownToParseQueue('file_no_parsing1'));
self::assertFalse($parseQueue->isFileKnownToParseQueue('other_file'));
self::assertTrue($parseQueue->doesFileRequireParsing('file_needs_parsing1'));
self::assertFalse($parseQueue->doesFileRequireParsing('file_no_parsing1'));
self::assertSame(['file_needs_parsing1'], $parseQueue->getAllFilesThatRequireParsing());
}
}

View file

@ -0,0 +1,241 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\Builder;
use ArrayIterator;
use Doctrine\RST\Builder\Scanner;
use Doctrine\RST\Meta\MetaEntry;
use Doctrine\RST\Meta\Metas;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use function time;
class ScannerTest extends TestCase
{
/** @var Finder|MockObject */
private $finder;
/** @var Metas|MockObject */
private $metas;
/** @var Scanner */
private $scanner;
/** @var SplFileInfo[]|MockObject[]|ArrayIterator<string, SplFileInfo> */
private $fileMocks;
/** @var MetaEntry[]|MockObject[] */
private $metaEntryMocks = [];
public function testScanWithNoMetas(): void
{
$this->metas->expects(self::any())
->method('get')
->willReturn(null);
$this->addFileMockToFinder('file1.rst');
$this->addFileMockToFinder('file2.rst');
$this->addFileMockToFinder('file3.rst');
$this->addFileMockToFinder('subdir/file4.rst');
$this->addFileMockToFinder('subdir/file5.rst');
$parseQueue = $this->scanner->scan();
self::assertSame([
'file1',
'file2',
'file3',
'subdir/file4',
'subdir/file5',
], $parseQueue->getAllFilesThatRequireParsing());
}
public function testScanWithNonFreshMetas(): void
{
$file1InfoMock = $this->addFileMockToFinder('file1.rst');
$file1MetaMock = $this->createMetaEntryMock('file1');
// file1.rst was modified 50 seconds ago
$file1InfoMock->method('getMTime')->willReturn(time() - 50);
// but file1 MetaEntry was modified 100 seconds ago (is out of date)
$file1MetaMock->method('getMTime')->willReturn(time() - 100);
// should never be called because the meta is definitely not fresh
$file1MetaMock->expects(self::never())->method('getDepends');
$file2InfoMock = $this->addFileMockToFinder('file2.rst');
$file2MetaMock = $this->createMetaEntryMock('file2');
// file2.rst was modified 50 seconds ago
$lastModifiedTime = time() - 50;
$file2InfoMock->method('getMTime')->willReturn($lastModifiedTime);
// and file2 MetaEntry was also 50 seconds ago, fresh
$file2MetaMock->method('getMTime')->willReturn($lastModifiedTime);
// ignore dependencies for this test
$file2MetaMock->expects(self::once())
->method('getDepends')
->willReturn([]);
$parseQueue = $this->scanner->scan();
self::assertSame(['file1'], $parseQueue->getAllFilesThatRequireParsing());
self::assertFalse($parseQueue->doesFileRequireParsing('file2'));
}
public function testScanWithDependencies(): void
{
/*
* Here is the dependency tree and results:
* * file1 (unmodified)
* depends on: file2
* * file2 (unmodified)
* depends on: file3, file1
* * file3 (unmodified)
* depends on: file4, file5, file3, file2
* * file4 (unmodified)
* depends on: nothing
* * file5 (MODIFIED)
* depends on: file3, file6
* * file6 (unmodified)
* depends on: file4
*
* Result is that the following files are fresh:
* * file1
* * file2
* * file4
* * file6
*/
$metaMTime = time() - 50;
$file1InfoMock = $this->addFileMockToFinder('file1.rst');
$file1InfoMock->method('getMTime')->willReturn($metaMTime);
$file1MetaMock = $this->createMetaEntryMock('file1');
$file1MetaMock->method('getDepends')
->willReturn(['file2']);
$file1MetaMock->method('getMTime')->willReturn($metaMTime);
$file2InfoMock = $this->addFileMockToFinder('file2.rst');
$file2InfoMock->method('getMTime')->willReturn($metaMTime);
$file2MetaMock = $this->createMetaEntryMock('file2');
$file2MetaMock->method('getDepends')
->willReturn(['file2', 'file3']);
$file2MetaMock->method('getMTime')->willReturn($metaMTime);
$file3InfoMock = $this->addFileMockToFinder('file3.rst');
$file3InfoMock->method('getMTime')->willReturn($metaMTime);
$file3MetaMock = $this->createMetaEntryMock('file3');
$file3MetaMock->method('getDepends')
->willReturn(['file4', 'file5', 'file3', 'file2']);
$file3MetaMock->method('getMTime')->willReturn($metaMTime);
$file4InfoMock = $this->addFileMockToFinder('file4.rst');
$file4InfoMock->method('getMTime')->willReturn($metaMTime);
$file4MetaMock = $this->createMetaEntryMock('file4');
$file4MetaMock->method('getDepends')
->willReturn([]);
$file4MetaMock->method('getMTime')->willReturn($metaMTime);
$file5InfoMock = $this->addFileMockToFinder('file5.rst');
// THIS file is the one file that's modified
$file5InfoMock->method('getMTime')->willReturn(time() - 10);
$file5MetaMock = $this->createMetaEntryMock('file5');
$file5MetaMock->method('getDepends')
->willReturn(['file3', 'file6']);
$file5MetaMock->method('getMTime')->willReturn($metaMTime);
$file6InfoMock = $this->addFileMockToFinder('file6.rst');
$file6InfoMock->method('getMTime')->willReturn($metaMTime);
$file6MetaMock = $this->createMetaEntryMock('file6');
$file6MetaMock->method('getDepends')
->willReturn(['file4']);
$file6MetaMock->method('getMTime')->willReturn($metaMTime);
$parseQueue = $this->scanner->scan();
self::assertSame([
'file3',
'file5',
], $parseQueue->getAllFilesThatRequireParsing());
}
public function testScanWithNonExistentDependency(): void
{
/*
* * file1 (unmodified)
* depends on: file2
* * file2 (does not exist)
* depends on: file3, file1
*
* Result is that file 1 DOES need to be parsed
*/
$metaMTime = time() - 50;
$file1InfoMock = $this->addFileMockToFinder('file1.rst');
$file1InfoMock->method('getMTime')->willReturn($metaMTime);
$file1MetaMock = $this->createMetaEntryMock('file1');
$file1MetaMock->method('getDepends')
->willReturn(['file2']);
$file1MetaMock->method('getMTime')->willReturn($metaMTime);
// no file info made for file2
$parseQueue = $this->scanner->scan();
self::assertSame(['file1'], $parseQueue->getAllFilesThatRequireParsing());
}
protected function setUp(): void
{
$this->fileMocks = new ArrayIterator();
$this->finder = $this->createMock(Finder::class);
$this->finder->expects(self::any())
->method('getIterator')
->willReturn($this->fileMocks);
$this->finder->expects(self::once())
->method('in')
->with('/directory')
->willReturnSelf();
$this->finder->expects(self::once())
->method('files')
->with()
->willReturnSelf();
$this->finder->expects(self::once())
->method('name')
->with('*.rst')
->willReturnSelf();
$this->metas = $this->createMock(Metas::class);
$this->metas->expects(self::any())
->method('get')
->willReturnCallback(function ($filename) {
return $this->metaEntryMocks[$filename] ?? null;
});
$this->scanner = new Scanner('rst', '/directory', $this->metas, $this->finder);
}
/** @return MockObject|SplFileInfo */
private function addFileMockToFinder(string $relativePath)
{
$fileInfo = $this->createMock(SplFileInfo::class);
$fileInfo->expects(self::any())
->method('getRelativePathname')
->willReturn($relativePath);
$this->fileMocks[$relativePath] = $fileInfo;
return $fileInfo;
}
/** @return MockObject|MetaEntry */
private function createMetaEntryMock(string $filename)
{
$meta = $this->createMock(MetaEntry::class);
$this->metaEntryMocks[$filename] = $meta;
return $meta;
}
}

View file

@ -0,0 +1,34 @@
.. url:: magic-link
Another page
============
Hello!
See also
--------
test
----
title with ampersand &
----------------------
A ``title with ticks``
----------------------
This same title named test exists in other documents. Make sure the link below goes to the one
in this doc and not the one in the other docs.
See also: :doc:`subdirective`
see `See also`_
see `Another page`_
see `test`_
see `title with ampersand &`_
see `A title with ticks`_

View file

@ -0,0 +1 @@
Example of static file!

View file

@ -0,0 +1,46 @@
Summary
=======
This is the builder test summary
.. _toc:
.. toctree::
introduction
subdirective
another
subdir/index
/subdir/file
.. _reference_anchor:
Link to :ref:`the same doc reference <same_doc_reference>`
.. _same_doc_reference:
Link to :ref:`the same doc reference with ticks <same_doc_reference_ticks>`
.. _`same_doc_reference_ticks`:
Link to :ref:`Subdirectory <subdirectory>`
Link to :ref:`Subdirectory Test <subdirectory>`
Link to :ref:`Subdirectory Child <subdirectory-child>`
Link to :ref:`Subdirectory Child Test <subdirectory-child>`
Link to :ref:`Subdirectory Child Level 2 <subdirectory-child-level-2>`
Link to :ref:`Subdirectory Child Level 2 Test <subdirectory-child-level-2>`
Link to :ref:`Subdirectory Child Level 3 <subdirectory-child-level-3>`
Link to :ref:`Subdirectory Child Level 3 Test <subdirectory-child-level-3>`
.. note::
:ref:`Reference in directory <introduction>`
Another h1
==========

View file

@ -0,0 +1,20 @@
Introduction page
=================
This is an introduction page!
Reference to the :doc:`index`
Reference to the :doc:`Link index absolutely </index>`
Reference to the :doc:`Index <index>`
Reference to the :doc:`Index, paragraph toc <index#toc>`
Reference to the :doc:`Glob TOC <toc-glob>`
Reference to the :ref:`Summary Reference <reference_anchor>`
Reference to the :ref:`Test Reference <test_reference>`
Reference to the :ref:`Camel Case Reference <camelCaseReference>`

View file

@ -0,0 +1,5 @@
Document with a Link to Index
-----------------------------
I have a reference to :doc:`index` and this link
is dependent on the title of that page.

View file

@ -0,0 +1,17 @@
Heading 1
#########
Heading 2
.........
Heading 3
:::::::::
Heading 4
_________
Heading 5
`````````
Heading 6
'''''''''

View file

@ -0,0 +1 @@
This file is included

View file

@ -0,0 +1,63 @@
.. url:: test
Subdirectory
============
Relative `link </to/resource>`_
Absolute `test <http://absolute/>`_
You can click `here <http://google.com>`__ or `here <http://yahoo.com>`__
This is `something`_, and this is again `something`_
This is a :ref:`test anchor <test-anchor>`
This is a :ref:`test subdir reference with anchor </subdir/index#test-subdir-anchor>`
.. _something: http://something.com/
.. _test-anchor:
Reference to the :doc:`/index`
.. _test_reference:
.. _camelCaseReference:
Link to :ref:`the subdir same doc reference <subdir_same_doc_reference>`
.. _subdir_same_doc_reference:
Subdirectory Child
------------------
Test subdirectory child.
Subdirectory Child Level 2
~~~~~~~~~~~~~~~~~~~~~~~~~~
Test subdirectory child level 2.
Subdirectory Child Level 3
**************************
Test subdirectory child level 3.
:doc:`Reference absolute to index </index>`
:doc:`Reference absolute to file </subdir/file>`
:doc:`Reference relative to file <file>`
Reference absolute to the :doc:`/index`
.. include:: /subdir/include.rst.inc
.. include:: include.rst.inc
`em`_
em
--

View file

@ -0,0 +1,10 @@
TOC in Subdir
=============
.. toctree::
/introduction
/subdirective
/another
/subdir/index
file

View file

@ -0,0 +1,14 @@
Sub directives
==============
Testing sub directives
.. note::
This is a simple note!
There is a title here
---------------------
.. note::
* This is a list
* With two points

View file

@ -0,0 +1,10 @@
TOC Reversed
============
.. toctree::
:glob:
:reversed:
index
*
introduction

View file

@ -0,0 +1,10 @@
TOC Glob
========
.. toctree::
:glob:
index
*
toc-glob
introduction

View file

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\BuilderCustomScannerFinder;
use Doctrine\RST\Builder;
use Doctrine\Tests\RST\BaseBuilderTest;
use Symfony\Component\Finder\Finder;
/**
* Tests a custom Finder for Scanner
*/
class BuilderCustomScannerFinderTest extends BaseBuilderTest
{
public function testCustomScannerFinder(): void
{
self::assertFileExists($this->targetFile('path1/file1.html'));
self::assertFileNotExists($this->targetFile('path2/file2.html'));
}
protected function getFixturesDirectory(): string
{
return 'BuilderCustomScannerFinder';
}
protected function configureBuilder(Builder $builder): void
{
$finder = new Finder();
$finder->exclude('path2');
$builder->setScannerFinder($finder);
}
}

View file

@ -0,0 +1,4 @@
Index
=====
a file

View file

@ -0,0 +1,4 @@
File1
=====
a file

View file

@ -0,0 +1,4 @@
Path 2 File
===========
a file

View file

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\BuilderInclude;
use Doctrine\Tests\RST\BaseBuilderTest;
use function assert;
use function file_exists;
use function file_get_contents;
/**
* Unit testing build with ".. include::" directive
*/
class BuilderIncludeTest extends BaseBuilderTest
{
public function testTocTreeGlob(): void
{
self::assertTrue(file_exists($this->targetFile('index.html')));
$contents = file_get_contents($this->targetFile('index.html'));
assert($contents !== false);
self::assertStringContainsString('This file is included', $contents);
foreach ($this->builder->getDocuments()->getAll() as $document) {
foreach ($document->getEnvironment()->getMetas()->getAll() as $meta) {
foreach ($meta->getTocs() as $toc) {
foreach ($toc as $tocLine) {
self::assertStringNotContainsString('include.inc', $tocLine);
}
}
}
}
}
protected function getFixturesDirectory(): string
{
return 'BuilderInclude';
}
}

View file

@ -0,0 +1,4 @@
File
====
a file

View file

@ -0,0 +1 @@
This file is included

View file

@ -0,0 +1,9 @@
Test include
============
.. include:: include.rst.inc
.. toctree::
:glob:
*

View file

@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\BuilderInvalidReferences;
use Doctrine\RST\Builder;
use Doctrine\RST\Configuration;
use Doctrine\RST\Kernel;
use Doctrine\Tests\RST\BaseBuilderTest;
use Throwable;
class BuilderInvalidReferencesTest extends BaseBuilderTest
{
/** @var Configuration */
private $configuration;
protected function setUp(): void
{
$this->configuration = new Configuration();
$this->configuration->setUseCachedMetas(false);
$this->configuration->silentOnError(true);
$this->builder = new Builder(new Kernel($this->configuration));
}
public function testInvalidReference(): void
{
$this->expectException(Throwable::class);
$this->expectExceptionMessage('Found invalid reference "does_not_exist" in file "index"');
$this->builder->build($this->sourceFile(), $this->targetFile());
}
public function testInvalidReferenceIgnored(): void
{
$this->configuration->setIgnoreInvalidReferences(true);
$this->builder->build($this->sourceFile(), $this->targetFile());
$contents = $this->getFileContents($this->targetFile('index.html'));
self::assertStringContainsString('<p>Test unresolved reference</p>', $contents);
}
protected function getFixturesDirectory(): string
{
return 'BuilderInvalidReferences';
}
}

View file

@ -0,0 +1,10 @@
Unresolved Reference
====================
Test :ref:`unresolved reference <does_not_exist>`
Test :ref:`resolved reference <reference>`
Test :ref:`test anchor <test_anchor>`
.. _test_anchor:

View file

@ -0,0 +1,4 @@
Reference
=========
Test

View file

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\BuilderMalformedReference;
use Doctrine\RST\Builder;
use Doctrine\RST\Configuration;
use Doctrine\RST\Kernel;
use Doctrine\Tests\RST\BaseBuilderTest;
class BuilderMalformedReferenceTest extends BaseBuilderTest
{
/** @var Configuration */
private $configuration;
protected function setUp(): void
{
$this->configuration = new Configuration();
$this->configuration->setUseCachedMetas(false);
$this->configuration->abortOnError(false);
$this->configuration->setIgnoreInvalidReferences(true);
$this->builder = new Builder(new Kernel($this->configuration));
}
public function testMalformedReference(): void
{
// test that invalid references can be ignored and no exception gets thrown
$this->builder->build($this->sourceFile(), $this->targetFile());
$contents = $this->getFileContents($this->targetFile('subdir/another.html'));
self::assertStringContainsString('<p>Test link to</p>', $contents);
$contents = $this->getFileContents($this->targetFile('subdir/index.html'));
self::assertStringContainsString('<a id="test_reference"></a>', $contents);
}
protected function getFixturesDirectory(): string
{
return 'BuilderMalformedReference';
}
}

View file

@ -0,0 +1 @@
Index

View file

@ -0,0 +1 @@
Test :doc:`link to <_test_reference>`

View file

@ -0,0 +1,3 @@
Example:
.. _test_reference:

View file

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\BuilderReferenceDoesNotExist;
use Doctrine\RST\Builder;
use Doctrine\RST\Configuration;
use Doctrine\RST\Kernel;
use Doctrine\Tests\RST\BaseBuilderTest;
class BuilderReferenceDoesNotExistTest extends BaseBuilderTest
{
/** @var Configuration */
private $configuration;
protected function setUp(): void
{
$this->configuration = new Configuration();
$this->configuration->setUseCachedMetas(false);
$this->configuration->abortOnError(false);
$this->configuration->silentOnError(true);
$this->configuration->setIgnoreInvalidReferences(false);
$this->builder = new Builder(new Kernel($this->configuration));
}
public function testReferenceDoesNotExist(): void
{
$this->builder->build($this->sourceFile(), $this->targetFile());
$contents = $this->getFileContents($this->targetFile('subdir/index.html'));
self::assertStringContainsString('<p>Test link 1 to</p>', $contents);
self::assertStringContainsString('<p>Test link 2 to</p>', $contents);
}
protected function getFixturesDirectory(): string
{
return 'BuilderReferenceDoesNotExist';
}
}

View file

@ -0,0 +1 @@
Index

View file

@ -0,0 +1,5 @@
Example:
Test :ref:`link 1 to <does-not-exist>`
Test :ref:`link 2 to <does-not-exist>`

View file

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\BuilderReferences;
use Doctrine\RST\Builder;
use Doctrine\Tests\RST\BaseBuilderTest;
use Gajus\Dindent\Indenter;
use Symfony\Component\Finder\Finder;
use function rtrim;
class BuilderReferencesTest extends BaseBuilderTest
{
protected function configureBuilder(Builder $builder): void
{
$builder->getConfiguration()->abortOnError(false);
$builder->getConfiguration()->silentOnError();
}
public function test(): void
{
$indenter = new Indenter();
foreach (Finder::create()->files()->in($this->targetFile() . '/../expected') as $file) {
$target = $this->targetFile($file->getRelativePathname());
self::assertFileExists($target);
self::assertEquals(rtrim($file->getContents()), rtrim($indenter->indent($this->getFileContents($target))));
}
}
protected function getFixturesDirectory(): string
{
return 'BuilderReferences';
}
}

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div class="section" id="references">
<h1>
References
</h1>
<p>Test <a href="reference.html">referencing a document</a></p>
<p>Test <a href="reference.html#test_anchor">referencing an anchor in another document</a></p>
<p>Test referencing a <a href="index.html#sub-section">Sub section</a> and Some Sub Section (invalid)</p>
<div class="section" id="sub-section">
<h2>
Sub section
</h2>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div class="section" id="reference-page">
<h1>
Reference Page
</h1>
<ul>
<li><a href="page.html#some-sub-section">Some Sub Section</a></li>
<li><a href="page.html#other">Other Sub Section</a></li>
<li><a href="page1.html#another-page">Section on another subpage</a></li>
</ul>
<p>And what about <a href="../reference.html#test_anchor">the test anchor</a>?</p>
<div class="section" id="some-sub-section">
<h2>
Some Sub Section
</h2>
<a id="other"></a>
</div>
<div class="section" id="other-sub-section">
<h2>
Other Sub Section
</h2>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,11 @@
References
==========
Test :ref:`referencing a document <reference>`
Test :ref:`referencing an anchor in another document <test_anchor>`
Test referencing a `Sub section`_ and `Some Sub Section`_ (invalid)
Sub section
-----------

View file

@ -0,0 +1,6 @@
.. _test_anchor:
Reference
=========
Test

View file

@ -0,0 +1,16 @@
Reference Page
==============
* `Some Sub Section`_
* :ref:`Other Sub Section <other>`
* :ref:`Section on another subpage <another-page>`
And what about :ref:`the test anchor <test_anchor>`?
Some Sub Section
----------------
.. _other:
Other Sub Section
-----------------

View file

@ -0,0 +1,7 @@
Reference Page 1
================
.. _another-page:
Section on Another Page
-----------------------

View file

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\BuilderToctree;
use Doctrine\Tests\RST\BaseBuilderTest;
use function file_exists;
class BuilderTocTreeTest extends BaseBuilderTest
{
public function testTocTreeGlob(): void
{
self::assertTrue(file_exists($this->targetFile('subdir/toctree.html')));
self::assertTrue(file_exists($this->targetFile('orphaned/file.html')));
self::assertTrue(file_exists($this->targetFile('wildcards/bugfix1.html')));
self::assertTrue(file_exists($this->targetFile('wildcards/feature1.html')));
self::assertTrue(file_exists($this->targetFile('wildcards/feature2.html')));
self::assertTrue(file_exists($this->targetFile('wildcards/index.html')));
}
public function testMaxDepth(): void
{
$contents = $this->getFileContents($this->targetFile('index.html'));
// :maxdepth: 1
self::assertStringContainsString('<div class="toc"><ul><li id="index-html-title" class="toc-item"><a href="index.html#title">Title</a></li></ul></div>', $contents);
// :maxdepth: 2
self::assertStringContainsString('<div class="toc"><ul><li id="index-html-title" class="toc-item"><a href="index.html#title">Title</a><ul><li id="index-html-max-depth-level-2" class="toc-item"><a href="index.html#max-depth-level-2">Max Depth Level 2</a></li></ul></li></ul></div>', $contents);
// :maxdepth: 3
self::assertStringContainsString('<div class="toc"><ul><li id="index-html-title" class="toc-item"><a href="index.html#title">Title</a><ul><li id="index-html-max-depth-level-2" class="toc-item"><a href="index.html#max-depth-level-2">Max Depth Level 2</a><ul><li id="index-html-max-depth-level-3" class="toc-item"><a href="index.html#max-depth-level-3">Max Depth Level 3</a></li></ul></li></ul></li></ul></div>', $contents);
// :maxdepth: 4
self::assertStringContainsString('<div class="toc"><ul><li id="index-html-title" class="toc-item"><a href="index.html#title">Title</a><ul><li id="index-html-max-depth-level-2" class="toc-item"><a href="index.html#max-depth-level-2">Max Depth Level 2</a><ul><li id="index-html-max-depth-level-3" class="toc-item"><a href="index.html#max-depth-level-3">Max Depth Level 3</a><ul><li id="index-html-max-depth-level-4" class="toc-item"><a href="index.html#max-depth-level-4">Max Depth Level 4</a></li></ul></li></ul></li></ul></li></ul></div>', $contents);
}
protected function getFixturesDirectory(): string
{
return 'BuilderToctree';
}
}

View file

@ -0,0 +1,43 @@
Title
=====
.. toctree::
subdir/toctree
Max Depth Level 2
---------
Max Depth Level 3
~~~~~~~
Max Depth Level 4
+++++++++++++++++
maxdepth 1 TOC:
.. toctree::
:depth: 1
index
maxdepth 2 TOC:
.. toctree::
:maxdepth: 2
index
maxdepth 3 TOC:
.. toctree::
:maxdepth: 3
index
maxdepth 4 TOC:
.. toctree::
:maxdepth: 4
index

View file

@ -0,0 +1,3 @@
This file should not be parsed
==============================

View file

@ -0,0 +1,13 @@
Toctree
=======
.. toctree::
:glob:
*
.. toctree::
:glob:
/subdir/*

View file

@ -0,0 +1,4 @@
Feature 3
=========
Lorem Ispusm dolor

View file

@ -0,0 +1,4 @@
Feature 1
=========
Lorem Ispusm dolor

View file

@ -0,0 +1,4 @@
Feature 2
=========
Lorem Ispusm dolor

View file

@ -0,0 +1,19 @@
Wildcards
=========
Features
========
.. toctree::
:glob:
feature*
Bugfixes
========
.. toctree::
:glob:
bugfix*

View file

@ -0,0 +1,149 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\BuilderUrl;
use Doctrine\RST\Builder;
use Doctrine\RST\Configuration;
use Doctrine\RST\Kernel;
use Doctrine\Tests\RST\BaseBuilderTest;
use function strpos;
class BuilderUrlTest extends BaseBuilderTest
{
/** @var Configuration */
private $configuration;
public function testBaseUrl(): void
{
$this->configuration->setBaseUrl('https://www.domain.com/directory');
$this->builder->build($this->sourceFile(), $this->targetFile());
$contents = $this->getFileContents($this->targetFile('index.html'));
self::assertStringContainsString(
'<a href="https://www.domain.com/directory/index.html">Test reference url</a>',
$contents
);
self::assertStringContainsString(
'<li id="index-html-base-url" class="toc-item"><a href="https://www.domain.com/directory/index.html#base-url">Base URL</a></li>',
$contents
);
$contents = $this->getFileContents($this->targetFile('subdir/index.html'));
self::assertStringContainsString(
'<a href="https://www.domain.com/directory/index.html">Test subdir reference url</a>',
$contents
);
self::assertStringContainsString(
'<li id="index-html" class="toc-item"><a href="https://www.domain.com/directory/index.html">Base URL</a></li>',
$contents
);
self::assertStringContainsString(
'<li id="file-html" class="toc-item"><a href="https://www.domain.com/directory/subdir/file.html">Subdirectory File</a></li>',
$contents
);
}
public function testBaseUrlEnabledCallable(): void
{
$this->configuration->setBaseUrl('https://www.domain.com/directory');
$this->configuration->setBaseUrlEnabledCallable(static function (string $path): bool {
return strpos($path, 'subdir/') !== 0;
});
$this->builder->build($this->sourceFile(), $this->targetFile());
$contents = $this->getFileContents($this->targetFile('index.html'));
self::assertStringContainsString(
'<a href="https://www.domain.com/directory/index.html">Test reference url</a>',
$contents
);
self::assertStringContainsString(
'<li id="index-html-base-url" class="toc-item"><a href="https://www.domain.com/directory/index.html#base-url">Base URL</a></li>',
$contents
);
$contents = $this->getFileContents($this->targetFile('subdir/index.html'));
self::assertStringContainsString(
'<a href="https://www.domain.com/directory/index.html">Test subdir reference url</a>',
$contents
);
self::assertStringContainsString(
'<a href="file.html">Test subdir file reference path</a>',
$contents
);
self::assertStringContainsString(
'<a href="index.html#subdirectory-index">Subdirectory Index</a>',
$contents
);
self::assertStringContainsString(
'<li id="index-html" class="toc-item"><a href="https://www.domain.com/directory/index.html">Base URL</a></li>',
$contents
);
self::assertStringContainsString(
'<li id="file-html" class="toc-item"><a href="file.html">Subdirectory File</a></li>',
$contents
);
}
public function testRelativeUrl(): void
{
$this->builder->build($this->sourceFile(), $this->targetFile());
$contents = $this->getFileContents($this->targetFile('index.html'));
self::assertStringContainsString(
'<a href="index.html">Test reference url</a>',
$contents
);
self::assertStringContainsString(
'<li id="index-html-base-url" class="toc-item"><a href="index.html#base-url">Base URL</a></li>',
$contents
);
$contents = $this->getFileContents($this->targetFile('subdir/index.html'));
self::assertStringContainsString(
'<a href="../index.html">Test subdir reference url</a>',
$contents
);
self::assertStringContainsString(
'<li id="index-html" class="toc-item"><a href="../index.html">Base URL</a></li>',
$contents
);
self::assertStringContainsString(
'<li id="file-html" class="toc-item"><a href="file.html">Subdirectory File</a></li>',
$contents
);
}
protected function setUp(): void
{
$this->configuration = new Configuration();
$this->configuration->setUseCachedMetas(false);
$this->builder = new Builder(new Kernel($this->configuration));
}
protected function getFixturesDirectory(): string
{
return 'BuilderUrl';
}
}

View file

@ -0,0 +1,12 @@
Base URL
========
:ref:`Test reference url </index>`
:ref:`Subdir </subdir/index>`
:ref:`Subdir file </subdir/file>`
.. toctree::
:glob:
index
*

View file

@ -0,0 +1,9 @@
Subdirectory File
=================
:ref:`Test subdir reference url </subdir/index>`
.. toctree::
:glob:
/*

View file

@ -0,0 +1,10 @@
Subdirectory Index
==================
:ref:`Test subdir reference url </index>`
:ref:`Test subdir file reference path </subdir/file>`
.. toctree::
:glob:
/*

View file

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\BuilderWithErrors;
use Doctrine\RST\Builder;
use Doctrine\Tests\RST\BaseBuilderTest;
use Symfony\Component\DomCrawler\Crawler;
use function trim;
class BuilderWithErrorsTest extends BaseBuilderTest
{
protected function configureBuilder(Builder $builder): void
{
$builder->getConfiguration()->abortOnError(false);
$builder->getConfiguration()->silentOnError(true);
}
public function testNoContentDirectiveError(): void
{
$contents = $this->getFileContents($this->targetFile('no_content_directive.html'));
$crawler = new Crawler($contents);
$bodyHtml = trim($crawler->filter('body')->html());
// the note is simply left out
self::assertSame(<<<'EOF'
<p>Testing wrapper node at end of file</p>
<p>And here is more text.</p>
EOF
, $bodyHtml);
self::assertEquals(
'Error while processing "note" directive: "Content expected, none found." in file "no_content_directive" at line 6',
$this->builder->getErrorManager()->getErrors()[0]->asString()
);
}
protected function getFixturesDirectory(): string
{
return 'BuilderWithErrors';
}
}

View file

@ -0,0 +1,4 @@
.. toctree::
:glob:
no_content_directive

View file

@ -0,0 +1,5 @@
Testing wrapper node at end of file
.. note::
And here is more text.

View file

@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST;
use Doctrine\RST\Configuration;
use PHPUnit\Framework\TestCase;
use function strpos;
class ConfigurationTest extends TestCase
{
/** @var Configuration */
private $configuration;
public function testBaseUrl(): void
{
self::assertSame('', $this->configuration->getBaseUrl());
$this->configuration->setBaseUrl('https://www.domain.com/directory');
self::assertSame('https://www.domain.com/directory', $this->configuration->getBaseUrl());
}
public function testBaseUrlEnabledCallable(): void
{
$callable = $this->configuration->getBaseUrlEnabledCallable();
self::assertNull($callable);
$callable = static function (string $path): bool {
return strpos($path, 'use-base-url') !== false;
};
$this->configuration->setBaseUrlEnabledCallable($callable);
self::assertSame($callable, $this->configuration->getBaseUrlEnabledCallable());
}
public function testIsBaseUrlEnabled(): void
{
self::assertFalse($this->configuration->isBaseUrlEnabled('/path'));
$callable = static function (string $path): bool {
return strpos($path, '/use-base-url') !== false;
};
$this->configuration->setBaseUrl('https://www.domain.com/directory');
$this->configuration->setBaseUrlEnabledCallable($callable);
self::assertTrue($this->configuration->isBaseUrlEnabled('/path/use-base-url'));
self::assertFalse($this->configuration->isBaseUrlEnabled('/path/do-not-use-base-url'));
}
public function testAbortOnError(): void
{
self::assertTrue($this->configuration->isAbortOnError());
$this->configuration->abortOnError(false);
self::assertFalse($this->configuration->isAbortOnError());
}
public function testIgnoreInvalidReferences(): void
{
self::assertFalse($this->configuration->getIgnoreInvalidReferences());
$this->configuration->setIgnoreInvalidReferences(true);
self::assertTrue($this->configuration->getIgnoreInvalidReferences());
}
public function testInitialHeaderLevel(): void
{
self::assertSame(1, $this->configuration->getInitialHeaderLevel());
$this->configuration->setInitialHeaderLevel(2);
self::assertSame(2, $this->configuration->getInitialHeaderLevel());
}
protected function setUp(): void
{
$this->configuration = new Configuration();
}
}

View file

@ -0,0 +1,313 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST;
use Doctrine\Common\EventManager;
use Doctrine\RST\Environment;
use Doctrine\RST\NodeFactory\DefaultNodeFactory;
use Doctrine\RST\NodeFactory\NodeInstantiator;
use Doctrine\RST\Nodes\AnchorNode;
use Doctrine\RST\Nodes\CodeNode;
use Doctrine\RST\Nodes\DocumentNode;
use Doctrine\RST\Nodes\ListNode;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\NodeTypes;
use Doctrine\RST\Nodes\ParagraphNode;
use Doctrine\RST\Nodes\QuoteNode;
use Doctrine\RST\Nodes\SeparatorNode;
use Doctrine\RST\Nodes\SpanNode;
use Doctrine\RST\Nodes\TableNode;
use Doctrine\RST\Nodes\TitleNode;
use Doctrine\RST\Nodes\TocNode;
use Doctrine\RST\Parser;
use Doctrine\RST\Parser\LineChecker;
use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
class DefaultNodeFactoryTest extends TestCase
{
/** @var EventManager */
private $eventManager;
public function testCreateDocument(): void
{
$returnClass = DocumentNode::class;
$type = NodeTypes::DOCUMENT;
$environment = $this->createMock(Environment::class);
$nodeInstantiator = $this->createMock(NodeInstantiator::class);
$expectedReturn = $this->createMock($returnClass);
$nodeInstantiator->expects(self::once())
->method('getType')
->willReturn($type);
$nodeInstantiator->expects(self::once())
->method('create')
->with([$environment])
->willReturn($expectedReturn);
$defaultNodeFactory = $this->createDefaultNodeFactory($nodeInstantiator);
self::assertSame($expectedReturn, $defaultNodeFactory->createDocumentNode($environment));
}
public function testCreateToc(): void
{
$returnClass = TocNode::class;
$type = NodeTypes::TOC;
$environment = $this->createMock(Environment::class);
$nodeInstantiator = $this->createMock(NodeInstantiator::class);
$expectedReturn = $this->createMock($returnClass);
$nodeInstantiator->expects(self::once())
->method('getType')
->willReturn($type);
$nodeInstantiator->expects(self::once())
->method('create')
->with([$environment, [], []])
->willReturn($expectedReturn);
$defaultNodeFactory = $this->createDefaultNodeFactory($nodeInstantiator);
self::assertSame($expectedReturn, $defaultNodeFactory->createTocNode($environment, [], []));
}
public function testCreateTitle(): void
{
$returnClass = TitleNode::class;
$type = NodeTypes::TITLE;
$node = $this->createMock(Node::class);
$nodeInstantiator = $this->createMock(NodeInstantiator::class);
$expectedReturn = $this->createMock($returnClass);
$nodeInstantiator->expects(self::once())
->method('getType')
->willReturn($type);
$nodeInstantiator->expects(self::once())
->method('create')
->with([$node, 1, 'test'])
->willReturn($expectedReturn);
$defaultNodeFactory = $this->createDefaultNodeFactory($nodeInstantiator);
self::assertSame($expectedReturn, $defaultNodeFactory->createTitleNode($node, 1, 'test'));
}
public function testCreateSeparator(): void
{
$returnClass = SeparatorNode::class;
$type = NodeTypes::SEPARATOR;
$nodeInstantiator = $this->createMock(NodeInstantiator::class);
$expectedReturn = $this->createMock($returnClass);
$nodeInstantiator->expects(self::once())
->method('getType')
->willReturn($type);
$nodeInstantiator->expects(self::once())
->method('create')
->with([1])
->willReturn($expectedReturn);
$defaultNodeFactory = $this->createDefaultNodeFactory($nodeInstantiator);
self::assertSame($expectedReturn, $defaultNodeFactory->createSeparatorNode(1));
}
public function testCreateCode(): void
{
$returnClass = CodeNode::class;
$type = NodeTypes::CODE;
$nodeInstantiator = $this->createMock(NodeInstantiator::class);
$expectedReturn = $this->createMock($returnClass);
$nodeInstantiator->expects(self::once())
->method('getType')
->willReturn($type);
$nodeInstantiator->expects(self::once())
->method('create')
->with([[]])
->willReturn($expectedReturn);
$defaultNodeFactory = $this->createDefaultNodeFactory($nodeInstantiator);
self::assertSame($expectedReturn, $defaultNodeFactory->createCodeNode([]));
}
public function testCreateQuote(): void
{
$returnClass = QuoteNode::class;
$type = NodeTypes::QUOTE;
$nodeInstantiator = $this->createMock(NodeInstantiator::class);
$expectedReturn = $this->createMock($returnClass);
$nodeInstantiator->expects(self::once())
->method('getType')
->willReturn($type);
$documentNode = $this->createMock(DocumentNode::class);
$nodeInstantiator->expects(self::once())
->method('create')
->with([$documentNode])
->willReturn($expectedReturn);
$defaultNodeFactory = $this->createDefaultNodeFactory($nodeInstantiator);
self::assertSame($expectedReturn, $defaultNodeFactory->createQuoteNode($documentNode));
}
public function testCreateParagraph(): void
{
$returnClass = ParagraphNode::class;
$type = NodeTypes::PARAGRAPH;
$nodeInstantiator = $this->createMock(NodeInstantiator::class);
$expectedReturn = $this->createMock($returnClass);
$nodeInstantiator->expects(self::once())
->method('getType')
->willReturn($type);
$parser = $this->createMock(Parser::class);
$spanNode = new SpanNode($parser, 'test');
$nodeInstantiator->expects(self::once())
->method('create')
->with([$spanNode])
->willReturn($expectedReturn);
$defaultNodeFactory = $this->createDefaultNodeFactory($nodeInstantiator);
self::assertSame($expectedReturn, $defaultNodeFactory->createParagraphNode($spanNode));
}
public function testCreateAnchor(): void
{
$returnClass = AnchorNode::class;
$type = NodeTypes::ANCHOR;
$nodeInstantiator = $this->createMock(NodeInstantiator::class);
$expectedReturn = $this->createMock($returnClass);
$nodeInstantiator->expects(self::once())
->method('getType')
->willReturn($type);
$nodeInstantiator->expects(self::once())
->method('create')
->with(['test'])
->willReturn($expectedReturn);
$defaultNodeFactory = $this->createDefaultNodeFactory($nodeInstantiator);
self::assertSame($expectedReturn, $defaultNodeFactory->createAnchorNode('test'));
}
public function testCreateList(): void
{
$returnClass = ListNode::class;
$type = NodeTypes::LIST;
$nodeInstantiator = $this->createMock(NodeInstantiator::class);
$expectedReturn = $this->createMock($returnClass);
$nodeInstantiator->expects(self::once())
->method('getType')
->willReturn($type);
$nodeInstantiator->expects(self::once())
->method('create')
->with([[], false])
->willReturn($expectedReturn);
$defaultNodeFactory = $this->createDefaultNodeFactory($nodeInstantiator);
self::assertSame($expectedReturn, $defaultNodeFactory->createListNode([], false));
}
public function testCreateTable(): void
{
$returnClass = TableNode::class;
$type = NodeTypes::TABLE;
$lineChecker = $this->createMock(LineChecker::class);
$nodeInstantiator = $this->createMock(NodeInstantiator::class);
$expectedReturn = $this->createMock($returnClass);
$nodeInstantiator->expects(self::once())
->method('getType')
->willReturn($type);
$separatorLineConfig = new Parser\TableSeparatorLineConfig(true, TableNode::TYPE_SIMPLE, [], '=', '=== ===');
$nodeInstantiator->expects(self::once())
->method('create')
->with([$separatorLineConfig, TableNode::TYPE_SIMPLE, $lineChecker])
->willReturn($expectedReturn);
$defaultNodeFactory = $this->createDefaultNodeFactory($nodeInstantiator);
self::assertSame($expectedReturn, $defaultNodeFactory->createTableNode($separatorLineConfig, TableNode::TYPE_SIMPLE, $lineChecker));
}
public function testCreateSpan(): void
{
$returnClass = SpanNode::class;
$type = NodeTypes::SPAN;
$parser = $this->createMock(Parser::class);
$nodeInstantiator = $this->createMock(NodeInstantiator::class);
$expectedReturn = $this->createMock($returnClass);
$nodeInstantiator->expects(self::once())
->method('getType')
->willReturn($type);
$nodeInstantiator->expects(self::once())
->method('create')
->with([$parser, 'test'])
->willReturn($expectedReturn);
$defaultNodeFactory = $this->createDefaultNodeFactory($nodeInstantiator);
self::assertSame($expectedReturn, $defaultNodeFactory->createSpanNode($parser, 'test'));
}
public function testGetNodeInstantiatorThrowsInvalidArgumentException(): void
{
$nodeInstantiator = $this->createMock(NodeInstantiator::class);
$nodeInstantiator->expects(self::once())
->method('getType')
->willReturn('invalid');
$defaultNodeFactory = $this->createDefaultNodeFactory($nodeInstantiator);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Could not find node instantiator of type list');
$defaultNodeFactory->createListNode([], false);
}
protected function setUp(): void
{
$this->eventManager = $this->createMock(EventManager::class);
}
private function createDefaultNodeFactory(NodeInstantiator $nodeInstantiator): DefaultNodeFactory
{
return new DefaultNodeFactory($this->eventManager, $nodeInstantiator);
}
}

View file

@ -0,0 +1,125 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST;
use Doctrine\RST\Configuration;
use Doctrine\RST\Environment;
use PHPUnit\Framework\TestCase;
use Throwable;
/**
* Unit testing for RST
*/
class EnvironmentTest extends TestCase
{
public function testRelativeUrl(): void
{
$environment = new Environment(new Configuration());
$environment->setCurrentFileName('path/to/something.rst');
$environment->setCurrentDirectory('input/dir');
self::assertSame('path/to/something.rst', $environment->getCurrentFileName());
self::assertSame('input/dir', $environment->getCurrentDirectory());
// Assert that rules of relative url are respected
self::assertSame($environment->relativeUrl('test.jpg'), 'test.jpg');
self::assertSame($environment->relativeUrl('/path/to/test.jpg'), 'test.jpg');
self::assertSame($environment->relativeUrl('/path/x/test.jpg'), '../../path/x/test.jpg');
self::assertSame($environment->relativeUrl('/test.jpg'), '../../test.jpg');
self::assertSame($environment->relativeUrl('http://example.com/test.jpg'), 'http://example.com/test.jpg');
self::assertSame($environment->relativeUrl('imgs/test.jpg'), 'imgs/test.jpg');
self::assertSame($environment->relativeUrl('/imgs/test.jpg'), '../../imgs/test.jpg');
}
public function testAbsoluteUrl(): void
{
$environment = new Environment(new Configuration());
$environment->setCurrentFileName('path/to/something.rst');
$environment->setCurrentDirectory('input/dir');
self::assertSame('/test', $environment->absoluteUrl('/test'));
self::assertSame('path/to/test', $environment->absoluteUrl('test'));
}
public function testCanonicalUrl(): void
{
$environment = new Environment(new Configuration());
$environment->setCurrentFileName('subdir1/subdir2/test.rst');
self::assertSame($environment->canonicalUrl('subdir1/subdir2/test.rst'), 'subdir1/subdir2/test.rst');
self::assertSame($environment->canonicalUrl('test.rst'), 'subdir1/subdir2/test.rst');
self::assertSame($environment->canonicalUrl('../index.rst'), 'subdir1/index.rst');
self::assertSame($environment->canonicalUrl('../../index.rst'), 'index.rst');
}
/** @dataProvider getMissingSectionTests */
public function testResolveForMissingSection(string $expectedMessage, ?string $currentFilename): void
{
$this->expectException(Throwable::class);
$this->expectExceptionMessage($expectedMessage);
$configuration = new Configuration();
$configuration->silentOnError(true);
$environment = new Environment($configuration);
if ($currentFilename !== null) {
$environment->setCurrentFileName($currentFilename);
}
$environment->resolve('doc', '/path/to/unknown/doc');
}
/** @return iterable<string, array{string, string|null}> */
public function getMissingSectionTests(): iterable
{
yield 'no_current_filename' => [
'Unknown reference section "doc"',
null,
];
yield 'with_current_filename' => [
'Unknown reference section "doc" in file "current_doc_filename"',
'current_doc_filename',
];
}
/** @dataProvider getTextsAndSlugs */
public function testSlugify(string $text, string $expectedSlug): void
{
self::assertSame($expectedSlug, Environment::slugify($text));
}
/** @return iterable<string, array{string, string}> */
public function getTextsAndSlugs(): iterable
{
yield 'empty string' => [
'',
'',
];
yield 'string with white spaces only' => [
' ',
'',
];
yield 'already slugged text' => [
'setting-up-a-database',
'setting-up-a-database',
];
yield 'English text' => [
'Setting up a Database',
'setting-up-a-database',
];
yield 'Japanese text' => [
'データベースをセットアップする',
'detabesuwosettoappusuru',
];
yield 'Ukrainian text' => [
'Налаштування бази даних',
'nalastuvanna-bazi-danih',
];
}
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST;
use Doctrine\RST\Configuration;
use Doctrine\RST\ErrorManager;
use PHPUnit\Framework\TestCase;
class ErrorManagerTest extends TestCase
{
public function testGetErrors(): void
{
$configuration = $this->createMock(Configuration::class);
$configuration->expects(self::atLeastOnce())
->method('isAbortOnError')
->willReturn(false);
$configuration->expects(self::atLeastOnce())
->method('isSilentOnError')
->willReturn(true);
$errorManager = new ErrorManager($configuration);
$errorManager->error('ERROR FOO');
$errorManager->error('ERROR BAR');
$errors = $errorManager->getErrors();
self::assertSame('ERROR FOO', $errors[0]->asString());
self::assertSame('ERROR BAR', $errors[1]->asString());
}
}

View file

@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST;
use Doctrine\RST\Environment;
use Doctrine\RST\FileIncluder;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use RuntimeException;
use function trim;
class FileIncluderTest extends TestCase
{
/** @var Environment|MockObject */
private $environment;
public function testInclude(): void
{
$this->environment->expects(self::once())
->method('absoluteRelativePath')
->with('include.rst')
->willReturn(__DIR__ . '/Parser/files/include.rst');
$fileIncluder = new FileIncluder($this->environment, true, __DIR__ . '/Parser/files');
$contents = $fileIncluder->includeFiles('.. include:: include.rst');
self::assertSame('I was actually included', trim($contents));
}
public function testIncludeWithEmptyIncludeRoot(): void
{
$this->environment->expects(self::once())
->method('absoluteRelativePath')
->with('include.rst')
->willReturn(__DIR__ . '/Parser/files/include.rst');
$fileIncluder = new FileIncluder($this->environment, true, '');
$contents = $fileIncluder->includeFiles('.. include:: include.rst');
self::assertSame('I was actually included', trim($contents));
}
public function testShouldThrowExceptionOnInvalidFileInclude(): void
{
$this->environment->expects(self::once())
->method('absoluteRelativePath')
->with('non-existent-file.rst')
->willReturn('non-existent-file.rst');
$fileIncluder = new FileIncluder($this->environment, true, '');
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Include ".. include:: non-existent-file.rst" does not exist or is not readable.');
$fileIncluder->includeFiles('.. include:: non-existent-file.rst');
}
protected function setUp(): void
{
$this->environment = $this->createMock(Environment::class);
}
}

View file

@ -0,0 +1,245 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\RST\Functional;
use Doctrine\RST\Builder;
use Doctrine\RST\Configuration;
use Doctrine\RST\Formats\Format;
use Doctrine\RST\Kernel;
use Doctrine\RST\Parser;
use Exception;
use Gajus\Dindent\Indenter;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Throwable;
use function array_map;
use function assert;
use function explode;
use function file_exists;
use function file_get_contents;
use function implode;
use function in_array;
use function is_string;
use function rtrim;
use function setlocale;
use function sprintf;
use function str_replace;
use function strpos;
use function trim;
use const LC_ALL;
class FunctionalTest extends TestCase
{
private const RENDER_DOCUMENT_FILES = ['main-directive'];
private const SKIP_INDENTER_FILES = ['code-block-diff'];
protected function setUp(): void
{
setlocale(LC_ALL, 'en_US.utf8');
}
/**
* @param Format::* $format
*
* @dataProvider getBuildTests
*/
public function testBuild(
string $file,
Parser $parser,
string $format,
string $expected
): void {
$configuration = new Configuration();
$configuration->setFileExtension(Format::HTML);
$configuration->setUseCachedMetas(false);
$kernel = new Kernel($configuration);
$builder = new Builder($kernel);
$builder->build(__DIR__ . '/tests/build/' . $file, __DIR__ . '/output/build/' . $file);
$outputFileFinder = new Finder();
$outputFileFinder
->files()
->in(__DIR__ . '/output/build/' . $file)
->name('index.html');
foreach ($outputFileFinder as $outputFile) {
$rendered = $outputFile->getContents();
self::assertSame(
$this->trimTrailingWhitespace($expected),
$this->trimTrailingWhitespace($rendered)
);
}
}
/**
* @param 'render'|'renderAll' $renderMethod
* @param Format::* $format
*
* @dataProvider getRenderTests
*/
public function testRender(
string $file,
Parser $parser,
string $renderMethod,
string $format,
string $rst,
string $expected,
bool $useIndenter = true
): void {
$expectedLines = explode("\n", $expected);
$firstLine = $expectedLines[0];
if (strpos($firstLine, 'Exception:') === 0) {
/** @psalm-var class-string<Throwable> */
$exceptionClass = str_replace('Exception: ', '', $firstLine);
$this->expectException($exceptionClass);
$expectedExceptionMessage = $expectedLines;
unset($expectedExceptionMessage[0]);
$expectedExceptionMessage = implode("\n", $expectedExceptionMessage);
$this->expectExceptionMessage($expectedExceptionMessage);
}
$document = $parser->parse($rst);
$rendered = $document->$renderMethod();
if ($format === Format::HTML && $useIndenter) {
$indenter = new Indenter();
$rendered = $indenter->indent($rendered);
}
self::assertSame(
$this->trimTrailingWhitespace($expected),
$this->trimTrailingWhitespace($rendered)
);
}
/** @return iterable<string, array{string, Parser, 'render'|'renderDocument', Format::*, string, string, bool}> */
public function getRenderTests(): iterable
{
$tests = [];
foreach ($this->findSubDirectories(__DIR__ . '/tests/render') as $dir) {
$rstFilename = $dir->getPathname() . '/' . $dir->getFilename() . '.rst';
if (! file_exists($rstFilename)) {
throw new Exception(sprintf('Could not find functional test file "%s"', $rstFilename));
}
$rst = file_get_contents($rstFilename);
assert(is_string($rst));
$basename = $dir->getFilename();
foreach ($this->findRstFiles($dir) as $file) {
$format = $file->getExtension();
if (! in_array($format, [Format::HTML, Format::LATEX], true)) {
throw new Exception(sprintf('Unexpected file extension in "%s"', $file->getPathname()));
}
if (strpos($file->getFilename(), $dir->getFilename()) !== 0) {
throw new Exception(sprintf('Test filename "%s" does not match directory name', $file->getPathname()));
}
$renderMethod = in_array($basename, self::RENDER_DOCUMENT_FILES, true)
? 'renderDocument'
: 'render';
yield $basename . '_' . $format => [
$basename,
$this->getParser($format, __DIR__ . '/tests/render/' . $basename),
$renderMethod,
$format,
$rst,
trim($file->getContents()),
! in_array($basename, self::SKIP_INDENTER_FILES, true),
];
}
}
}
/** @return iterable<string, array{string, Parser, Format::*, string}> */
public function getBuildTests(): iterable
{
foreach ($this->findSubDirectories(__DIR__ . '/tests/build') as $dir) {
$rstFilename = $dir->getPathname() . '/index.rst';
if (! file_exists($rstFilename)) {
throw new Exception(sprintf('Could not find functional test file "%s"', $rstFilename));
}
$basename = $dir->getFilename();
foreach ($this->findRstFiles($dir) as $file) {
$format = $file->getExtension();
if (! in_array($format, [Format::HTML, Format::LATEX], true)) {
throw new Exception(sprintf('Unexpected file extension in "%s"', $file->getPathname()));
}
if (strpos($file->getFilename(), 'index') !== 0) {
throw new Exception(sprintf('Test filename "%s" does not match index', $file->getPathname()));
}
yield $basename . '_' . $format => [
$basename,
$this->getParser($format, __DIR__ . '/tests/build/' . $basename),
$format,
trim($file->getContents()),
];
}
}
}
/** @return iterable<SplFileInfo> */
private function findSubDirectories(string $directory): iterable
{
$finder = new Finder();
return $finder
->directories()
->in($directory);
}
/** @return iterable<SplFileInfo> */
private function findRstFiles(SplFileInfo $dir): iterable
{
$fileFinder = new Finder();
return $fileFinder
->files()
->in($dir->getPathname())
->notName('*.rst');
}
/** @param Format::* $format */
private function getParser(string $format, string $currentDirectory): Parser
{
$configuration = new Configuration();
$configuration->setFileExtension($format);
$configuration->silentOnError(true);
$kernel = new Kernel($configuration);
$parser = new Parser($kernel);
$environment = $parser->getEnvironment();
$environment->setCurrentDirectory($currentDirectory);
return $parser;
}
private function trimTrailingWhitespace(string $string): string
{
$lines = explode("\n", $string);
$lines = array_map(static function (string $line): string {
return rtrim($line);
}, $lines);
return trim(implode("\n", $lines));
}
}

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div class="toc"><ul><li id="page1-html" class="toc-item"><a href="page1.html">Page 1</a></li><li id="page2-html" class="toc-item"><a href="page2.html">Page 2</a></li></ul></div>
</body>
</html>

View file

@ -0,0 +1,6 @@
.. toctree::
:titlesonly:
page1
page2

View file

@ -0,0 +1,8 @@
Page 1
======
Chapter 1
---------
Chapter 2
---------

View file

@ -0,0 +1,4 @@
Page 2
======
Lorem Ipsum Dolor

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div class="section" id="index">
<h1>index</h1>
<div class="toc"><ul><li id="page1-html" class="toc-item"><a href="page1.html">Page 1</a><ul><li id="page1-html-chapter-1" class="toc-item"><a href="page1.html#chapter-1">Chapter 1</a></li><li id="page1-html-chapter-2" class="toc-item"><a href="page1.html#chapter-2">Chapter 2</a></li></ul></li><li id="page2-html" class="toc-item"><a href="page2.html">Page 2</a></li></ul></div>
</div>
</body>
</html>

View file

@ -0,0 +1,7 @@
index
=====
.. toctree::
page1
page2

View file

@ -0,0 +1,8 @@
Page 1
======
Chapter 1
---------
Chapter 2
---------

View file

@ -0,0 +1,4 @@
Page 2
======
Lorem Ipsum Dolor

View file

@ -0,0 +1 @@
<p>@Anchor Section</p>

View file

@ -0,0 +1 @@
`@Anchor Section`_

View file

@ -0,0 +1,8 @@
<div class="section" id="anchors">
<h1>
Anchors
</h1>
<a id="lists"></a>
<p><a href="#lists">go to lists</a></p>
</div>

View file

@ -0,0 +1,6 @@
Anchors
-------
.. _lists:
`go to lists <#lists>`_

View file

@ -0,0 +1,3 @@
\chapter{Anchors}
\label{lists}
\ref{#lists}

View file

@ -0,0 +1 @@
<p>I love <a href="https://github.com/">GitHub</a>, <a href="https://gitlab.com/">GitLab</a> and <a href="https://facebook.com/">Facebook</a>. But I don't affect references to __CLASS__.</p>

View file

@ -0,0 +1,5 @@
I love GitHub__, GitLab__ and `Facebook`__. But I don't affect references to __CLASS__.
.. __: https://github.com/
.. __: https://gitlab.com/
.. __: https://facebook.com/

View file

@ -0,0 +1 @@
I love \href{https://github.com/}{GitHub}, \href{https://gitlab.com/}{GitLab} and \href{https://facebook.com/}{Facebook}. But I don't affect references to __CLASS__.

View file

@ -0,0 +1 @@

View file

@ -0,0 +1 @@
.. Should be a comment, with BOM

View file

@ -0,0 +1,35 @@
<p class="special-paragraph1">Test special-paragraph1 1.</p>
<p>Test special-paragraph1 2.</p>
<p class="special-paragraph2">Test special-paragraph2 1.</p>
<p class="special-paragraph2">Test special-paragraph2 2.</p>
<div class="note">
<p class="special-paragraph3">Test</p>
</div>
<ul class="special-list">
<li class="dash">Test list item 1.</li>
<li class="dash">Test list item 2.</li>
</ul>
<p class="rot-gelb-blau grun-2008">Weird class names.</p>
<p class="level1">Level 1</p>
<blockquote class="level1">
<p class="level2">Level2 1</p>
<p class="level2">Level2 2</p>
</blockquote>
<dl class="special-definition-list">
<dt>term 1</dt>
<dd> Definition 1 </dd>
</dl>
<table class="special-table">
<thead>
<tr>
<th>First col</th>
<th>Second col</th>
</tr>
</thead>
<tbody>
<tr>
<td>Second row</td>
<td>Other col</td>
</tr>
</tbody>
</table>

View file

@ -0,0 +1,49 @@
.. class:: special-paragraph1
Test special-paragraph1 1.
Test special-paragraph1 2.
.. class:: special-paragraph2
Test special-paragraph2 1.
Test special-paragraph2 2.
.. note::
.. class:: special-paragraph3
Test
.. class:: special-list
- Test list item 1.
- Test list item 2.
.. class:: Rot-Gelb.Blau Grün:+2008
Weird class names.
.. class:: level1
Level 1
.. class:: level2
Level2 1
Level2 2
.. class:: special-definition-list
term 1
Definition 1
.. class:: special-table
=========== ==========
First col Second col
=========== ==========
Second row Other col
=========== ==========

View file

@ -0,0 +1,14 @@
<pre><code class="diff">+ Added line
- Removed line
Normal line
- Removed line
+ Added line
</code></pre>
<pre><code class="diff"> Normal line
+ Added line
- Removed line
Normal line
- Removed line
+ Added line
</code></pre>

View file

@ -0,0 +1,18 @@
.. code-block:: diff
+ Added line
- Removed line
Normal line
- Removed line
+ Added line
.. code-block:: diff
Normal line
+ Added line
- Removed line
Normal line
- Removed line
+ Added line

View file

@ -0,0 +1,3 @@
<pre><code class="">A
B C
</code></pre>

View file

@ -0,0 +1,5 @@
.. code-block::
A
B
C

View file

@ -0,0 +1,4 @@
<pre><code class="c++">#include &lt;iostream&gt; using namespace std; int main(void)
{ cout &lt;&lt; &quot;Hello world!&quot; &lt;&lt; endl;
}
</code></pre>

View file

@ -0,0 +1,10 @@
.. code-block:: c++
#include <iostream>
using namespace std;
int main(void)
{
cout << "Hello world!" << endl;
}

View file

@ -0,0 +1,4 @@
<pre><code class="java">protected void f()
{
}
</code></pre>

View file

@ -0,0 +1,5 @@
.. code-block:: java
protected void f()
{
}

View file

@ -0,0 +1,3 @@
<pre><code class="">* Testing
* Hey
</code></pre>

View file

@ -0,0 +1,6 @@
.. This should not be interpreted as a list
.. code-block::
* Testing
* Hey

View file

@ -0,0 +1,2 @@
<pre><code class="">Test code block with whitespace.
</code></pre>

View file

@ -0,0 +1,3 @@
::
Test code block with whitespace.

View file

@ -0,0 +1,3 @@
<p>Code block:</p>
<pre><code class="">This is a code block You hou!
</code></pre>

View file

@ -0,0 +1,5 @@
Code block::
This is a code block
You hou!

View file

@ -0,0 +1,8 @@
Code block:
\lstset{language=}
\begin{lstlisting}
This is a code block
You hou!
\end{lstlisting}

Some files were not shown because too many files have changed in this diff Show more