# Copyright (C) 2005 Canonical Limited
#   Authors: Robert Collins <robert.collins@canonical.com>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

from bzrlib.tests import TestCaseInTempDir, TestCase
from bzrlib import repository
from bzrlib.osutils import has_symlinks
try:
    import pybaz
except ImportError:
    pybaz = None
import os
try:
    from bzrtools import cmd_baz_import
    from bzrtools.baz_import import (import_version, revision_id,
                                      make_archive, map_file_id)
except ImportError:
    from bzrlib.plugins.bzrtools import cmd_baz_import 
    from bzrlib.plugins.bzrtools.baz_import import (import_version, 
                                                    revision_id,
                                                    make_archive,
                                                    map_file_id)
import shutil
from StringIO import StringIO
import tempfile
from testresources import (TestResource, TestLoader, OptimisingTestSuite,
                               ResourcedTestCase)
    
import bzrlib
from bzrlib.errors import NoSuchRevision
try:
    from bzrtools.fai import namespace_previous
except ImportError:
    from bzrlib.plugins.bzrtools.fai import namespace_previous
from bzrlib.branch import Branch

def test_suite():
    if pybaz is None:
        from unittest import TestSuite
        return TestSuite()
    return TestLoader().loadTestsFromName(__name__)
 

class BazTreeResource(TestResource):

    def cleanUp(self):
        os.environ['HOME'] = self._oldhome
        shutil.rmtree(self._tmpdir)

    def __init__(self):
        self._tmpdir = tempfile.mkdtemp()
        self._homedir = os.path.join(self._tmpdir, 'home')
        self._oldhome = os.environ['HOME']
        os.mkdir(self._homedir)
        os.environ['HOME'] = self._homedir

        self._archiveroot = os.path.join(self._tmpdir, 'archive')
        self._archive = make_archive('demo@DONOTUSE', str(self._archiveroot))
        pybaz.set_my_id("Test User<test@example.org>")

        self.make_empty_import()

        self._empty_tag = 'demo@DONOTUSE/c--empty-tag--0'
        self._empty_tag_bzr = revision_id(self._empty_tag + '--base-0')
        pybaz.Revision('demo@DONOTUSE/c--import--0--base-0').make_continuation(
            pybaz.Version(self._empty_tag))

        self._empty_merged_tag = 'demo@DONOTUSE/c--empty-merged-tag--0'
        self._empty_merged_tag_bzr_base = revision_id(self._empty_merged_tag 
                                                 + '--base-0')
        self._empty_merged_tag_bzr = revision_id(self._empty_merged_tag 
                                                 + '--patch-1')
        pybaz.Revision('demo@DONOTUSE/c--import--0--base-0').make_continuation(
            pybaz.Version(self._empty_merged_tag))
        tree = pybaz.Revision(self._empty_merged_tag + '--base-0').get(
            os.path.join(self._tmpdir, 'tree'))
        tree.star_merge(self._empty_tag,
                        pybaz.Version('demo@DONOTUSE/c--import--0'))
        msg = tree.log_message()
        msg["summary"]="did a merge, yarh"
        tree.commit(msg)
        shutil.rmtree(os.path.join(self._tmpdir, 'tree'))
        
        # tree, two commits, includes merge of other branch
        self._empty_merged_tag_2 = 'demo@DONOTUSE/c--empty-tag-2--0'
        self._empty_merged_tag_2_bzr_base = revision_id(
            self._empty_merged_tag_2 + '--base-0')
        self._empty_merged_tag_2_bzr = revision_id(
            self._empty_merged_tag_2 + '--patch-1')
        pybaz.Revision('demo@DONOTUSE/c--import--0--base-0').make_continuation(
            pybaz.Version(self._empty_merged_tag_2))
        tree = pybaz.Revision(self._empty_merged_tag_2 + '--base-0').get (
            os.path.join(self._tmpdir, 'tree'))
        tree.star_merge(self._empty_merged_tag,
                        pybaz.Version('demo@DONOTUSE/c--import--0'))
        msg = tree.log_message()
        msg["summary"] = "merge in a merged tree."
        tree.commit(msg)
        shutil.rmtree(os.path.join(self._tmpdir, 'tree'))

        self._bad_id_tag = 'demo@DONOTUSE/c--bad-id--0'
        self._bad_id_tag_bzr_base = revision_id(self._bad_id_tag + '--base-0')
        self._bad_id_tag_bzr = revision_id(self._bad_id_tag + '--patch-1')
        pybaz.Revision('demo@DONOTUSE/c--import--0--base-0').make_continuation(
            pybaz.Version(self._bad_id_tag))
        tree = pybaz.Revision(self._bad_id_tag + '--base-0').get(
            os.path.join(self._tmpdir, 'tree'))
        from bzrlib.plugins.bzrtools.baz_import import add_file
        add_file(os.path.join(self._tmpdir,'tree/path'), 'text', 
                 'this_id/needs%escaping')
        msg = tree.log_message()
        msg["summary"] = "commit something which needs escaping."
        tree.commit(msg)
        shutil.rmtree(os.path.join(self._tmpdir, 'tree'))

        self.make_import_symlink()
        self.make_missing_ancestor()
        self.make_inbranch_continuation()

    def make_import_symlink(self):
        self._import_symlink = 'demo@DONOTUSE/c--import-symlink--0'
        self._import_symlink_bzr = revision_id(
            self._import_symlink + '--base-0')
        os.mkdir(os.path.join(self._tmpdir, 'tree'))
        tree = pybaz.init_tree(os.path.join(self._tmpdir, 'tree'),
                               self._import_symlink)
        link_path = os.path.join(self._tmpdir, 'tree', 'alink')
        os.symlink('missing-file-name', link_path)
        tree.add_tag('alink')
        id_file = open(os.path.join(tree, '.arch-ids', 'alink.id'), 'w')
        id_file.write('symlink_tag\n')
        id_file.close()
        msg = tree.log_message()
        msg["summary"] = "Import with a symlink"
        tree.import_(msg)
        os.unlink(link_path)
        f = file(link_path, 'w')
        f.write('Not a symlink no more!')
        f.close()
        msg = tree.log_message()
        msg["summary"] = "Turn a symlink into a file"
        tree.commit(msg)
        shutil.rmtree(os.path.join(self._tmpdir, 'tree'))

    def make_empty_import(self):
        self._import = 'demo@DONOTUSE/c--import--0'
        os.mkdir(os.path.join(self._tmpdir, 'tree'))
        tree = pybaz.init_tree(os.path.join(self._tmpdir, 'tree'), 
                               self._import)
        msg = tree.log_message()
        msg["summary"] = "I am importing now"
        tree.import_(msg)
        shutil.rmtree(os.path.join(self._tmpdir, 'tree'))

    def make_missing_ancestor(self):
        self._archivegoneroot = os.path.join(self._tmpdir, 'archivegone')
        self._archive = make_archive('demo-gone@DONOTUSE',
                                     str(self._archivegoneroot))
        self._missing_import = 'demo-gone@DONOTUSE/c--import--0'
        self._missing_import_bzr = revision_id(self._missing_import 
                                                 + '--base-0')
        self._missing_ancestor = 'demo@DONOTUSE/c--gone--0'
        self._missing_ancestor_bzr = revision_id(self._missing_ancestor 
                                                 + '--base-0')
        os.mkdir(os.path.join(self._tmpdir, 'tree'))
        tree = pybaz.init_tree(os.path.join(self._tmpdir, 'tree'), 
                               self._missing_import)
        msg = tree.log_message()
        msg["summary"] = "I am importing now"
        tree.import_(msg)
        shutil.rmtree(os.path.join(self._tmpdir, 'tree'))
        # tag into the kept archive
        pybaz.Revision(self._missing_import + '--base-0').make_continuation(
            pybaz.Version(self._missing_ancestor))

        # make an import for testing history-reuse logic.
        # note the use of a namespace layout here.
        self._missing_import_imported = os.path.join(self._tmpdir, 
                                                     'archivegone-bzr')
        os.mkdir(os.path.join(self._tmpdir, 'archivegone-bzr'))
        os.mkdir(os.path.join(self._tmpdir, 'archivegone-bzr', 'c'))
        import_version(os.path.join(self._tmpdir, 'archivegone-bzr', 
                                    'c', 'import'),
                       pybaz.Version(self._missing_import))
        # and make it inaccessible
        pybaz.Archive('demo-gone@DONOTUSE').unregister()

    def make_inbranch_continuation(self):
        self._inbranch_tag = 'demo@DONOTUSE/c--inbranch-tag--0'
        self._inbranch_tag_base = self._inbranch_tag + '--base-0'
        self._inbranch_tag_base_bzr = revision_id(self._inbranch_tag_base)
        pybaz.Revision('demo@DONOTUSE/c--import--0--base-0').make_continuation(
            pybaz.Version(self._inbranch_tag))
        self._inbranch_tag_head = self._inbranch_tag + '--patch-1'
        self._inbranch_tag_head_bzr = revision_id(self._inbranch_tag_head)
        pybaz.Revision(self._inbranch_tag_base).make_continuation(
            pybaz.Version(self._inbranch_tag))

    @classmethod
    def _makeResource(self):
        return BazTreeResource()

    @classmethod
    def _cleanResource(self, resource):
        resource.cleanUp()


