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")))))))