diff --git a/src/EntryPoints/REST/ValidateSubjectApi.php b/src/EntryPoints/REST/ValidateSubjectApi.php index 73d543e8..5adc60f6 100644 --- a/src/EntryPoints/REST/ValidateSubjectApi.php +++ b/src/EntryPoints/REST/ValidateSubjectApi.php @@ -63,7 +63,7 @@ public function getBodyParamSettings(): array { self::PARAM_SOURCE => 'body', ParamValidator::PARAM_TYPE => 'array', ParamValidator::PARAM_REQUIRED => true, - self::PARAM_DESCRIPTION => 'Proposed Statements (property/value pairs). Shape matches docs/SubjectFormat.md.', + self::PARAM_DESCRIPTION => 'Proposed Statements (property/value pairs). Shape matches docs/api/subject-format.md.', ], ]; } diff --git a/src/EntryPoints/REST/ValidateSubjectUpdateApi.php b/src/EntryPoints/REST/ValidateSubjectUpdateApi.php index 42289d45..a6396866 100644 --- a/src/EntryPoints/REST/ValidateSubjectUpdateApi.php +++ b/src/EntryPoints/REST/ValidateSubjectUpdateApi.php @@ -68,7 +68,7 @@ public function getBodyParamSettings(): array { self::PARAM_SOURCE => 'body', ParamValidator::PARAM_TYPE => 'array', ParamValidator::PARAM_REQUIRED => true, - self::PARAM_DESCRIPTION => 'Proposed Statements (property/value pairs) for the proposed update. Shape matches docs/SubjectFormat.md.', + self::PARAM_DESCRIPTION => 'Proposed Statements (property/value pairs) for the proposed update. Shape matches docs/api/subject-format.md.', ], 'comment' => [ self::PARAM_SOURCE => 'body', diff --git a/tests/phpunit/DocsPathReferencesTest.php b/tests/phpunit/DocsPathReferencesTest.php new file mode 100644 index 00000000..3db9a2b0 --- /dev/null +++ b/tests/phpunit/DocsPathReferencesTest.php @@ -0,0 +1,96 @@ +assertSame( + [], + $this->danglingDocsReferences(), + 'These src/ files cite a docs file that does not exist. Point them at the current path.' + ); + } + + /** + * @return list e.g. "src/EntryPoints/REST/ValidateSubjectApi.php:66 cites docs/Foo.md" + */ + private function danglingDocsReferences(): array { + $dangling = []; + + foreach ( $this->sourceFiles() as $file ) { + foreach ( $this->citedDocsPaths( $file ) as $line => $paths ) { + foreach ( $paths as $path ) { + if ( !file_exists( $this->extensionRoot() . '/' . $path ) ) { + $relativeFile = substr( $file, strlen( $this->extensionRoot() ) + 1 ); + $dangling[] = "$relativeFile:$line cites $path"; + } + } + } + } + + return $dangling; + } + + /** + * @return list absolute paths of every PHP file under src/. + */ + private function sourceFiles(): array { + $files = []; + + $directory = new RecursiveDirectoryIterator( $this->extensionRoot() . '/src' ); + /** @var SplFileInfo $file */ + foreach ( new RecursiveIteratorIterator( $directory ) as $file ) { + if ( $file->isFile() && $file->getExtension() === 'php' ) { + $files[] = $file->getPathname(); + } + } + + sort( $files ); + + return $files; + } + + /** + * @return array> docs paths cited in the file, keyed by line number. + */ + private function citedDocsPaths( string $file ): array { + $contents = file_get_contents( $file ); + $this->assertNotFalse( $contents, "Could not read $file" ); + + $cited = []; + + foreach ( explode( "\n", $contents ) as $index => $line ) { + preg_match_all( '#\bdocs/[A-Za-z0-9._/-]+\.md#', $line, $matches ); + + if ( $matches[0] !== [] ) { + $cited[$index + 1] = $matches[0]; + } + } + + return $cited; + } + + private function extensionRoot(): string { + return dirname( __DIR__, 2 ); + } + +}