| 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 unittest import TestCase |
|---|
| 9 | from datetime import datetime |
|---|
| 10 | from StringIO import StringIO |
|---|
| 11 | from vcpx.repository.darcs import changesets_from_darcschanges |
|---|
| 12 | from vcpx.shwrap import ExternalCommand, PIPE |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | class DarcsChangesParser(TestCase): |
|---|
| 16 | """Tests for the parser of darcs changes""" |
|---|
| 17 | |
|---|
| 18 | SIMPLE_TEST = """\ |
|---|
| 19 | <changelog> |
|---|
| 20 | <patch author='lele@nautilus.homeip.net' date='20040716123737' local_date='Fri Jul 16 14:37:37 CEST 2004' inverted='False' hash='20040716123737-97f81-9db0d923d2ba6f4c3808cb04a4ae4cf99fed185b.gz'> |
|---|
| 21 | <name>Fix the CVS parser to omit already seen changesets</name> |
|---|
| 22 | <comment>For some unknown reasons....</comment> |
|---|
| 23 | |
|---|
| 24 | <summary> |
|---|
| 25 | <modify_file>vcpx/cvs.py<removed_lines num='4'/><added_lines num='11'/></modify_file> |
|---|
| 26 | <modify_file>vcpx/tests/cvs.py<removed_lines num='14'/><added_lines num='32'/></modify_file> |
|---|
| 27 | </summary> |
|---|
| 28 | |
|---|
| 29 | </patch> |
|---|
| 30 | |
|---|
| 31 | <patch author='lele@nautilus.homeip.net' date='20040601140559' local_date='Tue Jun 1 16:05:59 CEST 2004' inverted='False' hash='20040601140559-97f81-b669594864cb35290fbe4848e6645e73057a8caf.gz'> |
|---|
| 32 | <name>Svn log parser with test</name> |
|---|
| 33 | |
|---|
| 34 | <summary> |
|---|
| 35 | <modify_file>cvsync/svn.py<removed_lines num='1'/><added_lines num='93'/></modify_file> |
|---|
| 36 | <modify_file>cvsync/tests/__init__.py<added_lines num='1'/></modify_file> |
|---|
| 37 | <add_file>cvsync/tests/svn.py</add_file> |
|---|
| 38 | <add_file>cvsync/tests/testrepo.dump</add_file> |
|---|
| 39 | </summary> |
|---|
| 40 | |
|---|
| 41 | </patch> |
|---|
| 42 | |
|---|
| 43 | </changelog> |
|---|
| 44 | """ |
|---|
| 45 | |
|---|
| 46 | def testBasicBehaviour(self): |
|---|
| 47 | """Verify basic darcs changes parser behaviour""" |
|---|
| 48 | |
|---|
| 49 | log = StringIO(self.SIMPLE_TEST) |
|---|
| 50 | |
|---|
| 51 | csets = changesets_from_darcschanges(log) |
|---|
| 52 | |
|---|
| 53 | cset = csets.next() |
|---|
| 54 | self.assertEqual(cset.revision, |
|---|
| 55 | "Fix the CVS parser to omit already seen changesets") |
|---|
| 56 | self.assertEqual(cset.author, "lele@nautilus.homeip.net") |
|---|
| 57 | self.assertEqual(cset.date, datetime(2004, 7, 16, 12, 37, 37)) |
|---|
| 58 | self.assertEqual(cset.log, |
|---|
| 59 | "Fix the CVS parser to omit already seen changesets\n" |
|---|
| 60 | "For some unknown reasons....") |
|---|
| 61 | entry = cset.entries[0] |
|---|
| 62 | self.assertEqual(entry.name, 'vcpx/cvs.py') |
|---|
| 63 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 64 | |
|---|
| 65 | cset = csets.next() |
|---|
| 66 | self.assertEqual(cset.revision, |
|---|
| 67 | "Svn log parser with test") |
|---|
| 68 | self.assertEqual(cset.date, datetime(2004, 6, 1, 14, 5, 59)) |
|---|
| 69 | self.assertEqual(len(cset.entries), 4) |
|---|
| 70 | self.assertEqual(cset.darcs_hash, |
|---|
| 71 | '20040601140559-97f81-b669594864cb35290fbe4848e6645e73057a8caf.gz') |
|---|
| 72 | |
|---|
| 73 | entry = cset.entries[0] |
|---|
| 74 | self.assertEqual(entry.name, 'cvsync/svn.py') |
|---|
| 75 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 76 | entry = cset.entries[1] |
|---|
| 77 | self.assertEqual(entry.name, 'cvsync/tests/__init__.py') |
|---|
| 78 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 79 | entry = cset.entries[2] |
|---|
| 80 | self.assertEqual(entry.name, 'cvsync/tests/svn.py') |
|---|
| 81 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 82 | entry = cset.entries[3] |
|---|
| 83 | self.assertEqual(entry.name, 'cvsync/tests/testrepo.dump') |
|---|
| 84 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 85 | |
|---|
| 86 | def testOnTailorOwnRepo(self): |
|---|
| 87 | """Verify fetching unidiff of a darcs patch""" |
|---|
| 88 | |
|---|
| 89 | from os import getcwd |
|---|
| 90 | |
|---|
| 91 | patchname = 'more detailed diags on SAXException' |
|---|
| 92 | changes = ExternalCommand(command=["darcs", "changes", "--xml", "--summary", |
|---|
| 93 | "--patches", patchname]) |
|---|
| 94 | csets = changesets_from_darcschanges(changes.execute(stdout=PIPE)[0], |
|---|
| 95 | unidiff=True, |
|---|
| 96 | repodir=getcwd()) |
|---|
| 97 | unidiff = csets.next().unidiff |
|---|
| 98 | head = unidiff.split('\n')[0] |
|---|
| 99 | self.assertEqual(head, 'Thu Jun 9 22:17:11 CEST 2005 zooko@zooko.com') |
|---|
| 100 | |
|---|
| 101 | ALL_ACTIONS_TEST = """\ |
|---|
| 102 | <changelog> |
|---|
| 103 | <patch author='' date='20050811140203' local_date='Thu Aug 11 16:02:03 CEST 2005' inverted='False' hash='20050811140203-da39a-0a36c886b2479b20ab9188781fe2e51f9a50a175.gz'> |
|---|
| 104 | <name>first</name> |
|---|
| 105 | <summary> |
|---|
| 106 | <add_file> |
|---|
| 107 | a.txt |
|---|
| 108 | </add_file> |
|---|
| 109 | <add_directory> |
|---|
| 110 | dir |
|---|
| 111 | </add_directory> |
|---|
| 112 | </summary> |
|---|
| 113 | </patch> |
|---|
| 114 | <patch author='' date='20050811140254' local_date='Thu Aug 11 16:02:54 CEST 2005' inverted='False' hash='20050811140254-da39a-b2ad279f1d7edae8e07b7b1ea8f3e63dbb242bf0.gz'> |
|---|
| 115 | <name>removed</name> |
|---|
| 116 | <summary> |
|---|
| 117 | <remove_directory> |
|---|
| 118 | dir |
|---|
| 119 | </remove_directory> |
|---|
| 120 | </summary> |
|---|
| 121 | </patch> |
|---|
| 122 | <patch author='' date='20050811140314' local_date='Thu Aug 11 16:03:14 CEST 2005' inverted='False' hash='20050811140314-da39a-de701bff466827b91e51658e411c768f43abc1b0.gz'> |
|---|
| 123 | <name>moved</name> |
|---|
| 124 | <summary> |
|---|
| 125 | <move from="bdir" to="dir"/> |
|---|
| 126 | <add_directory> |
|---|
| 127 | bdir |
|---|
| 128 | </add_directory> |
|---|
| 129 | </summary> |
|---|
| 130 | </patch> |
|---|
| 131 | <patch author='lele@metapensiero.it' date='20050811143245' local_date='Thu Aug 11 16:32:45 CEST 2005' inverted='False' hash='20050811143245-7a6fb-663bb3085e9b7996f554e4bd9d2f0b13208d65e0.gz'> |
|---|
| 132 | <name>modified</name> |
|---|
| 133 | <summary> |
|---|
| 134 | <modify_file> |
|---|
| 135 | a.txt<added_lines num='3'/> |
|---|
| 136 | </modify_file> |
|---|
| 137 | </summary> |
|---|
| 138 | </patch> |
|---|
| 139 | </changelog> |
|---|
| 140 | """ |
|---|
| 141 | |
|---|
| 142 | def testAllActions(self): |
|---|
| 143 | """Verify darcs changes parser understand all actions""" |
|---|
| 144 | |
|---|
| 145 | log = StringIO(self.ALL_ACTIONS_TEST) |
|---|
| 146 | |
|---|
| 147 | csets = list(changesets_from_darcschanges(log)) |
|---|
| 148 | |
|---|
| 149 | self.assertEqual(len(csets), 4) |
|---|
| 150 | |
|---|
| 151 | cset = csets[0] |
|---|
| 152 | self.assertEqual(cset.revision, 'first') |
|---|
| 153 | self.assertEqual(len(cset.entries), 2) |
|---|
| 154 | |
|---|
| 155 | entry = cset.entries[0] |
|---|
| 156 | self.assertEqual(entry.name, 'a.txt') |
|---|
| 157 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 158 | entry = cset.entries[1] |
|---|
| 159 | self.assertEqual(entry.name, 'dir') |
|---|
| 160 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 161 | |
|---|
| 162 | cset = csets[1] |
|---|
| 163 | self.assertEqual(cset.revision, 'removed') |
|---|
| 164 | self.assertEqual(len(cset.entries), 1) |
|---|
| 165 | |
|---|
| 166 | entry = cset.entries[0] |
|---|
| 167 | self.assertEqual(entry.name, 'dir') |
|---|
| 168 | self.assertEqual(entry.action_kind, entry.DELETED) |
|---|
| 169 | |
|---|
| 170 | cset = csets[2] |
|---|
| 171 | self.assertEqual(cset.revision, 'moved') |
|---|
| 172 | self.assertEqual(len(cset.entries), 2) |
|---|
| 173 | |
|---|
| 174 | entry = cset.entries[0] |
|---|
| 175 | self.assertEqual(entry.name, 'dir') |
|---|
| 176 | self.assertEqual(entry.action_kind, entry.RENAMED) |
|---|
| 177 | |
|---|
| 178 | entry = cset.entries[1] |
|---|
| 179 | self.assertEqual(entry.name, 'bdir') |
|---|
| 180 | self.assertEqual(entry.action_kind, entry.ADDED) |
|---|
| 181 | |
|---|
| 182 | cset = csets[3] |
|---|
| 183 | self.assertEqual(cset.revision, 'modified') |
|---|
| 184 | self.assertEqual(len(cset.entries), 1) |
|---|
| 185 | |
|---|
| 186 | entry = cset.entries[0] |
|---|
| 187 | self.assertEqual(entry.name, 'a.txt') |
|---|
| 188 | self.assertEqual(entry.action_kind, entry.UPDATED) |
|---|
| 189 | |
|---|
| 190 | def testIncrementalParser(self): |
|---|
| 191 | """Verify that the parser is effectively incremental""" |
|---|
| 192 | |
|---|
| 193 | log = StringIO(self.ALL_ACTIONS_TEST) |
|---|
| 194 | |
|---|
| 195 | csets = list(changesets_from_darcschanges(log, chunksize=100)) |
|---|
| 196 | self.assertEqual(len(csets), 4) |
|---|
| 197 | |
|---|
| 198 | OLD_DATE_FORMAT_TEST = """\ |
|---|
| 199 | <changelog> |
|---|
| 200 | <patch author='David Roundy <droundy@abridgegame.org>' date='Tue Oct 14 09:42:00 EDT 2003' local_date='Tue Oct 14 15:42:00 CEST 2003' inverted='False' hash='20031014094200-53a90-5896ac929692179d06a42af70f273800e4842603.gz'> |
|---|
| 201 | <name>use new select code in record.</name> |
|---|
| 202 | </patch> |
|---|
| 203 | <patch author='David Roundy <droundy@abridgegame.org>' date='20031014140231' local_date='Tue Oct 14 16:02:31 CEST 2003' inverted='False' hash='20031014140231-53a90-f5b6f441d32bd49d8ceacd6d804f31a462f94b88.gz'> |
|---|
| 204 | <name>use iso format for dates in record.</name> |
|---|
| 205 | </patch> |
|---|
| 206 | </changelog> |
|---|
| 207 | """ |
|---|
| 208 | |
|---|
| 209 | def testOldDateFormat(self): |
|---|
| 210 | """Verify that the parser understands date format used by old darcs""" |
|---|
| 211 | |
|---|
| 212 | log = StringIO(self.OLD_DATE_FORMAT_TEST) |
|---|
| 213 | |
|---|
| 214 | csets = changesets_from_darcschanges(log) |
|---|
| 215 | |
|---|
| 216 | cset = csets.next() |
|---|
| 217 | self.assertEqual(cset.date, datetime(2003, 10, 14, 9, 42, 0)) |
|---|
| 218 | |
|---|
| 219 | cset = csets.next() |
|---|
| 220 | self.assertEqual(cset.date, datetime(2003, 10, 14, 14, 2, 31)) |
|---|
| 221 | |
|---|
| 222 | RENAME_THEN_REMOVE_TEST = """ |
|---|
| 223 | <changelog> |
|---|
| 224 | <patch author='lele@nautilus.homeip.net' date='20060525213905' local_date='Thu May 25 23:39:05 CEST 2006' inverted='False' hash='20060525213905-97f81-292b84413dfdfca140fe104eb29273b50cb5701a.gz'> |
|---|
| 225 | <name>Move A to B and delete B</name> |
|---|
| 226 | <summary> |
|---|
| 227 | <move from="fileA" to="fileB"/> |
|---|
| 228 | <remove_file> |
|---|
| 229 | fileB |
|---|
| 230 | </remove_file> |
|---|
| 231 | </summary> |
|---|
| 232 | </patch> |
|---|
| 233 | </changelog> |
|---|
| 234 | """ |
|---|
| 235 | |
|---|
| 236 | def testRenameAndRemove(self): |
|---|
| 237 | """Verify that the parser degrades rename A B+remove B to remove A""" |
|---|
| 238 | |
|---|
| 239 | log = StringIO(self.RENAME_THEN_REMOVE_TEST) |
|---|
| 240 | csets = changesets_from_darcschanges(log) |
|---|
| 241 | |
|---|
| 242 | cset = csets.next() |
|---|
| 243 | self.assertEqual(len(cset.entries), 1) |
|---|
| 244 | |
|---|
| 245 | entry = cset.entries[0] |
|---|
| 246 | self.assertEqual(entry.name, 'fileA') |
|---|
| 247 | self.assertEqual(entry.action_kind, entry.DELETED) |
|---|
| 248 | |
|---|
| 249 | BAD_XML_ORDER_TEST = """ |
|---|
| 250 | <changelog> |
|---|
| 251 | <patch author='robert.mcqueen@collabora.co.uk' date='20060121232733' local_date='Sun Jan 22 00:27:33 CET 2006' inverted='False' hash='20060121232733-0e791-01925e82713877d33452566a27eaad4184e287df.gz'> |
|---|
| 252 | <name>remove any possibility for darcs crack when moving from generated XML or generated source to the live tree, by putting the generated code in the live tree, and make whoever is doing the generation pull the changes over manually</name> |
|---|
| 253 | <summary> |
|---|
| 254 | <move from="tools/Makefile.am" to="generate/Makefile.am"/> |
|---|
| 255 | <move from="tools/generrors.py" to="generate/generrors.py"/> |
|---|
| 256 | <move from="tools/gengobject.py" to="generate/gengobject.py"/> |
|---|
| 257 | <move from="gabble-connection-manager.xml" to="generate/xml-modified/gabble-connection-manager.xml"/> |
|---|
| 258 | <move from="gabble-connection.xml" to="generate/xml-modified/gabble-connection.xml"/> |
|---|
| 259 | <move from="gabble-im-channel.xml" to="generate/xml-modified/gabble-im-channel.xml"/> |
|---|
| 260 | <move from="tools/README-do_gen" to="generate/README"/> |
|---|
| 261 | <move from="tools/do_gen.sh" to="generate/do_src.sh"/> |
|---|
| 262 | <modify_file> |
|---|
| 263 | Makefile.am<removed_lines num='1'/><added_lines num='1'/> |
|---|
| 264 | </modify_file> |
|---|
| 265 | <add_directory> |
|---|
| 266 | generate |
|---|
| 267 | </add_directory> |
|---|
| 268 | <modify_file> |
|---|
| 269 | generate/README<removed_lines num='2'/><added_lines num='14'/> |
|---|
| 270 | </modify_file> |
|---|
| 271 | <modify_file> |
|---|
| 272 | generate/do_src.sh<removed_lines num='8'/><added_lines num='19'/> |
|---|
| 273 | </modify_file> |
|---|
| 274 | <add_file> |
|---|
| 275 | generate/do_xml.sh |
|---|
| 276 | </add_file> |
|---|
| 277 | <add_file> |
|---|
| 278 | generate/gabble.def |
|---|
| 279 | </add_file> |
|---|
| 280 | <remove_file> |
|---|
| 281 | generate/generrors.py |
|---|
| 282 | </remove_file> |
|---|
| 283 | <remove_file> |
|---|
| 284 | generate/gengobject.py |
|---|
| 285 | </remove_file> |
|---|
| 286 | <add_directory> |
|---|
| 287 | generate/src |
|---|
| 288 | </add_directory> |
|---|
| 289 | <add_file> |
|---|
| 290 | generate/src/gabble-connection-manager-signals-marshal.list |
|---|
| 291 | </add_file> |
|---|
| 292 | <add_file> |
|---|
| 293 | generate/src/gabble-connection-manager.c |
|---|
| 294 | </add_file> |
|---|
| 295 | <add_file> |
|---|
| 296 | generate/src/gabble-connection-manager.h |
|---|
| 297 | </add_file> |
|---|
| 298 | <add_file> |
|---|
| 299 | generate/src/gabble-connection-signals-marshal.list |
|---|
| 300 | </add_file> |
|---|
| 301 | <add_file> |
|---|
| 302 | generate/src/gabble-connection.c |
|---|
| 303 | </add_file> |
|---|
| 304 | <add_file> |
|---|
| 305 | generate/src/gabble-connection.h |
|---|
| 306 | </add_file> |
|---|
| 307 | <add_file> |
|---|
| 308 | generate/src/gabble-im-channel-signals-marshal.list |
|---|
| 309 | </add_file> |
|---|
| 310 | <add_file> |
|---|
| 311 | generate/src/gabble-im-channel.c |
|---|
| 312 | </add_file> |
|---|
| 313 | <add_file> |
|---|
| 314 | generate/src/gabble-im-channel.h |
|---|
| 315 | </add_file> |
|---|
| 316 | <add_file> |
|---|
| 317 | generate/src/telepathy-errors.h |
|---|
| 318 | </add_file> |
|---|
| 319 | <add_directory> |
|---|
| 320 | generate/xml-modified |
|---|
| 321 | </add_directory> |
|---|
| 322 | <add_directory> |
|---|
| 323 | generate/xml-pristine |
|---|
| 324 | </add_directory> |
|---|
| 325 | <add_file> |
|---|
| 326 | generate/xml-pristine/gabble-connection-manager.xml |
|---|
| 327 | </add_file> |
|---|
| 328 | <add_file> |
|---|
| 329 | generate/xml-pristine/gabble-connection.xml |
|---|
| 330 | </add_file> |
|---|
| 331 | <add_file> |
|---|
| 332 | generate/xml-pristine/gabble-im-channel.xml |
|---|
| 333 | </add_file> |
|---|
| 334 | <remove_directory> |
|---|
| 335 | tools |
|---|
| 336 | </remove_directory> |
|---|
| 337 | </summary> |
|---|
| 338 | </patch> |
|---|
| 339 | </changelog> |
|---|
| 340 | """ |
|---|
| 341 | |
|---|
| 342 | def testBadOrderedXML(self): |
|---|
| 343 | "Verify if the parser is able to correct the bad order produced by changes --xml" |
|---|
| 344 | |
|---|
| 345 | log = StringIO(self.BAD_XML_ORDER_TEST) |
|---|
| 346 | csets = changesets_from_darcschanges(log) |
|---|
| 347 | |
|---|
| 348 | cset = csets.next() |
|---|
| 349 | |
|---|
| 350 | # Verify that each renamed entry is not within a directory added or renamed |
|---|
| 351 | # by a following hunk |
|---|
| 352 | for i,e in enumerate(cset.entries): |
|---|
| 353 | if e.action_kind == e.RENAMED: |
|---|
| 354 | postadds = [n for n in cset.entries[i+1:] |
|---|
| 355 | if e.name.startswith(n.name+'/') and (n.action_kind==n.ADDED or |
|---|
| 356 | n.action_kind==n.RENAMED)] |
|---|
| 357 | for ee in postadds: |
|---|
| 358 | print ee |
|---|
| 359 | self.assertEqual(postadds, []) |
|---|