Changeset - 91f440a11b94
[Not reviewed]
beta
0 6 0
Marcin Kuzminski - 12 years ago 2013-05-29 00:20:27
marcin@python-works.com
fixes issues #849 IMC failed for non-ascii files

- added set of regression tests into vcs lib
6 files changed with 72 insertions and 6 deletions:
0 comments (0 inline, 0 general)
rhodecode/lib/vcs/backends/git/changeset.py
Show inline comments
 
@@ -101,13 +101,13 @@ class GitChangeset(BaseChangeset):
 
        """
 
        if path.endswith('/'):
 
            path = path.rstrip('/')
 
        return path
 

	
 
    def _get_id_for_path(self, path):
 

	
 
        path = safe_str(path)
 
        # FIXME: Please, spare a couple of minutes and make those codes cleaner;
 
        if not path in self._paths:
 
            path = path.strip('/')
 
            # set root tree
 
            tree = self.repository._repo[self._tree_id]
 
            if path == '':
 
@@ -151,13 +151,13 @@ class GitChangeset(BaseChangeset):
 
                        name = item
 
                    self._paths[name] = id
 
                    self._stat_modes[name] = stat
 
            if not path in self._paths:
 
                raise NodeDoesNotExistError("There is no file nor directory "
 
                    "at the given path '%s' at revision %s"
 
                    % (path, self.short_id))
 
                    % (path, safe_str(self.short_id)))
 
        return self._paths[path]
 

	
 
    def _get_kind(self, path):
 
        obj = self.repository._repo[self._get_id_for_path(path)]
 
        if isinstance(obj, objects.Blob):
 
            return NodeKind.FILE
 
@@ -251,12 +251,13 @@ class GitChangeset(BaseChangeset):
 

	
 
    def get_file_mode(self, path):
 
        """
 
        Returns stat mode of the file at the given ``path``.
 
        """
 
        # ensure path is traversed
 
        path = safe_str(path)
 
        self._get_id_for_path(path)
 
        return self._stat_modes[path]
 

	
 
    def get_file_content(self, path):
 
        """
 
        Returns content of the file at given ``path``.
rhodecode/lib/vcs/backends/git/inmemory.py
Show inline comments
 