class TestImportBranch(TestCaseInTempDir):

    _resources = [("_baz", BazTreeResource)]

    def setUp(self):
        TestCaseInTempDir.setUp(self)
        ResourcedTestCase.setUpResources(self)
        os.environ['HOME'] = self._baz._homedir

    def tearDown(self):
        ResourcedTestCase.tearDownResources(self)
        TestCaseInTempDir.tearDown(self)
 
    def test_import_empty(self):
        import_version('output', pybaz.Version(self._baz._import))
        # expected results:
        # one commit, no files, revision identifier of 
        # 'demo@DONOTUSE_c--import--0--base-0'
        branch = Branch.open('output')
        repo = branch.repository
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0'])
        rev = repo.get_revision('Arch-1:demo@DONOTUSE%c--import--0--base-0')
        # and again.
        import_version('output2', pybaz.Version('demo@DONOTUSE/c--import--0'))
        branch2 = Branch.open('output2')
        repo2 = branch2.repository
        self.assertEqual(branch.revision_history(), branch2.revision_history())
        rev2 = repo2.get_revision('Arch-1:demo@DONOTUSE%c--import--0--base-0')
        # they must be the same
        self.assertEqual(rev, rev2)

        # and we should get some expected values:
        self.assertEqual(rev.committer, "Test User<test@example.org>")
        self.assertEqual(rev.message, "I am importing now")
        self.assertEqual(rev.revision_id,
                         "Arch-1:demo@DONOTUSE%c--import--0--base-0")

    def test_empty_tagged(self):
        import_version('output', pybaz.Version(self._baz._empty_tag))
        # expected results:
        # two commits, no files, revision identifiers of 
        # 'demo@DONOTUSE_c--import--0--base-0' and
        # self._baz._empty_tag_bzr
        branch = Branch.open('output')
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0',
                          self._baz._empty_tag_bzr])
        rev = branch.repository.get_revision(self._baz._empty_tag_bzr)
        # and again.
        import_version('output2', pybaz.Version(self._baz._empty_tag))
        branch2 = Branch.open('output2')
        self.assertEqual(branch.revision_history(), branch2.revision_history())
        rev2 = branch2.repository.get_revision(self._baz._empty_tag_bzr)
        # they must be the same
        self.assertEqual(rev, rev2)

        # and we should get some expected values:
        self.assertEqual(rev.committer, "Test User<test@example.org>")
        self.assertEqual(rev.message, 
                         "tag of demo@DONOTUSE/c--import--0--base-0")
        self.assertEqual(rev.revision_id, self._baz._empty_tag_bzr)

    def test_empty_merged_tagged(self):
        import_version('output', pybaz.Version(self._baz._empty_merged_tag))
        # expected results:
        # two commits, no files, revision identifiers of 
        # 'demo@DONOTUSE_c--import--0--base-0' and
        # self._baz._empty_merged_tag_bzr_base
        # self._baz._empty_merged_tag_bzr
        # and a merged revision from the latter of
        # self._baz._empty_tag_bzr
        branch = Branch.open('output')
        repo = branch.repository
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0',
                          self._baz._empty_merged_tag_bzr_base,
                          self._baz._empty_merged_tag_bzr])
        # and again.
        import_version('output2', pybaz.Version(self._baz._empty_merged_tag))
        branch2 = Branch.open('output2')
        repo2 = branch2.repository
        # and import what we should be merged up against for checking with.
        import_version('output3', pybaz.Version(self._baz._empty_tag))
        branch3 = Branch.open('output3')
        
        self.assertEqual(branch.revision_history(), branch2.revision_history())
        self.assertNotEqual(branch.revision_history(), 
                            branch3.revision_history())
        # check revisions in the history.
        rev = repo.get_revision(self._baz._empty_merged_tag_bzr_base)
        rev2 = repo2.get_revision(self._baz._empty_merged_tag_bzr_base)
        # they must be the same
        self.assertEqual(rev, rev2)
        # and we should get some expected values:
        self.assertEqual(rev.committer, "Test User<test@example.org>")
        self.assertEqual(rev.message, 
                         "tag of demo@DONOTUSE/c--import--0--base-0")
        self.assertEqual(rev.revision_id, self._baz._empty_merged_tag_bzr_base)
        self.assertEqual(['Arch-1:demo@DONOTUSE%c--import--0--base-0'],
                         rev.parent_ids)

        # check next revisions in the history.
        rev = repo.get_revision(self._baz._empty_merged_tag_bzr)
        rev2 = repo2.get_revision(self._baz._empty_merged_tag_bzr)
        # they must be the same
        self.assertEqual(rev, rev2)
        # and we should get some expected values:
        self.assertEqual(rev.committer, "Test User<test@example.org>")
        self.assertEqual(rev.message, "did a merge, yarh")
        self.assertEqual(rev.revision_id, self._baz._empty_merged_tag_bzr)
        self.assertEqual(rev.parent_ids[0],
                         self._baz._empty_merged_tag_bzr_base)
        self.assertEqual(rev.parent_ids[1], self._baz._empty_tag_bzr)

        # this tree should have nothing missing from that tree.   
        # FIXME there is no code for this right now.
        # self.assertEqual(branch.missing_revisions(branch3), [])
        
    def test_merge_branch_with_merges(self):
        import_version('output', pybaz.Version(self._baz._empty_merged_tag_2))
        # expected results:
        # two commits, no files, revision identifiers of 
        # 'demo@DONOTUSE_c--import--0--base-0' and
        # self._baz._empty_merged_tag_2_bzr_base
        # self._baz._empty_merged_tag_2_bzr
        # and a merged revision from the latter of
        # self._baz._empty_merged_tag_bzr
        branch = Branch.open('output')
        repo = branch.repository
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0',
                          self._baz._empty_merged_tag_2_bzr_base,
                          self._baz._empty_merged_tag_2_bzr])
        # and again.
        import_version('output2', pybaz.Version(self._baz._empty_merged_tag_2))
        branch2 = Branch.open('output2')
        repo2 = branch2.repository
        # and import what we should be merged up against for checking with.
        import_version('output3', pybaz.Version(self._baz._empty_merged_tag))
        branch3 = Branch.open('output3')
        
        self.assertEqual(branch.revision_history(), branch2.revision_history())
        self.assertNotEqual(branch.revision_history(), 
                            branch3.revision_history())
        # check revisions in the history.
        rev = repo.get_revision(self._baz._empty_merged_tag_2_bzr_base)
        rev2 = repo2.get_revision(self._baz._empty_merged_tag_2_bzr_base)
        # they must be the same
        self.assertEqual(rev, rev2)
        # and we should get some expected values:
        self.assertEqual(rev.committer, "Test User<test@example.org>")
        self.assertEqual(rev.message, 
                         "tag of demo@DONOTUSE/c--import--0--base-0")
        self.assertEqual(rev.revision_id, 
                         self._baz._empty_merged_tag_2_bzr_base)

        # check next revisions in the history.
        rev = repo.get_revision(self._baz._empty_merged_tag_2_bzr)
        rev2 = repo2.get_revision(self._baz._empty_merged_tag_2_bzr)
        # they must be the same
        self.assertEqual(rev, rev2)
        # and we should get some expected values:
        self.assertEqual(rev.committer, "Test User<test@example.org>")
        self.assertEqual(rev.message, "merge in a merged tree.")
        self.assertEqual(rev.revision_id, self._baz._empty_merged_tag_2_bzr)
        self.assertEqual(rev.parent_ids[0],
                         self._baz._empty_merged_tag_2_bzr_base)
        self.assertEqual(rev.parent_ids[1],
                         self._baz._empty_merged_tag_bzr)

        # this tree should have nothing missing from that tree.   
        # FIXME there is no code for this right now.
        # self.assertEqual(branch.missing_revisions(branch3), [])
        
    def test_import_symlink(self):
        import_version('output', pybaz.Version(self._baz._import_symlink), 
                       max_count=1)
        # expected results:
        # two commits, no files, revision identifier of 
        # 'demo@DONOTUSE_c--import--0--base-0'
        branch = Branch.open('output')
        self.assertEqual(branch.revision_history(),
                         [self._baz._import_symlink_bzr])
        rev = branch.repository.get_revision(self._baz._import_symlink_bzr)
        # and again.
        import_version('output2', pybaz.Version(self._baz._import_symlink),
                       max_count=1)
        branch2 = Branch.open('output2')
        self.assertEqual(branch.revision_history(), branch2.revision_history())
        rev2 = branch2.repository.get_revision(self._baz._import_symlink_bzr)
        # they must be the same
        self.assertEqual(rev, rev2)

        # and we should get some expected values:
        self.assertEqual(rev.committer, "Test User<test@example.org>")
        self.assertEqual(rev.message, "Import with a symlink")
        self.assertEqual(rev.revision_id, self._baz._import_symlink_bzr)

        # and we want the symlink alink with target 'missing-file-name'
        inv = branch.repository.get_inventory(rev.revision_id)
        self.assertEqual(inv.path2id('alink'), 'x_symlink_tag')
        entry = inv['x_symlink_tag']
        self.assertEqual(entry.kind, 'symlink')
        self.assertEqual(entry.symlink_target, 'missing-file-name')

        # current bzr doesn't handle type changes
        self.assertRaises(AssertionError, import_version, 'output3',
                          pybaz.Version(self._baz._import_symlink))

    def test_missing_ancestor(self):
        import_version('output', pybaz.Version(self._baz._missing_ancestor))
        # expected results:
        # one commits, no files, revision identifiers of 
        # 'demo@DONOTUSE_c--gone--0--base-0' and
        # a merge of demo-gone@DONOTUSE%c--import--0
        branch = Branch.open('output')
        self.assertEqual(branch.revision_history(),
                         [self._baz._missing_ancestor_bzr])
        rev = branch.repository.get_revision(self._baz._missing_ancestor_bzr)
        # and again.
        import_version('output2', pybaz.Version(self._baz._missing_ancestor))
        branch2 = Branch.open('output2')
        self.assertEqual(branch.revision_history(), branch2.revision_history())
        rev2 = branch2.repository.get_revision(self._baz._missing_ancestor_bzr)
        # they must be the same
        self.assertEqual(rev, rev2)

        # and we should get some expected values:
        self.assertEqual(rev.committer, "Test User<test@example.org>")
        self.assertEqual(rev.message, 
                         "tag of demo-gone@DONOTUSE/c--import--0--base-0")
        self.assertEqual(rev.revision_id, self._baz._missing_ancestor_bzr)
        self.assertEqual(rev.parent_ids[0], self._baz._missing_import_bzr)
        self.assertEqual(1, len(rev.parent_ids))

        # must NOT be able to get the merged evision
        self.assertRaises(NoSuchRevision, branch.repository.get_revision, 
                          self._baz._missing_import_bzr)

    def test_missing_ancestor_reusing_history(self):
        import_version('output', pybaz.Version(self._baz._missing_ancestor),
                       reuse_history_from=[self._baz._missing_import_imported])
        # expected results:
        # one commits, no files, revision identifiers of 
        # 'demo-gone@DONOTUSE%c--import--0--base-0' and 
        # 'demo@DONOTUSE%c--gone--0--base-0'
        branch = Branch.open('output')
        self.assertEqual(branch.revision_history(),
                         [self._baz._missing_import_bzr,
                          self._baz._missing_ancestor_bzr])
        rev = branch.repository.get_revision(self._baz._missing_ancestor_bzr)
        # and again.
        import_version('output2', pybaz.Version(self._baz._missing_ancestor),
                       reuse_history_from=[self._baz._missing_import_imported])
        branch2 = Branch.open('output2')
        self.assertEqual(branch.revision_history(), branch2.revision_history())
        rev2 = branch2.repository.get_revision(self._baz._missing_ancestor_bzr)
        # they must be the same
        self.assertEqual(rev, rev2)

        # must be able to get the missing base revision
        branch.repository.get_revision(self._baz._missing_import_bzr)

        # and we should get some expected values:
        self.assertEqual(rev.committer, "Test User<test@example.org>")
        self.assertEqual(rev.message, 
                         "tag of demo-gone@DONOTUSE/c--import--0--base-0")
        self.assertEqual(rev.revision_id, self._baz._missing_ancestor_bzr)
        self.assertEqual(rev.parent_ids[0], self._baz._missing_import_bzr)
        self.assertEqual(1, len(rev.parent_ids))

    def test_bad_file_id(self):
        import_version('output', pybaz.Version(self._baz._bad_id_tag))
        # expected results:
        # three commits, one files, revision identifiers of 
        # 'demo@DONOTUSE_c--import--0--base-0' ,
        # 'demo@DONOTUSE/c--bad-id--0--base-0' ,
        # ''demo@DONOTUSE/c--bad-id--0--patch-1'
        branch = Branch.open('output')
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0',
                          self._baz._bad_id_tag_bzr_base,
                          self._baz._bad_id_tag_bzr])
        rev = branch.repository.get_revision(self._baz._bad_id_tag_bzr)
        inv = branch.repository.get_inventory(self._baz._bad_id_tag_bzr)
        self.assertEqual(inv.path2id('path'), 'x_this_id%2fneeds%25escaping')
        self.assertEqual('path', inv.id2path('x_this_id%2fneeds%25escaping'))

    def test_appending_revisions_already_present(self):
        import_version('output', pybaz.Version(self._baz._bad_id_tag),
                       max_count=2)
        # expected results:
        # three commits, one files, revision identifiers of 
        # 'demo@DONOTUSE_c--import--0--base-0' ,
        # 'demo@DONOTUSE/c--bad-id--0--base-0' ,
        # ''demo@DONOTUSE/c--bad-id--0--patch-1'
        branch = Branch.open('output')
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0',
                          self._baz._bad_id_tag_bzr_base])
        branch.set_revision_history(
            ['Arch-1:demo@DONOTUSE%c--import--0--base-0'])
        del branch
        branch = Branch.open('output')
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0'])
        del branch
        import_version('output', pybaz.Version(self._baz._bad_id_tag))
        branch = Branch.open('output')
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0',
                          self._baz._bad_id_tag_bzr_base,
                          self._baz._bad_id_tag_bzr])
        rev = branch.repository.get_revision(self._baz._bad_id_tag_bzr)
        inv = branch.repository.get_inventory(self._baz._bad_id_tag_bzr)
        self.assertEqual(inv.path2id('path'), 'x_this_id%2fneeds%25escaping')
        self.assertEqual('path', inv.id2path('x_this_id%2fneeds%25escaping'))

    def test_appending_revisions_all_already_present(self):
        import_version('output', pybaz.Version(self._baz._bad_id_tag))
        # expected results:
        # three commits, one files, revision identifiers of 
        # 'demo@DONOTUSE_c--import--0--base-0' ,
        # 'demo@DONOTUSE/c--bad-id--0--base-0' ,
        # ''demo@DONOTUSE/c--bad-id--0--patch-1'
        branch = Branch.open('output')
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0',
                          self._baz._bad_id_tag_bzr_base,
                          self._baz._bad_id_tag_bzr])
        branch.set_revision_history(
            ['Arch-1:demo@DONOTUSE%c--import--0--base-0'])
        del branch
        branch = Branch.open('output')
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0'])
        del branch
        import_version('output', pybaz.Version(self._baz._bad_id_tag))
        branch = Branch.open('output')
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0',
                          self._baz._bad_id_tag_bzr_base,
                          self._baz._bad_id_tag_bzr])
        rev = branch.repository.get_revision(self._baz._bad_id_tag_bzr)
        inv = branch.repository.get_inventory(self._baz._bad_id_tag_bzr)
        self.assertEqual(inv.path2id('path'), 'x_this_id%2fneeds%25escaping')
        self.assertEqual('path', inv.id2path('x_this_id%2fneeds%25escaping'))

    def test_inbranch_conversion(self):
        import_version('output', pybaz.Version(self._baz._inbranch_tag))
        # expected results:
        # three commits, no files, revision identifiers of 
        # 'demo@DONOTUSE_c--import--0--base-0' and
        # self._baz._inbranch_tag_base_bzr
        # self._baz._inbranch_tag_head_bzr
        # with no merges.
        branch = Branch.open('output')
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0',
                          self._baz._inbranch_tag_base_bzr,
                          self._baz._inbranch_tag_head_bzr])
        # and again.
        import_version('output2', pybaz.Version(self._baz._inbranch_tag))
        branch2 = Branch.open('output2')
        
        self.assertEqual(branch.revision_history(), branch2.revision_history())
        # check revisions in the history.
        rev = branch.repository.get_revision(self._baz._inbranch_tag_base_bzr)
        rev2 = branch2.repository.get_revision(self._baz._inbranch_tag_base_bzr)
        # they must be the same
        self.assertEqual(rev, rev2)
        # and we should get some expected values:
        self.assertEqual(rev.committer, "Test User<test@example.org>")
        self.assertEqual(rev.message, "tag of demo@DONOTUSE/c--import--0--base-0")
        self.assertEqual(rev.revision_id, self._baz._inbranch_tag_base_bzr)

        # check next revisions in the history.
        rev = branch.repository.get_revision(self._baz._inbranch_tag_head_bzr)
        rev2 = branch2.repository.get_revision(self._baz._inbranch_tag_head_bzr)
        # they must be the same
        self.assertEqual(rev, rev2)
        # and we should get some expected values:
        self.assertEqual(rev.committer, "Test User<test@example.org>")
        self.assertEqual(rev.message, "tag of demo@DONOTUSE/c--inbranch-tag--0--base-0")
        self.assertEqual(rev.revision_id, self._baz._inbranch_tag_head_bzr)
        self.assertEqual(rev.parent_ids,
                         [self._baz._inbranch_tag_base_bzr])

    def test_no_commits_same_as_missing(self):
        path = 'output'
        os.mkdir(path)
        branch = bzrlib.bzrdir.BzrDir.create_branch_convenience(path)
        import_version(path, pybaz.Version(self._baz._import))
        # expected results:
        # one commit, revision identifier of 
        # 'demo@DONOTUSE_c--import--0--base-0'
        self.assertEqual(branch.revision_history(),
                         ['Arch-1:demo@DONOTUSE%c--import--0--base-0'])


