# # # patch "ChangeLog" # from [97bda855566c0af9365a6375072eff9908e5f12a] # to [44fd082f5976f495f1f63b3728378c2189fcd069] # # patch "mtn.py" # from [be23fb4b716cb8a29ac4bf37981fe21a209c810f] # to [2e8eab27099d355cdc2785b1cf954aeea4fbb8a4] # # patch "tests.py" # from [4dd3dd2828cad46f83d81ae47a7fb3b22db8302c] # to [8e37aaecf8f3cc546ca94e5f7bd157b0a72b4f51] # ============================================================ --- ChangeLog 97bda855566c0af9365a6375072eff9908e5f12a +++ ChangeLog 44fd082f5976f495f1f63b3728378c2189fcd069 @@ -1,5 +1,12 @@ 2007-04-02 Grahame Bowland + * more tests; check regexps (and found a bug + or two with them, that might have done untoward + things!) and and start checking the string + subclasses in mtn.py + +2007-04-02 Grahame Bowland + * start of a test suite using PyUnit; first off, check that config.py is sane. This is actually useful for people that accidentally specify wrong ============================================================ --- mtn.py be23fb4b716cb8a29ac4bf37981fe21a209c810f +++ mtn.py 2e8eab27099d355cdc2785b1cf954aeea4fbb8a4 @@ -27,9 +27,10 @@ def group_compile(r): def group_compile(r): return re.compile('('+r+')') -hex_re = r'[A-Fa-f0-9]*' +sha1_len = 40 +hex_re = r'^[A-Fa-f0-9]*' hex_re_c = group_compile(hex_re) -revision_re = r'[A-Fa-f0-9]{40}' +revision_re = r'[A-Fa-f0-9]{%d}' % sha1_len revision_re_c = group_compile(revision_re) name_re = r'^[\S]+' name_re_c = group_compile(name_re) @@ -42,7 +43,7 @@ class Revision(str): # special case that must be handled: empty (initial) revision ID '' str.__init__(v) self.obj_type = "revision" - if v != '' and not revision_re_c.match(self): + if v != '' and not (revision_re_c.match(self) and len(self) == sha1_len): raise MonotoneException("Not a valid revision ID: %s" % (v)) def abbrev(self): return '[' + self[:8] + '..]' ============================================================ --- tests.py 4dd3dd2828cad46f83d81ae47a7fb3b22db8302c +++ tests.py 8e37aaecf8f3cc546ca94e5f7bd157b0a72b4f51 @@ -43,6 +43,12 @@ class ConfigTest(unittest.TestCase): def is_directory(self, fname): self.failIf (not stat.S_ISDIR(os.stat(fname).st_mode), "Must be a directory: " + fname) + # + # describe the config file with lists of functions that should + # succeed on the value found in the config file. for now, any + # option listed below is required (ViewMTN doesn't really have + # optional configuration directives, anyway..) + # check_keys = [(lambda self : self.config, lambda obj, key : hasattr(obj, key), lambda obj, key : getattr(obj, key), @@ -88,5 +94,40 @@ class ConfigTest(unittest.TestCase): val = get_func(to_check, key) map(lambda func : func(self, val), funcs) +class MTNRegexpTests(unittest.TestCase): + entirely_non_hex = 'NOTX' + starts_with_hex = 'A9NOTX' + ends_with_hex = 'NOTXA9' + valid_revision = 'abcdEf0123456789abcdEf0123456789abcdef12' + too_long_revision = valid_revision + '9' + too_short_revision = valid_revision[:-1] + non_hex_revision = valid_revision.replace('a', 'Q') + non_hex_start_revision = 'QQ' + valid_revision + non_hex_end_revision = valid_revision + 'QQ' + + def testHex(self): + "Test that mtn.py regular expressions do what we think they do" + self.assertEqual(mtn.hex_re_c.match('').groups(), ('',), 'hex_re must match empty string') + self.assertEqual(mtn.hex_re_c.match(self.entirely_non_hex).groups(), ('',), 'hex_re must match entirely non-hex and group empty string') + self.assertEqual(mtn.hex_re_c.match(self.starts_with_hex).groups(), ('A9',), 'hex_re must match hex followed by non-hex and group beginning hex') + self.assertEqual(mtn.hex_re_c.match(self.ends_with_hex).groups(), ('',), 'hex_re must match non-hex followed by hex and group empty string') + + self.assertEqual(mtn.revision_re_c.match(''), None, 'revision_re must not match empty string') + self.assertEqual(mtn.revision_re_c.match(self.valid_revision).groups(), (self.valid_revision,), 'revision_re must match valid revision') + self.failIf(mtn.revision_re_c.match(self.too_short_revision), 'revision_re must not match too-short revision') + self.failIf(mtn.revision_re_c.match(self.non_hex_revision), 'revision_re must not match non-hex revision') + self.failIf(mtn.revision_re_c.match(self.non_hex_start_revision), 'revision_re must not match non-hex followed by valid revision') + self.failIf(mtn.revision_re_c.match(self.non_hex_end_revision), 'revision_re must not match valid revision followed by non-hex') + + def testRevision(self): + "Test the mtn.Revision class" + self.assertEqual (mtn.Revision(''), '', 'Revision must work for empty revision, and subclass str()') + self.assertRaises (mtn.MonotoneException, lambda : mtn.Revision(self.too_long_revision)) + self.assertRaises (mtn.MonotoneException, lambda : mtn.Revision(self.too_short_revision)) + self.assertRaises (mtn.MonotoneException, lambda : mtn.Revision(self.non_hex_revision)) + self.assertRaises (mtn.MonotoneException, lambda : mtn.Revision(self.non_hex_start_revision)) + self.assertRaises (mtn.MonotoneException, lambda : mtn.Revision(self.non_hex_end_revision)) + self.assertEqual (mtn.Revision(self.valid_revision), self.valid_revision, 'Revision must work for valid revision, and subclass str()') + if __name__ == '__main__': unittest.main()