#             Perforce Defect Tracking Integration Project
#              <http://www.ravenbrook.com/project/p4dti/>
#
#      TEST_CHECK_CONFIG.PY -- UNIT TEST FOR CHECK_CONFIG MODULE
#
#             Gareth Rees, Ravenbrook Limited, 2001-03-14
#
#
# 1. INTRODUCTION
#
# This module defines a set of unit tests for the check_config module.
#
# It uses the PyUnit unit test framework [PyUnit].
#
# The intended readership is project developers.
#
# This document is not confidential.

import os
import sys
p4dti_path = os.path.join(os.getcwd(), os.pardir, 'code', 'replicator')
if p4dti_path not in sys.path:
    sys.path.append(p4dti_path)
import check_config
import p4dti_unittest
import types
import unittest


# 2. TEST CASES


# 2.1. Passing and failing simple checks
#
# This test case has a table of values together with the checks which
# each value is supposed to pass.  The value is given to each checker
# function in turn and the result compared with the expectation in the
# table.

class fns(p4dti_unittest.TestCase):

    class test:
        def method(self):
            pass

        def __call__(self):
            pass

    # The 'codes' table maps a code letter to a checking function in the
    # check_config module.
    codes = { 'b': check_config.check_bool,
              'd': check_config.check_date,
              'e': check_config.check_email,
              'f': check_config.check_function,
              'h': check_config.check_host,
              'i': check_config.check_int,
              's': check_config.check_string,
              'S': check_config.check_string_or_none,
              'I': check_config.check_identifier,
              'c': check_config.check_changelist_url,
              'j': check_config.check_job_url,
              'l': (lambda x, y: check_config.check_list_of
                    (x, y, types.IntType, 'integers')),
              'L': (lambda x, y: check_config.check_list_of
                    (x, y, types.StringType, 'strings')),
              'p': check_config.check_list_of_string_pairs,
              }

    # The 'data' table is a list of pairs (codes, value), where 'codes'
    # is a list of code letters indicating the checking functions that
    # the value will pass (other checking functions will fail).
    data = [ ( "b     i       ", 0 ),
             ( "b     i       ", 1 ),
             ( " c   h      sS", "http://www.fo.bar/?%%3a+%%%d%%+%%3d" ),
             ( " c   h      sS", "%d" ),
             ( " c      j    S", None ),
             ( "  d  h      sS", "2001-12-01 23:00:59" ),
             ( "  d  h      sS", "1971-01-31 00:59:00" ),
             ( "   e h      sS", "gdr@ravenbrook.com" ),
             ( "   e h      sS", "gdr&rb+foo/bar/baz@xyz.invalid" ),
             ( "   e h      sS", "gdr!foo!bar@ravenbrook" ),
             ( "   e h      sS", "foo.bar@foo.bar.baz.quux.spong" ),
             ( "   e h      sS", "!#$%&'*+-/0123456789=?AZ^_`az{|}@uk" ),
             ( "    f         ", test() ),              # Object
             ( "    f         ", test().method ),       # Method
             ( "    f         ", sys.stdout.write ),    # BuiltinMethod
             ( "    f         ", getattr ),             # BuiltinFunction
             ( "    f         ", (lambda (foo): None) ),# Function
             ( "     h I    sS", "abcdefg_0123456" ),
             ( "     h I    sS", "abcdefg" ),
             ( "     h I    sS", "_abcdefghijklmnopqrstuvwxyz56789" ),
             ( "     h I    sS", "_ABCDEFGHIJKLMNOPQRSTUVWXYZ01234" ),
             ( "     h I    sS", "_" ),
             ( "     h I    sS", "M" ),
             ( "     h I    sS", "A0Z" ),
             ( "     h  j   sS", "http://www.foo.bar/?%%%%2b+%s+%%" ),
             ( "     h  j   sS", "%s" ),
             ( "     h      sS", "www.ravenbrook.com" ),
             ( "     h      sS", "public.perforce.com" ),
             ( "     h      sS", "http://www.foo.bar/%d/%" ),
             ( "     h      sS", "http://%s/%x/%%%" ),
             ( "     h      sS", "gdr@foo@com" ),
             ( "     h      sS", "gdr@" ),
             ( "     h      sS", "gdr.ravenbrook.com" ),
             ( "     h      sS", "foo;bar@foo.com" ),
             ( "     h      sS", "foo,bar@baz.com>" ),
             ( "     h      sS", "abc@.foo.com" ),
             ( "     h      sS", "abc.@foo.com" ),
             ( "     h      sS", "@foo.com" ),
             ( "     h      sS", "@" ),
             ( "     h      sS", "<foo@bar.com>" ),
             ( "     h      sS", "9_" ),
             ( "     h      sS", "9_" ),
             ( "     h      sS", "9" ),
             ( "     h      sS", "5abc" ),
             ( "     h      sS", "2001/03/14 13:59:42" ),
             ( "     h      sS", "2001-3-4 3:59:42" ),
             ( "     h      sS", "2001-03-14T13:59:42Z" ),
             ( "     h      sS", "1971-13-01 00:00:00" ),
             ( "     h      sS", "1971-01-32 00:00:00" ),
             ( "     h      sS", "1971-01-01 24:00:00" ),
             ( "     h      sS", "1971-01-01 00:60:00" ),
             ( "     h      sS", "1971-01-01 00:00:60" ),
             ( "     h      sS", "1971-01-00 00:00:00" ),
             ( "     h      sS", "1971-00-01 00:00:00" ),
             ( "     h      sS", "0abc" ),
             ( "     h      sS", "01-03-14 13:59:42" ),
             ( "     h      sS", "" ),
             ( "      i       ", 99 ),
             ( "      i       ", -1 ),
             ( "         lLp  ", [] ),
             ( "         l    ", [1, 4, 7] ),
             ( "          L   ", ["list", "of", "strings"] ),
             ( "           p  ", [("a", "b")] ),
             ( "           p  ", [("list",""),("of",""),("string","pairs")]),
             ( "              ", ["Not", "all", -1, "strings"] ),
             ( "              ", [("some", "not"), "pairs"]),
             ]

    def runTest(self):
        "Checking functions (test_check_config.fns)"
        for (codes, value) in self.data:
            for (code, checker) in self.codes.items():
                try:
                    self.value = value
                    checker(self, 'value')
                except check_config.error:
                    if code in codes:
                        self.addFailure("Checker %s on '%s' failed "
                                        "(should have passed)."
                                        % (checker, value))
                else:
                    if code not in codes:
                        self.addFailure("Checker %s on '%s' passed "
                                        "(should have failed)."
                                        % (checker, value))


