branch: externals/phpinspect
commit f7d88a90f4d3ef35fd1b4e8b05b95690c54e4256
Author: Hugo Thunnissen <de...@hugot.nl>
Commit: Hugo Thunnissen <de...@hugot.nl>

    Implement some general tests for the parser code
---
 README.md                             | 10 +++++
 phpinspect.el                         | 16 +++++--
 test/fixtures/Block.el                |  1 +
 test/fixtures/Block.php               |  8 ++++
 test/fixtures/Functions.el            |  1 +
 test/fixtures/Functions.php           | 25 +++++++++++
 test/fixtures/NamespacedClass.el      |  1 +
 test/fixtures/NamespacedClass.php     | 84 +++++++++++++++++++++++++++++++++++
 test/fixtures/NamespacedFunctions.el  |  1 +
 test/fixtures/NamespacedFunctions.php | 27 +++++++++++
 test/phpinspect-test.el               | 71 +++++++++++++++++++++++++++++
 test/util/generate-test-data.el       | 13 ++++++
 12 files changed, 254 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md
index 3e80ef399b..54004ff11b 100644
--- a/README.md
+++ b/README.md
@@ -23,3 +23,13 @@ Example config:
 
 (add-hook 'php-mode-hook #'my-php-personal-hook)
 ```
+
+## Development
+
+### Running tests
+Tests are implemented using `ert`. You can run them in batch mode with the 
following
+command:
+
+```bash
+emacs -batch -l ert -l ./phpinspect.el -l ./test/phpinspect-test.el -f 
ert-run-tests-batch-and-exit
+```
diff --git a/phpinspect.el b/phpinspect.el
index e62af151d4..1df1270e83 100644
--- a/phpinspect.el
+++ b/phpinspect.el
@@ -706,6 +706,12 @@ the properties of the class"
       (goto-char (buffer-end 1))
       (insert (concat (apply 'format args) "\n")))))
 
+(defun phpinspect-parse-file (file)
+  (with-temp-buffer
+    (insert-file-contents-literally file)
+    (phpinspect-parse-current-buffer)))
+
+
 (defun phpinspect-parse-current-buffer ()
   (phpinspect-parse-buffer-until-point
    (current-buffer)
@@ -1507,6 +1513,9 @@ namespace if not provided"
    (phpinspect--get-project-root)
    class-fqn))
 
+(defun phpinspect-index-file (file-name)
+  (phpinspect--index-tokens (phpinspect-parse-file file-name)))
+
 (defun phpinspect-get-or-create-cached-project-class (project-root class-fqn)
   (let ((existing-index (phpinspect-get-cached-project-class
                          project-root
@@ -1524,9 +1533,7 @@ namespace if not provided"
            (if visited-buffer
                (setq new-index (with-current-buffer visited-buffer
                                  (phpinspect--index-current-buffer)))
-             (setq new-index (with-temp-buffer
-                               (insert-file-contents-literally class-file)
-                               (phpinspect--index-current-buffer))))
+             (setq new-index (phpinspect-index-file class-file)))
            (phpinspect--log "New index: %s" new-index)
            (dolist (class (alist-get 'classes new-index))
              (when class
@@ -2136,7 +2143,8 @@ level of START-FILE in stead of `default-directory`."
 
 ;; Use statements
 ;;;###autoload
-(defun phpinspect-fix-uses-interactive () "Add missing use statements to a php 
file"
+(defun phpinspect-fix-uses-interactive ()
+  "Add missing use statements to the currently visited PHP file."
        (interactive)
        (save-buffer)
        (let* ((project-root (phpinspect--get-project-root))
diff --git a/test/fixtures/Block.el b/test/fixtures/Block.el
new file mode 100644
index 0000000000..427b1f1928
--- /dev/null
+++ b/test/fixtures/Block.el
@@ -0,0 +1 @@
+(:root (:block (:word "return") (:word "new") (:word "Response") (:list 
(:variable "this") (:object-attrib (:word "twig")) (:object-attrib (:word 
"render")) (:list (:string "domain/manage.html.twig") (:comma ",") (:array 
(:string "domain") (:fat-arrow "=>") (:variable "this") (:object-attrib (:word 
"repo")) (:object-attrib (:word "find")) (:list (:variable "name")) (:comma 
",") (:string "users") (:fat-arrow "=>") (:variable "this") (:object-attrib 
(:word "user_repo")) (:object-attrib (:w [...]
diff --git a/test/fixtures/Block.php b/test/fixtures/Block.php
new file mode 100644
index 0000000000..c8cf052d0d
--- /dev/null
+++ b/test/fixtures/Block.php
@@ -0,0 +1,8 @@
+{
+    return new Response(
+        $this->twig->render('domain/manage.html.twig', [
+            'domain' => $this->repo->find($name),
+            'users' => $this->user_repo->findBy(['domain' => $name])
+        ])
+    );
+}
diff --git a/test/fixtures/Functions.el b/test/fixtures/Functions.el
new file mode 100644
index 0000000000..d8ca777249
--- /dev/null
+++ b/test/fixtures/Functions.el
@@ -0,0 +1 @@
+(:root (:function (:declaration (:word "function") (:word 
"MergeTwoArraysAndSomeOtherStuff") (:list (:word "array") (:variable "array1") 
(:comma ",") (:variable "untyped_variable")) (:word "Response")) (:block 
(:variable "merged") (:assignment "=") (:word "array_merge") (:list (:variable 
"array_1") (:comma ",") (:variable "untyped_variable")) (:terminator ";") 
(:variable "mapped") (:assignment "=") (:word "arrap_map") (:list (:function 
(:declaration (:word "function") (:list (:variable " [...]
diff --git a/test/fixtures/Functions.php b/test/fixtures/Functions.php
new file mode 100644
index 0000000000..374dcefb80
--- /dev/null
+++ b/test/fixtures/Functions.php
@@ -0,0 +1,25 @@
+<?php
+function MergeTwoArraysAndSomeOtherStuff(array $array1, $untyped_variable): 
Response
+{
+    $merged = array_merge($array_1, $untyped_variable);
+
+    $mapped = arrap_map(
+        function ($item) {
+            return $item;
+        },
+        $merged
+    );
+
+    $user = $this->user_repo->findOne($req->get('user'));
+
+    return new Response(
+        $this->twig->render('address/create.html.twig', [
+            'user' => $user,
+        ])
+    );
+}
+
+
+function BeTheSecondFunctionInTheFile() {
+    return [ "Very Impressive Result" => $result ];
+}
diff --git a/test/fixtures/NamespacedClass.el b/test/fixtures/NamespacedClass.el
new file mode 100644
index 0000000000..8551d7b2e0
--- /dev/null
+++ b/test/fixtures/NamespacedClass.el
@@ -0,0 +1 @@
+(:root (:word "declare") (:list (:word "strict_types") (:assignment "=")) 
(:terminator ";") (:namespace (:word "App\\Controller") (:terminator ";") (:use 
(:word "Symfony\\Component\\HttpFoundation\\Response") (:terminator ";")) (:use 
(:word "App\\Entity\\Address") (:terminator ";")) (:use (:word 
"Symfony\\Component\\HttpFoundation\\RedirectResponse") (:terminator ";")) 
(:use (:word "App\\Repository\\AddressRepository") (:terminator ";")) (:use 
(:word "App\\Repository\\UserRepository") (: [...]
diff --git a/test/fixtures/NamespacedClass.php 
b/test/fixtures/NamespacedClass.php
new file mode 100644
index 0000000000..2ad5938cd3
--- /dev/null
+++ b/test/fixtures/NamespacedClass.php
@@ -0,0 +1,84 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Controller;
+
+use Symfony\Component\HttpFoundation\Response;
+use App\Entity\Address;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use App\Repository\AddressRepository;
+use App\Repository\UserRepository;
+use Doctrine\ORM\EntityManagerInterface;
+use Twig\Environment;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Annotation\Route;
+
+class AddressController
+{
+    const A_CONSTANT_FOR_THE_SAKE_OF_HAVING_ONE = 'a value';
+    public const ARRAY_CONSTANT = [
+        'key' => 'value',
+        'key' => 0
+    ];
+
+    private $repo;
+    private $user_repo;
+    private $twig;
+    private $em;
+
+    public function __construct(
+        AddressRepository $repo,
+        UserRepository $user_repo,
+        Environment $twig,
+        EntityManagerInterface $em
+    ) {
+        $this->repo = $repo;
+        $this->user_repo = $user_repo;
+        $this->twig = $twig;
+        $this->em = $em;
+    }
+
+    /**
+     * @Route("/address/add", methods={"GET"})
+     */
+    public function addAddressPage(Request $req): Response
+    {
+        $user = $this->user_repo->findOne($req->get('user'));
+
+        return new Response(
+            $this->twig->render('address/create.html.twig', [
+                'user' => $user,
+            ])
+        );
+    }
+
+    /**
+     * @Route("/address/add", methods={"POST"})
+     */
+    public function addAddressAction(Request $req): Response
+    {
+        $user = $this->user_repo->findOne($req->request->get('user'));
+        $address_string = $req->request->get('address');
+
+        $address = new Address($user, $address_string);
+
+        $this->em->persist($address);
+        $this->em->flush();
+
+
+        return new RedirectResponse('/user/' . $user->getLoginName() . 
'/manage');
+    }
+
+    /**
+     * @Route("/address/delete", methods={"POST"})
+     */
+    public function deleteAddressAction(Request $req): Response
+    {
+        $address = $this->repo->find($req->request->get('address'));
+
+        $this->em->remove($address);
+        $this->em->flush();
+
+        return new RedirectResponse('/user/' . 
$address->getUser()->getLoginName() . '/manage');
+    }
+}
diff --git a/test/fixtures/NamespacedFunctions.el 
b/test/fixtures/NamespacedFunctions.el
new file mode 100644
index 0000000000..7a627e9581
--- /dev/null
+++ b/test/fixtures/NamespacedFunctions.el
@@ -0,0 +1 @@
+(:root (:namespace (:word "App\\Functions") (:terminator ";") (:function 
(:declaration (:word "function") (:word "MergeTwoArraysAndSomeOtherStuff") 
(:list (:word "array") (:variable "array1") (:comma ",") (:variable 
"untyped_variable")) (:word "Response")) (:block (:variable "merged") 
(:assignment "=") (:word "array_merge") (:list (:variable "array_1") (:comma 
",") (:variable "untyped_variable")) (:terminator ";") (:variable "mapped") 
(:assignment "=") (:word "arrap_map") (:list (:functi [...]
diff --git a/test/fixtures/NamespacedFunctions.php 
b/test/fixtures/NamespacedFunctions.php
new file mode 100644
index 0000000000..2c5ab557e3
--- /dev/null
+++ b/test/fixtures/NamespacedFunctions.php
@@ -0,0 +1,27 @@
+<?php
+namespace App\Functions;
+
+function MergeTwoArraysAndSomeOtherStuff(array $array1, $untyped_variable): 
Response
+{
+    $merged = array_merge($array_1, $untyped_variable);
+
+    $mapped = arrap_map(
+        function ($item) {
+            return $item;
+        },
+        $merged
+    );
+
+    $user = $this->user_repo->findOne($req->get('user'));
+
+    return new Response(
+        $this->twig->render('address/create.html.twig', [
+            'user' => $user,
+        ])
+    );
+}
+
+
+function BeTheSecondFunctionInTheFile() {
+    return [ "Very Impressive Result" => $result ];
+}
diff --git a/test/phpinspect-test.el b/test/phpinspect-test.el
new file mode 100644
index 0000000000..8e8ceee132
--- /dev/null
+++ b/test/phpinspect-test.el
@@ -0,0 +1,71 @@
+;;; phpinspect-test.el --- Unit tests for phpinslect.el  -*- lexical-binding: 
t; -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Hugo Thunnissen <de...@hugot.nl>
+
+;; This program 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.
+
+;; This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'ert)
+(require 'phpinspect)
+
+(defvar phpinspect-test-php-file-directory
+  (concat
+   (file-name-directory
+    (or load-file-name
+        buffer-file-name))
+   "/fixtures")
+  "Directory with syntax trees of example PHP files.")
+
+(defun phpinspect-test-read-fixture-tree (name)
+  (with-temp-buffer
+    (insert-file-contents-literally (concat phpinspect-test-php-file-directory 
"/" name ".el"))
+    (read (current-buffer))))
+
+(defun phpinspect-test-parse-fixture-code (name)
+  (phpinspect-parse-file
+   (concat phpinspect-test-php-file-directory "/" name ".php")))
+
+(ert-deftest phpinspect-parse-namespaced-class ()
+  "Test phpinspect-parse on a namespaced class"
+    (should
+   (equal (phpinspect-test-read-fixture-tree "NamespacedClass")
+          (phpinspect-test-parse-fixture-code "NamespacedClass"))))
+
+(ert-deftest phpinspect-parse-block ()
+  "Test phpinspect-parse for php blocks"
+  (should
+   (equal (phpinspect-test-read-fixture-tree "Block")
+          (phpinspect-test-parse-fixture-code "Block"))))
+
+(ert-deftest phpinspect-parse-functions ()
+  "Test phpinspect-parse for php functions"
+  (should
+   (equal (phpinspect-test-read-fixture-tree "Functions")
+          (phpinspect-test-parse-fixture-code "Functions"))))
+
+(ert-deftest phpinspect-parse-namespaced-functions ()
+  "Test phpinspect-parse for php blocks"
+  (should
+   (equal (phpinspect-test-read-fixture-tree "NamespacedFunctions")
+          (phpinspect-test-parse-fixture-code "NamespacedFunctions"))))
+
+(provide 'phpinspect-test)
+;;; phpinspect-test.el ends here
diff --git a/test/util/generate-test-data.el b/test/util/generate-test-data.el
new file mode 100644
index 0000000000..fcccd471dc
--- /dev/null
+++ b/test/util/generate-test-data.el
@@ -0,0 +1,13 @@
+
+(require 'phpinspect)
+
+(let ((here (file-name-directory
+             (or load-file-name
+                 buffer-file-name))))
+  (dolist (file (directory-files (concat here "/../fixtures" ) t "\\.php$"))
+    (with-temp-buffer
+      (insert-file-contents-literally file)
+      (let ((result (phpinspect-parse-current-buffer)))
+        (with-temp-buffer
+          (insert (prin1-to-string result))
+          (write-file (concat (string-remove-suffix ".php"  file) ".el")))))))

Reply via email to