Bring CHANGES up to date.
[cvs2svn.git] / cvs2svn_lib / test / rcs_stream_test.py
blobca160f859dad41d5d138ad39729b2c20e0647c12
1 #!/usr/bin/env python
2 # (Be in -*- python -*- mode.)
4 # ====================================================================
5 # Copyright (c) 2010 CollabNet. All rights reserved.
7 # This software is licensed as described in the file COPYING, which
8 # you should have received as part of this distribution. The terms
9 # are also available at http://subversion.tigris.org/license-1.html.
10 # If newer versions of this license are posted there, you may use a
11 # newer version instead, at your option.
13 # This software consists of voluntary contributions made by many
14 # individuals. For exact contribution history, see the revision
15 # history and logs, available at http://cvs2svn.tigris.org/.
16 # ====================================================================
18 """This program tests the RCSStream class.
20 When executed, this class conducts a number of unit tests of the
21 RCSStream class. It requires RCS's 'ci' program to be installed."""
23 import sys
24 import os
25 import shutil
26 import unittest
27 import subprocess
29 SRCPATH = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..'))
30 sys.path.insert(0, SRCPATH)
32 import unittest
34 from cvs2svn_lib.rcsparser import Sink
35 from cvs2svn_lib.rcsparser import parse
36 from cvs2svn_lib.rcs_stream import RCSStream
38 TMPDIR = os.path.join(SRCPATH, 'cvs2svn-tmp')
41 # Do we require that the inverse of an inverse delta is identical to
42 # the original delta? (This is not really required; it would be
43 # enough if the deltas were functionally the same.)
44 STRICT_INVERSES = True
47 class RCSRecorder(Sink):
48 def __init__(self):
49 self.texts = {}
51 def set_revision_info(self, rev, log, text):
52 self.texts[rev] = text
55 class RCSStreamTestCase(unittest.TestCase):
56 def __init__(self, name, doc, v1, v2):
57 unittest.TestCase.__init__(self)
58 self.name = name
59 self.doc = doc
60 self.v1 = v1
61 self.v2 = v2
62 self.filename = os.path.join(TMPDIR, 'rcsstream-%s' % self.name, 'a.txt')
64 def shortDescription(self):
65 return self.doc
67 def call(self, *args, **kwargs):
68 retcode = subprocess.call(*args, **kwargs)
69 self.assertEqual(retcode, 0)
71 def setUp(self):
72 if not os.path.isdir(os.path.dirname(self.filename)):
73 os.makedirs(os.path.dirname(self.filename))
75 f = open(self.filename, 'wb')
76 f.write(self.v1)
77 f.close()
79 self.call(
80 ['ci', '-q', '-i', '-t-' + self.name, '-mv1', '-l', self.filename],
83 f = open(self.filename, 'wb')
84 f.write(self.v2)
85 f.close()
87 self.call(
88 ['ci', '-q', '-f', '-mv2', self.filename],
91 def applyTest(self, old, delta, new):
92 s1 = RCSStream(old)
93 self.assertEqual(s1.get_text(), old)
94 s1.apply_diff(delta)
95 self.assertEqual(s1.get_text(), new)
97 s2 = RCSStream(old)
98 self.assertEqual(s2.get_text(), old)
99 s2.invert_diff(delta)
100 self.assertEqual(s2.get_text(), new)
102 def runTest(self):
103 self.assert_(os.path.isfile(self.filename + ',v'))
104 recorder = RCSRecorder()
106 f = open(self.filename + ',v', 'rb')
107 try:
108 parse(f, recorder)
109 finally:
110 f.close()
112 v2 = recorder.texts['1.2']
113 self.assertEqual(v2, self.v2)
114 delta = recorder.texts['1.1']
115 s = RCSStream(v2)
116 self.assertEqual(s.get_text(), self.v2)
117 invdelta = s.invert_diff(delta)
118 self.assertEqual(s.get_text(), self.v1)
119 delta2 = s.invert_diff(invdelta)
121 self.applyTest(self.v2, delta, self.v1)
122 self.applyTest(self.v1, invdelta, self.v2)
124 if STRICT_INVERSES:
125 self.assertEqual(delta2, delta)
126 elif delta2 != delta:
127 self.applyTest(self.v2, delta2, self.v1)
129 def tearDown(self):
130 shutil.rmtree(os.path.dirname(self.filename))
133 suite = unittest.TestSuite()
136 def add_test_pair(name, v1, v2):
137 suite.addTest(RCSStreamTestCase(name, name, v1, v2))
138 if v1 != v2:
139 suite.addTest(RCSStreamTestCase(name + '-reverse', name + '-reverse', v2, v1))
142 def add_test(name, v1, v2):
143 add_test_pair(name, v1, v2)
144 if v1.endswith('\n'):
145 add_test_pair(name + '-1', v1[:-1], v2)
146 if v2.endswith('\n'):
147 add_test_pair(name + '-2', v1, v2[:-1])
148 if v1.endswith('\n') and v2.endswith('\n'):
149 add_test_pair(name + '-3', v1[:-1], v2[:-1])
152 add_test('empty', '', '')
153 add_test('ab-initio', '', 'blah\n')
155 add_test('delete-at-start', 'a\nb\nc\n', 'b\nc\n')
156 add_test('delete-in-middle', 'a\nb\nc\n', 'a\nc\n')
157 add_test('delete-at-end', 'a\nb\nc\n', 'a\nb\n')
159 add_test('replace-at-start', 'a\nb\nc\n', 'a1\nb\nc\n')
160 add_test('replace-in-middle', 'a\nb\nc\n', 'a\nb1\nc\n')
161 add_test('replace-at-end', 'a\nb\nc\n', 'a\nb\nc1\n')
163 add_test('enlarge-at-start', 'a\nb\nc\n', 'a1\na2\nb\nc\n')
164 add_test('enlarge-in-middle', 'a\nb\nc\n', 'a\nb1\nb2\nc\n')
165 add_test('enlarge-at-end', 'a\nb\nc\n', 'a\nb\nc1\nc2\n')
168 unittest.TextTestRunner(verbosity=2).run(suite)