1# -*- coding: utf-8 -*-
2from hpack.table import HeaderTable, table_entry_size
3from hpack.exceptions import InvalidTableIndex
4import pytest
5import sys
6_ver = sys.version_info
7is_py2 = _ver[0] == 2
8is_py3 = _ver[0] == 3
9
10
11class TestPackageFunctions(object):
12    def test_table_entry_size(self):
13        res = table_entry_size(b'TestName', b'TestValue')
14        assert res == 49
15
16
17class TestHeaderTable(object):
18    def test_get_by_index_dynamic_table(self):
19        tbl = HeaderTable()
20        off = len(HeaderTable.STATIC_TABLE)
21        val = (b'TestName', b'TestValue')
22        tbl.add(*val)
23        res = tbl.get_by_index(off + 1)
24        assert res == val
25
26    def test_get_by_index_static_table(self):
27        tbl = HeaderTable()
28        exp = (b':authority', b'')
29        res = tbl.get_by_index(1)
30        assert res == exp
31        idx = len(HeaderTable.STATIC_TABLE)
32        exp = (b'www-authenticate', b'')
33        res = tbl.get_by_index(idx)
34        assert res == exp
35
36    def test_get_by_index_zero_index(self):
37        tbl = HeaderTable()
38        with pytest.raises(InvalidTableIndex):
39            tbl.get_by_index(0)
40
41    def test_get_by_index_out_of_range(self):
42        tbl = HeaderTable()
43        off = len(HeaderTable.STATIC_TABLE)
44        tbl.add(b'TestName', b'TestValue')
45        with pytest.raises(InvalidTableIndex) as e:
46            tbl.get_by_index(off + 2)
47
48        assert (
49            "InvalidTableIndex: Invalid table index %d" % (off + 2) in str(e)
50        )
51
52    def test_repr(self):
53        tbl = HeaderTable()
54        tbl.add(b'TestName1', b'TestValue1')
55        tbl.add(b'TestName2', b'TestValue2')
56        tbl.add(b'TestName2', b'TestValue2')
57        # Meh, I hate that I have to do this to test
58        # repr
59        if is_py3:
60            exp = (
61                "HeaderTable(4096, False, deque(["
62                "(b'TestName2', b'TestValue2'), "
63                "(b'TestName2', b'TestValue2'), "
64                "(b'TestName1', b'TestValue1')"
65                "]))"
66            )
67        else:
68            exp = (
69                "HeaderTable(4096, False, deque(["
70                "('TestName2', 'TestValue2'), "
71                "('TestName2', 'TestValue2'), "
72                "('TestName1', 'TestValue1')"
73                "]))"
74            )
75        res = repr(tbl)
76        assert res == exp
77
78    def test_add_to_large(self):
79        tbl = HeaderTable()
80        # Max size to small to hold the value we specify
81        tbl.maxsize = 1
82        tbl.add(b'TestName', b'TestValue')
83        # Table length should be 0
84        assert len(tbl.dynamic_entries) == 0
85
86    def test_search_in_static_full(self):
87        tbl = HeaderTable()
88        itm = (b':authority', b'')
89        exp = (1, itm[0], itm[1])
90        res = tbl.search(itm[0], itm[1])
91        assert res == exp
92
93    def test_search_in_static_partial(self):
94        tbl = HeaderTable()
95        exp = (1, b':authority', None)
96        res = tbl.search(b':authority', b'NotInTable')
97        assert res == exp
98
99    def test_search_in_dynamic_full(self):
100        tbl = HeaderTable()
101        idx = len(HeaderTable.STATIC_TABLE) + 1
102        tbl.add(b'TestName', b'TestValue')
103        exp = (idx, b'TestName', b'TestValue')
104        res = tbl.search(b'TestName', b'TestValue')
105        assert res == exp
106
107    def test_search_in_dynamic_partial(self):
108        tbl = HeaderTable()
109        idx = len(HeaderTable.STATIC_TABLE) + 1
110        tbl.add(b'TestName', b'TestValue')
111        exp = (idx, b'TestName', None)
112        res = tbl.search(b'TestName', b'NotInTable')
113        assert res == exp
114
115    def test_search_no_match(self):
116        tbl = HeaderTable()
117        tbl.add(b'TestName', b'TestValue')
118        res = tbl.search(b'NotInTable', b'NotInTable')
119        assert res is None
120
121    def test_maxsize_prop_getter(self):
122        tbl = HeaderTable()
123        assert tbl.maxsize == HeaderTable.DEFAULT_SIZE
124
125    def test_maxsize_prop_setter(self):
126        tbl = HeaderTable()
127        exp = int(HeaderTable.DEFAULT_SIZE / 2)
128        tbl.maxsize = exp
129        assert tbl.resized is True
130        assert tbl.maxsize == exp
131        tbl.resized = False
132        tbl.maxsize = exp
133        assert tbl.resized is False
134        assert tbl.maxsize == exp
135
136    def test_size(self):
137        tbl = HeaderTable()
138        for i in range(3):
139            tbl.add(b'TestName', b'TestValue')
140        res = tbl._current_size
141        assert res == 147
142
143    def test_shrink_maxsize_is_zero(self):
144        tbl = HeaderTable()
145        tbl.add(b'TestName', b'TestValue')
146        assert len(tbl.dynamic_entries) == 1
147        tbl.maxsize = 0
148        assert len(tbl.dynamic_entries) == 0
149
150    def test_shrink_maxsize(self):
151        tbl = HeaderTable()
152        for i in range(3):
153            tbl.add(b'TestName', b'TestValue')
154
155        assert tbl._current_size == 147
156        tbl.maxsize = 146
157        assert len(tbl.dynamic_entries) == 2
158        assert tbl._current_size == 98
159