| 1 | # -*- mode: python; coding: utf-8 -*- |
|---|
| 2 | # :Progetto: vcpx -- Darcs specific tests |
|---|
| 3 | # :Creato: sab 17 lug 2004 02:33:41 CEST |
|---|
| 4 | # :Autore: Lele Gaifax <lele@nautilus.homeip.net> |
|---|
| 5 | # :Licenza: GNU General Public License |
|---|
| 6 | # |
|---|
| 7 | |
|---|
| 8 | from datetime import datetime |
|---|
| 9 | from StringIO import StringIO |
|---|
| 10 | from unittest import TestCase |
|---|
| 11 | from vcpx.repository.darcs.source import changesets_from_darcschanges, \ |
|---|
| 12 | DarcsSourceWorkingDir |
|---|
| 13 | from vcpx.shwrap import ExternalCommand, PIPE |
|---|
| 14 | from vcpx.tzinfo import UTC |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | class DarcsParserTestCase(TestCase): |
|---|
| 18 | |
|---|
| 19 | def getDarcsOutput(self, testname, ext='.log'): |
|---|
| 20 | from os.path import split, join |
|---|
| 21 | |
|---|
| 22 | logfilename = join(split(__file__)[0], 'data', testname+ext) |
|---|
| 23 | return file(logfilename) |
|---|
| 24 | |
|---|
| 25 | |
|---|
| 26 | class DarcsChangesParser(DarcsParserTestCase): |
|---|
| 27 | """Tests for the parser of darcs changes""" |
|---|
| 28 | |
|---|
| 29 | def testBasicBehaviour(self): |
|---|
| 30 | """Verify basic darcs changes parser behaviour""" |
|---|
| 31 | |
|---|
| 32 | log = self.getDarcsOutput('darcs-simple_test') |
|---|
| 33 | |
|---|
| 34 | csets = changesets_from_darcschanges(log) |
|---|
| 35 | |
|---|
| 36 | cset = csets.next() |
|---|
| 37 | self.assertEqual(cset.revision, |
|---|
| 38 | "Fix the CVS parser to omit already seen changesets") |
|---|
| 39 | self.assertEqual(cset.author, "lele@nautilus.homeip.net") |
|---|
| 40 | self.assertEqual(cset.date, datetime(2004, 7, 16, 12, 37, 37, 0, UTC)) |
|---|
| 41 | self.assertEqual(cset.log, "For some unknown reasons....") |
|---|
| 42 | entry = cset.entries[0] |
|---|
| 43 | self.assertEqual(entry.name, 'vcpx/cvs.py') |
|---|
| 44 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 45 | |
|---|
| 46 | cset = csets.next() |
|---|
| 47 | self.assertEqual(cset.revision, |
|---|
| 48 | "Svn log parser with test") |
|---|
| 49 | self.assertEqual(cset.date, datetime(2004, 6, 1, 14, 5, 59, 0, UTC)) |
|---|
| 50 | self.assertEqual(len(cset.entries), 4) |
|---|
| 51 | self.assertEqual(cset.darcs_hash, |
|---|
| 52 | '20040601140559-97f81-b669594864cb35290fbe4848e6645e73057a8caf.gz') |
|---|
| 53 | |
|---|
| 54 | entry = cset.entries[0] |
|---|
| 55 | self.assertEqual(entry.name, 'cvsync/svn.py') |
|---|
| 56 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 57 | entry = cset.entries[1] |
|---|
| 58 | self.assertEqual(entry.name, 'cvsync/tests/__init__.py') |
|---|
| 59 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 60 | entry = cset.entries[2] |
|---|
| 61 | self.assertEqual(entry.name, 'cvsync/tests/svn.py') |
|---|
| 62 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 63 | entry = cset.entries[3] |
|---|
| 64 | self.assertEqual(entry.name, 'cvsync/tests/testrepo.dump') |
|---|
| 65 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 66 | |
|---|
| 67 | def testOnTailorOwnRepo(self): |
|---|
| 68 | """Verify fetching unidiff of a darcs patch""" |
|---|
| 69 | |
|---|
| 70 | from os import getcwd |
|---|
| 71 | |
|---|
| 72 | patchname = 'more detailed diags on SAXException' |
|---|
| 73 | changes = ExternalCommand(command=["darcs", "changes", "--xml", "--summary", |
|---|
| 74 | "--patches", patchname]) |
|---|
| 75 | csets = changesets_from_darcschanges(changes.execute(stdout=PIPE, TZ='UTC')[0], |
|---|
| 76 | unidiff=True, |
|---|
| 77 | repodir=getcwd()) |
|---|
| 78 | unidiff = csets.next().unidiff |
|---|
| 79 | head = unidiff.split('\n')[0] |
|---|
| 80 | self.assertEqual(head, 'Thu Jun 9 20:17:11 UTC 2005 zooko@zooko.com') |
|---|
| 81 | |
|---|
| 82 | def testAllActions(self): |
|---|
| 83 | """Verify darcs changes parser understand all actions""" |
|---|
| 84 | |
|---|
| 85 | log = self.getDarcsOutput('darcs-all_actions_test') |
|---|
| 86 | |
|---|
| 87 | csets = list(changesets_from_darcschanges(log)) |
|---|
| 88 | |
|---|
| 89 | self.assertEqual(len(csets), 4) |
|---|
| 90 | |
|---|
| 91 | cset = csets[0] |
|---|
| 92 | self.assertEqual(cset.revision, 'first') |
|---|
| 93 | self.assertEqual(len(cset.entries), 2) |
|---|
| 94 | |
|---|
| 95 | entry = cset.entries[0] |
|---|
| 96 | self.assertEqual(entry.name, 'a.txt') |
|---|
| 97 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 98 | self.assertEqual(entry.is_directory, False) |
|---|
| 99 | |
|---|
| 100 | entry = cset.entries[1] |
|---|
| 101 | self.assertEqual(entry.name, 'dir') |
|---|
| 102 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 103 | self.assertEqual(entry.is_directory, True) |
|---|
| 104 | |
|---|
| 105 | cset = csets[1] |
|---|
| 106 | self.assertEqual(cset.revision, 'removed') |
|---|
| 107 | self.assertEqual(len(cset.entries), 1) |
|---|
| 108 | |
|---|
| 109 | entry = cset.entries[0] |
|---|
| 110 | self.assertEqual(entry.name, 'dir') |
|---|
| 111 | self.assertEqual(entry.action_kind, entry.DELETED) |
|---|
| 112 | self.assertEqual(entry.is_directory, True) |
|---|
| 113 | |
|---|
| 114 | cset = csets[2] |
|---|
| 115 | self.assertEqual(cset.revision, 'moved') |
|---|
| 116 | self.assertEqual(len(cset.entries), 1) |
|---|
| 117 | |
|---|
| 118 | entry = cset.entries[0] |
|---|
| 119 | self.assertEqual(entry.name, 'dir') |
|---|
| 120 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 121 | self.assertEqual(entry.is_directory, True) |
|---|
| 122 | |
|---|
| 123 | entry = cset.entries[0] |
|---|
| 124 | self.assertEqual(entry.name, 'dir') |
|---|
| 125 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 126 | self.assertEqual(entry.is_directory, True) |
|---|
| 127 | |
|---|
| 128 | cset = csets[3] |
|---|
| 129 | self.assertEqual(cset.revision, 'modified') |
|---|
| 130 | self.assertEqual(len(cset.entries), 1) |
|---|
| 131 | |
|---|
| 132 | entry = cset.entries[0] |
|---|
| 133 | self.assertEqual(entry.name, 'a.txt') |
|---|
| 134 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 135 | self.assertEqual(entry.is_directory, False) |
|---|
| 136 | |
|---|
| 137 | def testIncrementalParser(self): |
|---|
| 138 | """Verify that the parser is effectively incremental""" |
|---|
| 139 | |
|---|
| 140 | log = self.getDarcsOutput('darcs-all_actions_test') |
|---|
| 141 | |
|---|
| 142 | csets = list(changesets_from_darcschanges(log, chunksize=100)) |
|---|
| 143 | self.assertEqual(len(csets), 4) |
|---|
| 144 | |
|---|
| 145 | def testOldDateFormat(self): |
|---|
| 146 | """Verify that the parser understands date format used by old darcs""" |
|---|
| 147 | |
|---|
| 148 | log = self.getDarcsOutput('darcs-old_date_format_test') |
|---|
| 149 | |
|---|
| 150 | csets = changesets_from_darcschanges(log) |
|---|
| 151 | |
|---|
| 152 | cset = csets.next() |
|---|
| 153 | self.assertEqual(cset.date, datetime(2003, 10, 14, 9, 42, 0, 0, UTC)) |
|---|
| 154 | |
|---|
| 155 | cset = csets.next() |
|---|
| 156 | self.assertEqual(cset.date, datetime(2003, 10, 14, 14, 2, 31, 0, UTC)) |
|---|
| 157 | |
|---|
| 158 | def testRenameAndRemove(self): |
|---|
| 159 | """Verify that the parser degrades rename A B+remove B to remove A""" |
|---|
| 160 | |
|---|
| 161 | log = self.getDarcsOutput('darcs-rename_then_remove_test') |
|---|
| 162 | csets = changesets_from_darcschanges(log) |
|---|
| 163 | |
|---|
| 164 | cset = csets.next() |
|---|
| 165 | self.assertEqual(len(cset.entries), 1) |
|---|
| 166 | |
|---|
| 167 | entry = cset.entries[0] |
|---|
| 168 | self.assertEqual(entry.name, 'fileA') |
|---|
| 169 | self.assertEqual(entry.action_kind, entry.DELETED) |
|---|
| 170 | |
|---|
| 171 | def testRenameAndAdd(self): |
|---|
| 172 | """Verify that the parser reduce rename A B+add B to rename A B""" |
|---|
| 173 | |
|---|
| 174 | log = self.getDarcsOutput('darcs-rename_and_add_test') |
|---|
| 175 | csets = changesets_from_darcschanges(log) |
|---|
| 176 | |
|---|
| 177 | cset = csets.next() |
|---|
| 178 | self.assertEqual(len(cset.entries), 5) |
|---|
| 179 | |
|---|
| 180 | entry = cset.entries[0] |
|---|
| 181 | self.assertEqual(entry.name, 'Autoconf.lhs.in') |
|---|
| 182 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 183 | |
|---|
| 184 | entry = cset.entries[1] |
|---|
| 185 | self.assertEqual(entry.name, 'Makefile') |
|---|
| 186 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 187 | |
|---|
| 188 | entry = cset.entries[2] |
|---|
| 189 | self.assertEqual(entry.name, 'autoconf.mk.in') |
|---|
| 190 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 191 | |
|---|
| 192 | entry = cset.entries[3] |
|---|
| 193 | self.assertEqual(entry.name, 'configure.in') |
|---|
| 194 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 195 | |
|---|
| 196 | entry = cset.entries[4] |
|---|
| 197 | self.assertEqual(entry.name, 'darcs_cgi.lhs') |
|---|
| 198 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 199 | |
|---|
| 200 | def testRenameAndAddDir(self): |
|---|
| 201 | """Verify that the parser reduce rename A B+add B to rename A B""" |
|---|
| 202 | |
|---|
| 203 | log = self.getDarcsOutput('darcs-rename_and_add_dir_test') |
|---|
| 204 | csets = changesets_from_darcschanges(log) |
|---|
| 205 | |
|---|
| 206 | cset = csets.next() |
|---|
| 207 | self.assertEqual(len(cset.entries), 7) |
|---|
| 208 | |
|---|
| 209 | entry = cset.entries[0] |
|---|
| 210 | self.assertEqual(entry.name, 'logos/plain_logo.png') |
|---|
| 211 | self.assertEqual(entry.action_kind, entry.RENAMED) |
|---|
| 212 | self.assertEqual(entry.old_name, 'logo.png') |
|---|
| 213 | |
|---|
| 214 | entry = cset.entries[1] |
|---|
| 215 | self.assertEqual(entry.name, 'logos') |
|---|
| 216 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 217 | |
|---|
| 218 | entry = cset.entries[2] |
|---|
| 219 | self.assertEqual(entry.name, 'logos/large_logo.png') |
|---|
| 220 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 221 | |
|---|
| 222 | def testBadOrderedXML(self): |
|---|
| 223 | "Verify if the parser is able to correct the bad order produced by changes --xml" |
|---|
| 224 | |
|---|
| 225 | log = self.getDarcsOutput('darcs-bad_xml_order_test') |
|---|
| 226 | csets = changesets_from_darcschanges(log) |
|---|
| 227 | |
|---|
| 228 | cset = csets.next() |
|---|
| 229 | |
|---|
| 230 | # Verify that each renamed entry is not within a directory added or renamed |
|---|
| 231 | # by a following hunk |
|---|
| 232 | for i,e in enumerate(cset.entries): |
|---|
| 233 | if e.action_kind == e.RENAMED: |
|---|
| 234 | postadds = [n.name for n in cset.entries[i+1:] |
|---|
| 235 | if ((e.name.startswith(n.name+'/') or (e.old_name==n.name)) and |
|---|
| 236 | (n.action_kind==n.ADDED or n.action_kind==n.RENAMED))] |
|---|
| 237 | self.assertEqual(postadds, []) |
|---|
| 238 | |
|---|
| 239 | def testAddAndRename(self): |
|---|
| 240 | "Verify if the parser degrades (add A)+(rename A B) to (add B)" |
|---|
| 241 | |
|---|
| 242 | log = self.getDarcsOutput('darcs-add_then_rename_test') |
|---|
| 243 | csets = changesets_from_darcschanges(log) |
|---|
| 244 | |
|---|
| 245 | cset = csets.next() |
|---|
| 246 | |
|---|
| 247 | entry = cset.entries[2] |
|---|
| 248 | self.assertEqual(entry.name, 'vcpx/repository/git/__init__.py') |
|---|
| 249 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 250 | |
|---|
| 251 | log = self.getDarcsOutput('darcs-mixed_test') |
|---|
| 252 | csets = changesets_from_darcschanges(log) |
|---|
| 253 | |
|---|
| 254 | cset = csets.next() |
|---|
| 255 | self.assertEqual([], [e for e in cset.entries if e.name == 'ancillary/mbox2rpc.py']) |
|---|
| 256 | self.assertEqual([], [e for e in cset.entries if e.action_kind == e.RENAMED]) |
|---|
| 257 | |
|---|
| 258 | def testAddRenameEdit(self): |
|---|
| 259 | "Verify if the parser degrades (rename A B)+(add A)+(edit B) to (rename A B)+(edit B)" |
|---|
| 260 | |
|---|
| 261 | log = self.getDarcsOutput('darcs-rename_add_edit_test') |
|---|
| 262 | csets = changesets_from_darcschanges(log) |
|---|
| 263 | |
|---|
| 264 | cset = csets.next() |
|---|
| 265 | self.assertEqual(len(cset.entries), 5) |
|---|
| 266 | |
|---|
| 267 | entry = cset.entries[0] |
|---|
| 268 | self.assertEqual(entry.name, 'vcpx/repository/git') |
|---|
| 269 | self.assertEqual(entry.is_directory, True) |
|---|
| 270 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 271 | |
|---|
| 272 | entry = cset.entries[1] |
|---|
| 273 | self.assertEqual(entry.name, 'vcpx/repository/git/target.py') |
|---|
| 274 | self.assertEqual(entry.old_name, 'vcpx/repository/git.py') |
|---|
| 275 | self.assertEqual(entry.action_kind, entry.RENAMED) |
|---|
| 276 | |
|---|
| 277 | entry = cset.entries[2] |
|---|
| 278 | self.assertEqual(entry.name, 'vcpx/repository/git/__init__.py') |
|---|
| 279 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 280 | |
|---|
| 281 | entry = cset.entries[3] |
|---|
| 282 | self.assertEqual(entry.name, 'vcpx/repository/git/source.py') |
|---|
| 283 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 284 | |
|---|
| 285 | entry = cset.entries[4] |
|---|
| 286 | self.assertEqual(entry.name, 'vcpx/repository/git/target.py') |
|---|
| 287 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 288 | |
|---|
| 289 | def testAddAndRemove(self): |
|---|
| 290 | "Verify if the parser annihilate (add A)+(remove A)" |
|---|
| 291 | |
|---|
| 292 | log = self.getDarcsOutput('darcs-add_then_remove_test') |
|---|
| 293 | csets = changesets_from_darcschanges(log) |
|---|
| 294 | |
|---|
| 295 | cset = csets.next() |
|---|
| 296 | |
|---|
| 297 | self.assertEqual([], [e for e in cset.entries |
|---|
| 298 | if e.name == 'Carpet/CarpetWeb/binaries/darcs-1.0.3-static-linux-i386.gz']) |
|---|
| 299 | |
|---|
| 300 | |
|---|
| 301 | class DarcsPullParser(DarcsParserTestCase): |
|---|
| 302 | """Tests for the parser of darcs pull""" |
|---|
| 303 | |
|---|
| 304 | def testParsePull(self): |
|---|
| 305 | """Verify basic darcs pull parser behaviour""" |
|---|
| 306 | |
|---|
| 307 | from vcpx.changes import Changeset |
|---|
| 308 | |
|---|
| 309 | output = self.getDarcsOutput('darcs-pull_parser_test') |
|---|
| 310 | hashes = self.getDarcsOutput('darcs-pull_parser_test', ext='.hashes') |
|---|
| 311 | |
|---|
| 312 | class FauxRepository(object): |
|---|
| 313 | name = 'foo' |
|---|
| 314 | dswd = DarcsSourceWorkingDir(FauxRepository()) |
|---|
| 315 | results = list(dswd._parseDarcsPull(output)) |
|---|
| 316 | |
|---|
| 317 | expected_changesets = [ |
|---|
| 318 | Changeset('Monotone add is no longer recursive by default ' |
|---|
| 319 | '(as of 2006-11-02).', |
|---|
| 320 | datetime(2006,12,12,05,30,20, tzinfo=UTC), |
|---|
| 321 | 'elb@elitists.net', |
|---|
| 322 | 'Use add --recursive when adding subtrees.'), |
|---|
| 323 | Changeset('Fix ticket #87', |
|---|
| 324 | datetime(2006,12,14,23,45,04, tzinfo=UTC), |
|---|
| 325 | 'Edgar Alves <edgar.alves@gmail.com>', |
|---|
| 326 | ''), |
|---|
| 327 | Changeset("Don't assume the timestamp in darcs log is exactly " |
|---|
| 328 | "28 chars long", |
|---|
| 329 | datetime(2006,11,17,20,26,28, tzinfo=UTC), |
|---|
| 330 | 'lele@nautilus.homeip.net', |
|---|
| 331 | ''), |
|---|
| 332 | Changeset('tagged Version 0.9.27', |
|---|
| 333 | datetime(2006,12,11,21,07,48, tzinfo=UTC), |
|---|
| 334 | 'lele@nautilus.homeip.net', |
|---|
| 335 | ''), |
|---|
| 336 | Changeset('darcs: factor parsing from process invocation in DarcsSourceWorkingDir._getUpstreamChangesets', |
|---|
| 337 | datetime(2007, 1, 6, 1,52,50, tzinfo=UTC), |
|---|
| 338 | 'Kevin Turner <kevin@janrain.com>', |
|---|
| 339 | ''), |
|---|
| 340 | ] |
|---|
| 341 | for changeset, expected_hash in zip(expected_changesets, hashes): |
|---|
| 342 | changeset.darcs_hash = expected_hash.strip() |
|---|
| 343 | |
|---|
| 344 | self.failUnlessEqual(len(expected_changesets), len(results)) |
|---|
| 345 | |
|---|
| 346 | for expected, result in zip(expected_changesets, results): |
|---|
| 347 | self.failUnlessEqual(expected, result, |
|---|
| 348 | "%s != %s" % (expected, result)) |
|---|
| 349 | self.failUnlessEqual(expected.darcs_hash, result.darcs_hash, |
|---|
| 350 | 'hash failed for %s\n %s !=\n %s' % |
|---|
| 351 | (result, expected.darcs_hash, |
|---|
| 352 | result.darcs_hash)) |
|---|
| 353 | |
|---|
| 354 | output = self.getDarcsOutput('darcs-pull_parser_test2') |
|---|
| 355 | results = list(dswd._parseDarcsPull(output)) |
|---|
| 356 | first = results[0] |
|---|
| 357 | self.failUnlessEqual(first.revision, 'Added some basic utility functions') |
|---|
| 358 | self.failUnlessEqual(first.date, datetime(2003,10,10,16,23,44, tzinfo=UTC)) |
|---|
| 359 | self.failUnlessEqual(first.author, 'John Goerzen <jgoerzen@complete.org>') |
|---|
| 360 | self.failUnlessEqual(first.log, '\n\n(jgoerzen@complete.org--projects/tla-buildpackage--head--1.0--patch-2)') |
|---|
| 361 | last = results[-1] |
|---|
| 362 | self.failUnlessEqual(last.log, 'Keywords:\n\nAdded some code in Python to get things going.\n') |
|---|