| #!/usr/bin/python2.4 |
| # |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| """Unit tests for the blip module.""" |
| |
| |
| import unittest |
| |
| import blip |
| import element |
| import ops |
| import simplejson |
| |
| TEST_BLIP_DATA = { |
| 'childBlipIds': [], |
| 'content': '\nhello world!\nanother line', |
| 'contributors': ['robot@test.com', 'user@test.com'], |
| 'creator': 'user@test.com', |
| 'lastModifiedTime': 1000, |
| 'parentBlipId': None, |
| 'annotations': [{'range': {'start': 2, 'end': 3}, |
| 'name': 'key', 'value': 'val'}], |
| 'waveId': 'test.com!w+g3h3im', |
| 'waveletId': 'test.com!root+conv', |
| 'elements':{'14':{'type':'GADGET','properties':{'url':'http://a/b.xml'}}}, |
| } |
| |
| CHILD_BLIP_ID = 'b+42' |
| ROOT_BLIP_ID = 'b+43' |
| |
| |
| class TestBlip(unittest.TestCase): |
| """Tests the primary data structures for the wave model.""" |
| |
| def assertBlipStartswith(self, expected, totest): |
| actual = totest.text[:len(expected)] |
| self.assertEquals(expected, actual) |
| |
| def new_blip(self, **args): |
| """Create a blip for testing.""" |
| data = TEST_BLIP_DATA.copy() |
| data.update(args) |
| res = blip.Blip(data, self.all_blips, self.operation_queue) |
| self.all_blips[res.blip_id] = res |
| return res |
| |
| def setUp(self): |
| self.all_blips = {} |
| self.operation_queue = ops.OperationQueue() |
| |
| def testBlipProperties(self): |
| root = self.new_blip(blipId=ROOT_BLIP_ID, |
| childBlipIds=[CHILD_BLIP_ID]) |
| child = self.new_blip(blipId=CHILD_BLIP_ID, |
| parentBlipId=ROOT_BLIP_ID) |
| self.assertEquals(ROOT_BLIP_ID, root.blip_id) |
| self.assertEquals([CHILD_BLIP_ID], root.child_blip_ids) |
| self.assertEquals(set(TEST_BLIP_DATA['contributors']), root.contributors) |
| self.assertEquals(TEST_BLIP_DATA['creator'], root.creator) |
| self.assertEquals(TEST_BLIP_DATA['content'], root.text) |
| self.assertEquals(TEST_BLIP_DATA['lastModifiedTime'], |
| root.last_modified_time) |
| self.assertEquals(TEST_BLIP_DATA['parentBlipId'], root.parent_blip_id) |
| self.assertEquals(TEST_BLIP_DATA['waveId'], root.wave_id) |
| self.assertEquals(TEST_BLIP_DATA['waveletId'], root.wavelet_id) |
| self.assertEquals(TEST_BLIP_DATA['content'][3], root[3]) |
| self.assertEquals(element.Gadget.class_type, root[14].type) |
| self.assertEquals('http://a/b.xml', root[14].url) |
| self.assertEquals('a', root.text[14]) |
| self.assertEquals(len(TEST_BLIP_DATA['content']), len(root)) |
| self.assertTrue(root.is_root()) |
| self.assertFalse(child.is_root()) |
| self.assertEquals(root, child.parent_blip) |
| |
| def testBlipSerialize(self): |
| root = self.new_blip(blipId=ROOT_BLIP_ID, |
| childBlipIds=[CHILD_BLIP_ID]) |
| serialized = root.serialize() |
| unserialized = blip.Blip(serialized, self.all_blips, self.operation_queue) |
| self.assertEquals(root.blip_id, unserialized.blip_id) |
| self.assertEquals(root.child_blip_ids, unserialized.child_blip_ids) |
| self.assertEquals(root.contributors, unserialized.contributors) |
| self.assertEquals(root.creator, unserialized.creator) |
| self.assertEquals(root.text, unserialized.text) |
| self.assertEquals(root.last_modified_time, unserialized.last_modified_time) |
| self.assertEquals(root.parent_blip_id, unserialized.parent_blip_id) |
| self.assertEquals(root.wave_id, unserialized.wave_id) |
| self.assertEquals(root.wavelet_id, unserialized.wavelet_id) |
| self.assertTrue(unserialized.is_root()) |
| |
| def testDocumentOperations(self): |
| blip = self.new_blip(blipId=ROOT_BLIP_ID) |
| newlines = [x for x in blip.find('\n')] |
| self.assertEquals(2, len(newlines)) |
| blip.first('world').replace('jupiter') |
| bits = blip.text.split('\n') |
| self.assertEquals(3, len(bits)) |
| self.assertEquals('hello jupiter!', bits[1]) |
| blip.range(2, 5).delete() |
| self.assertBlipStartswith('\nho jupiter', blip) |
| |
| blip.first('ho').insert_after('la') |
| self.assertBlipStartswith('\nhola jupiter', blip) |
| blip.at(3).insert(' ') |
| self.assertBlipStartswith('\nho la jupiter', blip) |
| |
| def testElementHandling(self): |
| blip = self.new_blip(blipId=ROOT_BLIP_ID) |
| url = 'http://www.test.com/image.png' |
| |
| org_len = len(blip) |
| blip.append(element.Image(url=url)) |
| |
| elems = [elem for elem in blip.find(element.Image, url=url)] |
| self.assertEquals(1, len(elems)) |
| elem = elems[0] |
| self.assertTrue(isinstance(elem, element.Image)) |
| blip.at(1).insert('twelve chars') |
| self.assertTrue(blip.text.startswith('\ntwelve charshello')) |
| |
| elem = blip[org_len + 12].value() |
| self.assertTrue(isinstance(elem, element.Image)) |
| |
| blip.first('twelve ').delete() |
| self.assertTrue(blip.text.startswith('\nchars')) |
| |
| elem = blip[org_len + 12 - len('twelve ')].value() |
| self.assertTrue(isinstance(elem, element.Image)) |
| |
| blip.first('chars').replace(element.Image(url=url)) |
| elems = [elem for elem in blip.find(element.Image, url=url)] |
| self.assertEquals(2, len(elems)) |
| self.assertTrue(blip.text.startswith('\n hello')) |
| elem = blip[1].value() |
| self.assertTrue(isinstance(elem, element.Image)) |
| |
| def testAnnotationHandling(self): |
| key = 'style/fontWeight' |
| |
| def get_bold(): |
| for an in blip.annotations[key]: |
| if an.value == 'bold': |
| return an |
| return None |
| |
| json = ('[{"range":{"start":3,"end":6},"name":"%s","value":"bold"}]' |
| % key) |
| blip = self.new_blip(blipId=ROOT_BLIP_ID, |
| annotations=simplejson.loads(json)) |
| self.assertEquals(1, len(blip.annotations)) |
| self.assertNotEqual(None, get_bold().value) |
| self.assertTrue(key in blip.annotations) |
| |
| # extend the bold annotation by adding: |
| blip.range(5, 8).annotate(key, 'bold') |
| self.assertEquals(1, len(blip.annotations)) |
| self.assertEquals(8, get_bold().end) |
| |
| # clip by adding a same keyed: |
| blip[4:12].annotate(key, 'italic') |
| self.assertEquals(2, len(blip.annotations[key])) |
| self.assertEquals(4, get_bold().end) |
| |
| # now split the italic one: |
| blip.range(6, 7).clear_annotation(key) |
| self.assertEquals(3, len(blip.annotations[key])) |
| |
| # test names and iteration |
| self.assertEquals(1, len(blip.annotations.names())) |
| self.assertEquals(3, len([x for x in blip.annotations])) |
| blip[3: 5].annotate('foo', 'bar') |
| self.assertEquals(2, len(blip.annotations.names())) |
| self.assertEquals(4, len([x for x in blip.annotations])) |
| blip[3: 5].clear_annotation('foo') |
| |
| # clear the whole thing |
| blip.all().clear_annotation(key) |
| # getting to the key should now throw an exception |
| self.assertRaises(KeyError, blip.annotations.__getitem__, key) |
| |
| def testBlipOperations(self): |
| blip = self.new_blip(blipId=ROOT_BLIP_ID) |
| self.assertEquals(1, len(self.all_blips)) |
| |
| otherblip = blip.reply() |
| otherblip.append('hello world') |
| self.assertEquals('hello world', otherblip.text) |
| self.assertEquals(blip.blip_id, otherblip.parent_blip_id) |
| self.assertEquals(2, len(self.all_blips)) |
| |
| another = blip.continue_thread() |
| another.append('hello world') |
| self.assertEquals('hello world', another.text) |
| self.assertEquals(blip.parent_blip_id, another.parent_blip_id) |
| self.assertEquals(3, len(self.all_blips)) |
| |
| inline = blip.insert_inline_blip(3) |
| self.assertEquals(blip.blip_id, inline.parent_blip_id) |
| self.assertEquals(4, len(self.all_blips)) |
| |
| def testInsertInlineBlipCantInsertAtTheBeginning(self): |
| blip = self.new_blip(blipId=ROOT_BLIP_ID) |
| self.assertEquals(1, len(self.all_blips)) |
| self.assertRaises(IndexError, blip.insert_inline_blip, 0) |
| self.assertEquals(1, len(self.all_blips)) |
| |
| def testDocumentModify(self): |
| blip = self.new_blip(blipId=ROOT_BLIP_ID) |
| blip.all().replace('a text with text and then some text') |
| blip[7].insert('text ') |
| blip.all('text').replace('thing') |
| self.assertEquals('a thing thing with thing and then some thing', |
| blip.text) |
| |
| def testIteration(self): |
| blip = self.new_blip(blipId=ROOT_BLIP_ID) |
| blip.all().replace('aaa 012 aaa 345 aaa 322') |
| count = 0 |
| prev = -1 |
| for start, end in blip.all('aaa'): |
| count += 1 |
| self.assertTrue(prev < start) |
| prev = start |
| self.assertEquals(3, count) |
| |
| |
| def testBlipRefValue(self): |
| blip = self.new_blip(blipId=ROOT_BLIP_ID) |
| content = blip.text |
| content = content[:4] + content[5:] |
| del blip[4] |
| self.assertEquals(content, blip.text) |
| |
| content = content[:2] + content[3:] |
| del blip[2:3] |
| self.assertEquals(content, blip.text) |
| |
| blip[2:3] = 'bike' |
| content = content[:2] + 'bike' + content[3:] |
| self.assertEquals(content, blip.text) |
| |
| url = 'http://www.test.com/image.png' |
| blip.append(element.Image(url=url)) |
| self.assertEqual(url, blip.first(element.Image).url) |
| |
| url2 = 'http://www.test.com/another.png' |
| blip[-1].update_element({'url': url2}) |
| self.assertEqual(url2, blip.first(element.Image).url) |
| |
| self.assertTrue(blip[3:5] == blip.text[3:5]) |
| |
| blip.append('geheim') |
| self.assertTrue(blip.first('geheim')) |
| self.assertFalse(blip.first(element.Button)) |
| blip.append(element.Button(name='test1', value='Click')) |
| button = blip.first(element.Button) |
| button.update_element({'name': 'test2'}) |
| self.assertEqual('test2', button.name) |
| |
| def testReplace(self): |
| blip = self.new_blip(blipId=ROOT_BLIP_ID) |
| blip.all().replace('\nxxxx') |
| blip.all('yyy').replace('zzz') |
| self.assertEqual('\nxxxx', blip.text) |
| |
| def testDeleteRangeThatSpansAcrossAnnotationEndPoint(self): |
| json = ('[{"range":{"start":1,"end":3},"name":"style","value":"bold"}]') |
| blip = self.new_blip(blipId=ROOT_BLIP_ID, |
| annotations=simplejson.loads(json), |
| content='\nFoo bar.') |
| blip.range(2, 4).delete() |
| self.assertEqual('\nF bar.', blip.text) |
| self.assertEqual(1, blip.annotations['style'][0].start) |
| self.assertEqual(2, blip.annotations['style'][0].end) |
| |
| def testInsertBeforeAnnotationStartPoint(self): |
| json = ('[{"range":{"start":4,"end":9},"name":"style","value":"bold"}]') |
| blip = self.new_blip(blipId=ROOT_BLIP_ID, |
| annotations=simplejson.loads(json), |
| content='\nFoo bar.') |
| blip.at(4).insert('d and') |
| self.assertEqual('\nFood and bar.', blip.text) |
| self.assertEqual(9, blip.annotations['style'][0].start) |
| self.assertEqual(14, blip.annotations['style'][0].end) |
| |
| def testDeleteRangeInsideAnnotation(self): |
| json = ('[{"range":{"start":1,"end":5},"name":"style","value":"bold"}]') |
| blip = self.new_blip(blipId=ROOT_BLIP_ID, |
| annotations=simplejson.loads(json), |
| content='\nFoo bar.') |
| blip.range(2, 4).delete() |
| |
| self.assertEqual('\nF bar.', blip.text) |
| self.assertEqual(1, blip.annotations['style'][0].start) |
| self.assertEqual(3, blip.annotations['style'][0].end) |
| |
| def testReplaceInsideAnnotation(self): |
| json = ('[{"range":{"start":1,"end":5},"name":"style","value":"bold"}]') |
| blip = self.new_blip(blipId=ROOT_BLIP_ID, |
| annotations=simplejson.loads(json), |
| content='\nFoo bar.') |
| blip.range(2, 4).replace('ooo') |
| self.assertEqual('\nFooo bar.', blip.text) |
| self.assertEqual(1, blip.annotations['style'][0].start) |
| self.assertEqual(6, blip.annotations['style'][0].end) |
| |
| blip.range(2, 5).replace('o') |
| self.assertEqual('\nFo bar.', blip.text) |
| self.assertEqual(1, blip.annotations['style'][0].start) |
| self.assertEqual(4, blip.annotations['style'][0].end) |
| |
| def testReplaceSpanAnnotation(self): |
| json = ('[{"range":{"start":1,"end":4},"name":"style","value":"bold"}]') |
| blip = self.new_blip(blipId=ROOT_BLIP_ID, |
| annotations=simplejson.loads(json), |
| content='\nFoo bar.') |
| blip.range(2, 9).replace('') |
| self.assertEqual('\nF', blip.text) |
| self.assertEqual(1, blip.annotations['style'][0].start) |
| self.assertEqual(2, blip.annotations['style'][0].end) |
| |
| def testSearchWithNoMatchShouldNotGenerateOperation(self): |
| blip = self.new_blip(blipId=ROOT_BLIP_ID) |
| self.assertEqual(-1, blip.text.find(':(')) |
| self.assertEqual(0, len(self.operation_queue)) |
| blip.all(':(').replace(':)') |
| self.assertEqual(0, len(self.operation_queue)) |
| |
| def testBlipsRemoveWithId(self): |
| blip_dict = { |
| ROOT_BLIP_ID: self.new_blip(blipId=ROOT_BLIP_ID, |
| childBlipIds=[CHILD_BLIP_ID]), |
| CHILD_BLIP_ID: self.new_blip(blipId=CHILD_BLIP_ID, |
| parentBlipId=ROOT_BLIP_ID) |
| } |
| blips = blip.Blips(blip_dict) |
| blips._remove_with_id(CHILD_BLIP_ID) |
| self.assertEqual(1, len(blips)) |
| self.assertEqual(0, len(blips[ROOT_BLIP_ID].child_blip_ids)) |
| |
| def testAppendMarkup(self): |
| blip = self.new_blip(blipId=ROOT_BLIP_ID, content='\nFoo bar.') |
| markup = '<p><span>markup<span> content</p>' |
| blip.append_markup(markup) |
| self.assertEqual(1, len(self.operation_queue)) |
| self.assertEqual('\nFoo bar.\nmarkup content', blip.text) |
| |
| def testBundledAnnotations(self): |
| blip = self.new_blip(blipId=ROOT_BLIP_ID, content='\nFoo bar.') |
| blip.append('not bold') |
| blip.append('bold', bundled_annotations=[('style/fontWeight', 'bold')]) |
| self.assertEqual(2, len(blip.annotations)) |
| self.assertEqual('bold', blip.annotations['style/fontWeight'][0].value) |
| |
| def testInlineBlipOffset(self): |
| offset = 14 |
| self.new_blip(blipId=ROOT_BLIP_ID, |
| childBlipIds=[CHILD_BLIP_ID], |
| elements={str(offset): |
| {'type': element.Element.INLINE_BLIP_TYPE, |
| 'properties': {'id': CHILD_BLIP_ID}}}) |
| child = self.new_blip(blipId=CHILD_BLIP_ID, |
| parentBlipId=ROOT_BLIP_ID) |
| self.assertEqual(offset, child.inline_blip_offset) |
| |
| if __name__ == '__main__': |
| unittest.main() |