1#!/usr/bin/env python
2#
3#  getopt_tests.py:  testing the svn command line processing
4#
5#  Subversion is a tool for revision control.
6#  See http://subversion.apache.org for more information.
7#
8# ====================================================================
9#    Licensed to the Apache Software Foundation (ASF) under one
10#    or more contributor license agreements.  See the NOTICE file
11#    distributed with this work for additional information
12#    regarding copyright ownership.  The ASF licenses this file
13#    to you under the Apache License, Version 2.0 (the
14#    "License"); you may not use this file except in compliance
15#    with the License.  You may obtain a copy of the License at
16#
17#      http://www.apache.org/licenses/LICENSE-2.0
18#
19#    Unless required by applicable law or agreed to in writing,
20#    software distributed under the License is distributed on an
21#    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22#    KIND, either express or implied.  See the License for the
23#    specific language governing permissions and limitations
24#    under the License.
25######################################################################
26
27# General modules
28import sys, re, os.path, logging
29
30logger = logging.getLogger()
31
32# Our testing module
33import svntest
34
35
36######################################################################
37# Tests
38
39#----------------------------------------------------------------------
40
41# Naming convention for golden files: take the svn command line as a
42# single string and apply the following sed transformations:
43#   echo svn option1 option2 ... | sed -e 's/ /_/g' -e 's/_--/--/g'
44# Then append either _stdout or _stderr for the file descriptor to
45# compare against.
46
47def load_expected_output(basename):
48  "load the expected standard output and standard error"
49
50  # This directory contains all the expected output from svn.
51  getopt_output_dir = os.path.join(os.path.dirname(sys.argv[0]),
52                                   'getopt_tests_data')
53
54  stdout_filename = os.path.join(getopt_output_dir, basename + '_stdout')
55  stderr_filename = os.path.join(getopt_output_dir, basename + '_stderr')
56
57  exp_stdout = open(stdout_filename, 'r').readlines()
58  exp_stderr = open(stderr_filename, 'r').readlines()
59
60  return exp_stdout, exp_stderr
61
62# With plaintext password storage enabled, `svn --version' emits a warning:
63warn_line_re = re.compile("WARNING: Plaintext password storage")
64
65# This is a list of lines to delete.
66del_lines_res = [
67                 # In 'svn --version', the date line is variable, for example:
68                 # "compiled Apr  5 2002, 10:08:45"
69                 re.compile(r'\s+compiled\s+'),
70
71                 # Also for 'svn --version':
72                 re.compile(r"\* ra_(neon|local|svn|serf) :"),
73                 re.compile(r"  - handles '(https?|file|svn)' scheme"),
74                 re.compile(r"  - with Cyrus SASL authentication"),
75                 re.compile(r"  - using serf \d+\.\d+\.\d+"),
76                 re.compile(r"\* fs_(base|fs) :"),
77
78                 # Remove 'svn --version' list of platform-specific
79                 # auth cache providers.
80                 re.compile(r"\* Wincrypt cache.*"),
81                 re.compile(r"\* Plaintext cache.*"),
82                 re.compile(r"\* Gnome Keyring"),
83                 re.compile(r"\* GPG-Agent"),
84                 re.compile(r"\* Mac OS X Keychain"),
85                 re.compile(r"\* KWallet \(KDE\)"),
86                ]
87
88# This is a list of lines to search and replace text on.
89rep_lines_res = [
90                 # In 'svn --version', this line varies, for example:
91                 # "Subversion Client, version 0.10.2-dev (under development)"
92                 # "Subversion Client, version 0.10.2 (r1729)"
93                 (re.compile(r'version \d+\.\d+\.\d+(-[^ ]*)? \(.*\)'),
94                  'version X.Y.Z '),
95                 # The copyright end date keeps changing; fix forever.
96                 (re.compile(r'Copyright \(C\) 20\d\d The Apache '
97                              'Software Foundation\.'),
98                  'Copyright (C) YYYY The Apache Software Foundation'),
99                 # In 'svn --version --quiet', we print only the version
100                 # number in a single line.
101                 (re.compile(r'^\d+\.\d+\.\d+(-[a-zA-Z0-9]+)?$'), 'X.Y.Z\n'),
102                ]
103
104# This is a trigger pattern that selects the secondary set of
105# delete/replace patterns
106switch_res_line = 'System information:'
107
108# This is a list of lines to delete after having seen switch_res_line.
109switched_warn_line_re = None
110switched_del_lines_res = [
111                          # In svn --version --verbose, dependent libs loaded
112                          # shared libs are optional.
113                          re.compile(r'^\* (loaded|linked)'),
114                          # In svn --version --verbose, remove everything from
115                          # the extended lists
116                          re.compile(r'^  - '),
117                         ]
118
119# This is a list of lines to search and replace text on after having
120# seen switch_res_line.
121switched_rep_lines_res = [
122                          # We don't care about the actual canonical host
123                          (re.compile('^\* running on.*$'), '* running on'),
124                         ]
125
126def process_lines(lines):
127  "delete lines that should not be compared and search and replace the rest"
128  output = [ ]
129  warn_re = warn_line_re
130  del_res = del_lines_res
131  rep_res = rep_lines_res
132
133  skip_next_line = 0
134  for line in lines:
135    if skip_next_line:
136      skip_next_line = 0
137      continue
138
139    if line.startswith(switch_res_line):
140      warn_re = switched_warn_line_re
141      del_res = switched_del_lines_res
142      rep_res = switched_rep_lines_res
143
144    # Skip these lines from the output list.
145    delete_line = 0
146    if warn_re and warn_re.match(line):
147      delete_line = 1
148      skip_next_line = 1     # Ignore the empty line after the warning
149    else:
150      for delete_re in del_res:
151        if delete_re.match(line):
152          delete_line = 1
153          break
154    if delete_line:
155      continue
156
157    # Search and replace text on the rest.
158    for replace_re, replace_str in rep_res:
159      line = replace_re.sub(replace_str, line)
160
161    output.append(line)
162
163  return output
164
165def run_one_test(sbox, basename, *varargs):
166  "run svn with args and compare against the specified output files"
167
168  ### no need to use sbox.build() -- we don't need a repos or working copy
169  ### for these tests.
170
171  exp_stdout, exp_stderr = load_expected_output(basename)
172
173  # special case the 'svn' test so that no extra arguments are added
174  if basename != 'svn':
175    exit_code, actual_stdout, actual_stderr = svntest.main.run_svn(1, *varargs)
176  else:
177    exit_code, actual_stdout, actual_stderr = svntest.main.run_command(svntest.main.svn_binary,
178                                                                       1, False, *varargs)
179
180  # Delete and perform search and replaces on the lines from the
181  # actual and expected output that may differ between build
182  # environments.
183  exp_stdout    = process_lines(exp_stdout)
184  exp_stderr    = process_lines(exp_stderr)
185  actual_stdout = process_lines(actual_stdout)
186  actual_stderr = process_lines(actual_stderr)
187
188  svntest.verify.compare_and_display_lines("Standard output does not match.",
189                                           "STDOUT", exp_stdout, actual_stdout)
190
191  svntest.verify.compare_and_display_lines("Standard error does not match.",
192                                           "STDERR", exp_stderr, actual_stderr)
193
194def getopt_no_args(sbox):
195  "run svn with no arguments"
196  run_one_test(sbox, 'svn')
197
198def getopt__version(sbox):
199  "run svn --version"
200  run_one_test(sbox, 'svn--version', '--version')
201
202def getopt__version__quiet(sbox):
203  "run svn --version --quiet"
204  run_one_test(sbox, 'svn--version--quiet', '--version', '--quiet')
205
206def getopt__version__verbose(sbox):
207  "run svn --version --verbose"
208  run_one_test(sbox, 'svn--version--verbose', '--version', '--verbose')
209
210def getopt__help(sbox):
211  "run svn --help"
212  run_one_test(sbox, 'svn--help', '--help')
213
214def getopt_help(sbox):
215  "run svn help"
216  run_one_test(sbox, 'svn_help', 'help')
217
218def getopt_help_log_switch(sbox):
219  "run svn help log switch"
220  run_one_test(sbox, 'svn_help_log_switch', 'help', 'log', 'switch')
221
222def getopt_help_bogus_cmd(sbox):
223  "run svn help bogus-cmd"
224  run_one_test(sbox, 'svn_help_bogus-cmd', 'help', 'bogus-cmd')
225
226def getopt_config_option(sbox):
227  "--config-option's spell checking"
228  sbox.build(create_wc=False, read_only=True)
229  expected_stderr = '.*W205000.*did you mean.*'
230  expected_stdout = svntest.verify.AnyOutput
231  svntest.actions.run_and_verify_svn2(expected_stdout, expected_stderr, 0,
232                                      'info',
233                                      '--config-option',
234                                      'config:miscellanous:diff-extensions=' +
235                                        '-u -p',
236                                      sbox.repo_url)
237
238########################################################################
239# Run the tests
240
241
242# list all tests here, starting with None:
243test_list = [ None,
244              getopt_no_args,
245              getopt__version,
246              getopt__version__quiet,
247              getopt__version__verbose,
248              getopt__help,
249              getopt_help,
250              getopt_help_bogus_cmd,
251              getopt_help_log_switch,
252              getopt_config_option,
253            ]
254
255if __name__ == '__main__':
256  svntest.main.run_tests(test_list)
257  # NOTREACHED
258
259
260### End of file.
261