Skip to content

Commit

Permalink
Check the Category tag against APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewnicols committed Feb 23, 2024
1 parent a2f4209 commit 354e93d
Show file tree
Hide file tree
Showing 8 changed files with 450 additions and 3 deletions.
82 changes: 82 additions & 0 deletions moodle/Sniffs/Commenting/CategorySniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

namespace MoodleHQ\MoodleCS\moodle\Sniffs\Commenting;

// phpcs:disable moodle.NamingConventions

use MoodleHQ\MoodleCS\moodle\Util\MoodleUtil;
use MoodleHQ\MoodleCS\moodle\Util\Docblocks;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;

/**
* Checks that all test classes and global functions have appropriate @package tags.
*
* @copyright 2024 Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class CategorySniff implements Sniff {

/**
* Register for open tag (only process once per file).
*/
public function register() {
return [
T_DOC_COMMENT_OPEN_TAG,
];
}

/**
* Processes php files and perform various checks with file.
*
* @param File $phpcsFile The file being scanned.
* @param int $stackPtr The position in the stack.
*/
public function process(File $phpcsFile, $stackPtr) {
// The apis.json was introduced in Moodle 4.02.
// Make and exception for codechecker phpunit tests, so they are run always.
if (!MoodleUtil::meetsMinimumMoodleVersion($phpcsFile, 402) && !MoodleUtil::isUnitTestRunning()) {
return; // @codeCoverageIgnore
}

$categoryTokens = Docblocks::getMatchingDocTags($phpcsFile, $stackPtr, '@category');
if (empty($categoryTokens)) {
return;
}

$tokens = $phpcsFile->getTokens();
$apis = MoodleUtil::getMoodleApis($phpcsFile);

$docblock = Docblocks::getDocBlock($phpcsFile, $stackPtr);
foreach ($categoryTokens as $tokenPtr) {
$categoryValuePtr = $phpcsFile->findNext(
T_DOC_COMMENT_STRING,
$tokenPtr,
$docblock['comment_closer']
);
$categoryValue = $tokens[$categoryValuePtr]['content'];
if (!in_array($categoryValue, $apis)) {
$phpcsFile->addError(
'Invalid @category tag value "%s".',
$categoryValuePtr,
'Invalid',
[$categoryValue]
);
}
}
}
}
4 changes: 4 additions & 0 deletions moodle/Tests/MoodleCSBaseTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ public function set_component_mapping(array $mapping): void {
\MoodleHQ\MoodleCS\moodle\Util\MoodleUtil::setMockedComponentMappings($mapping);
}

public function set_api_mapping(array $mapping): void {
\MoodleHQ\MoodleCS\moodle\Util\MoodleUtil::setMockedApiMappings($mapping);
}

/**
* Set the name of the standard to be tested.
*
Expand Down
70 changes: 70 additions & 0 deletions moodle/Tests/Sniffs/Commenting/CategorySniffTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.

namespace MoodleHQ\MoodleCS\moodle\Tests\Sniffs\Commenting;

use MoodleHQ\MoodleCS\moodle\Tests\MoodleCSBaseTestCase;

// phpcs:disable moodle.NamingConventions

/**
* Test the CategorySniff sniff.
*
* @category test
* @copyright 2024 onwards Andrew Lyons <[email protected]>
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* @covers \MoodleHQ\MoodleCS\moodle\Sniffs\Commenting\CategorySniff
*/
class CategorySniffTest extends MoodleCSBaseTestCase
{

/**
* @dataProvider provider
*/
public function test_from_provider(
string $fixture,
array $errors,
array $warnings
): void {
$this->set_standard('moodle');
$this->set_sniff('moodle.Commenting.Category');
$this->set_fixture(sprintf("%s/fixtures/%s.php", __DIR__, $fixture));
$this->set_warnings($warnings);
$this->set_errors($errors);
$this->set_api_mapping([
'test' => [
'component' => 'core',
'allowspread' => true,
'allowlevel2' => false,
],
]);

$this->verify_cs_results();
}

public static function provider(): array {
return [
'Standard fixes' => [
'fixture' => 'category_tags',
'errors' => [
13 => 'Invalid @category tag value "core"',
],
'warnings' => [],
],
];
}
}
22 changes: 22 additions & 0 deletions moodle/Tests/Sniffs/Commenting/fixtures/category_tags.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace MoodleHQ\MoodleCS\moodle\Tests\Sniffs\PHPUnit;

defined('MOODLE_INTERNAL') || die(); // Make this always the 1st line in all CS fixtures.

/**
* @category test
*/
class category_valid {}

/**
* @category core
*/
class category_invalid {}

/**
* Some docblock without a category.
*/
class category_missing {}

class no_docblock {}
18 changes: 18 additions & 0 deletions moodle/Tests/Util/DocblocksTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,24 @@ public function testGetDocBlockTags(): void {
$methodPointer = $phpcsFile->findNext(T_FUNCTION, $classPointer);
$this->assertNull(Docblocks::getDocBlock($phpcsFile, $methodPointer));
$this->assertCount(0, Docblocks::getMatchingDocTags($phpcsFile, $methodPointer, '@property'));

// Get the docblock from pointers at the start, middle, and end, of a docblock.
$tokens = $phpcsFile->getTokens();
$startDocPointer = $phpcsFile->findNext(T_DOC_COMMENT_OPEN_TAG, 0);
$endDocPointer = $phpcsFile->findNext(T_DOC_COMMENT_CLOSE_TAG, $startDocPointer);
$middleDocPointer = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $startDocPointer, $endDocPointer);

$docblock = Docblocks::getDocBlock($phpcsFile, $startDocPointer);
$this->assertIsArray($docblock);
$this->assertEquals($tokens[$startDocPointer], $docblock);

$docblock = Docblocks::getDocBlock($phpcsFile, $middleDocPointer);
$this->assertIsArray($docblock);
$this->assertEquals($tokens[$startDocPointer], $docblock);

$docblock = Docblocks::getDocBlock($phpcsFile, $endDocPointer);
$this->assertIsArray($docblock);
$this->assertEquals($tokens[$startDocPointer], $docblock);
}

public function testGetDocBlockClassOnly(): void {
Expand Down
Loading

0 comments on commit 354e93d

Please sign in to comment.