meta.t 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. # Copyright (C) 2015-2019 Alex Schroeder <alex@gnu.com>
  2. # Copyright (C) 2015 Alex Jakimenko <alex.jakimenko@gmail.com>
  3. #
  4. # This program is free software: you can redistribute it and/or modify it under
  5. # the terms of the GNU General Public License as published by the Free Software
  6. # Foundation, either version 3 of the License, or (at your option) any later
  7. # version.
  8. #
  9. # This program is distributed in the hope that it will be useful, but WITHOUT
  10. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License along with
  14. # this program. If not, see <http://www.gnu.org/licenses/>.
  15. use strict;
  16. use warnings;
  17. use v5.10;
  18. use utf8;
  19. package OddMuse;
  20. require './t/test.pl';
  21. use Test::More tests => 29;
  22. use File::Basename;
  23. use Pod::Strip;
  24. use Pod::Simple::TextContent;
  25. my @modules = grep { $_ ne 'modules/404handler.pl' } <modules/*.pl>;
  26. my @other = 'wiki.pl';
  27. my %text = (map { $_ => ReadFileOrDie($_) } @modules, @other);
  28. my @badModules;
  29. @badModules = grep { (stat $_)[2] != oct '100644' } @modules;
  30. unless (ok(@badModules == 0, 'Consistent file permissions of modules')) {
  31. diag(sprintf "$_ has %o but 100644 was expected", (stat $_)[2]) for @badModules;
  32. diag("▶▶▶ Use this command to fix it: chmod 644 @badModules");
  33. }
  34. @badModules = grep { $text{$_} !~ / ^ use \s+ strict; /mx } @modules;
  35. unless (ok(@badModules == 0, '"use strict;" in modules')) {
  36. diag(qq{$_ has no "use strict;"}) for @badModules;
  37. }
  38. @badModules = grep { $text{$_} !~ / ^ use \s+ v5\.10; /mx } @modules;
  39. unless (ok(@badModules == 0, '"use v5.10;" in modules')) {
  40. diag(qq{$_ has no "use v5.10;"}) for @badModules;
  41. diag(q{Minimum perl version for the core is v5.10, it seems like there is no reason not to have "use v5.10;" everywhere else.});
  42. }
  43. @badModules = grep {
  44. my $code = $text{$_};
  45. # check Perl source code
  46. my $perl;
  47. my $pod_stripper = Pod::Strip->new;
  48. $pod_stripper->output_string(\$perl);
  49. $pod_stripper->parse_string_document($code);
  50. $perl =~ s/#.*//g;
  51. my $bad_perl = $perl !~ / ^ use \s+ utf8; /mx && $perl =~ / ([[:^ascii:]]+) /x;
  52. diag(qq{$_ has no "use utf8;" but contains non-ASCII characters in Perl code, eg. "$1"}) if $bad_perl;
  53. # check POD
  54. my $pod;
  55. my $pod_text = Pod::Simple::TextContent->new;
  56. $pod_text->output_string(\$pod);
  57. $pod_text->parse_string_document($code);
  58. my $bad_pod = $code !~ / ^ =encoding \s+ utf8 /mx && $pod =~ / ([[:^ascii:]]+) /x;
  59. diag(qq{$_ has no "=encoding utf8" but contains non-ASCII characters in POD, eg. "$1"}) if $bad_pod;
  60. $bad_perl || $bad_pod;
  61. } @modules;
  62. ok(@badModules == 0, 'utf8 in modules');
  63. SKIP: {
  64. skip 'documentation tests, we did not try to document every module yet', 1;
  65. @badModules = grep { $text{$_} !~ / ^ AddModuleDescription\(' [^\']+ ', /mx } @modules;
  66. unless (ok(@badModules == 0, 'link to the documentation in modules')) {
  67. diag(qq{$_ has no link to the documentation}) for @badModules;
  68. }
  69. }
  70. @badModules = grep {
  71. $text{$_} =~ / ^ package \s+ OddMuse; /imx
  72. && $_ ne 'modules/ban-contributors.pl'
  73. } @modules;
  74. unless (ok(@badModules == 0, 'no "package OddMuse;" in modules')) {
  75. diag(qq{$_ has "package OddMuse;"}) for @badModules;
  76. diag(q{When we do "do 'somemodule.pl';" it ends up being in the same namespace of a caller, so there is no need to use "package OddMuse;"});
  77. }
  78. @badModules = grep { $text{$_} =~ / ^ use \s+ vars /mx } @modules;
  79. unless (ok(@badModules == 0, 'no "use vars" in modules')) {
  80. diag(qq{$_ is using "use vars"}) for @badModules;
  81. diag('▶▶▶ Use "our ($var, ...)" instead of "use vars qw($var ...)"');
  82. diag(q{▶▶▶ Use this command to do automatic conversion: perl -0pi -e 's/^([\t ]*)use vars qw\s*\(\s*(.*?)\s*\);/$x = $2; $x =~ s{(?<=\w)\b(?!$)}{,}g;"$1our ($x);"/gems' } . "@badModules");
  83. }
  84. @badModules = grep { $text{$_} =~ / [ \t]+ $ /mx } @modules, @other;
  85. unless (ok(@badModules == 0, 'no trailing whitespace in modules (and other perl files)')) {
  86. diag(qq{$_ has trailing whitespace}) for @badModules;
  87. diag(q{▶▶▶ Use this command to do automatic trailing whitespace removal: perl -pi -e 's/[ \t]+$//g' } . "@badModules");
  88. }
  89. @badModules = grep {
  90. $text{$_} =~ / This (program|file) is free software /x
  91. && $text{$_} =~ / http:\/\/www.gnu.org\/licenses\/ /x
  92. } @modules;
  93. unless (ok(@badModules == 0, 'license is specified in every module')) {
  94. diag(qq{$_ has no license specified}) for @badModules;
  95. }
  96. @badModules = grep {
  97. my ($name, $path, $suffix) = fileparse($_, '.pl');
  98. $text{$_} !~ /^AddModuleDescription\('$name.pl'/mx;
  99. } @modules;
  100. unless (ok(@badModules == 0, 'AddModuleDescription is used in every module')) {
  101. diag(qq{$_ does not use AddModuleDescription}) for @badModules;
  102. }
  103. # we have to use shell to redirect the output :(
  104. @badModules = grep { system("perl -c \Q$_\E > /dev/null 2>&1") != 0 } @modules;
  105. unless (ok(@badModules == 0, 'modules are syntatically correct')) {
  106. diag(qq{$_ has syntax errors}) for @badModules;
  107. diag("▶▶▶ Use this command to see the problems: for f in @badModules; do perl -c \$f; done");
  108. }
  109. my %changes = (
  110. '-f' => 'IsFile',
  111. '-e' => 'IsFile',
  112. '-r' => 'IsFile',
  113. '-d' => 'IsDir',
  114. '-z' => 'ZeroSize',
  115. '-M' => '$Now - Modified',
  116. 'unlink' => 'Unlink',
  117. 'stat(.*)[9]' => 'Modified',
  118. 'bsd_glob' => 'Glob',
  119. 'chmod' => 'ChangeMod',
  120. 'rename' => 'Rename',
  121. 'rmdir' => 'RemoveDir',
  122. 'chdir' => 'ChangeDir',
  123. 'mkdir' => 'CreateDir',
  124. );
  125. for my $re (sort keys %changes) {
  126. @badModules = grep {
  127. my $text = $text{$_};
  128. $text =~s/#.*\n//g; # get rid of comments
  129. $text =~s/Tss?\([^\)]+//g; # getting rid of "rename" in strings
  130. $text =~s/\{\w+\}//g; # getting rid of "rename" in $Action{rename}
  131. $text =~s/'\w+'//g; # getting rid of "rename" in 'rename'
  132. $text =~s/rename-//g; # rename-page is OK
  133. not ($_ eq 'modules/pygmentize.pl' and $re eq '-f'
  134. or $_ eq 'modules/static-copy.pl' and $re eq 'chmod'
  135. or $_ eq 'modules/static-hybrid.pl' and $re eq 'chmod')
  136. and (substr($re, 0, 1) eq '-' and $text =~ /[ (] $re \s/x
  137. or $re eq 'stat(.*)[9]' and $text =~ /\b $re /x
  138. or $re =~ /^\w+$/ and $text =~ /\b $re \b/x);
  139. } @modules;
  140. unless (ok(@badModules == 0, "modules do not use $re")) {
  141. diag(qq{$_ uses $re instead of $changes{$re}}) for @badModules;
  142. }
  143. }
  144. for my $fun ('open.*,.*[<>]', 'sysopen', 'tie', 'opendir') {
  145. @badModules = grep {
  146. my @lines = map { s/#.*//; $_ } split(/\n/, $text{$_});
  147. grep(!/encode_utf8/, grep(/\b $fun \b/x, @lines));
  148. } @modules;
  149. unless (ok(@badModules == 0, qq{modules use encode_utf8 with $fun})) {
  150. diag(qq{$_ does not use encode_utf8 with $fun}) for @badModules;
  151. }
  152. }