#
# Copyright (c) SAS Institute Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


from testrunner import testhelp
import os
import signal
import stat
import StringIO
import tempfile
import time
import zlib
import base64
import subprocess
from conary.lib import util
from conary.lib.ext import file_utils
from conary_test import resources


class UtilTest(testhelp.TestCase):
    def testBraceGlob(self):
        d = tempfile.mkdtemp()
        expected = []
        for sub in ('foo', 'fred'):
            subdir = os.sep.join((d, sub))
            os.mkdir(subdir)
            path = os.sep.join((subdir, 'bar'))
            expected.append(path)
            f = open(path, 'w')
            f.write('hello\n')
            f.close()
        f = open(os.sep.join((d, 'file')), 'w')
        f.write('hello\n')
        f.close()
        actual = util.braceGlob(os.sep.join((d, '*', 'bar')))
        expected.sort()
        actual.sort()
        if expected != actual:
            self.fail('glob did not yield expected results.  expected "%s" got "%s"', expected, actual)
        util.rmtree(d)

    def testBraceExpand(self):
        data = [
            ('', []),
            ('a', ['a']),
            ('{a}', ['{a}']),
            ('{{a}}', ['{{a}}']),
            ('{a,b}', ['a', 'b']),
            ('{a,{b,c}}', ['a', 'b', 'c']),
            ('{a,{{b,c},d}}', ['a', 'b', 'c', 'd']),
            ('{a{b,c}}', ['{ab}', '{ac}']),
            ('{a{b},c}', ['a{b}', 'c']),
            ('{{a,b}{c,d}}', ['{ac}', '{ad}', '{bc}', '{bd}']),
            ('{{a,b}{c,d},{e,f}{g,h}}',
                ['ac', 'ad', 'bc', 'bd', 'eg', 'eh', 'fg', 'fh',]),
            ('{,a}', ['a']),
            ('a{,b}', ['a', 'ab']),
            ('a{b,}', ['ab', 'a']),
            ('{a}{b}', ['{a}{b}']),
            ('{{ab,}}', ['{ab}', '{}']),
            ('{{a,}}', ['{a}', '{}']),
            ('abc', ['abc']),
            ('aa{bb,cc}dd', ['aabbdd', 'aaccdd']),
            ('aa{bb,cc}dd{e}', ['aabbdd{e}', 'aaccdd{e}']),
            ('{a,b}}', ['a}', 'b}']),
            ('{{a,b}', ['{a', '{b']),
            ('{{{a,b}', ['{{a', '{{b']),
            ('c{{{a,b}', ['c{{a', 'c{{b']),
            ('a{,{a,b}', ['a{,a', 'a{,b']),
            (r'\{a,b}', ['{a,b}']),
            (r'{a,b\}', ['{a,b}']),
            (r'{a,b\\}', ['a', 'b\\']),
            (r'{a\,b}', ['{a,b}']),
            (r'{a\\,b}', ['a\\', 'b']),
            (r'a\b', ['ab']),
            (r'{a\b}', ['{ab}']),
        ]
        for inString, expected in data:
            self.assertEqual(util.braceExpand(inString), expected)

        # This is so we have coverage for __repr__
        l = util.BraceExpander.Alternative(['a', 'b'])
        self.assertEqual(repr(l), "Alternative['a', 'b']")
        l = util.BraceExpander.Product(['a', 'b'])
        self.assertEqual(repr(l), "Product['a', 'b']")

    def testRmtree(self):
        # test that rmtree on a directory that doesn't exist fails
        d = tempfile.mkdtemp()
        os.rmdir(d)
        self.assertRaises(OSError, util.rmtree, d)
        
        # test that rmtree on a directory that does not exist does not
        # raise an error if ignore_errors is true
        d = tempfile.mkdtemp()
        os.rmdir(d)
        util.rmtree(d, ignore_errors=True)
        assert(not os.path.exists(d))

        # test that rmtree on a file works
        d = tempfile.mkdtemp()
        fn = os.sep.join((d, 'hello'))
        f = open(fn, 'w')
        f.write('hello')
        f.close()
        util.rmtree(fn)
        assert(not os.path.exists(fn) and os.path.isdir(d))

        # test that rmtree on a dangling symlink works
        d = tempfile.mkdtemp()
        fn = os.sep.join((d, 'dangle'))
        os.symlink('dangle', fn)
        util.rmtree(fn)
        assert(not os.path.exists(fn) and os.path.isdir(d))

        # test that rmtree works
        d = tempfile.mkdtemp()
        fn = os.sep.join((d, 'hello'))
        f = open(fn, 'w')
        f.write('hello')
        f.close()
        util.rmtree(d)
        assert(not os.path.exists(d))

    def testRemove(self):
        # test removing a file while keeping the subdir
        d = tempfile.mkdtemp()
        fn = os.sep.join((d, 'hello'))
        f = open(fn, 'w')
        f.write('hello')
        subdir = os.sep.join((d, 'subdir'))
        os.mkdir(subdir)
        self.logFilter.add()
        util.remove(os.sep.join((d, '*')))
        self.logFilter.remove()
        self.logFilter.compare(('warning: Not removing directory %s' %subdir))
        assert(not os.path.exists(fn) and os.path.isdir(subdir))
        util.rmtree(d)

    def testRemoveSymlinkToDir(self):
        # test removing a symlink to a dir -- it should not follow symlink
        # even when recursive = True
        d = tempfile.mkdtemp()
        fn = os.sep.join((d, 'hello'))
        f = open(fn, 'w')
        f.write('hello')
        subdir = os.sep.join((d, 'subdir'))
        os.mkdir(subdir)
        subdir2 = os.sep.join((d, 'subdir2'))
        os.mkdir(subdir2)
        os.symlink(subdir, subdir2 + '/symlink')
        util.rmtree(subdir2 + '/*')
        assert(os.path.exists(subdir))
        assert(os.path.exists(subdir2))
        assert(not os.path.exists(subdir2 + '/symlink'))
        os.symlink(subdir, subdir2 + '/symlink')
        util.remove(subdir2 + '/*')
        assert(os.path.exists(subdir))
        assert(os.path.exists(subdir2))
        assert(not os.path.exists(subdir2 + '/symlink'))
        util.rmtree(d)

    def testCopyTree(self):
        # test copying tree with different syntaxes

        d = tempfile.mkdtemp()
        subdir = os.sep.join((d, 'subdir'))
        os.mkdir(subdir)
        fn = os.sep.join((subdir, 'hello'))
        f = open(fn, 'w')
        f.write('hello')
        d2 = tempfile.mkdtemp()
        subdir2 = os.sep.join((d2, 'subdir'
))
        fn2 = os.sep.join((subdir2, 'hello'))
        util.copytree(subdir, d2)
        assert(os.path.isdir(subdir2) and os.path.exists(fn2))
        util.rmtree(subdir2)
        util.copytree(subdir + '/', d2)
        assert(os.path.isdir(subdir2) and os.path.exists(fn2))
        util.rmtree(d)

    def testTupleListBsearchInsert(self):
        def fn(a, b):
            if a[1] == b[1]:
                return 0
            elif a[1] < b[1]:
                return -1
            return 1

        # this runs all of the inserts twice to make sure duplicates don't
        # get added
        l = []

        util.tupleListBsearchInsert(l, ('v', 5), fn)
        assert(l == [('v', 5)])
        util.tupleListBsearchInsert(l, ('v', 5), fn)
        assert(l == [('v', 5)])

        util.tupleListBsearchInsert(l, ('e', 22), fn)
        assert(l == [('v', 5), ('e', 22)])
        util.tupleListBsearchInsert(l, ('e', 22), fn)
        assert(l == [('v', 5), ('e', 22)])

        util.tupleListBsearchInsert(l, ('b', 25), fn)
        assert(l == [('v', 5), ('e', 22), ('b', 25)])
        util.tupleListBsearchInsert(l, ('b', 25), fn)
        assert(l == [('v', 5), ('e', 22), ('b', 25)])

        util.tupleListBsearchInsert(l, ('y', 2), fn)
        assert(l == [('y', 2), ('v', 5), ('e', 22), ('b', 25)])
        util.tupleListBsearchInsert(l, ('y', 2), fn)
        assert(l == [('y', 2), ('v', 5), ('e', 22), ('b', 25)])

        util.tupleListBsearchInsert(l, ('g', 20), fn)
        assert(l == [('y', 2), ('v', 5), ('g', 20), ('e', 22), ('b', 25)])
        util.tupleListBsearchInsert(l, ('g', 20), fn)
        assert(l == [('y', 2), ('v', 5), ('g', 20), ('e', 22), ('b', 25)])

        util.tupleListBsearchInsert(l, ('t', 18), fn)
        assert(l == [('y', 2), ('v', 5), ('t', 18), ('g', 20), ('e', 22), ('b', 25)])
        util.tupleListBsearc