Make WordPress Core

Ticket #35065: docblocks.2.diff

File docblocks.2.diff, 7.1 KB (added by johnbillion, 9 years ago)
  • tests/phpunit/tests/docs/docblocks.php

     
     1<?php
     2
     3require_once dirname( dirname( dirname( __FILE__ ) ) ) . '/vendor/autoload.php';
     4
     5class Tests_DocBlocks extends WP_UnitTestCase {
     6
     7        protected static $ignore_empty  = true;
     8        protected static $method_refs   = array();
     9        protected static $function_refs = array();
     10
     11        public function remove_variadic_params( $param_doc ) {
     12                return ( false === strpos( $param_doc, ',...' ) );
     13        }
     14
     15        /**
     16         * Test a function or method for a given class
     17         *
     18         * @dataProvider dataReflectionTestFunctions
     19         *
     20         * @param string|array $function The function name, or array of class name and method name.
     21         * @param string       $file     The file name.
     22         */
     23        public function testFunctionDocBlock( $function, $filename ) {
     24
     25                if ( is_array( $function ) ) {
     26                        $name = $function[0] . '::' . $function[1] . '()';
     27                        $ref  = self::$method_refs[ $filename ][ $function[0] ][ $name ];
     28                } else {
     29                        $name = $function;
     30                        $ref  = self::$function_refs[ $filename ][ $name ];
     31                }
     32
     33                $name     = ltrim( $name, '\\' );
     34                $docblock = $ref->getDocblock();
     35
     36                if ( self::$ignore_empty && empty( $docblock ) ) {
     37                        return;
     38                }
     39
     40                $this->assertNotEmpty( $docblock, sprintf(
     41                        'The docblock for `%s` should not be missing.',
     42                        $name
     43                ) );
     44
     45                $method_params = $ref->getArguments();
     46                $doc_params    = $docblock->getTagsByName( 'param' );
     47                $desc          = $docblock->getDescription();
     48
     49                if ( self::$ignore_empty && empty( $desc ) ) {
     50                        return;
     51                }
     52
     53                $this->assertNotEmpty( $desc, sprintf(
     54                        'The docblock description for `%s` should not be empty.',
     55                        $name
     56                ) );
     57
     58                if ( count( $method_params ) < count( $doc_params ) ) {
     59                        $non_variadic_doc_params = array_filter( $doc_params, array( $this, 'remove_variadic_params' ) );
     60                } else {
     61                        $non_variadic_doc_params = $doc_params;
     62                }
     63
     64                $this->assertSame( count( $method_params ), count( $non_variadic_doc_params ), sprintf(
     65                        'The number of @param docs for `%s` should match its number of parameters.',
     66                        $name
     67                ) );
     68
     69                foreach ( $method_params as $i => $param ) {
     70
     71                        $param_doc   = $doc_params[ $i ];
     72                        $description = (string) $param_doc->getDescription();
     73                        $is_hash     = ( ( 0 === strpos( $description, '{' ) ) && ( ( strlen( $description ) - 1 ) === strrpos( $description, '}' ) ) );
     74
     75                        if ( $is_hash ) {
     76                                $lines = explode( "\n", $description );
     77                                $description = $lines[1];
     78                        }
     79
     80                        if ( self::$ignore_empty && empty( $description ) ) {
     81                                return;
     82                        }
     83
     84                        $this->assertNotEmpty( $description, sprintf(
     85                                'The @param description for the `$%s` parameter of `%s` should not be empty.',
     86                                $param_doc->getVariableName(),
     87                                $name
     88                        ) );
     89
     90                        $param_doc_name = $param_doc->getVariableName();
     91                        $param_doc_type = (string) $param_doc->getType();
     92
     93                        $this->assertSame( $param->getName(), $param_doc_name, sprintf(
     94                                'The @param name for the `%s` parameter of `%s` is incorrect.',
     95                                $param->getName(),
     96                                $name
     97                        ) );
     98
     99                        // if ( $param->isOptional() ) {
     100                        //      $this->assertNotFalse( strpos( $description, 'Optional' ), sprintf(
     101                        //              'The @param description for the optional `%s` parameter of `%s` should state that it is optional.',
     102                        //              $param_doc_name,
     103                        //              $name
     104                        //      ) );
     105                        // } else {
     106                        //      $this->assertFalse( strpos( $description, 'Optional.' ), sprintf(
     107                        //              'The @param description for the required `%s` parameter of `%s` should not state that it is optional.',
     108                        //              $param_doc_name,
     109                        //              $name
     110                        //      ) );
     111                        // }
     112
     113                        // if ( $param->isDefaultValueAvailable() ) {
     114                        //      $this->assertNotFalse( strpos( $description, 'Default ' ), sprintf(
     115                        //              'The @param description for the `%s` parameter of `%s` should state its default value.',
     116                        //              $param_doc_name,
     117                        //              $name
     118                        //      ) );
     119                        // } else {
     120                        //      $this->assertFalse( strpos( $description, 'Default ' ), sprintf(
     121                        //              'The @param description for the `%s` parameter of `%s` should not state a default value.',
     122                        //              $param_doc_name,
     123                        //              $name
     124                        //      ) );
     125                        // }
     126
     127                }
     128
     129        }
     130
     131        protected static function rsearch( $folder, $ext ) {
     132                $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $folder ) );
     133
     134                $files = array();
     135
     136                foreach ( $iterator as $file ) {
     137
     138                        if ( $file->isDir() ) {
     139                                continue;
     140                        }
     141                        if ( $ext !== $file->getExtension() ) {
     142                                continue;
     143                        }
     144
     145                        $files[] = $file->getPathname();
     146
     147                }
     148                return $files;
     149        }
     150
     151        public function dataReflectionTestFunctions() {
     152
     153                $to_search = ABSPATH . 'wp-includes/';
     154
     155                // Recursive:
     156                $files = self::rsearch( $to_search, 'php' );
     157
     158                // Non-recursive
     159                // $files = glob( $to_search . '*.php' );
     160
     161                $ignore_files = array(
     162
     163                        ABSPATH . 'wp-admin/includes/class-pclzip.php',
     164                        ABSPATH . 'wp-admin/includes/class-ftp.php',
     165                        ABSPATH . 'wp-admin/includes/class-ftp-pure.php',
     166                        ABSPATH . 'wp-admin/includes/class-ftp-sockets.php',
     167                        ABSPATH . 'wp-admin/includes/export.php',
     168                        ABSPATH . 'wp-admin/includes/file.php',
     169
     170                        ABSPATH . 'wp-includes/class-IXR.php',
     171                        ABSPATH . 'wp-includes/rss.php',
     172
     173                );
     174                $files = array_diff( $files, $ignore_files );
     175                $files = array_filter( $files, function( $file ) {
     176
     177                        $ignore_dirs = array(
     178                                ABSPATH . 'wp-includes/ID3/',
     179                                ABSPATH . 'wp-includes/SimplePie/',
     180                                ABSPATH . 'wp-includes/Text/',
     181                        );
     182
     183                        foreach ( $ignore_dirs as $dir ) {
     184                                if ( 0 === strpos( $file, $dir ) ) {
     185                                        return false;
     186                                }
     187                        }
     188                        return true;
     189
     190                } );
     191                $data  = array();
     192
     193                $projectFactory = \phpDocumentor\Reflection\Php\ProjectFactory::createInstance();
     194
     195                foreach ( $files as $project_file ) {
     196                        try {
     197                                $project = $projectFactory->create( 'WordPress', array( $project_file ) );
     198                        } catch ( InvalidArgumentException $e ) {
     199                                // This catches files where functions are defined within functions.
     200                                // eg. redirect_canonical()::lowercase_octets() in wp-includes/canonical.php
     201                                continue;
     202                        }
     203
     204                        foreach ( $project->getFiles() as $filename => $file ) {
     205
     206                                foreach ( $file->getFunctions() as $f => $func_ref ) {
     207
     208                                        self::$function_refs[ $filename ][ $f ] = $func_ref;
     209
     210                                        $data[] = array(
     211                                                (string) $func_ref->getFqsen(),
     212                                                $filename,
     213                                        );
     214
     215                                }
     216
     217                                foreach ( $file->getClasses() as $c => $class_ref ) {
     218
     219                                        foreach ( $class_ref->getMethods() as $m => $method_ref ) {
     220
     221                                                self::$method_refs[ $filename ][ $c ][ $m ] = $method_ref;
     222
     223                                                $data[] = array(
     224                                                        array(
     225                                                                (string) $class_ref->getFqsen(),
     226                                                                $method_ref->getName(),
     227                                                        ),
     228                                                        $filename,
     229                                                );
     230
     231                                        }
     232
     233                                }
     234
     235                        }
     236
     237                }
     238
     239                return $data;
     240
     241        }
     242
     243}
  • tests/phpunit/composer.json

     
     1{
     2    "name": "wordpress/tests",
     3    "description": "Tests!",
     4    "require": {
     5        "phpdocumentor/reflection": "~2.0"
     6    }
     7}