1"""
2Test accuracy of the mappings of color names and values, by extracting
3the definitions of the colors from the relevant standards documents.
4
5"""
6
7import re
8import unittest
9
10from bs4 import BeautifulSoup
11import html5lib
12import requests
13
14import webcolors
15
16
17class HTML4DefinitionTests(unittest.TestCase):
18    """
19    Extract the names and values of the 16 defined HTML 4 colors from
20    the online version of the standard, and check them against this
21    module's definitions of them.
22
23    """
24    def setUp(self):
25        self.html4_colors = {}
26        soup = BeautifulSoup(
27            requests.get('http://www.w3.org/TR/html401/types.html').content,
28            "html.parser"
29        )
30        color_table = soup.find(
31            'table',
32            attrs={
33                'summary': 'Table of color names and their sRGB values'})
34        for td in color_table.findAll('td'):
35            if u'width' not in td.attrs:
36                color_name, color_value = td.text.split(' = ')
37                self.html4_colors[color_name] = color_value.replace('"', '').strip()
38
39    def test_color_definitions(self):
40        for color_name, color_value in self.html4_colors.items():
41            self.assertEqual(color_value.lower(),
42                             webcolors.HTML4_NAMES_TO_HEX[color_name.lower()])
43
44
45class CSS21DefinitionTests(unittest.TestCase):
46    """
47    Extract the names and values of the 17 defined CSS 2.1 colors from
48    the online version of the standard, and check them against this
49    module's definitions of them.
50
51    """
52    def setUp(self):
53        self.color_matching_re = re.compile(r'^([a-z]+) (#[a-fA-F0-9]{6})$')
54        self.css21_colors = {}
55        soup = BeautifulSoup(
56            requests.get('http://www.w3.org/TR/CSS2/syndata.html').content,
57            "html.parser"
58        )
59        color_table = soup.find('div',
60                                attrs={'id': 'TanteksColorDiagram20020613'})
61        for color_square in color_table.findAll('span',
62                                                attrs={
63                                                    'class': 'colorsquare'}):
64            color_name, color_value = self.color_matching_re.search(
65                color_square.text
66                ).groups()
67            self.css21_colors[color_name] = color_value
68
69    def test_color_definitions(self):
70        for color_name, color_value in self.css21_colors.items():
71            self.assertEqual(color_value.lower(),
72                             webcolors.CSS21_NAMES_TO_HEX[color_name.lower()])
73
74
75class CSS3DefinitionTests(unittest.TestCase):
76    """
77    Extract the names and values of the 147 defined CSS 3 colors from
78    the online version of the standard, and check them against this
79    module's definitions of them.
80
81    """
82    def setUp(self):
83        self.css3_colors = {}
84        soup = BeautifulSoup(
85            requests.get('http://www.w3.org/TR/css3-color/').content,
86            "html5lib"
87        )
88        color_table = soup.findAll('table',
89                                   attrs={'class': 'colortable'})[1]
90        color_names = [dfn.text for dfn in color_table.findAll('dfn')]
91        hex_values = [td.text.strip() for
92                      td in
93                      color_table.findAll('td',
94                                          attrs={'class': 'c',
95                                                 'style': 'background:silver'})
96                      if td.text.startswith('#')]
97        rgb_values = [td.text.strip() for
98                      td in
99                      color_table.findAll('td',
100                                          attrs={'class': 'c',
101                                                 'style': 'background:silver'})
102                      if not td.text.startswith('#') and
103                      not td.text.startswith('&') and
104                      td.text.strip()]
105        for i, color_name in enumerate(color_names):
106            self.css3_colors[color_name] = {
107                'hex': hex_values[i],
108                'rgb': tuple(map(int, rgb_values[i].split(',')))}
109
110    def test_color_definitions(self):
111        for color_name, color_values in self.css3_colors.items():
112            self.assertEqual(color_values['hex'].lower(),
113                             webcolors.CSS3_NAMES_TO_HEX[color_name.lower()])
114            self.assertEqual(color_values['rgb'],
115                             webcolors.name_to_rgb(color_name))
116
117
118if __name__ == '__main__':
119    unittest.main()
120