diff --git a/.gitignore b/.gitignore
index de4a392..8cab567 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/vendor
/composer.lock
+.idea
diff --git a/composer.json b/composer.json
index 61bf3d6..a75a72c 100644
--- a/composer.json
+++ b/composer.json
@@ -17,5 +17,18 @@
"nette/neon": "~2.3",
"latte/latte": "~2.3"
},
+ "require-dev": {
+ "nette/tester": "1.4.0"
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "autoload-dev": {
+ "classmap": [
+ "tests/"
+ ]
+ },
"bin": ["src/code-checker.php"]
}
diff --git a/src/CodeCheckers/EntityChecker.php b/src/CodeCheckers/EntityChecker.php
new file mode 100644
index 0000000..29716e0
--- /dev/null
+++ b/src/CodeCheckers/EntityChecker.php
@@ -0,0 +1,38 @@
+is('php')) {
+ return;
+ }
+
+ if (Strings::contains($s, '@ORM\Entity') && !Strings::contains($s, '@ORM\Entity(')) {
+ $checker->fix('Missing Entity`()`');
+ $s = str_replace('@ORM\Entity', '@ORM\Entity()', $s);
+ }
+
+ if (Strings::contains($s, '@ORM\Table()')) {
+ $checker->fix('Missing `name="table_name"`');
+ $s = str_replace('@ORM\Table()', '@ORM\Table(name="")', $s);
+ }
+
+ if (Strings::contains($s, '@ORM\Table') && !Strings::contains($s, '@ORM\Table(')) {
+ $checker->fix('Missing `name="table_name"`');
+ $s = str_replace('@ORM\Table', '@ORM\Table(name="")', $s);
+ }
+
+ return $s;
+ };
+ }
+}
diff --git a/src/CodeCheckers/Html5Checker.php b/src/CodeCheckers/Html5Checker.php
new file mode 100644
index 0000000..d383dd1
--- /dev/null
+++ b/src/CodeCheckers/Html5Checker.php
@@ -0,0 +1,25 @@
+is('latte')) {
+ return;
+ }
+
+ if (Strings::match($s, '#
#')) {
+ $checker->error('contains XHTML');
+ }
+ };
+ }
+}
diff --git a/src/CodeCheckers/LineLengthChecker.php b/src/CodeCheckers/LineLengthChecker.php
new file mode 100644
index 0000000..a9275ea
--- /dev/null
+++ b/src/CodeCheckers/LineLengthChecker.php
@@ -0,0 +1,37 @@
+is('php') && !$checker->is('phpt')) {
+ return;
+ }
+
+ $i = 0;
+ foreach (explode("\n", $s) as $line) {
+ $i++;
+ $line = str_replace("\t", str_repeat(' ', 4), $line);
+ $lineLength = Strings::length($line);
+ $message = sprintf('Line %s have %d characters', Strings::truncate(Strings::trim($line), 30), $lineLength);
+
+ if ($lineLength > $errorLineLength) {
+ $checker->error($message, $i);
+ continue;
+ }
+ if ($warningLineLength !== NULL && $lineLength > $warningLineLength) {
+ $checker->warning($message, $i);
+ }
+ }
+ };
+ }
+}
diff --git a/src/CodeCheckers/NeonChecker.php b/src/CodeCheckers/NeonChecker.php
new file mode 100644
index 0000000..4d96a7c
--- /dev/null
+++ b/src/CodeCheckers/NeonChecker.php
@@ -0,0 +1,32 @@
+is('neon')) {
+ return;
+ }
+
+ $lines = explode("\n", $s);
+ foreach ($lines as &$line) {
+ if (preg_match('~^(.*):( )?(yes|on|no|off)$~i', $line)) {
+ $message = sprintf('Boolean values should be true/false: %s', $line);
+ $checker->fix($message);
+ $line = preg_replace('~:( )?(yes|on)$~i', ': true', $line);
+ $line = preg_replace('~:( )?(no|off)$~i', ': false', $line);
+ }
+ }
+
+ return implode("\n", $lines);
+ };
+ }
+}
diff --git a/src/code-checker.php b/src/code-checker.php
old mode 100644
new mode 100755
index 06f7d17..62f5ddc
--- a/src/code-checker.php
+++ b/src/code-checker.php
@@ -6,10 +6,19 @@
* This file is part of the Nette Framework (https://nette.org)
*/
-use Nette\Utils\Strings;
+use CodeCheckers\EntityChecker;
+use CodeCheckers\LineLengthChecker;
+use CodeCheckers\Html5Checker;
+use CodeCheckers\NeonChecker;
use Nette\CommandLine\Parser;
+use Nette\Utils\Strings;
+
+$loaders = array_filter([
+ __DIR__ . '/../vendor/autoload.php',
+ __DIR__ . '/../../../autoload.php',
+], 'file_exists');
-if (@!include __DIR__ . '/../vendor/autoload.php') {
+if (@!include reset($loaders)) {
echo('Install packages using `composer update`');
exit(1);
}
@@ -373,6 +382,27 @@ public function is($extensions)
}
};
+// cs, missing @testCase in phpt files
+$checker->tasks[] = function (CodeChecker $checker, $s) {
+ if ($checker->is('phpt')) {
+ if (!Strings::contains($s, ' * @testCase')) {
+ $checker->error('Missing @testCase');
+ }
+ }
+};
+
+// cs, entity
+$checker->tasks[] = EntityChecker::createAnnotationsChecker();
+
+//max line length
+$checker->tasks[] = LineLengthChecker::createLineLengthChecker(NULL, 360);
+
+//html5
+$checker->tasks[] = Html5Checker::createHtml5CheckerChecker();
+
+//boolean (yes, on -> true, no, off -> false)
+$checker->tasks[] = NeonChecker::createBooleanValuesChecker();
+
$ok = $checker->run($options['-d']);
exit($ok ? 0 : 1);
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 0000000..a7ffcfd
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1,3 @@
+/*/output
+/test.log
+/tmp
diff --git a/tests/CodeCheckers/EntityChecker.phpt b/tests/CodeCheckers/EntityChecker.phpt
new file mode 100644
index 0000000..a597daa
--- /dev/null
+++ b/tests/CodeCheckers/EntityChecker.phpt
@@ -0,0 +1,100 @@
+fixMessages[] = $message;
+ }
+
+
+
+ public function is($file)
+ {
+ return TRUE;
+ }
+}
+
+
+
+class EntityCheckerTest extends TestCase
+{
+ /**
+ * @var FakeChecker
+ */
+ private $fakeChecker;
+
+
+
+ public function setup()
+ {
+ $this->fakeChecker = new FakeChecker();
+ }
+
+
+
+ /**
+ * @dataProvider getDataForTestEntity
+ */
+ public function testEntity($input, $output, $countOfFixMessages)
+ {
+ $annotationChecker = EntityChecker::createAnnotationsChecker();
+ Assert::same($output, $annotationChecker($this->fakeChecker, $input));
+ Assert::count($countOfFixMessages, $this->fakeChecker->fixMessages);
+ }
+
+
+
+ public function getDataForTestEntity()
+ {
+ return [
+ ['@ORM\Entity', '@ORM\Entity()', 1],
+ ['@ORM\Entity()', '@ORM\Entity()', 0],
+ ];
+ }
+
+
+
+ /**
+ * @dataProvider getDataForTestTableName
+ */
+ public function testTableName($input, $output, $countOfFixMessages)
+ {
+ $annotationChecker = EntityChecker::createAnnotationsChecker();
+ Assert::same($output, $annotationChecker($this->fakeChecker, $input));
+ Assert::count($countOfFixMessages, $this->fakeChecker->fixMessages);
+ }
+
+
+
+ public function getDataForTestTableName()
+ {
+ return [
+ ['@ORM\Table()', '@ORM\Table(name="")', 1],
+ ['@ORM\Table', '@ORM\Table(name="")', 1],
+ ['@ORM\Table(name="table_name")', '@ORM\Table(name="table_name")', 0],
+ ];
+ }
+}
+
+
+
+\run(new EntityCheckerTest());
diff --git a/tests/CodeCheckers/Html5Checker.phpt b/tests/CodeCheckers/Html5Checker.phpt
new file mode 100644
index 0000000..b6c93f2
--- /dev/null
+++ b/tests/CodeCheckers/Html5Checker.phpt
@@ -0,0 +1,106 @@
+errors[] = $message;
+ }
+
+
+
+ public function is($file)
+ {
+ return TRUE;
+ }
+}
+
+
+
+class Html5CheckerTest extends Tester\TestCase
+{
+
+ /**
+ * @var FakeChecker
+ */
+ private $fakeChecker;
+
+
+
+ public function setup()
+ {
+ $this->fakeChecker = new FakeChecker();
+ }
+
+
+
+ /**
+ * @dataProvider getDataForTestPass
+ */
+ public function testPass($s)
+ {
+ $html5Checker = Html5Checker::createHtml5CheckerChecker();
+ $html5Checker($this->fakeChecker, $s);
+ Assert::count(0, $this->fakeChecker->errors);
+ }
+
+
+
+ public function getDataForTestPass()
+ {
+ return [
+ [NULL],
+ ['
lol
lol