from __future__ import print_function

import unittest
import time, os, sys
import logging
import inspect
import platform
import P4

pythonVer = "python"
if sys.version_info[0] >= 3:
    pythonVer = "python3"

parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, parent_dir)

from p4testutils import TestCase, P4Server
import CheckCaseTrigger

# from TestTriggers import TestTriggers

os.environ["LOGS"] = "."
LOGGER_NAME = "TestCheckCaseTrigger"
LOG_FILE = "log-TestCheckCaseTrigger.log"

# Run tests on a case-sensitive server or a case-insensitive server.
# NOTE: For case-insensitive server, add case_sensitive=false to end of TestCheckCaseTrigger arguments.

case_sensitive = platform.system() == "Linux"
default_depot = "depot"

# Handle Python2 version of os.makedirs
def makedirs(folder, *args, **kwargs):
    if not os.path.exists(folder):
        os.makedirs(folder)

def connect(func):
    def func_wrapper(self):
        if not self.p4.connected():
            self.p4.connect()
        self.assertTrue(self.p4.connected(), "Not connected")
        func(self)
        self.p4.disconnect()
        # os.chdir(self.server.client_root)

    return func_wrapper


class TestCheckCaseTriggerBasic(TestCase):
    """Test class which doesn't reqired p4d scaffolding"""

    def __init__(self, methodName='runTest'):
        super(TestCheckCaseTriggerBasic, self).__init__(LOGGER_NAME, LOG_FILE, methodName=methodName)

    def testBasic(self):
        # Fudge issues with trigger
        CheckCaseTrigger.AllowBypass = 0
        args = ["1"]
        ct = CheckCaseTrigger.CheckCaseTrigger(*args)
        f = []
        self.assertEqual({}, ct.getDirList(f))
        self.assertEqual({}, ct.getFileDirList(f))

        f = ["//d/a.txt"]
        ct.caseSensitive = True
        self.assertEqual({"d": "d"}, ct.getDirList(f))
        self.assertEqual({"d": "d"}, ct.getFileDirList(f))
        ct.caseSensitive = False
        self.assertEqual({"d": "d"}, ct.getDirList(f))
        self.assertEqual({"d": "d"}, ct.getFileDirList(f))

        # Depot name case
        f = ["//D/a.txt"]
        ct.caseSensitive = True
        self.assertEqual({"D": "D"}, ct.getDirList(f))
        self.assertEqual({"D": "D"}, ct.getFileDirList(f))
        ct.caseSensitive = False
        self.assertEqual({"d": "D"}, ct.getDirList(f))
        self.assertEqual({"d": "D"}, ct.getFileDirList(f))

        f = ["//d/a/b.txt"]
        self.assertEqual({"d": "d", "d/a": "d/a"}, ct.getDirList(f))
        self.assertEqual({"d": "d/a", "d/a": "d/a"}, ct.getFileDirList(f))

        f = [
            "//d/a/b.txt",
            "//d/b/c.txt",
            ]
        self.assertEqual(set(["d", "d/a", "d/b"]), set(ct.getDirList(f).keys()))
        self.assertEqual(set(["d", "d/a", "d/b"]), set(ct.getFileDirList(f).keys()))

        f = [
            "//d/a/f.txt",
            "//d/b/c/d/g.txt",
            ]
        self.assertEqual(set(["d", "d/a", "d/b", "d/b/c", "d/b/c/d"]), set(ct.getDirList(f).keys()))
        self.assertEqual(set(["d", "d/a", "d/b", "d/b/c", "d/b/c/d"]), set(ct.getFileDirList(f).keys()))

        f = [
            "//d/a/f.txt",
            "//d/a/b/C/g.txt",
            "//d/a/b/C/h.txt",
            ]
        ct.caseSensitive = True
        self.assertEqual(set(["d", "d/a", "d/a/b", "d/a/b/C"]), set(ct.getDirList(f).keys()))
        self.assertEqual(set(["d", "d/a", "d/a/b", "d/a/b/C"]), set(ct.getFileDirList(f).keys()))
        ct.caseSensitive = False
        self.assertEqual(set(["d", "d/a", "d/a/b", "d/a/b/c"]), set(ct.getDirList(f).keys()))
        self.assertEqual(set(["d", "d/a", "d/a/b", "d/a/b/c"]), set(ct.getFileDirList(f).keys()))

    def setUp(self):
        CheckCaseTrigger.AllowBypass = 0
        args = ["1"]
        self.trigger = CheckCaseTrigger.CheckCaseTrigger(*args)
        self.files = []
        self.depotFiles = []
        self.trigger.options.log = "_log.test.log"
        self.trigger.options.verbosity = logging.DEBUG
        self.trigger.init_logger()
        self.logger = self.trigger.logger
        self.trigger.depotCache['depot'] = 'depot'

    def addFile(self, name, depot=default_depot):
        self.files.append("%s/%s" % (depot, name))

    def createFiles(self, testDir, depot=default_depot):
        files = ('foo.txt', 'bar.txt', 'baz.txt')
        for f in files:
            self.addFile("%s/%s" % (testDir, f), depot=depot)

    def applySubmitState(self):
        "Pretend to do a submit by adding all files from latest submit to the depot"
        self.depotFiles.extend(self.files)
        self.files = []
        self.logger.debug("depot files: %s" % self.depotFiles)

    def expectFailSubmit(self, msg, desc=None):
        """validate depot files"""
        # Look for files in cache. This includes looking for directories in file path.
        badlist = {}
        depotFiles = ["//" + f for f in self.depotFiles]
        depotFiles.extend(["//" + f for f in self.files])
        self.trigger.searchCache(depotFiles, badlist)
        self.logger.debug("badlist: %s" % badlist)
        if len(badlist) == 0:
            self.fail(msg)

    def expectSucceedSubmit(self, msg, desc=None):
        """expect validation to succeed"""
        badlist = {}
        depotFiles = ["//" + f for f in self.depotFiles]
        depotFiles.extend(["//" + f for f in self.files])
        self.trigger.searchCache(depotFiles, badlist)
        self.logger.debug("badlist: %s" % badlist)
        if len(badlist) != 0:
            self.fail(msg)
        self.applySubmitState()

    def testSimpleSubmit(self):
        testDir = 'test_files'
        self.createFiles(testDir)
        self.expectSucceedSubmit("failed")

    def testSimpleFail(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("foo")
        self.expectSucceedSubmit("Adding one file should not fail")

        self.addFile("Foo")
        self.expectFailSubmit("Did not catch foo != Foo")

    def testSimpleSubmitMD(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Submit with multiple depots
        depot2 = "depot2"
        self.trigger.depotCache['depot2'] = 'depot2'
        testDir = 'test_files'

        self.createFiles(testDir)
        self.createFiles(testDir, depot=depot2)
        self.expectSucceedSubmit("Failed to submit the add", "My Add Test")

    def testDirectoryFail(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("foo/bar")
        self.expectSucceedSubmit("Adding one file should not fail", "Simple Add")

        self.addFile("FOO/bar")
        self.expectFailSubmit("Did not catch foo != FOO/bar", "bar")

    def testDirectoryFail_4(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("bar/bar/bar/foo1")
        self.expectSucceedSubmit("Adding one file should not fail", "Simple Add")

        self.addFile("bar/bar/bar/foo2")
        self.expectSucceedSubmit("Adding file with different name should not fail", "foo2")

        self.addFile("bar/bar/bar/foo3")
        self.expectSucceedSubmit("Adding file with different name should not fail", "foo3")

        self.addFile("bar/bar/bar/FOO2")
        self.expectFailSubmit("Adding file that differs by case should fail", "FOO2")

    def testDirectoryFail_5(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("bar/bar/bar1/foo")
        self.expectSucceedSubmit("Adding one file should not fail", "foo")

        self.addFile("bar/bar/bar2/foo")
        self.expectSucceedSubmit("Adding file with different name should not fail", "foo")

        self.addFile("bar/bar/bar3/foo")
        self.expectSucceedSubmit("Adding file with different name should not fail", "foo")

        self.addFile("bar/bar/bar4/Foo")
        self.expectSucceedSubmit("Adding file with different name should not fail", "Foo")

        self.addFile("bar/bar/bar1/Foo")
        self.expectFailSubmit("Adding file that differs by case should fail", "Foo")

    def testDirectoryFail_6(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Single file in unique directories; Two levels
        self.addFile("case_test/1_lowercase.text")
        self.expectSucceedSubmit("Adding one file should not fail", "foo")

        self.addFile("case_tesT/1_lowercase.text")
        self.addFile("case_tEst/1_lowercase.text")
        self.addFile("case_Test/1_lowercase.text")
        self.addFile("case_TEst/1_lowercase.text")
        self.addFile("casE_test/1_lowercase.text")
        self.addFile("cAse_test/1_lowercase.text")
        self.expectFailSubmit("Directories differ only by case", "case_test")

    def testDirectoryFail_7(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Unique files in single directory; Two levels.
        self.addFile("case_test/1_lowercase.text")
        self.expectSucceedSubmit("Adding one file should not fail", "foo")

        self.addFile("cAse_test/1_lowercase.text")
        self.addFile("cAse_test/10_lowercase.text")
        self.addFile("cAse_test/100_lowercase.text")
        self.addFile("cAse_test/1000_lowercase.text")
        self.addFile("cAse_test/10000_lowercase.text")
        self.expectFailSubmit("Directories differ only by case", "case_test")

    def testDirectoryFail_8(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Multiple files; Three levels.
        self.addFile("A/case_test/1_lowercase.text")
        self.addFile("A/case_test/10_lowercase.text")
        self.addFile("A/case_test/100_lowercase.text")
        self.addFile("A/case_test/1000_lowercase.text")
        self.addFile("A/case_test/10000_lowercase.text")
        self.expectSucceedSubmit("Adding files in A/case_test should not fail", "foo")

        # self.p4.run_sync("@0")
        self.addFile("A/cAse_test/1_lowercase.text")
        self.addFile("A/cAse_test/10_lowercase.text")
        self.addFile("A/cAse_test/100_lowercase.text")
        self.addFile("A/cAse_test/1000_lowercase.text")
        self.addFile("A/cAse_test/10000_lowercase.text")
        self.expectFailSubmit("A/case_test & A/cAse_test differ only by case", "case_test")

    def testDirectoryFail_9(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Multiple files; Three levels.
        self.addFile("A/case_test/1_lowercase.text")
        self.addFile("A/case_test/10_lowercase.text")
        self.addFile("A/case_test/100_lowercase.text")
        self.addFile("A/case_test/1000_lowercase.text")
        self.addFile("A/case_test/10000_lowercase.text")
        self.expectSucceedSubmit("Adding files in A/case_test should not fail", "foo")

        self.addFile("A/B/case_test/1_lowercase.text")
        self.addFile("A/B/case_test/10_lowercase.text")
        self.addFile("A/B/case_test/100_lowercase.text")
        self.addFile("A/B/case_test/1000_lowercase.text")
        self.addFile("A/B/case_test/10000_lowercase.text")
        self.expectSucceedSubmit("Adding files in A/B/case_test should not fail", "foo")

        self.addFile("A/cAse_test/1_lowercase.text")
        self.addFile("A/cAse_test/10_lowercase.text")
        self.addFile("A/cAse_test/100_lowercase.text")
        self.addFile("A/cAse_test/1000_lowercase.text")
        self.addFile("A/cAse_test/10000_lowercase.text")

        self.addFile("A/B/cAse_test/1_lowercase.text")
        self.addFile("A/B/cAse_test/10_lowercase.text")
        self.addFile("A/B/cAse_test/100_lowercase.text")
        self.addFile("A/B/cAse_test/1000_lowercase.text")
        self.addFile("A/B/cAse_test/10000_lowercase.text")
        self.expectFailSubmit("A/B/case_test & A/B/cAse_test differ only by case", "case_test")

    def testDirectoryFail_10(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Multiple files; Three levels; Differ at every level.
        self.addFile("A/B/case_test/1_lowercase.text")
        self.addFile("A/B/case_test/10_lowercase.text")
        self.addFile("A/B/case_test/100_lowercase.text")
        self.addFile("A/B/case_test/1000_lowercase.text")
        self.addFile("A/B/case_test/10000_lowercase.text")
        self.expectSucceedSubmit("Adding files in A/case_test should not fail", "foo")

        # Adds differ only by case at every level.
        self.addFile("a/b/cAse_test/1_Lowercase.text")
        self.addFile("a/b/cAse_test/10_Lowercase.text")
        self.addFile("a/b/cAse_test/100_Lowercase.text")
        self.addFile("a/b/cAse_test/1000_Lowercase.text")
        self.addFile("a/b/cAse_test/10000_Lowercase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "a/b/cAse_test")

    def testDirectoryFail_11(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # One file at each level; Three levels; Differ at every level.
        self.addFile("A/1_lowercase.text")
        self.addFile("A/B/1_lowercase.text")
        self.addFile("A/B/case_test/1_lowercase.text")
        self.expectSucceedSubmit("Adding unique files should not fail", "A/B/case_test")

        # Adds differ only by case at every level.
        self.addFile("a/1_lowerCase.text")
        self.addFile("a/b/1_lowerCase.text")
        self.addFile("a/b/cAse_test/1_lowerCase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "a/b/cAse_test")

    def testDirectoryFail_12(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Two files at each level; Three levels; Differ at every level.
        self.addFile("A/1_lowercase.text")
        self.addFile("A/10_lowercase.text")
        self.addFile("A/B/1_lowercase.text")
        self.addFile("A/B/10_lowercase.text")
        self.addFile("A/B/case_test/1_lowercase.text")
        self.addFile("A/B/case_test/10_lowercase.text")
        self.expectSucceedSubmit("Adding unique files should not fail", "A/B/case_test")

        # Adds differ only by case at every level.
        self.addFile("a/1_lowerCase.text")
        self.addFile("a/10_lowerCase.text")
        self.addFile("a/b/1_lowerCase.text")
        self.addFile("a/b/10_lowerCase.text")
        self.addFile("a/b/cAse_test/1_lowerCase.text")
        self.addFile("a/b/cAse_test/10_lowerCase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "a/b/cAse_test")

    def testDirectoryFail_13(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Two files at each level; Four levels; Differ at every level.
        self.addFile("A/1_lowercase.text")
        self.addFile("A/10_lowercase.text")
        self.addFile("A/B/1_lowercase.text")
        self.addFile("A/B/10_lowercase.text")
        self.addFile("A/B/case_test/1_lowercase.text")
        self.addFile("A/B/case_test/10_lowercase.text")
        self.expectSucceedSubmit("Adding unique files should not fail", "A/B/case_test")

        # Unique adds.
        self.addFile("A/2_lowercase.text")
        self.addFile("A/20_lowercase.text")
        self.addFile("A/B/2_lowercase.text")
        self.addFile("A/B/20_lowercase.text")
        self.addFile("A/B/case_test/2_lowercase.text")
        self.addFile("A/B/case_test/20_lowercase.text")
        self.expectSucceedSubmit("Adding unique files should not fail", "A/B/case_test")

        # Some adds differ by case only at first level.
        self.addFile("A/B/case_test/3_lowercase.text")
        self.addFile("a/B/case_test/30_lowercase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "A/B/case_test")

        # Some adds differ by case only at second level.
        self.addFile("A/B/case_test/4_lowercase.text")
        self.addFile("A/b/case_test/40_lowerCase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "A/B/case_test")

        # Some adds differ by case only at third level.
        self.addFile("A/B/case_test/5_lowercase.text")
        self.addFile("A/B/Case_test/50_lowerCase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "A/B/case_test")

        self.addFile("A/B/case_test/6_lowercase.text")
        self.addFile("A/B/case_test/20_lowerCASE.text")
        self.expectFailSubmit("Should not add files that differ only by case", "A/B/case_test")

        # Adds differ by case-only at every level
        self.addFile("a/2_lowerCase.text")
        self.addFile("a/20_lowerCase.text")
        self.addFile("a/b/2_lowerCase.text")
        self.addFile("a/b/20_lowerCase.text")
        self.addFile("a/b/case_Test/2_lowerCase.text")
        self.addFile("a/b/case_Test/20_lowerCase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "A/B/case_test")

class TestCheckCaseTrigger(TestCase):

    def __init__(self, methodName='runTest'):
        super(TestCheckCaseTrigger, self).__init__(LOGGER_NAME, LOG_FILE, methodName=methodName)

    def setUp(self):
        # Set up server as case-sensitive (default) or using argv argument.
        self.server = P4Server(case_sensitive_flag=case_sensitive)
        trigpath = os.path.join(parent_dir, "CheckCaseTrigger.py")
        p4 = self.server.p4
        self.client_root = self.server.client_root
        self.p4 = p4
        p4.logger = self.logger
        # This works if no spaces in server root pathname!
        port = p4.port.replace('"', '')
        self.logger.debug("port: |%s|" % port)
        triggers = p4.fetch_triggers()
        triggers['Triggers'] = ['CheckCase change-submit //... " {} {} -p %quote%{}%quote% '
                                '-u {} -v DEBUG %change% "'.format(pythonVer, trigpath, port, p4.user)]
        self.logger.debug(triggers)
        p4.save_triggers(triggers)
        # Reconnect to pick up changes
        p4.disconnect()
        p4.connect()
        # Reset client to include depot in RHS
        client = self.p4.fetch_client(self.server.client_name)
        client._view = "//%s/... //%s/%s/..." % (default_depot, self.server.client_name, default_depot)
        p4.save_client(client)

    def tearDown(self):
        if self.p4.connected():
            self.p4.disconnect()
        time.sleep(1)
        # self.server.cleanupTestTree()

    def localFile(self, name):
        return os.path.join(self.client_root, default_depot, name)

    def addFile(self, name, depot=default_depot):
        makedirs(os.path.join(self.client_root, depot), exist_ok=True)
        path, filename = os.path.split(name)
        if path:
            pname = os.path.join(self.client_root, depot, path)
            makedirs(pname, exist_ok=True)
        fname = os.path.join(self.client_root, depot, name)
        with open(fname, "w") as f:
            f.write("Content")
        self.p4.run_add(fname)

    def _doSubmit(self, msg, *args):
        """Submits the changes"""
        try:
            result = self.p4.save_submit(*args)
            self.assertTrue('submittedChange' in result[-1], msg)
        except P4.P4Exception as inst:
            self.fail("submit failed with exception ")

    def createFiles(self, testDir, depot=default_depot):
        testAbsoluteDir = os.path.join(self.client_root, depot, testDir)
        makedirs(testAbsoluteDir)
        # create a bunch of files
        files = ('foo.txt', 'bar.txt', 'baz.txt')
        for file in files:
            fname = os.path.join(testAbsoluteDir, file)
            f = open(fname, "w")
            f.write("Test Text")
            f.close()
            self.p4.run_add(fname)

        if depot == default_depot:
            self.assertEqual(len(self.p4.run_opened()), len(files), "Unexpected number of open files")
        return files

    def expectFailSubmit(self, msg, desc):
        """Submits the changes, but expects to fail the trigger"""
        try:
            result = self.p4.run_submit("-d", desc)
            self.fail(msg)
        except P4.P4Exception as inst:
            pass # expected

    def expectSucceedSubmit(self, msg, desc):
        """Submits the change, but expects to succeed"""
        change = self.p4.fetch_change()
        change._description = desc
        self._doSubmit(msg, change)

    def createDepot(self, depot):
        """Creates specified depot and add to client view - for multi depot tests"""
        d = self.p4.fetch_depot(depot)
        self.p4.save_depot(d)
        
        client = self.p4.fetch_client(self.server.client_name)
        client._view = [
            "//%s/... //%s/%s/..." % (default_depot, self.server.client_name, default_depot),
            "//%s/... //%s/%s/..." % (depot, self.server.client_name, depot)
        ]
        self.p4.save_client(client)

    @connect
    def testSimpleSubmit(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.assertEqual(len(self.p4.run_opened()), 0, "Shouldn't have open files")

        testDir = 'test_files'
        self.createFiles(testDir)
        self.expectSucceedSubmit("Failed to submit the add", "My Add Test")


    @connect
    def testSimpleEdit(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.assertEqual(len(self.p4.run_opened()), 0, "Shouldn't have open files")

        testDir = 'test_files'
        self.createFiles(testDir)
        self.expectSucceedSubmit("Failed to submit the add", "My Add Test")

        self.p4.run_edit("//depot/test_files/bar.txt")
        self.expectSucceedSubmit("Failed to submit the edit ", "My Edit Test")

        # self.p4.run_populate("//depot/test_files/...", "//depot/test_files2/...")
        # self.expectSucceedSubmit("Failed to submit the populate", "My Populate Test")

    @connect
    def testSimpleSubmitMD(self):
        # Submit with multiple depots
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.assertEqual(len(self.p4.run_opened()), 0, "Shouldn't have open files")

        depot = "depot2"
        self.createDepot(depot)
        testDir = 'test_files'

        self.createFiles(testDir)
        self.createFiles(testDir, depot=depot)
        self.expectSucceedSubmit("Failed to submit the add", "My Add Test")

        depot = "Depot3"
        self.createDepot(depot)
        testDir = 'test_files2'
        self.createFiles(testDir, depot=depot)
        self.expectSucceedSubmit("Failed to submit the add", "My Add Test")

    @connect
    def testSimpleFail(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("foo")
        self.expectSucceedSubmit("Adding one file should not fail", "Simple Add")

        self.p4.run_sync("@0")
        self.addFile("Foo")
        self.expectFailSubmit("Did not catch foo != Foo", "Foo")

    @connect
    def testSimpleFailMD(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        depot2 = "depot2"
        self.createDepot(depot2)
        self.addFile("foo")
        self.addFile("foo", depot=depot2)
        self.expectSucceedSubmit("Adding one file per depot should not fail", "Simple Add")

        self.p4.run_sync("@0")
        self.addFile("Foo")
        self.addFile("Foo", depot=depot2)
        self.expectFailSubmit("Did not catch foo != Foo", "Foo")

    @connect
    def testP4Files(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Test whether p4 files -i ignores case of file string.
        self.addFile("A/case_test/1_lowercase.text")
        self.addFile("A/case_test/10_lowercase.text")
        self.addFile("A/case_test/100_lowercase.text")
        self.addFile("A/case_test/1000_lowercase.text")
        self.addFile("A/case_test/10000_lowercase.text")
        self.addFile("A/B/case_test/1_lowercase.text")
        self.addFile("A/B/case_test/10_lowercase.text")
        self.addFile("A/B/case_test/100_lowercase.text")
        self.addFile("A/B/case_test/1000_lowercase.text")
        self.addFile("A/B/case_test/10000_lowercase.text")
        self.expectSucceedSubmit("Adding files in A/case_test & A/B/case_test should not fail", "foo")

        # p4 files with -i option should ignore case of file string on case-sensitive server.
        self.assertEqual(len(self.p4.run_files("-i", "//depot/a/...")), 10, "Should return 10 files")

    @connect
    def testCaseInsensitive(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Test whether p4 files -i ignores case of file string.
        self.addFile("A/CASE_TEST/FOO1.TXT")
        self.expectSucceedSubmit("Adding unique files should not fail", "A/CASE_TEST")

        if not case_sensitive:
            return

        # Case Variant Adds Should Fail on either case-sensitive or case-insensitive server.
        # NOTE: For case-insensitive server use case_sensitive=False command-line argument.
        # For case-insensitive server, the duplication is caught in the p4 submit command
        # and the file removed from the changelist.
        self.addFile("a/case_test/foo1.txt")
        self.expectFailSubmit("Should not be able to add case-variant files", "a/case_test")

    @connect
    def testDirectoryFail(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("foo/bar")
        self.expectSucceedSubmit("Adding one file should not fail", "Simple Add")

        self.p4.run_sync("@0")
        self.addFile("FOO/bar")
        self.expectFailSubmit("Did not catch foo != FOO/bar", "bar")

    @connect
    def testDirectoryFail_2(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("foo/bar/bar2")
        self.expectSucceedSubmit("Adding one file should not fail", "Simple Add")

        self.p4.run_sync("@0")
        self.addFile("FOO/bar2")
        self.expectFailSubmit("Did not catch foo/bar/bar2 != FOO/bar2", "bar")

        self.addFile("FOO/bar/bar")
        self.expectFailSubmit("Did not catch foo/bar/bar2 != FOO/bar/bar", "bar")

        self.addFile("FOO/bar/bar2")
        self.expectFailSubmit("Did not catch foo/bar/bar2 != FOO/bar/bar2", "bar")

        if case_sensitive:
            self.addFile("FOO/BAR")
            self.expectFailSubmit("Did not catch foo/bar/bar2 != FOO/BAR", "bar")

            self.addFile("foo/BAR/bar")
            self.expectFailSubmit("Did not catch foo/bar/bar2 != foo/BAR/bar", "bar")

            self.addFile("foo/bar/BAR")
            self.expectSucceedSubmit("Should be able to add both foo/bar/bar2 & foo/bar/BAR", "bar")

    @connect
    def testDirectoryFail_3(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("foo/bar")
        self.expectSucceedSubmit("Adding one file should not fail", "Simple Add")

        self.p4.run_sync("@0")
        self.addFile("foo/bar/BAR/bar2")
        # Can't have file and directory with the same name.
        self.expectFailSubmit("Can't have file bar and directory bar", "bar")

    @connect
    def testDirectoryFail_4(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("bar/bar/bar/foo1")
        self.expectSucceedSubmit("Adding one file should not fail", "Simple Add")

        self.p4.run_sync("@0")
        self.addFile("bar/bar/bar/foo2")
        self.expectSucceedSubmit("Adding file with different name should not fail", "foo2")

        self.p4.run_sync("@0")
        self.addFile("bar/bar/bar/foo3")
        self.expectSucceedSubmit("Adding file with different name should not fail", "foo3")

        self.p4.run_sync("@0")
        self.addFile("bar/bar/bar/FOO2")
        self.expectFailSubmit("Adding file that differs by case should fail", "FOO2")

    @connect
    def testDirectoryFail_5(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("bar/bar/bar1/foo")
        self.expectSucceedSubmit("Adding one file should not fail", "foo")

        self.p4.run_sync("@0")
        self.addFile("bar/bar/bar2/foo")
        self.expectSucceedSubmit("Adding file with different name should not fail", "foo")

        self.p4.run_sync("@0")
        self.addFile("bar/bar/bar3/foo")
        self.expectSucceedSubmit("Adding file with different name should not fail", "foo")

        self.p4.run_sync("@0")
        self.addFile("bar/bar/bar4/Foo")
        self.expectSucceedSubmit("Adding file with different name should not fail", "Foo")

        self.p4.run_sync("@0")
        self.addFile("bar/bar/bar1/Foo")
        self.expectFailSubmit("Adding file that differs by case should fail", "Foo")

    @connect
    def testDirectoryFail_6(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Single file in unique directories; Two levels
        self.addFile("case_test/1_lowercase.text")
        self.expectSucceedSubmit("Adding one file should not fail", "foo")

        self.p4.run_sync("@0")
        if not case_sensitive:
            self.addFile("case_tesT/1_lowercase1.text")
        else:
            self.addFile("case_tesT/1_lowercase.text")
            self.addFile("case_tEst/1_lowercase.text")
            self.addFile("case_Test/1_lowercase.text")
            self.addFile("case_TEst/1_lowercase.text")
            self.addFile("casE_test/1_lowercase.text")
            self.addFile("cAse_test/1_lowercase.text")
        self.expectFailSubmit("Directories differ only by case", "case_test")

    @connect
    def testDirectoryFail_7(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Unique files in single directory; Two levels.
        self.addFile("case_test/1_lowercase.text")
        self.expectSucceedSubmit("Adding one file should not fail", "foo")

        if case_sensitive:
            self.addFile("cAse_test/1_lowercase.text")
        self.addFile("cAse_test/10_lowercase.text")
        self.addFile("cAse_test/10_lowercase.text")
        self.addFile("cAse_test/100_lowercase.text")
        self.addFile("cAse_test/1000_lowercase.text")
        self.addFile("cAse_test/10000_lowercase.text")
        self.expectFailSubmit("Directories differ only by case", "case_test")

    @connect
    def testDirectoryFail_8(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Multiple files; Three levels.
        self.addFile("A/case_test/1_lowercase.text")
        self.addFile("A/case_test/10_lowercase.text")
        self.addFile("A/case_test/100_lowercase.text")
        self.addFile("A/case_test/1000_lowercase.text")
        self.addFile("A/case_test/10000_lowercase.text")
        self.expectSucceedSubmit("Adding files in A/case_test should not fail", "foo")

        # self.p4.run_sync("@0")
        if not case_sensitive:
            self.addFile("A/cAse_test/1_lowercase1.text")
            self.addFile("A/cAse_test/10_lowercase1.text")
            self.addFile("A/cAse_test/100_lowercase1.text")
            self.addFile("A/cAse_test/1000_lowercase1.text")
            self.addFile("A/cAse_test/10000_lowercase1.text")
        else:
            self.addFile("A/cAse_test/1_lowercase.text")
            self.addFile("A/cAse_test/10_lowercase.text")
            self.addFile("A/cAse_test/100_lowercase.text")
            self.addFile("A/cAse_test/1000_lowercase.text")
            self.addFile("A/cAse_test/10000_lowercase.text")
        self.expectFailSubmit("A/case_test & A/cAse_test differ only by case", "case_test")

    @connect
    def testDirectoryFail_9(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Multiple files; Three levels.
        self.addFile("A/case_test/1_lowercase.text")
        self.addFile("A/case_test/10_lowercase.text")
        self.addFile("A/case_test/100_lowercase.text")
        self.addFile("A/case_test/1000_lowercase.text")
        self.addFile("A/case_test/10000_lowercase.text")
        self.expectSucceedSubmit("Adding files in A/case_test should not fail", "foo")

        self.addFile("A/B/case_test/1_lowercase.text")
        self.addFile("A/B/case_test/10_lowercase.text")
        self.addFile("A/B/case_test/100_lowercase.text")
        self.addFile("A/B/case_test/1000_lowercase.text")
        self.addFile("A/B/case_test/10000_lowercase.text")
        self.expectSucceedSubmit("Adding files in A/B/case_test should not fail", "foo")

        if not case_sensitive:
            self.addFile("A/cAse_test/1_lowercase1.text")
            self.addFile("A/B/cAse_test/1_lowercase1.text")
        else:
            self.addFile("A/cAse_test/1_lowercase.text")
            self.addFile("A/cAse_test/10_lowercase.text")
            self.addFile("A/cAse_test/100_lowercase.text")
            self.addFile("A/cAse_test/1000_lowercase.text")
            self.addFile("A/cAse_test/10000_lowercase.text")

            self.addFile("A/B/cAse_test/1_lowercase.text")
            self.addFile("A/B/cAse_test/10_lowercase.text")
            self.addFile("A/B/cAse_test/100_lowercase.text")
            self.addFile("A/B/cAse_test/1000_lowercase.text")
            self.addFile("A/B/cAse_test/10000_lowercase.text")
        self.expectFailSubmit("A/B/case_test & A/B/cAse_test differ only by case", "case_test")

    @connect
    def testDirectoryFail_10(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Multiple files; Three levels; Differ at every level.
        self.addFile("A/B/case_test/1_lowercase.text")
        self.addFile("A/B/case_test/10_lowercase.text")
        self.addFile("A/B/case_test/100_lowercase.text")
        self.addFile("A/B/case_test/1000_lowercase.text")
        self.addFile("A/B/case_test/10000_lowercase.text")
        self.expectSucceedSubmit("Adding files in A/case_test should not fail", "foo")

        # Adds differ only by case at every level.
        if not case_sensitive:
            self.addFile("a/b/cAse_test/1_Lowercase1.text")
        else:
            self.addFile("a/b/cAse_test/1_Lowercase.text")
            self.addFile("a/b/cAse_test/10_Lowercase.text")
            self.addFile("a/b/cAse_test/100_Lowercase.text")
            self.addFile("a/b/cAse_test/1000_Lowercase.text")
            self.addFile("a/b/cAse_test/10000_Lowercase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "a/b/cAse_test")

    @connect
    def testDirectoryFail_11(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # One file at each level; Three levels; Differ at every level.
        self.addFile("A/1_lowercase.text")
        self.addFile("A/B/1_lowercase.text")
        self.addFile("A/B/case_test/1_lowercase.text")
        self.expectSucceedSubmit("Adding unique files should not fail", "A/B/case_test")

        # Adds differ only by case at every level.
        if not case_sensitive:
            self.addFile("a/1_lowerCase1.text")
            self.addFile("a/b/1_lowerCase1.text")
            self.addFile("a/b/cAse_test/1_lowerCase1.text")
        else:
            self.addFile("a/1_lowerCase.text")
            self.addFile("a/b/1_lowerCase.text")
            self.addFile("a/b/cAse_test/1_lowerCase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "a/b/cAse_test")

    @connect
    @unittest.skipUnless(sys.platform.startswith("linux"), "requires linux")
    def testDirectoryFail_12(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Two files at each level; Three levels; Differ at every level.
        self.addFile("A/1_lowercase.text")
        self.addFile("A/10_lowercase.text")
        self.addFile("A/B/1_lowercase.text")
        self.addFile("A/B/10_lowercase.text")
        self.addFile("A/B/case_test/1_lowercase.text")
        self.addFile("A/B/case_test/10_lowercase.text")
        self.expectSucceedSubmit("Adding unique files should not fail", "A/B/case_test")

        # Adds differ only by case at every level.
        self.addFile("a/1_lowerCase.text")
        self.addFile("a/10_lowerCase.text")
        self.addFile("a/b/1_lowerCase.text")
        self.addFile("a/b/10_lowerCase.text")
        self.addFile("a/b/cAse_test/1_lowerCase.text")
        self.addFile("a/b/cAse_test/10_lowerCase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "a/b/cAse_test")

    @connect
    def testDirectoryFail_13(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # Two files at each level; Four levels; Differ at every level.
        self.addFile("A/1_lowercase.text")
        self.addFile("A/10_lowercase.text")
        self.addFile("A/B/1_lowercase.text")
        self.addFile("A/B/10_lowercase.text")
        self.addFile("A/B/case_test/1_lowercase.text")
        self.addFile("A/B/case_test/10_lowercase.text")
        self.expectSucceedSubmit("Adding unique files should not fail", "A/B/case_test")

        # Unique adds.
        self.addFile("A/2_lowercase.text")
        self.addFile("A/20_lowercase.text")
        self.addFile("A/B/2_lowercase.text")
        self.addFile("A/B/20_lowercase.text")
        self.addFile("A/B/case_test/2_lowercase.text")
        self.addFile("A/B/case_test/20_lowercase.text")
        self.expectSucceedSubmit("Adding unique files should not fail", "A/B/case_test")

        # Some adds differ by case only at first level.
        self.addFile("A/B/case_test/3_lowercase.text")
        self.addFile("a/B/case_test/30_lowercase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "A/B/case_test")

        # Some adds differ by case only at second level.
        self.addFile("A/B/case_test/4_lowercase.text")
        self.addFile("A/b/case_test/40_lowerCase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "A/B/case_test")

        # Some adds differ by case only at third level.
        self.addFile("A/B/case_test/5_lowercase.text")
        self.addFile("A/B/Case_test/50_lowerCase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "A/B/case_test")

        # Some adds differ by case only at fourth level.
        if case_sensitive:
            self.addFile("A/B/case_test/6_lowercase.text")
            self.addFile("A/B/case_test/20_lowerCASE.text")
            self.expectFailSubmit("Should not add files that differ only by case", "A/B/case_test")
        else:
            self.p4.run_sync("@0")

        # Adds differ by case-only at every level
        self.addFile("a/2_lowerCase.text")
        self.addFile("a/20_lowerCase.text")
        self.addFile("a/b/2_lowerCase.text")
        self.addFile("a/b/20_lowerCase.text")
        self.addFile("a/b/case_Test/2_lowerCase.text")
        self.addFile("a/b/case_Test/20_lowerCase.text")
        self.expectFailSubmit("Should not add files that differ only by case", "A/B/case_test")


    @connect
    def testRenameFile(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("foo")
        self.expectSucceedSubmit("Adding one file should not fail", "Simple Add")

        self.p4.run_edit(self.localFile("foo"))
        self.p4.run_move(self.localFile("foo"), self.localFile("bar"))
        self.expectSucceedSubmit("Renaming a file should not fail", "Simple Move")

    @connect
    @unittest.skipUnless(sys.platform.startswith("linux"), "requires linux")
    def testRenameFail(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("foo")
        self.addFile("bar")
        self.expectSucceedSubmit("Adding two files should not fail", "Double Add")
        if case_sensitive:
            self.p4.run_sync("%s@0" % self.localFile("bar"))
            self.p4.run_edit(self.localFile("foo"))
            self.p4.run_move(self.localFile("foo"), self.localFile("BAR"))
            self.p4.run_move(self.localFile("foo"), self.localFile("bar"))
            self.expectFailSubmit("Moving into a file with existing naming conflict should not succeed", "Illegal move")

    @connect
    def testDirectoryConflictFail(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("foo")
        self.expectSucceedSubmit("Adding single file should not fail", "Simple Add")

        self.p4.run_sync("@0")
        # self.logger.debug("testDirectoryConflictFail1: dirs= %s", self.p4.run_dirs("//depot/*"))
        # self.logger.debug("testDirectoryConflictFail1: files= %s", self.p4.run_files("//depot/..."))
        self.addFile("FOO/bar")
        self.expectFailSubmit("Adding a directory conflicting with an existing file should not succeed", "Illegal add")

    @connect
    def testMultipleLevelWildcardFail(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        # 9 *'s
        self.addFile("1/2/3/4/5/6/7/8/9/foo9.txt")
        self.expectSucceedSubmit("Adding single file should not fail", "1/2/3/4/5/6/7/8/9/foo9.txt")

        self.p4.run_sync("@0")
        # 9 *'s + 2 *
        self.addFile("1/2/3/4/5/6/7/8/9/10/foo10.txt")
        self.expectSucceedSubmit("Adding single file should not fail", "1/2/3/4/5/6/7/8/9/10/foo10.txt")

        self.p4.run_sync("@0")
        # 18 *'s
        self.addFile("1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/foo18.txt")
        self.expectSucceedSubmit("Adding single file should not fail", "1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/foo18.txt")

        self.p4.run_sync("@0")
        # 18 *'s + 2 *
        self.addFile("1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/foo19.txt")
        self.expectSucceedSubmit("Adding single file should not fail", "1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/foo19.txt")

        self.p4.run_sync("@0")
        # Add file that only differs by case.
        self.addFile("1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/FOO19.txt")
        self.expectFailSubmit("Adding a file conflicting with an existing file should not succeed", "Illegal add")

    @connect
    def testFileWithDirectoryConflictFail(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.logger.debug("testFileWithDirectoryConflict: dirs= %s", self.p4.run_dirs("//depot/*"))

        self.addFile("FOO/bar")
        self.expectSucceedSubmit("Adding single file should not fail", "Simple Add")

        self.p4.run_sync("@0")
        os.rmdir(os.path.join(self.client_root, default_depot, "FOO"))
        self.addFile("foo")
        self.expectFailSubmit("Adding a file conflicting with an existing directory should not succeed", "Illegal add")

    @connect
    @unittest.skipUnless(sys.platform.startswith("linux"), "requires linux")
    def testFileWithDirectorySameChangeFail(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        self.addFile("FOO/bar")
        self.addFile("foo")
        self.expectFailSubmit("Adding a file conflicting with an existing directory should not succeed", "Illegal add")

    @connect
    @unittest.skipUnless(sys.platform.startswith("linux"), "requires linux")
    def testMultipleFilesFail(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        if case_sensitive:
            self.addFile("foo")
            self.addFile("FOO")
            self.expectFailSubmit("Adding two conflicting files should not succeed", "Illegal add")

    @connect
    @unittest.skipUnless(sys.platform.startswith("linux"), "requires linux")
    def testMultipleDirectoriesFail(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        if case_sensitive:
            self.addFile("foo/foo")
            self.addFile("FOO/foo")
            self.expectFailSubmit("Adding two conflicting directories should not succeed", "Illegal add")

    @connect
    @unittest.skipUnless(sys.platform.startswith("linux"), "requires linux")
    def testMessageFail(self):
        self.logger.debug("================ %s" % inspect.stack()[0][3])
        if case_sensitive:
            self.addFile("foo")
            self.addFile("Foo")

            try:
                self.p4.run_submit('-d','Expect to fail')
                self.fail("Illegal add did not cause exception")
            except P4.P4Exception as exc:
                error = exc.errors[0]
                self.logger.debug("testMessageFail: error = %s", error)
                self.assertTrue('//depot/foo' in error)
                self.assertTrue('//depot/Foo' in error)


if __name__ == '__main__':

    # Determine if we're testing on a case-sensitive or case-insensitive server.
    kwargs = {}
    for arg in sys.argv[1:]:
        p = arg.split("=", 1)
        if len(p) != 1:
            kwargs[p[0]] = p[1]

    # print("kwargs: %s" % kwargs)

    # case_sensitive is initialized to True
    # Note: Need to remove 'case_sensitive' after test as it's not a valid unittest argument.
    if 'case_sensitive' in kwargs:
        if kwargs['case_sensitive'] == 'False':
            case_sensitive = False
        sys.argv.pop()

    # print("case_sensitive: = %s" % case_sensitive)
    # print("cmd_entry2: %s" % sys.argv)


    unittest.main()
