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()