# 3. RUNNING THE TESTS

def tests():
    suite = unittest.TestSuite()
    suite.addTest(fns())
    return suite

if __name__ == "__main__":
    unittest.main(defaultTest="tests")


# A. REFERENCES
#
# [PyUnit] "PyUnit - a unit testing framework for Python"; Steve
# Purcell; <http://pyunit.sourceforge.net/>.
#
#
# B. DOCUMENT HISTORY
#
# 2001-03-14 GDR Created.
#
# 2001-03-24 GDR Added tests for check_changelist_url and
# check_identfier.
#
# 2001-04-24 GDR Use p4dti_unittest to collect many failures per test
# case.
#
# 2001-07-09 NB Added check_job_url test.
#
# 2001-11-21 GDR Use new check_* calling convention.  Test
# check_function against built-ins and methods.
#
# 2001-12-05 GDR Test check_list_of.
#
# 2003-11-25 NB Added tests for check_list_of_string_pairs.
#
#
# C. COPYRIGHT AND LICENSE
#
# This file is copyright (c) 2001 Perforce Software, Inc.  All rights
# reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1.  Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#
# 2.  Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in
#     the documentation and/or other materials provided with the
#     distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
#
#
# $Id: //info.ravenbrook.com/project/p4dti/version/2.2/test/test_check_config.py#1 $