@@ -43,13 +43,13 @@ class GitInMemoryChangeset(BaseInMemoryC
 
        # Create tree and populates it with blobs
 
        commit_tree = self.parents[0] and repo[self.parents[0]._commit.tree] or\
 
            objects.Tree()
 
        for node in self.added + self.changed:
 
            # Compute subdirs if needed
 
            dirpath, nodename = posixpath.split(node.path)
 
            dirnames = dirpath and dirpath.split('/') or []
 
            dirnames = map(safe_str, dirpath and dirpath.split('/') or [])
 
            parent = commit_tree
 
            ancestors = [('', parent)]
 

	
 
            # Tries to dig for the deepest existing tree
 
            while dirnames:
 
                curdir = dirnames.pop(0)
rhodecode/lib/vcs/nodes.py
Show inline comments
 
@@ -13,13 +13,13 @@ import stat
 
import posixpath
 
import mimetypes
 

	
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
from rhodecode.lib.vcs.exceptions import NodeError, RemovedFileNodeError
 
from rhodecode.lib.vcs.utils.lazy import LazyProperty
 
from rhodecode.lib.vcs.utils import safe_unicode
 
from rhodecode.lib.vcs.utils import safe_unicode, safe_str
 

	
 

	
 
class NodeKind:
 
    SUBMODULE = -1
 
    DIR = 1
 
    FILE = 2
 
@@ -98,13 +98,13 @@ class Node(object):
 
    """
 

	
 
    def __init__(self, path, kind):
 
        if path.startswith('/'):
 
            raise NodeError("Cannot initialize Node objects with slash at "
 
                "the beginning as only relative paths are supported")
 
        self.path = path.rstrip('/')
 
        self.path = safe_str(path.rstrip('/'))  # we store paths as str
 
        if path == '' and kind != NodeKind.DIR:
 
            raise NodeError("Only DirNode and its subclasses may be "
 
                            "initialized with empty path")
 
        self.kind = kind
 
        #self.dirs, self.files = [], []
 
        if self.is_root() and not self.is_dir():
rhodecode/model/scm.py
Show inline comments
 
@@ -577,14 +577,14 @@ class ScmModel(BaseModel):
 
        processed_nodes = []
 
        for f_path in nodes:
 
            if f_path.startswith('/') or f_path.startswith('.') or '../' in f_path:
 
                raise NonRelativePathError('%s is not an relative path' % f_path)
 
            if f_path:
 
                f_path = os.path.normpath(f_path)
 
            content = nodes[f_path]['content']
 
            f_path = safe_str(f_path)
 
            content = nodes[f_path]['content']
 
            # decoding here will force that we have proper encoded values
 
            # in any other case this will throw exceptions and deny commit
 
            if isinstance(content, (basestring,)):
 
                content = safe_str(content)
 
            elif isinstance(content, (file, cStringIO.OutputType,)):
 
                content = content.read()
rhodecode/tests/vcs/test_changesets.py
Show inline comments
 
# encoding: utf8
 
from __future__ import with_statement
 

	
 
import time
 
import datetime
 
from rhodecode.lib import vcs
 
from rhodecode.tests.vcs.base import BackendTestMixin
 
@@ -299,12 +300,13 @@ class ChangesetsChangesTestCaseMixin(Bac
 
            {
 
                'message': u'Initial',
 
                'author': u'Joe Doe <joe.doe@example.com>',
 
                'date': datetime.datetime(2010, 1, 1, 20),
 
                'added': [
 
                    FileNode('foo/bar', content='foo'),
 
                    FileNode('foo/bał', content='foo'),
 
                    FileNode('foobar', content='foo'),
 
                    FileNode('qwe', content='foo'),
 
                ],
 
            },
 
            {
 
                'message': u'Massive changes',
 
@@ -320,12 +322,13 @@ class ChangesetsChangesTestCaseMixin(Bac
 
        ]
 

	
 
    def test_initial_commit(self):
 
        changeset = self.repo.get_changeset(0)
 
        self.assertItemsEqual(changeset.added, [
 
            changeset.get_node('foo/bar'),
 
            changeset.get_node('foo/bał'),
 
            changeset.get_node('foobar'),
 
            changeset.get_node('qwe'),
 
        ])
 
        self.assertItemsEqual(changeset.changed, [])
 
        self.assertItemsEqual(changeset.removed, [])
 

	
 
@@ -341,12 +344,20 @@ class ChangesetsChangesTestCaseMixin(Bac
 
            changeset.get_node('foobar'),
 
        ])
 
        self.assertTrue(isinstance(changeset.removed, RemovedFileNodesGenerator))
 
        self.assertEqual(len(changeset.removed), 1)
 
        self.assertEqual(list(changeset.removed)[0].path, 'qwe')
 

	
 
    def test_get_filemode(self):
 
        changeset = self.repo.get_changeset()
 
        self.assertEqual(33188, changeset.get_file_mode('foo/bar'))
 

	
 
    def test_get_filemode_non_ascii(self):
 
        changeset = self.repo.get_changeset()
 
        self.assertEqual(33188, changeset.get_file_mode('foo/bał'))
 
        self.assertEqual(33188, changeset.get_file_mode(u'foo/bał'))
 

	
 
# For each backend create test case class
 
for alias in SCM_TESTS:
 
    attrs = {
 
        'backend_alias': alias,
 
    }
rhodecode/tests/vcs/test_inmemchangesets.py
Show inline comments
 
# encoding: utf8
 
"""
 
Tests so called "in memory changesets" commit API of vcs.
 
"""
 
from __future__ import with_statement
 

	
 
import time
 
@@ -15,12 +16,13 @@ from rhodecode.lib.vcs.exceptions import
 
from rhodecode.lib.vcs.exceptions import NodeAlreadyChangedError
 
from rhodecode.lib.vcs.exceptions import NodeDoesNotExistError
 
from rhodecode.lib.vcs.exceptions import NodeNotChangedError
 
from rhodecode.lib.vcs.nodes import DirNode
 
from rhodecode.lib.vcs.nodes import FileNode
 
from rhodecode.lib.vcs.utils.compat import unittest
 
from rhodecode.lib.vcs.utils import safe_unicode
 

	
 

	
 
class InMemoryChangesetTestMixin(object):
 
    """
 
    This is a backend independent test case class which should be created
 
    with ``type`` method.
 
@@ -109,12 +111,34 @@ class InMemoryChangesetTestMixin(object)
 
        self.assertEqual(changeset.get_node('foo/bar/foobaz/bar').content, 'foo')
 
        self.assertEqual(changeset.get_node('foo/bar/another/bar').content, 'foo')
 
        self.assertEqual(changeset.get_node('foo/baz.txt').content, 'foo')
 
        self.assertEqual(changeset.get_node('foobar/foobaz/file').content, 'foo')
 
        self.assertEqual(changeset.get_node('foobar/barbaz').content, 'foo')
 

	
 
    def test_add_non_ascii_files(self):
 
        rev_count = len(self.repo.revisions)
 
        to_add = [
 
            FileNode('żółwik/zwierzątko', content='ćććć'),
 
            FileNode(u'żółwik/zwierzątko_uni', content=u'ćććć'),
 
        ]
 
        for node in to_add:
 
            self.imc.add(node)
 
        message = u'Added: %s' % ', '.join((node.path for node in self.nodes))
 
        author = unicode(self.__class__)
 
        changeset = self.imc.commit(message=message, author=author)
 

	
 
        newtip = self.repo.get_changeset()
 
        self.assertEqual(changeset, newtip)
 
        self.assertEqual(rev_count + 1, len(self.repo.revisions))
 
        self.assertEqual(newtip.message, message)
 
        self.assertEqual(newtip.author, author)
 
        self.assertTrue(not any((self.imc.added, self.imc.changed,
 
            self.imc.removed)))
 
        for node in to_add:
 
            self.assertEqual(newtip.get_node(node.path).content, node.content)
 

	
 
    def test_add_raise_already_added(self):
 
        node = FileNode('foobar', content='baz')
 
        self.imc.add(node)
 
        self.assertRaises(NodeAlreadyAddedError, self.imc.add, node)
 

	
 
    def test_check_integrity_raise_already_exist(self):
 
@@ -139,12 +163,42 @@ class InMemoryChangesetTestMixin(object)
 
        newtip = self.repo.get_changeset()
 
        self.assertNotEqual(tip, newtip)
 
        self.assertNotEqual(tip.id, newtip.id)
 
        self.assertEqual(newtip.get_node('foo/bar/baz').content,
 
            'My **changed** content')
 

	
 
    def test_change_non_ascii(self):
 
        to_add = [
 
            FileNode('żółwik/zwierzątko', content='ćććć'),
 
            FileNode(u'żółwik/zwierzątko_uni', content=u'ćććć'),
 
        ]
 
        for node in to_add:
 
            self.imc.add(node)
 

	
 
        tip = self.imc.commit(u'Initial', u'joe.doe@example.com')
 

	
 
        # Change node's content
 
        node = FileNode('żółwik/zwierzątko', content='My **changed** content')
 
        self.imc.change(node)
 
        self.imc.commit(u'Changed %s' % safe_unicode(node.path),
 
                        u'joe.doe@example.com')
 

	
 
        node = FileNode(u'żółwik/zwierzątko_uni', content=u'My **changed** content')
 
        self.imc.change(node)
 
        self.imc.commit(u'Changed %s' % safe_unicode(node.path),
 
                        u'joe.doe@example.com')
 

	
 
        newtip = self.repo.get_changeset()
 
        self.assertNotEqual(tip, newtip)
 
        self.assertNotEqual(tip.id, newtip.id)
 

	
 
        self.assertEqual(newtip.get_node('żółwik/zwierzątko').content,
 
                         'My **changed** content')
 
        self.assertEqual(newtip.get_node('żółwik/zwierzątko_uni').content,
 
                         'My **changed** content')
 

	
 
    def test_change_raise_empty_repository(self):
 
        node = FileNode('foobar')
 
        self.assertRaises(EmptyRepositoryError, self.imc.change, node)
 

	
 
    def test_check_integrity_change_raise_node_does_not_exist(self):
 
        node = FileNode('foobar', content='baz')
0 comments (0 inline, 0 general)