Tests for WBE Chapter 3 ======================= Chapter 3 (Formatting Text) adds on font metrics and simple font styling via HTML tags. This file contains tests for the additional functionality. >>> import wbemocks >>> _ = wbemocks.socket.patch().start() >>> _ = wbemocks.ssl.patch().start() >>> import browser Make sure you have the expected default values for `HSTEP`, `VSTEP`, `WIDTH`, and `HEIGHT`. >>> browser.HSTEP 13 >>> browser.VSTEP 18 >>> browser.WIDTH 800 >>> browser.HEIGHT 600 Notes ===== You might need to modify the `__repr__` method on `Text` and `Tag` if you factored your project into multiple files: (This is especially true if you see a mismatched output of the form `<layout.Tag object at ...>`) ``` class Text: ... def __repr__(self): return "Text('{}')".format(self.text) class Tag: ... def __repr__(self): return "Tag('{}')".format(self.tag) ``` Testing `lex` ------------- The `lex` function in chapter three has been beefed up to return an array of `Tag` or `Text` objects, rather than just the stream of characters from the input. To allow us to print these in a readable form please add a `__repr__(self):` method to your `Tag` and `Text` classes. The bodies of these methods should, respectively, be `return "Tag('{}')".format(self.tag)` and `return "Text('{}')".format(self.text)` >>> browser.lex('<body>hello</body>') [Tag('body'), Text('hello'), Tag('/body')] >>> browser.lex('he<body>llo</body>') [Text('he'), Tag('body'), Text('llo'), Tag('/body')] >>> browser.lex('he<body>l</body>lo') [Text('he'), Tag('body'), Text('l'), Tag('/body'), Text('lo')] >>> browser.lex('he<body>l<div>l</div>o</body>') [Text('he'), Tag('body'), Text('l'), Tag('div'), Text('l'), Tag('/div'), Text('o'), Tag('/body')] Note that the tags do not have to match: >>> browser.lex('he<body>l</div>lo') [Text('he'), Tag('body'), Text('l'), Tag('/div'), Text('lo')] >>> browser.lex('he<body>l<div>l</body>o</div>') [Text('he'), Tag('body'), Text('l'), Tag('div'), Text('l'), Tag('/body'), Text('o'), Tag('/div')] Testing `Layout` ---------------- This chapter also creates a Layout class to output a display list that can format text. However, note that this test doesn't use real tkinter fonts, but rather a mock font that has faked metrics. >>> def test_layout(text): ... dl = browser.Layout(browser.lex(text)).display_list ... return wbemocks.normalize_display_list(dl) >>> test_layout("abc") [(13.0, 21.0, 'abc', Font size=16 weight=normal slant=roman style=None)] >>> test_layout("<b>abc</b>") [(13.0, 21.0, 'abc', Font size=16 weight=bold slant=roman style=None)] >>> test_layout("<big>abc</big>") [(13.0, 21.75, 'abc', Font size=20 weight=normal slant=roman style=None)] >>> test_layout("<big><big>abc</big></big>") [(13.0, 22.5, 'abc', Font size=24 weight=normal slant=roman style=None)] >>> test_layout("<big><big><i>abc</i></big></big>") [(13.0, 22.5, 'abc', Font size=24 weight=normal slant=italic style=None)] >>> test_layout("<big><big><i>abc</i></big>def</big>") #doctest: +NORMALIZE_WHITESPACE [(13.0, 22.5, 'abc', Font size=24 weight=normal slant=italic style=None), (109.0, 25.5, 'def', Font size=20 weight=normal slant=roman style=None)] Lines of text are spaced to make room for the tallest text. Let's lay out text with mixed font sizes, and then measure the line heights: >>> def baseline(word): ... return word[1] + word[3].metrics("ascent") >>> test_layout("Start<br>Regular<br>Regular <big><big>Big") #doctest: +NORMALIZE_WHITESPACE [(13.0, 21.0, 'Start', Font size=16 weight=normal slant=roman style=None), (13.0, 41.0, 'Regular', Font size=16 weight=normal slant=roman style=None), (13.0, 68.5, 'Regular', Font size=16 weight=normal slant=roman style=None), (141.0, 62.5, 'Big', Font size=24 weight=normal slant=roman style=None)] >>> display_list = test_layout("Start<br>Regular<br>Regular <big><big>Big") >>> baseline(display_list[1]) - baseline(display_list[0]) 20.0 >>> baseline(display_list[3]) - baseline(display_list[1]) 27.5 The differing line heights don't occur when text gets smaller: >>> test_layout("Start<br>Regular<br>Regular <small><small>Small") #doctest: +NORMALIZE_WHITESPACE [(13.0, 21.0, 'Start', Font size=16 weight=normal slant=roman style=None), (13.0, 41.0, 'Regular', Font size=16 weight=normal slant=roman style=None), (13.0, 61.0, 'Regular', Font size=16 weight=normal slant=roman style=None), (141.0, 64.0, 'Small', Font size=12 weight=normal slant=roman style=None)] >>> display_list = test_layout("Start<br>Regular<br>Regular <small><small>Small") >>> baseline(display_list[1]) - baseline(display_list[0]) 20.0 >>> baseline(display_list[3]) - baseline(display_list[1]) 20.0 Testing `Browser` ----------------- Now let's test integration of layout into the Browser class. >>> url = 'http://wbemocks.test/chapter3-example1' >>> wbemocks.socket.respond_200(url=url, ... body="<small>abc<i>def</i></small>") >>> this_browser = browser.Browser() >>> this_browser.load(browser.URL(url)) Testing the display list output of this URL: >>> wbemocks.normalize_display_list(this_browser.display_list) #doctest: +NORMALIZE_WHITESPACE [(13.0, 20.625, 'abc', Font size=14 weight=normal slant=roman style=None), (69.0, 20.625, 'def', Font size=14 weight=normal slant=italic style=None)] And the canvas: >>> wbemocks.patch_canvas() >>> this_browser = browser.Browser() >>> this_browser.load(browser.URL(url)) create_text: x=13 y=20.625 text=abc font=Font size=14 weight=normal slant=roman style=None anchor=nw create_text: x=69 y=20.625 text=def font=Font size=14 weight=normal slant=italic style=None anchor=nw >>> wbemocks.unpatch_canvas()