Home | History | Annotate | Download | only in tests
      1 #!/usr/bin/env python
      2 # Copyright 2014 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 import optparse
      7 import os
      8 import sys
      9 import unittest
     10 
     11 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
     12 PARENT_DIR = os.path.dirname(SCRIPT_DIR)
     13 
     14 sys.path.append(PARENT_DIR)
     15 
     16 import quote
     17 
     18 verbose = False
     19 
     20 
     21 # Wrapped versions of the functions that we're testing, so that during
     22 # debugging we can more easily see what their inputs were.
     23 
     24 def VerboseQuote(in_string, specials, *args, **kwargs):
     25   if verbose:
     26     sys.stdout.write('Invoking quote(%s, %s, %s)\n' %
     27                      (repr(in_string), repr(specials),
     28                       ', '.join([repr(a) for a in args] +
     29                                 [repr(k) + ':' + repr(v)
     30                                  for k, v in kwargs])))
     31   return quote.quote(in_string, specials, *args, **kwargs)
     32 
     33 
     34 def VerboseUnquote(in_string, specials, *args, **kwargs):
     35   if verbose:
     36     sys.stdout.write('Invoking unquote(%s, %s, %s)\n' %
     37                      (repr(in_string), repr(specials),
     38                       ', '.join([repr(a) for a in args] +
     39                                 [repr(k) + ':' + repr(v)
     40                                  for k, v in kwargs])))
     41   return quote.unquote(in_string, specials, *args, **kwargs)
     42 
     43 
     44 class TestQuote(unittest.TestCase):
     45   # test utilities
     46   def generic_test(self, fn, in_args, expected_out_obj):
     47     actual = apply(fn, in_args)
     48     self.assertEqual(actual, expected_out_obj)
     49 
     50   def check_invertible(self, in_string, specials, escape='\\'):
     51     q = VerboseQuote(in_string, specials, escape)
     52     qq = VerboseUnquote(q, specials, escape)
     53     self.assertEqual(''.join(qq), in_string)
     54 
     55   def run_test_tuples(self, test_tuples):
     56     for func, in_args, expected in test_tuples:
     57       self.generic_test(func, in_args, expected)
     58 
     59   def testQuote(self):
     60     test_tuples = [[VerboseQuote,
     61                     ['foo, bar, baz, and quux too!', 'abc'],
     62                     'foo, \\b\\ar, \\b\\az, \\and quux too!'],
     63                    [VerboseQuote,
     64                     ['when \\ appears in the input', 'a'],
     65                     'when \\\\ \\appe\\ars in the input']]
     66     self.run_test_tuples(test_tuples)
     67 
     68   def testUnquote(self):
     69     test_tuples = [[VerboseUnquote,
     70                     ['key\\:still_key:value\\:more_value', ':'],
     71                     ['key:still_key', ':', 'value:more_value']],
     72                    [VerboseUnquote,
     73                     ['about that sep\\ar\\ator in the beginning', 'ab'],
     74                     ['', 'ab', 'out th', 'a', 't separator in the ',
     75                      'b', 'eginning']],
     76                    [VerboseUnquote,
     77                     ['the rain in spain fall\\s ma\\i\\nly on the plains',
     78                      'ins'],
     79                     ['the ra', 'in', ' ', 'in', ' ', 's', 'pa', 'in',
     80                      ' falls mainly o', 'n', ' the pla', 'ins']],
     81                    ]
     82     self.run_test_tuples(test_tuples)
     83 
     84   def testInvertible(self):
     85     self.check_invertible('abcdefg', 'bc')
     86     self.check_invertible('a\\bcdefg', 'bc')
     87     self.check_invertible('ab\\cdefg', 'bc')
     88     self.check_invertible('\\ab\\cdefg', 'abc')
     89     self.check_invertible('abcde\\fg', 'efg')
     90     self.check_invertible('a\\b', '')
     91 
     92 
     93 # Invoke this file directly for simple manual testing.  For running
     94 # the unittests, use the -t flag.  Any flags to be passed to the
     95 # unittest module should be passed as after the optparse processing,
     96 # e.g., "quote_test.py -t -- -v" to pass the -v flag to the unittest
     97 # module.
     98 
     99 def main(argv):
    100   global verbose
    101   parser = optparse.OptionParser(
    102     usage='Usage: %prog [options] word...')
    103   parser.add_option('-s', '--special-chars', dest='special_chars', default=':',
    104                     help='Special characters to quote (default is ":")')
    105   parser.add_option('-q', '--quote', dest='quote', default='\\',
    106                     help='Quote or escape character (default is "\")')
    107   parser.add_option('-t', '--run-tests', dest='tests', action='store_true',
    108                     help='Run built-in tests\n')
    109   parser.add_option('-u', '--unquote-input', dest='unquote_input',
    110                     action='store_true', help='Unquote command line argument')
    111   parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
    112                     help='Verbose test output')
    113   options, args = parser.parse_args(argv)
    114 
    115   if options.verbose:
    116     verbose = True
    117 
    118   num_errors = 0
    119   if options.tests:
    120     sys.argv = [sys.argv[0]] + args
    121     unittest.main()
    122   else:
    123     for word in args:
    124       # NB: there are inputs x for which quote(unquote(x) != x, but
    125       # there should be no input x for which unquote(quote(x)) != x.
    126       if options.unquote_input:
    127         qq = quote.unquote(word, options.special_chars, options.quote)
    128         sys.stdout.write('unquote(%s) = %s\n'
    129                          % (word, ''.join(qq)))
    130         # There is no expected output for unquote -- this is just for
    131         # manual testing, so it is okay that we do not (and cannot)
    132         # update num_errors here.
    133       else:
    134         q = quote.quote(word, options.special_chars, options.quote)
    135         qq = quote.unquote(q, options.special_chars, options.quote)
    136         sys.stdout.write('quote(%s) = %s, unquote(%s) = %s\n'
    137                          % (word, q, q, ''.join(qq)))
    138         if word != ''.join(qq):
    139           num_errors += 1
    140     if num_errors > 0:
    141       sys.stderr.write('[  FAILED  ] %d test failures\n' % num_errors)
    142   return num_errors
    143 
    144 if __name__ == '__main__':
    145   sys.exit(main(sys.argv[1:]))
    146