Update website
This commit is contained in:
parent
4413528994
commit
1d90fbf296
6865 changed files with 1091082 additions and 0 deletions
412
vendor/doctrine/rst-parser/tests/Builder/BuilderTest.php
vendored
Normal file
412
vendor/doctrine/rst-parser/tests/Builder/BuilderTest.php
vendored
Normal 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 &</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';
|
||||
}
|
||||
}
|
48
vendor/doctrine/rst-parser/tests/Builder/CopierTest.php
vendored
Normal file
48
vendor/doctrine/rst-parser/tests/Builder/CopierTest.php
vendored
Normal 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);
|
||||
}
|
||||
}
|
95
vendor/doctrine/rst-parser/tests/Builder/DocumentsTest.php
vendored
Normal file
95
vendor/doctrine/rst-parser/tests/Builder/DocumentsTest.php
vendored
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
85
vendor/doctrine/rst-parser/tests/Builder/ParseQueueProcessorTest.php
vendored
Normal file
85
vendor/doctrine/rst-parser/tests/Builder/ParseQueueProcessorTest.php
vendored
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
27
vendor/doctrine/rst-parser/tests/Builder/ParseQueueTest.php
vendored
Normal file
27
vendor/doctrine/rst-parser/tests/Builder/ParseQueueTest.php
vendored
Normal 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());
|
||||
}
|
||||
}
|
241
vendor/doctrine/rst-parser/tests/Builder/ScannerTest.php
vendored
Normal file
241
vendor/doctrine/rst-parser/tests/Builder/ScannerTest.php
vendored
Normal 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;
|
||||
}
|
||||
}
|
34
vendor/doctrine/rst-parser/tests/Builder/input/another.rst
vendored
Normal file
34
vendor/doctrine/rst-parser/tests/Builder/input/another.rst
vendored
Normal 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`_
|
1
vendor/doctrine/rst-parser/tests/Builder/input/file.txt
vendored
Normal file
1
vendor/doctrine/rst-parser/tests/Builder/input/file.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
Example of static file!
|
46
vendor/doctrine/rst-parser/tests/Builder/input/index.rst
vendored
Normal file
46
vendor/doctrine/rst-parser/tests/Builder/input/index.rst
vendored
Normal 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
|
||||
==========
|
20
vendor/doctrine/rst-parser/tests/Builder/input/introduction.rst
vendored
Normal file
20
vendor/doctrine/rst-parser/tests/Builder/input/introduction.rst
vendored
Normal 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>`
|
5
vendor/doctrine/rst-parser/tests/Builder/input/link-to-index.rst
vendored
Normal file
5
vendor/doctrine/rst-parser/tests/Builder/input/link-to-index.rst
vendored
Normal 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.
|
17
vendor/doctrine/rst-parser/tests/Builder/input/subdir/file.rst
vendored
Normal file
17
vendor/doctrine/rst-parser/tests/Builder/input/subdir/file.rst
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
Heading 1
|
||||
#########
|
||||
|
||||
Heading 2
|
||||
.........
|
||||
|
||||
Heading 3
|
||||
:::::::::
|
||||
|
||||
Heading 4
|
||||
_________
|
||||
|
||||
Heading 5
|
||||
`````````
|
||||
|
||||
Heading 6
|
||||
'''''''''
|
1
vendor/doctrine/rst-parser/tests/Builder/input/subdir/include.rst.inc
vendored
Normal file
1
vendor/doctrine/rst-parser/tests/Builder/input/subdir/include.rst.inc
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
This file is included
|
63
vendor/doctrine/rst-parser/tests/Builder/input/subdir/index.rst
vendored
Normal file
63
vendor/doctrine/rst-parser/tests/Builder/input/subdir/index.rst
vendored
Normal 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
|
||||
--
|
10
vendor/doctrine/rst-parser/tests/Builder/input/subdir/toc.rst
vendored
Normal file
10
vendor/doctrine/rst-parser/tests/Builder/input/subdir/toc.rst
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
TOC in Subdir
|
||||
=============
|
||||
|
||||
.. toctree::
|
||||
|
||||
/introduction
|
||||
/subdirective
|
||||
/another
|
||||
/subdir/index
|
||||
file
|
14
vendor/doctrine/rst-parser/tests/Builder/input/subdirective.rst
vendored
Normal file
14
vendor/doctrine/rst-parser/tests/Builder/input/subdirective.rst
vendored
Normal 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
|
10
vendor/doctrine/rst-parser/tests/Builder/input/toc-glob-reversed.rst
vendored
Normal file
10
vendor/doctrine/rst-parser/tests/Builder/input/toc-glob-reversed.rst
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
TOC Reversed
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:glob:
|
||||
:reversed:
|
||||
|
||||
index
|
||||
*
|
||||
introduction
|
10
vendor/doctrine/rst-parser/tests/Builder/input/toc-glob.rst
vendored
Normal file
10
vendor/doctrine/rst-parser/tests/Builder/input/toc-glob.rst
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
TOC Glob
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:glob:
|
||||
|
||||
index
|
||||
*
|
||||
toc-glob
|
||||
introduction
|
Loading…
Add table
Add a link
Reference in a new issue