def testGitDelete(self): p = patch.FilePatchDiff('tools/clang_check/README.chromium', GIT.DELETE, []) self._check_patch(p, 'tools/clang_check/README.chromium', GIT.DELETE, is_delete=True, is_git_diff=True, patchlevel=1)
def _check_exception(self, co, err_msg): co.prepare(None) try: co.apply_patch( [patch.FilePatchDiff('chrome/file.cc', BAD_PATCH, [])]) self.fail() except checkout.PatchApplicationFailed, e: self.assertEquals(e.filename, 'chrome/file.cc') self.assertEquals(e.status, err_msg)
def testRelPathEmpty(self): patches = patch.PatchSet([ patch.FilePatchDiff('chrome\\file.cc', RAW.PATCH, []), patch.FilePatchDelete('other\\place\\foo', True), ]) patches.set_relpath('') self.assertEquals(['chrome/file.cc', 'other/place/foo'], [f.filename for f in patches]) self.assertEquals([None, None], [f.source_filename for f in patches])
def testFilePatchDiffGitNew(self): # The code path is different for git and svn. p = patch.FilePatchDiff('foo', GIT.NEW, []) self._check_patch(p, 'foo', GIT.NEW, is_new=True, is_git_diff=True, patchlevel=1)
def testGitPatchShortHunkHeader(self): p = patch.FilePatchDiff('chrome/browser/api/OWNERS', GIT.PATCH_SHORT_HUNK_HEADER, []) self._check_patch(p, 'chrome/browser/api/OWNERS', GIT.PATCH_SHORT_HUNK_HEADER, is_git_diff=True, patchlevel=1, nb_hunks=1)
def get_patch(self, issue, patchset): """Returns a PatchSet object containing the details to apply this patch.""" props = self.get_patchset_properties(issue, patchset) or {} out = [] for filename, state in props.get('files', {}).iteritems(): logging.debug('%s' % filename) # If not status, just assume it's a 'M'. Rietveld often gets it wrong and # just has status: null. Oh well. status = state.get('status') or 'M' if status[0] not in ('A', 'D', 'M', 'R'): raise patch.UnsupportedPatchFormat( filename, 'Change with status \'%s\' is not supported.' % status) svn_props = self.parse_svn_properties( state.get('property_changes', ''), filename) if state.get('is_binary'): if status[0] == 'D': if status[0] != status.strip(): raise patch.UnsupportedPatchFormat( filename, 'Deleted file shouldn\'t have property change.') out.append(patch.FilePatchDelete(filename, state['is_binary'])) else: content = self.get_file_content(issue, patchset, state['id']) if not content: # As a precaution due to a bug in upload.py for git checkout, refuse # empty files. If it's empty, it's not a binary file. raise patch.UnsupportedPatchFormat( filename, 'Binary file is empty. Maybe the file wasn\'t uploaded in the ' 'first place?') out.append(patch.FilePatchBinary( filename, content, svn_props, is_new=(status[0] == 'A'))) continue try: diff = self.get_file_diff(issue, patchset, state['id']) except urllib2.HTTPError, e: if e.code == 404: raise patch.UnsupportedPatchFormat( filename, 'File doesn\'t have a diff.') raise # FilePatchDiff() will detect file deletion automatically. p = patch.FilePatchDiff(filename, diff, svn_props) out.append(p) if status[0] == 'A': # It won't be set for empty file. p.is_new = True if (len(status) > 1 and status[1] == '+' and not (p.source_filename or p.svn_properties)): raise patch.UnsupportedPatchFormat( filename, 'Failed to process the svn properties')
def testBackSlash(self): mangled_patch = RAW.PATCH.replace('chrome/', 'chrome\\') patches = patch.PatchSet([ patch.FilePatchDiff('chrome\\file.cc', mangled_patch, []), patch.FilePatchDelete('other\\place\\foo', True), ]) expected = ['chrome/file.cc', 'other/place/foo'] self.assertEquals(expected, patches.filenames) self.assertEquals(RAW.PATCH, patches.patches[0].get())
def testGitCopy(self): p = patch.FilePatchDiff('pp', GIT.COPY, []) self._check_patch(p, 'pp', GIT.COPY, is_git_diff=True, patchlevel=1, source_filename='PRESUBMIT.py', is_new=True)
class SvnCheckout(SvnBaseTest): def _get_co(self, post_processors): self.assertNotEqual(False, post_processors) return checkout.SvnCheckout(self.root_dir, self.name, self.usr, self.pwd, self.svn_url, post_processors) def testAll(self): expected = { 'author': self.FAKE_REPOS.USERS[0][0], 'revprops': [('realauthor', self.FAKE_REPOS.USERS[1][0])] } root = os.path.join(self.root_dir, self.name) self._check_base(self._get_co(None), root, expected) def testException(self): self._check_exception( self._get_co(None), 'While running patch -p1 --forward --force --no-backup-if-mismatch;\n' ' patching file chrome/file.cc\n' ' Hunk #1 FAILED at 3.\n' ' 1 out of 1 hunk FAILED -- saving rejects to file ' 'chrome/file.cc.rej\n') def testSvnProps(self): co = self._get_co(None) co.prepare(None) try: # svn:ignore can only be applied to directories. svn_props = [('svn:ignore', 'foo')] co.apply_patch( [patch.FilePatchDiff('chrome/file.cc', RAW.PATCH, svn_props)]) self.fail() except checkout.PatchApplicationFailed, e: self.assertEquals(e.filename, 'chrome/file.cc') self.assertEquals( e.status, 'While running svn propset svn:ignore foo chrome/file.cc ' '--non-interactive;\n' ' patching file chrome/file.cc\n' ' svn: Cannot set \'svn:ignore\' on a file (\'chrome/file.cc\')\n' ) co.prepare(None) svn_props = [('svn:eol-style', 'LF'), ('foo', 'bar')] co.apply_patch( [patch.FilePatchDiff('chrome/file.cc', RAW.PATCH, svn_props)]) filepath = os.path.join(self.root_dir, self.name, 'chrome/file.cc') # Manually verify the properties. props = subprocess2.check_output(['svn', 'proplist', filepath], cwd=self.root_dir).splitlines()[1:] props = sorted(p.strip() for p in props) expected_props = dict(svn_props) self.assertEquals(sorted(expected_props.iterkeys()), props) for k, v in expected_props.iteritems(): value = subprocess2.check_output( ['svn', 'propget', '--strict', k, filepath], cwd=self.root_dir).strip() self.assertEquals(v, value)
def testGitCopyPartial(self): p = patch.FilePatchDiff('wtf2', GIT.COPY_PARTIAL, []) self._check_patch(p, 'wtf2', GIT.COPY_PARTIAL, source_filename='wtf', is_git_diff=True, patchlevel=1, is_new=True)
def testGitNewExe(self): p = patch.FilePatchDiff('natsort_test.py', GIT.NEW_EXE, []) self._check_patch(p, 'natsort_test.py', GIT.NEW_EXE, is_new=True, is_git_diff=True, patchlevel=1, svn_properties=[('svn:executable', '*')])
def testFilePatchDiffHeaderModeIndex(self): p = patch.FilePatchDiff('git_cl/git-cl', GIT.MODE_EXE_JUNK, []) self._check_patch(p, 'git_cl/git-cl', GIT.MODE_EXE_JUNK, is_git_diff=True, patchlevel=1, svn_properties=[('svn:executable', '.')], nb_hunks=0)
def testGitRename(self): p = patch.FilePatchDiff('tools/run_local_server.sh', GIT.RENAME, []) self._check_patch(p, 'tools/run_local_server.sh', GIT.RENAME, is_git_diff=True, patchlevel=1, source_filename='tools/run_local_server.PY', is_new=True)
def testGitNewMode(self): p = patch.FilePatchDiff('natsort_test.py', GIT.NEW_MODE, []) self._check_patch(p, 'natsort_test.py', GIT.NEW_MODE, is_new=True, is_git_diff=True, patchlevel=1, nb_hunks=1)
def testRelPathBad(self): patches = patch.PatchSet([ patch.FilePatchDiff('chrome\\file.cc', RAW.PATCH, []), patch.FilePatchDelete('other\\place\\foo', True), ]) try: patches.set_relpath('..') self.fail() except patch.UnsupportedPatchFormat: pass
def testSvn(self): # Should not throw. p = patch.FilePatchDiff('chrome/file.cc', RAW.PATCH, []) lines = RAW.PATCH.splitlines(True) header = ''.join(lines[:4]) hunks = ''.join(lines[4:]) self.assertEquals(header, p.diff_header) self.assertEquals(hunks, p.diff_hunks) self.assertEquals(RAW.PATCH, p.get(True)) self.assertEquals(RAW.PATCH, p.get(False))
def testGitRenamePartial(self): p = patch.FilePatchDiff('chromeos/views/webui_menu_widget.h', GIT.RENAME_PARTIAL, []) self._check_patch(p, 'chromeos/views/webui_menu_widget.h', GIT.RENAME_PARTIAL, source_filename='chromeos/views/DOMui_menu_widget.h', is_git_diff=True, patchlevel=1, is_new=True)
def testFilePatchDiffBadHeader(self): try: diff = ( '+++ b/foo\n' '@@ -0,0 +1 @@\n' '+bar\n') patch.FilePatchDiff('foo', diff, []) self.fail() except patch.UnsupportedPatchFormat: pass
def testBadHunkCommas(self): try: patch.FilePatchDiff( 'file_a', '--- file_a\n' '+++ file_a\n' '@@ -0,,0 +1 @@\n' '+foo\n', []) self.fail() except patch.UnsupportedPatchFormat: pass
def testFilePatchDiffHeaderNotExecutable(self): p = patch.FilePatchDiff('build/android/ant/create.js', GIT.NEW_NOT_EXECUTABLE, []) self._check_patch(p, 'build/android/ant/create.js', GIT.NEW_NOT_EXECUTABLE, is_git_diff=True, patchlevel=1, is_new=True, nb_hunks=1)
def get_patch(self, issue, patchset): """Returns a PatchSet object containing the details to apply this patch.""" props = self.get_patchset_properties(issue, patchset) or {} out = [] for filename, state in props.get('files', {}).iteritems(): logging.debug('%s' % filename) status = state.get('status') if not status: raise patch.UnsupportedPatchFormat( filename, 'File\'s status is None, patchset upload is incomplete.') if status[0] not in ('A', 'D', 'M'): raise patch.UnsupportedPatchFormat( filename, 'Change with status \'%s\' is not supported.' % status) svn_props = self.parse_svn_properties( state.get('property_changes', ''), filename) if state.get('is_binary'): if status[0] == 'D': if status[0] != status.strip(): raise patch.UnsupportedPatchFormat( filename, 'Deleted file shouldn\'t have property change.') out.append( patch.FilePatchDelete(filename, state['is_binary'])) else: out.append( patch.FilePatchBinary(filename, self.get_file_content( issue, patchset, state['id']), svn_props, is_new=(status[0] == 'A'))) continue try: diff = self.get_file_diff(issue, patchset, state['id']) except urllib2.HTTPError, e: if e.code == 404: raise patch.UnsupportedPatchFormat( filename, 'File doesn\'t have a diff.') raise # FilePatchDiff() will detect file deletion automatically. p = patch.FilePatchDiff(filename, diff, svn_props) out.append(p) if status[0] == 'A': # It won't be set for empty file. p.is_new = True if (len(status) > 1 and status[1] == '+' and not (p.source_filename or p.svn_properties)): raise patch.UnsupportedPatchFormat( filename, 'Failed to process the svn properties')
def testFilePatchDiffGitBadHeaderReversed(self): try: diff = ('diff --git a/foo b/foo\n' '+++ b/foo\n' '--- b/foo\n' '@@ -0,0 +1 @@\n' '+bar\n') patch.FilePatchDiff('foo', diff, []) self.fail() except patch.UnsupportedPatchFormat: pass
def testValidSvn(self): # pylint: disable=R0201 # Method could be a function # Should not throw. p = patch.FilePatchDiff('chrome/file.cc', RAW.PATCH, []) lines = RAW.PATCH.splitlines(True) header = ''.join(lines[:4]) hunks = ''.join(lines[4:]) self.assertEquals(header, p.diff_header) self.assertEquals(hunks, p.diff_hunks) self.assertEquals(RAW.PATCH, p.get())
def testUnicodeFilenameGet(self): p = patch.FilePatchDiff(u'filé_b', RAW.RENAME_UTF8, []) self._check_patch( p, u'filé_b', RAW.RENAME_UTF8, source_filename=u'file_à', is_new=True, nb_hunks=1) self.assertTrue(isinstance(p.get(False), str)) p.set_relpath('foo') self.assertTrue(isinstance(p.get(False), str)) self.assertEquals(u'foo/file_à'.encode('utf-8'), p.source_filename_utf8) self.assertEquals(u'foo/file_à', p.source_filename) self.assertEquals(u'foo/filé_b'.encode('utf-8'), p.filename_utf8) self.assertEquals(u'foo/filé_b', p.filename)
def testPatchsetOrder(self): # Deletes must be last. # File renames/move/copy must be first. patches = [ patch.FilePatchDiff('chrome/file.cc', RAW.PATCH, []), patch.FilePatchDiff( 'tools\\clang_check/README.chromium', GIT.DELETE, []), patch.FilePatchDiff('tools/run_local_server.sh', GIT.RENAME, []), patch.FilePatchDiff( 'chromeos\\views/webui_menu_widget.h', GIT.RENAME_PARTIAL, []), patch.FilePatchDiff('pp', GIT.COPY, []), patch.FilePatchDiff('foo', GIT.NEW, []), patch.FilePatchDelete('other/place/foo', True), patch.FilePatchBinary('bar', 'data', [], is_new=False), ] expected = [ 'pp', 'chromeos/views/webui_menu_widget.h', 'tools/run_local_server.sh', 'bar', 'chrome/file.cc', 'foo', 'other/place/foo', 'tools/clang_check/README.chromium', ] patchset = patch.PatchSet(patches) self.assertEquals(expected, patchset.filenames)
def testFilePatchDiffInvalidGit(self): try: patch.FilePatchDiff('svn_utils_test.txt', ( 'diff --git a/tests/svn_utils_test_data/svn_utils_test.txt ' 'b/tests/svn_utils_test_data/svn_utils_test.txt\n' 'index 0e4de76..8320059 100644\n' '--- a/svn_utils_test.txt\n' '+++ b/svn_utils_test.txt\n' '@@ -3,6 +3,7 @@ bb\n' 'ccc\n' 'dd\n' 'e\n' '+FOO!\n' 'ff\n' 'ggg\n' 'hh\n'), []) self.fail() except patch.UnsupportedPatchFormat: pass try: patch.FilePatchDiff('svn_utils_test2.txt', ( 'diff --git a/svn_utils_test_data/svn_utils_test.txt ' 'b/svn_utils_test.txt\n' 'index 0e4de76..8320059 100644\n' '--- a/svn_utils_test.txt\n' '+++ b/svn_utils_test.txt\n' '@@ -3,6 +3,7 @@ bb\n' 'ccc\n' 'dd\n' 'e\n' '+FOO!\n' 'ff\n' 'ggg\n' 'hh\n'), []) self.fail() except patch.UnsupportedPatchFormat: pass
def testSvnProps(self): co = self._get_co(None) co.prepare(None) try: svn_props = [('foo', 'bar')] co.apply_patch( [patch.FilePatchDiff('chrome/file.cc', RAW.PATCH, svn_props)]) self.fail() except patch.UnsupportedPatchFormat, e: self.assertEquals(e.filename, 'chrome/file.cc') self.assertEquals( e.status, 'Cannot apply svn property foo to file chrome/file.cc.')
def testSvnProps(self): co = self._get_co(False) co.prepare(None) try: svn_props = [('foo', 'bar')] co.apply_patch( [patch.FilePatchDiff('svn_utils_test.txt', NAKED_PATCH, svn_props)]) self.fail() except patch.UnsupportedPatchFormat, e: self.assertEquals(e.filename, 'svn_utils_test.txt') self.assertEquals( e.status, 'Cannot apply svn property foo to file svn_utils_test.txt.')
class GitSvnCheckout(SvnBaseTest): name = 'foo.git' def _get_co(self, post_processors): self.assertNotEqual(False, post_processors) return checkout.GitSvnCheckout(self.root_dir, self.name[:-4], self.usr, self.pwd, self.svn_base, self.svn_trunk, post_processors) def testAll(self): expected = { 'author': self.FAKE_REPOS.USERS[0][0], } root = os.path.join(self.root_dir, self.name) self._check_base(self._get_co(None), root, True, expected) def testGitSvnPremade(self): # Test premade git-svn clone. First make a git-svn clone. git_svn_co = self._get_co(None) revision = git_svn_co.prepare(None) self.assertEquals(self.previous_log['revision'], revision) # Then use GitSvnClone to clone it to lose the git-svn connection and verify # git svn init / git svn fetch works. git_svn_clone = checkout.GitSvnPremadeCheckout( self.root_dir, self.name[:-4] + '2', 'trunk', self.usr, self.pwd, self.svn_base, self.svn_trunk, git_svn_co.project_path) self.assertEquals(self.previous_log['revision'], git_svn_clone.prepare(None)) def testException(self): self._check_exception(self._get_co(None), 'fatal: corrupt patch at line 12\n') def testSvnProps(self): co = self._get_co(None) co.prepare(None) try: svn_props = [('foo', 'bar')] co.apply_patch( [patch.FilePatchDiff('chrome/file.cc', RAW.PATCH, svn_props)]) self.fail() except patch.UnsupportedPatchFormat, e: self.assertEquals(e.filename, 'chrome/file.cc') self.assertEquals( e.status, 'Cannot apply svn property foo to file chrome/file.cc.') co.prepare(None) # svn:eol-style is ignored. svn_props = [('svn:eol-style', 'LF')] co.apply_patch( [patch.FilePatchDiff('chrome/file.cc', RAW.PATCH, svn_props)])
def testSvnProps(self): co = self._get_co(False) co.prepare(None) try: # svn:ignore can only be applied to directories. svn_props = [('svn:ignore', 'foo')] co.apply_patch( [patch.FilePatchDiff('svn_utils_test.txt', NAKED_PATCH, svn_props)]) self.fail() except checkout.PatchApplicationFailed, e: self.assertEquals(e.filename, 'svn_utils_test.txt') self.assertEquals( e.status, 'While running svn propset svn:ignore foo svn_utils_test.txt ' '--non-interactive;\n' 'patching file svn_utils_test.txt\n' 'svn: Cannot set \'svn:ignore\' on a file (\'svn_utils_test.txt\')\n')