class TestNamespacePrevious(TestCase):

    def setUp(self):
        TestCase.setUp(self)
        self.version = pybaz.Version('foo@example.com/c--b--0')

    def test_base0_none(self):
        self.assertEqual(namespace_previous(self.version['base-0']), None)

    def test_patch1_base0(self):
        self.assertEqual(namespace_previous(self.version['patch-1']),
                         self.version['base-0'])
        
    def test_patch3000_patch2999(self):
        self.assertEqual(namespace_previous(self.version['patch-3000']),
                         self.version['patch-2999'])
        
    def test_version0_raises(self):
        self.assertRaises(RuntimeError, namespace_previous,
                          self.version['version-0'])

    def test_version1_version0(self):
        self.assertEqual(namespace_previous(self.version['versionfix-1']),
                         self.version['version-0'])

    def test_version3000_patch2999(self):
        self.assertEqual(namespace_previous(self.version['versionfix-3000']),
                         self.version['versionfix-2999'])


class TestNamespaceMapping(TestCase):

    def test_namespace_mapping_branch(self):
        from bzrlib.plugins.bzrtools.baz_import import map_namespace
        branch = pybaz.Branch('foo@example.com/c--b')
        self.assertRaises(pybaz.errors.NamespaceError, map_namespace, branch)
        self.assertEqual('c/b', map_namespace(branch['0']))
        self.assertEqual('c/0.1/b', map_namespace(branch['0.1']))

    def test_namespace_mapping_no_branch(self):
        from bzrlib.plugins.bzrtools.baz_import import map_namespace
        category = pybaz.Category('foo@example.com/c')
        self.assertRaises(pybaz.errors.NamespaceError, map_namespace, category)
        self.assertEqual('c/+trunk', 
                         map_namespace(pybaz.Version("%s--0" % category)))
        self.assertEqual('c/0.1/+trunk',
                         map_namespace(pybaz.Version('%s--0.1' % category)))


