Skip to content

Commit

Permalink
MNT Add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli committed Nov 1, 2023
1 parent 4534fd6 commit cb5a657
Show file tree
Hide file tree
Showing 15 changed files with 465 additions and 4 deletions.
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: CI

on:
push:
pull_request:
workflow_dispatch:

jobs:
ci:
name: CI
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1
16 changes: 16 additions & 0 deletions .github/workflows/dispatch-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Dispatch CI

on:
# At 6:30 PM UTC, only on Sunday and Monday
schedule:
- cron: '30 18 * * 0,1'

jobs:
dispatch-ci:
name: Dispatch CI
# Only run cron on the silverstripe account
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
runs-on: ubuntu-latest
steps:
- name: Dispatch CI
uses: silverstripe/gha-dispatch-ci@v1
4 changes: 2 additions & 2 deletions .github/workflows/merge-up.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: Merge-up

on:
# At 6:30 PM UTC, only on Sunday
# At 6:30 PM UTC, only on Thursday
schedule:
- cron: '30 18 * * 0'
- cron: '30 18 * * 4'
workflow_dispatch:

jobs:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/vendor/
/composer.lock
.phpunit.result.cache
8 changes: 6 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@
},
"autoload": {
"psr-4": {
"SilverStripe\\MD_PHP_CodeSniffer\\": "src/"
"SilverStripe\\MD_PHP_CodeSniffer\\": "src/",
"SilverStripe\\MD_PHP_CodeSniffer\\Tests\\": "tests/"
}
},
"bin": [
"bin/mdphpcs"
]
],
"require-dev": {
"phpunit/phpunit": "^9.6"
}
}
12 changes: 12 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php" colors="true">
<testsuites>
<testsuite name="all-except-fixing">
<directory>tests</directory>
<exclude>tests/SnifferFixTest.php</exclude>
</testsuite>
<testsuite name="fixing-only">
<file>tests/SnifferFixTest.php</file>
</testsuite>
</testsuites>
</phpunit>
4 changes: 4 additions & 0 deletions src/Sniffer.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ private function prepareConfig(bool $usingExplicitStandard, string $lintLanguage
// Creating the Config object populates it with all required settings based on the phpcs/phpcbf CLI arguments provided.
$config = new Config();

if (defined('PHP_CODESNIFFER_IN_TESTS') && PHP_CODESNIFFER_IN_TESTS) {
$config->files = [str_replace('/src', '/tests/fixtures', __DIR__ )];
}

// We don't support STDIN for passing markdown in
if ($config->stdin === true) {
// 3 is the exit code phpcs uses for errors like this
Expand Down
50 changes: 50 additions & 0 deletions tests/CodeBlockTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace SilverStripe\MD_PHP_CodeSniffer\Test;

use ReflectionProperty;
use PHP_CodeSniffer\Config;
use PHP_CodeSniffer\Ruleset;
use PHPUnit\Framework\TestCase;
use SilverStripe\MD_PHP_CodeSniffer\CodeBlock;

class CodeBlockTest extends TestCase
{
public static function setUpBeforeClass(): void
{
parent::setUpBeforeClass();

if (!defined('PHP_CODESNIFFER_CBF')) {
define('PHP_CODESNIFFER_CBF', false);
}
}

public function testGetContent()
{
$config = new Config();
$block = new CodeBlock('This is the content', new Ruleset($config), $config);

$this->assertSame('This is the content', $block->getContent());

$block->setContent('New content now');

$this->assertSame('New content now', $block->getContent());
}

public function testCleanup()
{
$config = new Config();
$block = new CodeBlock('This is the content', new Ruleset($config), $config);
$block->cleanUp();

$this->assertSame('This is the content', $block->getContent());

$reflectionContent = new ReflectionProperty($block, 'content');
$reflectionContent->setAccessible(true);
$reflectionFinalContent = new ReflectionProperty($block, 'finalContent');
$reflectionFinalContent->setAccessible(true);

$this->assertNull($reflectionContent->getValue($block));
$this->assertSame('This is the content', $reflectionFinalContent->getValue($block));
}
}
66 changes: 66 additions & 0 deletions tests/SnifferFixTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace SilverStripe\MD_PHP_CodeSniffer\Test;

use PHP_CodeSniffer\Files\FileList;
use PHP_CodeSniffer\Ruleset;
use PHPUnit\Framework\TestCase;
use ReflectionMethod;
use SilverStripe\MD_PHP_CodeSniffer\Sniffer;

/**
* Because of PHP CodeSniffer's reliance on constants, this has to be done separately from the other tests.
*/
class SnifferFixTest extends TestCase
{
public function testFix()
{
if (!defined('PHP_CODESNIFFER_CBF')) {
define('PHP_CODESNIFFER_CBF', true);
}

$sniffer = new Sniffer();

// backup original content
$orig = [];
$paths = self::getFilesList($sniffer);
/** @var string $path */
foreach ($paths as $path => $v) {
$orig[$path] = file_get_contents($path);
}

try {
ob_start();
$exitCode = $sniffer->run('PHP', true, true);
$output = ob_get_clean();

// Validate that the files which should change did, and which shouldn't change didn't
foreach ($orig as $path => $content) {
$this->assertFileExists($path);

if (str_contains($path, 'lint-with-problems')) {
$this->assertFileEquals(str_replace('/fixtures/', '/expected-after-fixing/', $path), $path);
} else {
$this->assertSame($content, file_get_contents($path));
}
}

// There are no remaining auto-fixable problems
$this->assertSame(1, $exitCode);
} finally {
// Put the original content back
foreach ($orig as $path => $content) {
file_put_contents($path, $content);
}
}
}

private static function getFilesList(Sniffer $sniffer): FileList
{
$prepareConfig = new ReflectionMethod($sniffer, 'prepareConfig');
$prepareConfig->setAccessible(true);
$config = $prepareConfig->invoke($sniffer, false, 'PHP', true);

return new FileList($config, new Ruleset($config));
}
}
141 changes: 141 additions & 0 deletions tests/SnifferTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php

namespace SilverStripe\MD_PHP_CodeSniffer\Test;

use PHP_CodeSniffer\Files\FileList;
use PHP_CodeSniffer\Ruleset;
use PHPUnit\Framework\TestCase;
use ReflectionMethod;
use SilverStripe\MD_PHP_CodeSniffer\Sniffer;

class SnifferTest extends TestCase
{
/**
* Validates that fenced code blocks are correctly identified and have the expected data
*
* @dataProvider provideFindFencedBlocks
*/
public function testFindFencedCodeBlocks(string $path, bool $exists, string $realPath = '', int $num = 0, string $content = '')
{
if (!defined('PHP_CODESNIFFER_CBF')) {
define('PHP_CODESNIFFER_CBF', false);
}

$sniffer = new Sniffer();
$files = self::getFilesList($sniffer);

$findFencedCodeblocks = new ReflectionMethod($sniffer, 'findFencedCodeblocks');
$findFencedCodeblocks->setAccessible(true);
$blocks = $findFencedCodeblocks->invoke($sniffer, $files, 'PHP');

$blockKey = __DIR__ . $path;

if ($exists) {
$this->assertArrayHasKey($blockKey, $blocks, 'block must be found');

$block = $blocks[$blockKey];
$this->assertSame($blockKey, $block['path'], 'block path must be correct');
$this->assertSame(__DIR__ . $realPath, $block['realpath'], 'block realpath must be correct');
$this->assertSame($num, $block['num'], 'block must be numbered correctly');
$this->assertSame($content, ltrim($block['content']), 'block content must be correct');
} else {
$this->assertArrayNotHasKey($blockKey, $blocks, 'block must not be found');
}
}

public function provideFindFencedBlocks()
{
return [
'nothing to lint 1' => [
'path' => '/fixtures/nothing-to-lint.md',
'exists' => false,
],
'nothing to lint 2' => [
'path' => '/fixtures/nothing-to-lint_1.md',
'exists' => false,
],
'file paths all include block numbers' => [
'path' => '/fixtures/lint-but-no-problems.md',
'exists' => false,
],
[
'path' => '/fixtures/lint-but-no-problems_1.md',
'exists' => true,
'realpath' => '/fixtures/lint-but-no-problems.md',
'num' => 1,
'content' => <<<'MD'
<?php
namespace App;
class MyClass
{
private string $myProperty = 'this is the value';
}

MD
],
'no hallucinated block' => [
'path' => '/fixtures/lint-but-no-problems_2.md',
'exists' => false,
],
// No need to check lint-with-problems_1 and lint-with-problems_2 - they're functionality
// identical to lint-but-no-problems_1 for the purposes of this test.
'language identifier not case sensitive' => [
'path' => '/fixtures/lint-with-problems_3.md',
'exists' => true,
'realpath' => '/fixtures/lint-with-problems.md',
'num' => 3,
'content' => <<<'MD'
<?php
class AnotherClass {
private string $anotherProperty='this is the value';
}

MD
],
'indentation not in content' => [
'path' => '/fixtures/lint-with-problems_4.md',
'exists' => true,
'realpath' => '/fixtures/lint-with-problems.md',
'num' => 4,
'content' => <<<'MD'
<?php
class FinalClass {
private string $lastProperty='this is the value';
}

MD
],
];
}

public function testSniff()
{
$sniffer = new Sniffer();
ob_start();
$exitCode = $sniffer->run('PHP', false, true);
$output = ob_get_clean();

// There are auto-fixable problems
$this->assertSame(2, $exitCode);

// Check we didn't find problems where there aren't any
$this->assertStringNotContainsString('nothing-to-lint', $output, 'nothing to lint, so nothing found');
$this->assertStringNotContainsString('lint-but-no-problems', $output, 'linted but no problems found');
$this->assertStringNotContainsString('lint-with-problems_2', $output, 'that code block has no linting problems');

// Check we did find problems where there are plenty
$this->assertStringContainsString('lint-with-problems_1', $output);
$this->assertStringContainsString('lint-with-problems_3', $output);
$this->assertStringContainsString('lint-with-problems_4', $output);
}

private static function getFilesList(Sniffer $sniffer): FileList
{
$prepareConfig = new ReflectionMethod($sniffer, 'prepareConfig');
$prepareConfig->setAccessible(true);
$config = $prepareConfig->invoke($sniffer, false, 'PHP', true);

return new FileList($config, new Ruleset($config));
}
}
28 changes: 28 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

// php_codesniffer autoloader
$autoloadCandidates = [
// running from package itself as root
__DIR__ . '/../vendor/squizlabs/php_codesniffer/autoload.php',
// running from package in vendor/silverstripe/markdown-php-codesniffer
__DIR__ . '/../../../squizlabs/php_codesniffer/autoload.php',
];

$autoloaded = false;
foreach ($autoloadCandidates as $candidate) {
if (is_file($candidate)) {
require_once $candidate;
$autoloaded = true;
break;
}
}

if (!defined('PHP_CODESNIFFER_VERBOSITY')) {
define('PHP_CODESNIFFER_VERBOSITY', 0);
}

if (!defined('PHP_CODESNIFFER_IN_TESTS')) {
define('PHP_CODESNIFFER_IN_TESTS', true);
}

$_SERVER['argv'][] = '--standard=' . str_replace('/tests', '/phpcs.default.xml', __DIR__);
Loading

0 comments on commit cb5a657

Please sign in to comment.