181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org"""
281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgTestCommon.py:  a testing framework for commands and scripts
381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                with commonly useful error handling
481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgThe TestCommon module provides a simple, high-level interface for writing
681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgtests of executable commands and scripts, especially commands and scripts
781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgthat interact with the file system.  All methods throw exceptions and
881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgexit on failure, with useful error messages.  This makes a number of
981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgexplicit checks unnecessary, making the test scripts themselves simpler
1081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgto write and easier to read.
1181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
1281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgThe TestCommon class is a subclass of the TestCmd class.  In essence,
1381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgTestCommon is a wrapper that handles common TestCmd error conditions in
1481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orguseful ways.  You can use TestCommon directly, or subclass it for your
1581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgprogram and add additional (or override) methods to tailor it to your
1681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgprogram's specific needs.  Alternatively, the TestCommon class serves
1781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgas a useful example of how to define your own TestCmd subclass.
1881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
1981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgAs a subclass of TestCmd, TestCommon provides access to all of the
2081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgvariables and methods from the TestCmd module.  Consequently, you can
2181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orguse any variable or method documented in the TestCmd module without
2281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orghaving to explicitly import TestCmd.
2381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
2481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgA TestCommon environment object is created via the usual invocation:
2581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
2681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    import TestCommon
2781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test = TestCommon.TestCommon()
2881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
2981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgYou can use all of the TestCmd keyword arguments when instantiating a
3081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgTestCommon object; see the TestCmd documentation for details.
3181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
3281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgHere is an overview of the methods and keyword arguments that are
3381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgprovided by the TestCommon class:
3481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
3581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.must_be_writable('file1', ['file2', ...])
3681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
3781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.must_contain('file', 'required text\n')
3881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
3981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.must_contain_all_lines(output, lines, ['title', find])
4081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
4181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.must_contain_any_line(output, lines, ['title', find])
4281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
4381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.must_exist('file1', ['file2', ...])
4481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
4581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.must_match('file', "expected contents\n")
4681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
4781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.must_not_be_writable('file1', ['file2', ...])
4881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
49c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org    test.must_not_contain('file', 'banned text\n')
50c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org
5181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.must_not_contain_any_line(output, lines, ['title', find])
5281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
5381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.must_not_exist('file1', ['file2', ...])
5481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
5581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    test.run(options = "options to be prepended to arguments",
5681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org             stdout = "expected standard output from the program",
5781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org             stderr = "expected error output from the program",
5881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org             status = expected_status,
5981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org             match = match_function)
6081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
6181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgThe TestCommon module also provides the following variables
6281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
6381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCommon.python_executable
6481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCommon.exe_suffix
6581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCommon.obj_suffix
6681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCommon.shobj_prefix
6781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCommon.shobj_suffix
6881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCommon.lib_prefix
6981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCommon.lib_suffix
7081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCommon.dll_prefix
7181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    TestCommon.dll_suffix
7281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
7381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org"""
7481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
75c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org# Copyright 2000-2010 Steven Knight
7681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# This module is free software, and you may redistribute it and/or modify
7781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# it under the same terms as Python itself, so long as this copyright message
7881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# and disclaimer are retained in their original form.
7981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org#
8081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
8181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
8281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
8381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# DAMAGE.
8481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org#
8581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
8681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
8781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
8881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
8981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
9081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
9181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org__author__ = "Steven Knight <knight at baldmt dot com>"
92c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org__revision__ = "TestCommon.py 0.37.D001 2010/01/11 16:55:50 knight"
93c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org__version__ = "0.37"
9481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
9581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport copy
9681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport os
9781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport os.path
9881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport stat
9981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport string
10081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport sys
10181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport types
10281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgimport UserList
10381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
10481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgfrom TestCmd import *
10581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgfrom TestCmd import __all__
10681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
10781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org__all__.extend([ 'TestCommon',
10881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                 'exe_suffix',
10981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                 'obj_suffix',
11081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                 'shobj_prefix',
11181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                 'shobj_suffix',
11281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                 'lib_prefix',
11381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                 'lib_suffix',
11481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                 'dll_prefix',
11581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                 'dll_suffix',
11681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org               ])
11781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
11881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# Variables that describe the prefixes and suffixes on this system.
11981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgif sys.platform == 'win32':
12081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    exe_suffix   = '.exe'
12181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    obj_suffix   = '.obj'
12281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    shobj_suffix = '.obj'
12381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    shobj_prefix = ''
12481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    lib_prefix   = ''
12581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    lib_suffix   = '.lib'
12681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    dll_prefix   = ''
12781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    dll_suffix   = '.dll'
12881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgelif sys.platform == 'cygwin':
12981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    exe_suffix   = '.exe'
13081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    obj_suffix   = '.o'
13181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    shobj_suffix = '.os'
13281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    shobj_prefix = ''
13381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    lib_prefix   = 'lib'
13481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    lib_suffix   = '.a'
13581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    dll_prefix   = ''
13681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    dll_suffix   = '.dll'
13781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgelif string.find(sys.platform, 'irix') != -1:
13881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    exe_suffix   = ''
13981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    obj_suffix   = '.o'
14081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    shobj_suffix = '.o'
14181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    shobj_prefix = ''
14281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    lib_prefix   = 'lib'
14381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    lib_suffix   = '.a'
14481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    dll_prefix   = 'lib'
14581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    dll_suffix   = '.so'
14681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgelif string.find(sys.platform, 'darwin') != -1:
14781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    exe_suffix   = ''
14881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    obj_suffix   = '.o'
14981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    shobj_suffix = '.os'
15081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    shobj_prefix = ''
15181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    lib_prefix   = 'lib'
15281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    lib_suffix   = '.a'
15381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    dll_prefix   = 'lib'
15481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    dll_suffix   = '.dylib'
15581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgelif string.find(sys.platform, 'sunos') != -1:
15681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    exe_suffix   = ''
15781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    obj_suffix   = '.o'
15881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    shobj_suffix = '.os'
15981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    shobj_prefix = 'so_'
16081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    lib_prefix   = 'lib'
16181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    lib_suffix   = '.a'
16281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    dll_prefix   = 'lib'
16381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    dll_suffix   = '.dylib'
16481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgelse:
16581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    exe_suffix   = ''
16681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    obj_suffix   = '.o'
16781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    shobj_suffix = '.os'
16881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    shobj_prefix = ''
16981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    lib_prefix   = 'lib'
17081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    lib_suffix   = '.a'
17181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    dll_prefix   = 'lib'
17281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    dll_suffix   = '.so'
17381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
17481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef is_List(e):
17581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    return type(e) is types.ListType \
17681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        or isinstance(e, UserList.UserList)
17781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
17881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef is_writable(f):
17981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    mode = os.stat(f)[stat.ST_MODE]
18081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    return mode & stat.S_IWUSR
18181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
18281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgdef separate_files(flist):
18381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    existing = []
18481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    missing = []
18581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    for f in flist:
18681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if os.path.exists(f):
18781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            existing.append(f)
18881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
18981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            missing.append(f)
19081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    return existing, missing
19181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
192ca50e4158e519b054520ed2a897503a991889a94thakis@chromium.orgdef _failed(self, status = 0):
193ca50e4158e519b054520ed2a897503a991889a94thakis@chromium.org    if self.status is None or status is None:
194ca50e4158e519b054520ed2a897503a991889a94thakis@chromium.org        return None
195ca50e4158e519b054520ed2a897503a991889a94thakis@chromium.org    try:
196ca50e4158e519b054520ed2a897503a991889a94thakis@chromium.org        return _status(self) not in status
197ca50e4158e519b054520ed2a897503a991889a94thakis@chromium.org    except TypeError:
198ca50e4158e519b054520ed2a897503a991889a94thakis@chromium.org        # status wasn't an iterable
19981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return _status(self) != status
20054d2f6fe6d8a7b9d9786bd1f8540df6b4f46b83fsbc@chromium.org
201ca50e4158e519b054520ed2a897503a991889a94thakis@chromium.orgdef _status(self):
202ca50e4158e519b054520ed2a897503a991889a94thakis@chromium.org    return self.status
20381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
20481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.orgclass TestCommon(TestCmd):
20581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
20681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    # Additional methods from the Perl Test::Cmd::Common module
20781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    # that we may wish to add in the future:
20881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    #
20981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    #  $test->subdir('subdir', ...);
21081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    #
21181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    #  $test->copy('src_file', 'dst_file');
21281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
21381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def __init__(self, **kw):
21481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Initialize a new TestCommon instance.  This involves just
21581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        calling the base class initialization, and then changing directory
21681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        to the workdir.
21781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
21881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        apply(TestCmd.__init__, [self], kw)
21981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        os.chdir(self.workdir)
22081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
22181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def must_be_writable(self, *files):
22281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Ensures that the specified file(s) exist and are writable.
22381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        An individual file can be specified as a list of directory names,
22481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        in which case the pathname will be constructed by concatenating
22581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        them.  Exits FAILED if any of the files does not exist or is
22681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        not writable.
22781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
22881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
22981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        existing, missing = separate_files(files)
23081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        unwritable = filter(lambda x, iw=is_writable: not iw(x), existing)
23181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if missing:
23281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print "Missing files: `%s'" % string.join(missing, "', `")
23381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if unwritable:
23481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print "Unwritable files: `%s'" % string.join(unwritable, "', `")
23581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.fail_test(missing + unwritable)
23681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
23781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def must_contain(self, file, required, mode = 'rb'):
23881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Ensures that the specified file contains the required text.
23981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
24081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        file_contents = self.read(file, mode)
24181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        contains = (string.find(file_contents, required) != -1)
24281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not contains:
24381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print "File `%s' does not contain required string." % file
24481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print self.banner('Required string ')
24581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print required
24681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print self.banner('%s contents ' % file)
24781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print file_contents
24881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.fail_test(not contains)
24981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
25081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def must_contain_all_lines(self, output, lines, title=None, find=None):
25181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Ensures that the specified output string (first argument)
25281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        contains all of the specified lines (second argument).
25381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
25481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        An optional third argument can be used to describe the type
25581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        of output being searched, and only shows up in failure output.
25681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
25781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        An optional fourth argument can be used to supply a different
25881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        function, of the form "find(line, output), to use when searching
25981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for lines in the output.
26081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
26181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if find is None:
26281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            find = lambda o, l: string.find(o, l) != -1
26381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        missing = []
26481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for line in lines:
26581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if not find(output, line):
26681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                missing.append(line)
26781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
26881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if missing:
26981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if title is None:
27081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                title = 'output'
27181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sys.stdout.write("Missing expected lines from %s:\n" % title)
27281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            for line in missing:
27381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                sys.stdout.write('    ' + repr(line) + '\n')
27481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sys.stdout.write(self.banner(title + ' '))
27581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sys.stdout.write(output)
27681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.fail_test()
27781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
27881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def must_contain_any_line(self, output, lines, title=None, find=None):
27981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Ensures that the specified output string (first argument)
28081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        contains at least one of the specified lines (second argument).
28181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
28281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        An optional third argument can be used to describe the type
28381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        of output being searched, and only shows up in failure output.
28481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
28581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        An optional fourth argument can be used to supply a different
28681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        function, of the form "find(line, output), to use when searching
28781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for lines in the output.
28881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
28981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if find is None:
29081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            find = lambda o, l: string.find(o, l) != -1
29181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for line in lines:
29281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if find(output, line):
29381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                return
29481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
29581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if title is None:
29681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            title = 'output'
29781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        sys.stdout.write("Missing any expected line from %s:\n" % title)
29881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for line in lines:
29981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sys.stdout.write('    ' + repr(line) + '\n')
30081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        sys.stdout.write(self.banner(title + ' '))
30181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        sys.stdout.write(output)
30281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.fail_test()
30381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
30481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def must_contain_lines(self, lines, output, title=None):
30581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        # Deprecated; retain for backwards compatibility.
30681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return self.must_contain_all_lines(output, lines, title)
30781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
30881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def must_exist(self, *files):
30981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Ensures that the specified file(s) must exist.  An individual
31081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        file be specified as a list of directory names, in which case the
31181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        pathname will be constructed by concatenating them.  Exits FAILED
31281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if any of the files does not exist.
31381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
31481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
31581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        missing = filter(lambda x: not os.path.exists(x), files)
31681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if missing:
31781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print "Missing files: `%s'" % string.join(missing, "', `")
31881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.fail_test(missing)
31981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
32081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def must_match(self, file, expect, mode = 'rb'):
32181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Matches the contents of the specified file (first argument)
32281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        against the expected contents (second argument).  The expected
32381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        contents are a list of lines or a string which will be split
32481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        on newlines.
32581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
32681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        file_contents = self.read(file, mode)
32781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        try:
32881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.fail_test(not self.match(file_contents, expect))
32981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        except KeyboardInterrupt:
33081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            raise
33181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        except:
33281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print "Unexpected contents of `%s'" % file
33381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.diff(expect, file_contents, 'contents ')
33481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            raise
33581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
33684f26de1771168933a19776955b0713d3b5892b1bradnelson@google.com    def must_not_contain(self, file, banned, mode = 'rb'):
33784f26de1771168933a19776955b0713d3b5892b1bradnelson@google.com        """Ensures that the specified file doesn't contain the banned text.
33884f26de1771168933a19776955b0713d3b5892b1bradnelson@google.com        """
33984f26de1771168933a19776955b0713d3b5892b1bradnelson@google.com        file_contents = self.read(file, mode)
34084f26de1771168933a19776955b0713d3b5892b1bradnelson@google.com        contains = (string.find(file_contents, banned) != -1)
34184f26de1771168933a19776955b0713d3b5892b1bradnelson@google.com        if contains:
34284f26de1771168933a19776955b0713d3b5892b1bradnelson@google.com            print "File `%s' contains banned string." % file
34384f26de1771168933a19776955b0713d3b5892b1bradnelson@google.com            print self.banner('Banned string ')
34484f26de1771168933a19776955b0713d3b5892b1bradnelson@google.com            print banned
34584f26de1771168933a19776955b0713d3b5892b1bradnelson@google.com            print self.banner('%s contents ' % file)
34684f26de1771168933a19776955b0713d3b5892b1bradnelson@google.com            print file_contents
347c3836fd58fdfa6f8bb2c70e40e6aaf11dfaa76d5sgk@chromium.org            self.fail_test(contains)
34884f26de1771168933a19776955b0713d3b5892b1bradnelson@google.com
34981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def must_not_contain_any_line(self, output, lines, title=None, find=None):
35081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Ensures that the specified output string (first argument)
35181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        does not contain any of the specified lines (second argument).
35281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
35381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        An optional third argument can be used to describe the type
35481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        of output being searched, and only shows up in failure output.
35581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
35681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        An optional fourth argument can be used to supply a different
35781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        function, of the form "find(line, output), to use when searching
35881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for lines in the output.
35981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
36081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if find is None:
36181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            find = lambda o, l: string.find(o, l) != -1
36281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        unexpected = []
36381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        for line in lines:
36481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if find(output, line):
36581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                unexpected.append(line)
36681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
36781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if unexpected:
36881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if title is None:
36981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                title = 'output'
37081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sys.stdout.write("Unexpected lines in %s:\n" % title)
37181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            for line in unexpected:
37281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                sys.stdout.write('    ' + repr(line) + '\n')
37381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sys.stdout.write(self.banner(title + ' '))
37481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sys.stdout.write(output)
37581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.fail_test()
37681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
37781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def must_not_contain_lines(self, lines, output, title=None):
37881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        return self.must_not_contain_any_line(output, lines, title)
37981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
38081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def must_not_exist(self, *files):
38181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Ensures that the specified file(s) must not exist.
38281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        An individual file be specified as a list of directory names, in
38381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        which case the pathname will be constructed by concatenating them.
38481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        Exits FAILED if any of the files exists.
38581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
38681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
38781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        existing = filter(os.path.exists, files)
38881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if existing:
38981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print "Unexpected files exist: `%s'" % string.join(existing, "', `")
39081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.fail_test(existing)
39181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
39281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def must_not_be_writable(self, *files):
39381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Ensures that the specified file(s) exist and are not writable.
39481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        An individual file can be specified as a list of directory names,
39581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        in which case the pathname will be constructed by concatenating
39681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        them.  Exits FAILED if any of the files does not exist or is
39781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        writable.
39881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
39981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
40081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        existing, missing = separate_files(files)
40181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        writable = filter(is_writable, existing)
40281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if missing:
40381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print "Missing files: `%s'" % string.join(missing, "', `")
40481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if writable:
40581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print "Writable files: `%s'" % string.join(writable, "', `")
40681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self.fail_test(missing + writable)
40781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
40881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def _complete(self, actual_stdout, expected_stdout,
40981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        actual_stderr, expected_stderr, status, match):
41081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
41181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        Post-processes running a subcommand, checking for failure
41281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        status and displaying output appropriately.
41381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
41481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if _failed(self, status):
41581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            expect = ''
41681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if status != 0:
41781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                expect = " (expected %s)" % str(status)
41881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print "%s returned %s%s" % (self.program, str(_status(self)), expect)
41981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print self.banner('STDOUT ')
42081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print actual_stdout
42181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print self.banner('STDERR ')
42281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print actual_stderr
42381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.fail_test()
42481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not expected_stdout is None and not match(actual_stdout, expected_stdout):
42581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.diff(expected_stdout, actual_stdout, 'STDOUT ')
42681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if actual_stderr:
42781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                print self.banner('STDERR ')
42881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                print actual_stderr
42981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.fail_test()
43081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if not expected_stderr is None and not match(actual_stderr, expected_stderr):
43181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print self.banner('STDOUT ')
43281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print actual_stdout
43381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.diff(expected_stderr, actual_stderr, 'STDERR ')
43481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.fail_test()
43581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
43681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def start(self, program = None,
43781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    interpreter = None,
43881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    arguments = None,
43981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    universal_newlines = None,
44081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                    **kw):
44181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
44281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        Starts a program or script for the test environment.
44381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
44481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        This handles the "options" keyword argument and exceptions.
44581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
4463afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org        options = kw.pop('options', None)
4473afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org        if options:
4483afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org            if arguments is None:
4493afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org                arguments = options
4503afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org            else:
4513afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org                arguments = options + " " + arguments
4523afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org
45381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        try:
45481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            return apply(TestCmd.start,
45581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                         (self, program, interpreter, arguments, universal_newlines),
45681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                         kw)
45781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        except KeyboardInterrupt:
45881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            raise
45981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        except Exception, e:
46081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print self.banner('STDOUT ')
46181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
46281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                print self.stdout()
46381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except IndexError:
46481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                pass
46581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            print self.banner('STDERR ')
46681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            try:
46781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                print self.stderr()
46881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            except IndexError:
46981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                pass
47081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            cmd_args = self.command_args(program, interpreter, arguments)
47181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sys.stderr.write('Exception trying to execute: %s\n' % cmd_args)
47281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            raise e
47381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
47481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def finish(self, popen, stdout = None, stderr = '', status = 0, **kw):
47581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
47681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        Finishes and waits for the process being run under control of
47781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        the specified popen argument.  Additional arguments are similar
47881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        to those of the run() method:
47981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
48081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                stdout  The expected standard output from
48181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        the command.  A value of None means
48281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        don't test standard output.
48381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
48481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                stderr  The expected error output from
48581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        the command.  A value of None means
48681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        don't test error output.
48781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
48881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                status  The expected exit status from the
48981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        command.  A value of None means don't
49081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        test exit status.
49181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
49281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        apply(TestCmd.finish, (self, popen,), kw)
49381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        match = kw.get('match', self.match)
49481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self._complete(self.stdout(), stdout,
49581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                       self.stderr(), stderr, status, match)
49681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
49781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def run(self, options = None, arguments = None,
49881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                  stdout = None, stderr = '', status = 0, **kw):
49981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Runs the program under test, checking that the test succeeded.
50081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
50181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        The arguments are the same as the base TestCmd.run() method,
50281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        with the addition of:
50381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
50481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                options Extra options that get appended to the beginning
50581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        of the arguments.
50681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
50781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                stdout  The expected standard output from
50881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        the command.  A value of None means
50981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        don't test standard output.
51081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
51181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                stderr  The expected error output from
51281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        the command.  A value of None means
51381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        don't test error output.
51481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
51581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                status  The expected exit status from the
51681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        command.  A value of None means don't
51781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                        test exit status.
51881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
51981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        By default, this expects a successful exit (status = 0), does
52081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        not test standard output (stdout = None), and expects that error
52181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        output is empty (stderr = "").
52281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
52381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if options:
52481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            if arguments is None:
52581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                arguments = options
52681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            else:
52781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                arguments = options + " " + arguments
52881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        kw['arguments'] = arguments
5293afe3277af466c60b6d35a56f578c09a4c5f4c98sbc@chromium.org        match = kw.pop('match', self.match)
53081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        apply(TestCmd.run, [self], kw)
53181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        self._complete(self.stdout(), stdout,
53281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org                       self.stderr(), stderr, status, match)
53381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
53481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org    def skip_test(self, message="Skipping test.\n"):
53581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """Skips a test.
53681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
53781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        Proper test-skipping behavior is dependent on the external
53881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        TESTCOMMON_PASS_SKIPS environment variable.  If set, we treat
53981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        the skip as a PASS (exit 0), and otherwise treat it as NO RESULT.
54081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        In either case, we print the specified message as an indication
54181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        that the substance of the test was skipped.
54281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
54381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        (This was originally added to support development under Aegis.
54481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        Technically, skipping a test is a NO RESULT, but Aegis would
54581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        treat that as a test failure and prevent the change from going to
54681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        the next step.  Since we ddn't want to force anyone using Aegis
54781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        to have to install absolutely every tool used by the tests, we
54881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        would actually report to Aegis that a skipped test has PASSED
54981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        so that the workflow isn't held up.)
55081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        """
55181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if message:
55281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sys.stdout.write(message)
55381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            sys.stdout.flush()
55481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        pass_skips = os.environ.get('TESTCOMMON_PASS_SKIPS')
55581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        if pass_skips in [None, 0, '0']:
55681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # skip=1 means skip this function when showing where this
55781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # result came from.  They only care about the line where the
55881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # script called test.skip_test(), not the line number where
55981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # we call test.no_result().
56081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.no_result(skip=1)
56181ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org        else:
56281ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # We're under the development directory for this change,
56381ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            # so this is an Aegis invocation; pass the test (exit 0).
56481ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org            self.pass_test()
56581ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org
56681ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# Local Variables:
56781ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# tab-width:4
56881ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# indent-tabs-mode:nil
56981ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# End:
57081ac0047a01ca7d34b493fba09e7fd6a5acf09c5sgk@chromium.org# vim: set expandtab tabstop=4 shiftwidth=4:
571