*/ 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; } }