privoxy-regression-test.pl: Allow '[' and ']' in URLs
[privoxy.git] / tools / privoxy-regression-test.pl
index 1238c44..69a9ee7 100755 (executable)
@@ -7,8 +7,6 @@
 # A regression test "framework" for Privoxy. For documentation see:
 # perldoc privoxy-regression-test.pl
 #
-# $Id: privoxy-regression-test.pl,v 1.86 2013/01/06 18:15:27 fabiankeil Exp $
-#
 # Wish list:
 #
 # - Update documentation
@@ -19,7 +17,7 @@
 # - Document magic Expect Header values
 # - Internal fuzz support?
 #
-# Copyright (c) 2007-2013 Fabian Keil <fk@fabiankeil.de>
+# Copyright (c) 2007-2016 Fabian Keil <fk@fabiankeil.de>
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -40,7 +38,7 @@ use strict;
 use Getopt::Long;
 
 use constant {
-    PRT_VERSION => 'Privoxy-Regression-Test 0.6',
+    PRT_VERSION => 'Privoxy-Regression-Test 0.7.1',
  
     CURL => 'curl',
 
@@ -66,8 +64,6 @@ use constant {
     DEBUG_LEVEL_VERBOSE_SUCCESS => 0,
     DEBUG_LEVEL_STATUS          => 1,
 
-    VERBOSE_TEST_DESCRIPTION    => 1,
-
     # Internal use, don't modify
     # Available debug bits:
     LL_SOFT_ERROR       =>  1,
@@ -92,7 +88,6 @@ sub init_our_variables () {
     our $leading_log_time = LEADING_LOG_TIME;
     our $leading_log_date = LEADING_LOG_DATE;
     our $privoxy_cgi_url  = PRIVOXY_CGI_URL;
-    our $verbose_test_description = VERBOSE_TEST_DESCRIPTION;
     our $log_level = get_default_log_level();
 }
 
@@ -137,7 +132,7 @@ sub parse_tag ($) {
 sub check_for_forbidden_characters ($) {
 
     my $string = shift;
-    my $allowed = '[-=\dA-Za-z~{}:./();\t ,+@"_%?&*^]';
+    my $allowed = '[-=\dA-Za-z~{}\[\]:./();\t ,+@"_%?&*^]';
 
     unless ($string =~ m/^$allowed*$/o) {
         my $forbidden = $string;
@@ -279,7 +274,7 @@ sub load_regression_tests_from_file ($) {
                 l(LL_FILE_LOADING, "Sticky actions: " . $sticky_actions);
                 $regression_tests[$si][$ri]{'sticky-actions'} = $sticky_actions;
             } else {
-                log_and_die("Sticky URL without Sticky Actions: $value");
+                log_and_die("Sticky URL without Sticky Actions in $action_file: $value");
             }
 
         } else {
@@ -344,7 +339,7 @@ sub load_regression_tests_through_privoxy () {
             $privoxy_features{$feature} = $1 if defined $feature;
             $feature = undef;
 
-        } elsif (m@This is <a href="http://www.privoxy.org/">Privoxy</a> (\d+\.\d+\.\d+) on@) {
+        } elsif (m@This is <a href="https?://www.privoxy.org/">Privoxy</a> (\d+\.\d+\.\d+) on@) {
             $privoxy_version = $1;
         }
     }
@@ -373,8 +368,9 @@ sub tokenize ($) {
 
     my ($token, $value) = (undef, undef);
 
-    # Remove leading and trailing white space.
-    s@^\s*@@;
+    # Remove leading and trailing white space and a
+    # a leading <pre> which is part of the first line.
+    s@^\s*(<pre>)?@@;
     s@\s*$@@;
 
     # Reverse HTML-encoding
@@ -494,10 +490,9 @@ sub mark_matching_tests_for_skipping($) {
                 my $message = sprintf("Marking test %s for ignoring. Overwrite condition: %s.",
                                       $regression_tests[$s][$r]{'number'}, $overwrite_condition);
 
-                # XXX: Should eventually be downgraded to LL_FILE_LOADING.
-                log_message($message);
+                l(LL_FILE_LOADING, $message);
 
-                # XXX: Should eventuall get it's own key so get_skip_reason()
+                # XXX: Should eventually get its own key so get_skip_reason()
                 #      can tell about the overwrite condition.
                 $regression_tests[$s][$r]{'ignore'} = 1;
             }
@@ -529,6 +524,7 @@ sub load_action_files ($) {
         my $curl_url = quote($actionfiles[$file_number]);
         my $actionfile = undef;
         my $sticky_actions = undef;
+        my $level_offset = 0;
 
         foreach (@{get_cgi_page_or_else($curl_url)}) {
 
@@ -548,6 +544,11 @@ sub load_action_files ($) {
             next unless defined $token;
 
             # Load regression tests
+            if ($token eq 'default level offset') {
+
+                $level_offset = $value;
+                l(LL_FILE_LOADING, "Setting default level offset to " . $level_offset);
+            }
 
             if (token_starts_new_test($token)) {
 
@@ -556,6 +557,9 @@ sub load_action_files ($) {
                 $count++;
                 enlist_new_test(\@regression_tests, $token, $value, $si, $ri, $count);
                 $no_checks = 1; # Already validated by enlist_new_test().
+                if ($level_offset != 0) {
+                    $regression_tests[$si][$ri]{'level'} += $level_offset;
+                }
             }
 
             if ($token =~ /level\s+(\d+)/i) {
@@ -650,7 +654,7 @@ sub load_action_files ($) {
                     l(LL_FILE_LOADING, "Sticky actions: " . $sticky_actions);
                     $regression_tests[$si][$ri]{'sticky-actions'} = $sticky_actions;
                 } else {
-                    log_and_die("Sticky URL without Sticky Actions: $value");
+                    log_and_die("Sticky URL without Sticky Actions in $actionfile: $value");
                 }
 
             } else {
@@ -720,12 +724,12 @@ sub execute_regression_tests () {
             #      from different sections isn't possible.
             #      Is this worth changing the layout?
             fisher_yates_shuffle(\@regression_tests);
-            for (my $s = 0;  $s < @regression_tests; $s++) {
+            for (my $s = 0; $s < @regression_tests; $s++) {
                 fisher_yates_shuffle($regression_tests[$s]);
             }
         }
 
-        for (my $s = 0;  $s < @regression_tests; $s++) {
+        for (my $s = 0; $s < @regression_tests; $s++) {
 
             my $r = 0;
 
@@ -1448,6 +1452,8 @@ sub get_page_with_curl ($) {
     $curl_line .= " --user-agent '" . PRT_VERSION . "' ";
     # We aren't too patient
     $curl_line .= " --max-time '" . get_cli_option('max-time') . "' ";
+    # We don't want curl to treat "[]", "{}" etc. special
+    $curl_line .= " --globoff ";
 
     $curl_line .= $parameters;
     # XXX: still necessary?
@@ -1546,86 +1552,81 @@ sub log_message ($) {
 
 sub log_result ($$) {
 
-    our $verbose_test_description;
     our $filtered_request;
 
     my $test = shift;
     my $result = shift;
     my $number = shift;
 
-    my $message = '';
+    my $message = sprintf("%s for test %d",
+                          interpret_result($result),
+                          $test->{'number'});
 
-    $message .= interpret_result($result);
-    $message .= " for test ";
-    $message .= $number;
-    $message .= '/';
-    $message .= $test->{'number'};
-    $message .= '/';
-    $message .= $test->{'section-id'};
-    $message .= '/';
-    $message .= $test->{'regression-test-id'};
-    $message .= '.';
+    if (cli_option_is_set('verbose')) {
+        $message .= sprintf(" (%d/%d/%d)", $number,
+                            $test->{'section-id'},
+                            $test->{'regression-test-id'});
+    }
 
-    if ($verbose_test_description) {
+    $message .= '. ';
 
-        if ($test->{'type'} == CLIENT_HEADER_TEST) {
+    if ($test->{'type'} == CLIENT_HEADER_TEST) {
 
-            $message .= ' Header ';
-            $message .= quote($test->{'data'});
-            $message .= ' and tag ';
-            $message .= quote($test->{'tag'});
+        $message .= 'Header ';
+        $message .= quote($test->{'data'});
+        $message .= ' and tag ';
+        $message .= quote($test->{'tag'});
 
-        } elsif ($test->{'type'} == SERVER_HEADER_TEST) {
+    } elsif ($test->{'type'} == SERVER_HEADER_TEST) {
 
-            $message .= ' Request Header ';
-            $message .= quote($test->{'data'});
-            $message .= ' and tag ';
-            $message .= quote($test->{'tag'});
+        $message .= 'Request Header ';
+        $message .= quote($test->{'data'});
+        $message .= ' and tag ';
+        $message .= quote($test->{'tag'});
 
-        } elsif ($test->{'type'} == DUMB_FETCH_TEST) {
+    } elsif ($test->{'type'} == DUMB_FETCH_TEST) {
 
-            $message .= ' URL ';
-            $message .= quote($test->{'data'});
-            $message .= ' and expected status code ';
-            $message .= quote($test->{'expected-status-code'});
+        $message .= 'URL ';
+        $message .= quote($test->{'data'});
+        $message .= ' and expected status code ';
+        $message .= quote($test->{'expected-status-code'});
 
-        } elsif ($test->{'type'} == TRUSTED_CGI_REQUEST) {
+    } elsif ($test->{'type'} == TRUSTED_CGI_REQUEST) {
 
-            $message .= ' CGI URL ';
-            $message .= quote($test->{'data'});
-            $message .= ' and expected status code ';
-            $message .= quote($test->{'expected-status-code'});
+        $message .= 'CGI URL ';
+        $message .= quote($test->{'data'});
+        $message .= ' and expected status code ';
+        $message .= quote($test->{'expected-status-code'});
 
-        } elsif ($test->{'type'} == METHOD_TEST) {
+    } elsif ($test->{'type'} == METHOD_TEST) {
 
-            $message .= ' HTTP method ';
-            $message .= quote($test->{'data'});
-            $message .= ' and expected status code ';
-            $message .= quote($test->{'expected-status-code'});
+        $message .= 'HTTP method ';
+        $message .= quote($test->{'data'});
+        $message .= ' and expected status code ';
+        $message .= quote($test->{'expected-status-code'});
 
-        } elsif ($test->{'type'} == BLOCK_TEST) {
+    } elsif ($test->{'type'} == BLOCK_TEST) {
 
-            $message .= ' Supposedly-blocked URL: ';
-            $message .= quote($test->{'data'});
+        $message .= 'Supposedly-blocked URL: ';
+        $message .= quote($test->{'data'});
 
-        } elsif ($test->{'type'} == STICKY_ACTIONS_TEST) {
+    } elsif ($test->{'type'} == STICKY_ACTIONS_TEST) {
 
-            $message .= ' Sticky Actions: ';
-            $message .= quote($test->{'sticky-actions'});
-            $message .= ' and URL: ';
-            $message .= quote($test->{'data'});
+        $message .= 'Sticky Actions: ';
+        $message .= quote($test->{'sticky-actions'});
+        $message .= ' and URL: ';
+        $message .= quote($test->{'data'});
 
-        } elsif ($test->{'type'} == REDIRECT_TEST) {
+    } elsif ($test->{'type'} == REDIRECT_TEST) {
 
-            $message .= ' Redirected URL: ';
-            $message .= quote($test->{'data'});
-            $message .= ' and redirect destination: ';
-            $message .= quote($test->{'redirect destination'});
+        $message .= 'Redirected URL: ';
+        $message .= quote($test->{'data'});
+        $message .= ' and redirect destination: ';
+        $message .= quote($test->{'redirect destination'});
 
-        } else {
+    } else {
 
-            die "Incomplete support for test type " . $test->{'type'} .  " detected.";
-        }
+        die "Incomplete support for test type " . $test->{'type'} .  " detected.";
     }
 
     log_message($message) if (!$result or cli_option_is_set('verbose'));
@@ -1912,7 +1913,7 @@ To verify that requests for a URL get redirected, use:
 
 To skip a test, add the following line:
 
-# Ignore = Yes
+    # Ignore = Yes
 
 The difference between a skipped test and a removed one is that removing
 a test affects the numbers of the following tests, while a skipped test
@@ -1925,20 +1926,20 @@ is likely to get lost with the next update.
 
 Overwrite conditions are an alternative and can be added in any action
 file as long as the come after the test that is expected to fail.
-They causes all previous tests a matching the condition to be skipped.
+They cause all previous tests that match the condition to be skipped.
 
 It is recommended to put the overwrite condition below the custom Privoxy
 section that causes the expected test failure and before the custom test
 that verifies that tests the now expected behaviour. Example:
 
-# The following section is expected to overwrite a section in
-# default.action, whose effect is tested. Thus also disable the
-# test that is now expected to fail and add a new one.
-#
-{+block{Facebook makes Firefox even more unstable. Do not want.}}
-# Overwrite condition = http://apps.facebook.com/onthefarm/track.php?creative=&cat=friendvisit&subcat=weeds&key=a789a971dc687bee4c20c044834fabdd&next=index.php%3Fref%3Dnotif%26visitId%3D898835505
-# Blocked URL = http://apps.facebook.com/
-.facebook./
+    # The following section is expected to overwrite a section in
+    # default.action, whose effect is being tested. Thus also disable
+    # the test that is now expected to fail and add a new one.
+    #
+    {+block{Facebook makes Firefox even more unstable. Do not want.}}
+    # Overwrite condition = http://apps.facebook.com/onthefarm/track.php?creative=&cat=friendvisit&subcat=weeds&key=a789a971dc687bee4c20c044834fabdd&next=index.php%3Fref%3Dnotif%26visitId%3D898835505
+    # Blocked URL = http://apps.facebook.com/
+    .facebook./
 
 =head1 TEST LEVELS
 
@@ -1957,6 +1958,13 @@ max-level value as failed tests will result in outgoing
 connections. Use the B<--max-level> option to run them
 as well.
 
+The "Default level offset" directive can be used to change
+the default level by a given value. This directive affects
+all tests located after it until the end of the file or a another
+"Default level offset" directive is reached. The purpose of this
+directive is to make it more convenient to skip similar tests in
+a given file without having to remove or disable the tests completely.
+
 =head1 OPTIONS
 
 B<--debug bitmask> Add the bitmask provided as integer