Bug 13618: Add tests
[koha.git] / xt / find-missing-filters.t
diff --git a/xt/find-missing-filters.t b/xt/find-missing-filters.t
new file mode 100755 (executable)
index 0000000..7236a1e
--- /dev/null
@@ -0,0 +1,141 @@
+#!/usr/bin/perl
+
+# This file is part of Koha.
+#
+# Koha 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.
+#
+# Koha 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 Koha; if not, see <http://www.gnu.org/licenses>.
+
+use Modern::Perl;
+use Test::More tests => 1;
+use File::Find;
+use File::Slurp;
+use Data::Dumper;
+
+my @themes;
+
+# OPAC themes
+my $opac_dir  = 'koha-tmpl/opac-tmpl';
+opendir ( my $dh, $opac_dir ) or die "can't opendir $opac_dir: $!";
+for my $theme ( grep { not /^\.|lib|js|xslt/ } readdir($dh) ) {
+    push @themes, "$opac_dir/$theme/en";
+}
+close $dh;
+
+# STAFF themes
+my $staff_dir = 'koha-tmpl/intranet-tmpl';
+opendir ( $dh, $staff_dir ) or die "can't opendir $staff_dir: $!";
+for my $theme ( grep { not /^\.|lib|js/ } readdir($dh) ) {
+    push @themes, "$staff_dir/$theme/en";
+}
+close $dh;
+
+my @files;
+sub wanted {
+    my $name = $File::Find::name;
+    push @files, $name
+        if $name =~ m[\.(tt|inc)$] and -f $name;
+}
+
+my @tt_directives = (
+    qr{^\s*INCLUDE},
+    qr{^\s*USE},
+    qr{^\s*IF},
+    qr{^\s*UNLESS},
+    qr{^\s*ELSE},
+    qr{^\s*ELSIF},
+    qr{^\s*END},
+    qr{^\s*SET},
+    qr{^\s*FOR},
+    qr{^\s*FOREACH},
+    qr{^\s*MACRO},
+    qr{^\s*SWITCH},
+    qr{^\s*CASE},
+    qr{^\s*PROCESS},
+    qr{^\s*DEFAULT},
+    qr{^\s*TRY},
+    qr{^\s*CATCH},
+    qr{^\s*BLOCK},
+    qr{^\s*FILTER},
+    qr{^\s*STOP},
+);
+
+sub process_tt_content {
+    my ($content) = @_;
+    my ( $use_raw, $has_use_raw );
+    my @errors;
+    for my $line ( split "\n", $content ) {
+        if ( $line =~ m{\[%[^%]+%\]} ) {
+
+            # handle exceptions first
+            $use_raw = 1
+              if $line =~ m{|\s*\$raw};    # Is the file use the raw filter?
+
+            # Do we have Asset without the raw filter?
+            if ( $line =~ m{^\s*\[% Asset} ) {
+                push @errors, { error => 'asset_must_be_raw', line => $line }
+                  and next
+                  unless $line =~ m{\|\s*\$raw};
+            }
+
+            $has_use_raw++
+              if $line =~ m{\[% USE raw %\]};    # Does [% Use raw %] exist?
+
+            # Loop on TT blocks
+            while (
+                $line =~ m{
+                    \[%
+                    (?<pre_chomp>(\s|\-|~)*)
+                    (?<tt_block>[^%\-~]+)
+                    (?<post_chomp>(\s|\-|~)*)
+                    %\]}gmxs
+              )
+            {
+                my $tt_block = $+{tt_block};
+
+                if ( $tt_block =~ m{^(?<before>\S+)\s+UNLESS\s+(?<after>\S+)} )
+                {    # Specific for [% foo UNLESS bar %]
+                    push @errors, { error => 'missing_filter', line => $line };
+                }
+
+                # It's a TT directive, no filters needed
+                next if grep { $tt_block =~ $_ } @tt_directives;
+
+                next
+                  if $tt_block =~ m{\s?\|\s?\$KohaDates\s?$}
+                  ;    # We could escape it but should be safe
+                next if $tt_block =~ m{^\#};    # Is a comment, skip it
+
+                push @errors, { error => 'missing_filter', line => $line }
+                  if $tt_block !~ m{\|\s?\$raw}   # already escaped correctly with raw
+                  && $tt_block !~ m{=}            # assignment, maybe we should require to use SET (?)
+                  && $tt_block !~ m{\|\s?ur(l|i)} # already has url or uri filter
+                  && $tt_block !~ m{\|\s?html}    # already has html filter
+            }
+        }
+    }
+
+    return @errors;
+}
+
+find({ wanted => \&wanted, no_chdir => 1 }, @themes );
+
+my @errors;
+for my $file ( @files ) {
+    say $file;
+    my $content = read_file($file);
+    my @e = process_tt_content($content);
+    push @errors, { file => $file, errors => \@e } if @e;
+}
+
+is( @errors, 0, "Template variables should be correctly escaped" )
+    or diag(Dumper @errors);