class TestFileIdMapping(TestCase):

    def test_slash(self):
        self.assertEqual('c%2fc', map_file_id('c/c'))
        self.assertEqual('c%25c', map_file_id('c%c'))


class TestImport(TestCaseInTempDir):

    def setUp(self):
        TestCaseInTempDir.setUp(self)
        self._oldhome = os.environ['HOME']
        self._tmpdir = tempfile.mkdtemp()
        self._homedir = os.path.join(self._tmpdir, 'home')
        os.mkdir(self._homedir)
        os.environ['HOME'] = self._homedir
        self._archiveroot = os.path.join(self._tmpdir, 'archive')
        self._archive = make_archive('demo@DONOTUSE', str(self._archiveroot))

    def tearDown(self):
        os.environ['HOME'] = self._oldhome
        shutil.rmtree(self._tmpdir)
        TestCaseInTempDir.tearDown(self)

    def make_import(self, namespace):
        self._import = 'demo@DONOTUSE/%s' % namespace
        os.mkdir(os.path.join(self._tmpdir, 'tree'))
        tree = pybaz.init_tree(os.path.join(self._tmpdir, 'tree'), 
                               self._import)
        msg = tree.log_message()
        msg["summary"] = "I am importing now"
        tree.import_(msg)
        shutil.rmtree(os.path.join(self._tmpdir, 'tree'))

    def test_cmd_exists(self):
        from bzrlib.plugins.bzrtools import cmd_baz_import

    def test_empty_archive(self):
        command = cmd_baz_import()
        command.run(os.path.join(self._tmpdir, 'output'), 'demo@DONOTUSE')
        self.failUnless(os.path.exists(os.path.join(self._tmpdir,'output')))
        walk_len = len(list(os.walk(os.path.join(self._tmpdir,'output'))))
        self.assertEqual(7, walk_len)

    def test_two_branches(self):
        self.make_import('c--0')
        self.make_import('c1--branch--0.2')
        command = cmd_baz_import()
        command.run(os.path.join(self._tmpdir, 'output'), 'demo@DONOTUSE')
        self.failUnless(os.path.exists(os.path.join(self._tmpdir,'output')))
        self.failUnless(os.path.exists(os.path.join(self._tmpdir,'output', 
                                       'c','+trunk')))
        self.failUnless(os.path.exists(os.path.join(self._tmpdir,'output', 
                                                    'c1', '0.2','branch')))
        default_format = repository.RepositoryFormat.get_default_format()
        if getattr(default_format, 'rich_root_data', False):
            num_files = 21
        else:
            num_files = 20
        walk_len = len(list(os.walk(os.path.join(self._tmpdir,'output'))))
        self.assertEqual(num_files, walk_len)

    def test_run_twice(self):
        self.make_import('c--0')
        command = cmd_baz_import()
        command.run(os.path.join(self._tmpdir, 'output'), 'demo@DONOTUSE')
        command.run(os.path.join(self._tmpdir, 'output'), 'demo@DONOTUSE')
        
    def test_accepts_reuse_history(self):
        self.make_import('c--0')
        self.run_bzr('baz-import', os.path.join(self._tmpdir, 'output'),
                     'demo@DONOTUSE', '.', '.')
        
    def test_does_not_need_reuse_history(self):
        self.make_import('c--0')
        self.run_bzr('baz-import', os.path.join(self._tmpdir, 'output'),
                     'demo@DONOTUSE')

