File: control_line.py

package info (click to toggle)
python-stem 1.2.2-1.1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 4,568 kB
  • ctags: 2,036
  • sloc: python: 20,108; makefile: 127; sh: 3
file content (174 lines) | stat: -rw-r--r-- 6,796 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
"""
Unit tests for the stem.response.ControlLine class.
"""

import unittest

import stem.response

# response made by having 'DataDirectory /tmp/my data\"dir/' in the torrc
PROTOCOLINFO_RESPONSE = (
  'PROTOCOLINFO 1',
  'AUTH METHODS=COOKIE COOKIEFILE="/tmp/my data\\\\\\"dir//control_auth_cookie"',
  'VERSION Tor="0.2.1.30"',
  'OK',
)


class TestControlLine(unittest.TestCase):
  def test_pop_examples(self):
    """
    Checks that the pop method's pydoc examples are correct.
    """

    line = stem.response.ControlLine("\"We're all mad here.\" says the grinning cat.")
    self.assertEquals(line.pop(True), "We're all mad here.")
    self.assertEquals(line.pop(), 'says')
    self.assertEquals(line.remainder(), 'the grinning cat.')

    line = stem.response.ControlLine('"this has a \\" and \\\\ in it" foo=bar more_data')
    self.assertEquals(line.pop(True, True), 'this has a " and \\ in it')

  def test_string(self):
    """
    Basic checks that we behave as a regular immutable string.
    """

    line = stem.response.ControlLine(PROTOCOLINFO_RESPONSE[0])
    self.assertEquals(line, 'PROTOCOLINFO 1')
    self.assertTrue(line.startswith('PROTOCOLINFO '))

    # checks that popping items doesn't effect us
    line.pop()
    self.assertEquals(line, 'PROTOCOLINFO 1')
    self.assertTrue(line.startswith('PROTOCOLINFO '))

  def test_general_usage(self):
    """
    Checks a basic use case for the popping entries.
    """

    # pops a series of basic, space separated entries
    line = stem.response.ControlLine(PROTOCOLINFO_RESPONSE[0])
    self.assertEquals(line.remainder(), 'PROTOCOLINFO 1')
    self.assertFalse(line.is_empty())
    self.assertFalse(line.is_next_quoted())
    self.assertFalse(line.is_next_mapping())
    self.assertEquals(None, line.peek_key())

    self.assertRaises(ValueError, line.pop_mapping)
    self.assertEquals(line.pop(), 'PROTOCOLINFO')
    self.assertEquals(line.remainder(), '1')
    self.assertFalse(line.is_empty())
    self.assertFalse(line.is_next_quoted())
    self.assertFalse(line.is_next_mapping())
    self.assertEquals(None, line.peek_key())

    self.assertRaises(ValueError, line.pop_mapping)
    self.assertEquals(line.pop(), '1')
    self.assertEquals(line.remainder(), '')
    self.assertTrue(line.is_empty())
    self.assertFalse(line.is_next_quoted())
    self.assertFalse(line.is_next_mapping())
    self.assertEquals(None, line.peek_key())

    self.assertRaises(IndexError, line.pop_mapping)
    self.assertRaises(IndexError, line.pop)
    self.assertEquals(line.remainder(), '')
    self.assertTrue(line.is_empty())
    self.assertFalse(line.is_next_quoted())
    self.assertFalse(line.is_next_mapping())
    self.assertEquals(None, line.peek_key())

  def test_pop_mapping(self):
    """
    Checks use cases when parsing KEY=VALUE mappings.
    """

    # version entry with a space
    version_entry = 'Tor="0.2.1.30 (0a083b0188cacd2f07838ff0446113bd5211a024)"'

    line = stem.response.ControlLine(version_entry)
    self.assertEquals(line.remainder(), version_entry)
    self.assertFalse(line.is_empty())
    self.assertFalse(line.is_next_quoted())
    self.assertTrue(line.is_next_mapping())
    self.assertTrue(line.is_next_mapping(key = 'Tor'))
    self.assertTrue(line.is_next_mapping(key = 'Tor', quoted = True))
    self.assertTrue(line.is_next_mapping(quoted = True))
    self.assertEquals('Tor', line.peek_key())

    # try popping this as a non-quoted mapping
    self.assertEquals(line.pop_mapping(), ('Tor', '"0.2.1.30'))
    self.assertEquals(line.remainder(), '(0a083b0188cacd2f07838ff0446113bd5211a024)"')
    self.assertFalse(line.is_empty())
    self.assertFalse(line.is_next_quoted())
    self.assertFalse(line.is_next_mapping())
    self.assertRaises(ValueError, line.pop_mapping)
    self.assertEquals(None, line.peek_key())

    # try popping this as a quoted mapping
    line = stem.response.ControlLine(version_entry)
    self.assertEquals(line.pop_mapping(True), ('Tor', '0.2.1.30 (0a083b0188cacd2f07838ff0446113bd5211a024)'))
    self.assertEquals(line.remainder(), '')
    self.assertTrue(line.is_empty())
    self.assertFalse(line.is_next_quoted())
    self.assertFalse(line.is_next_mapping())
    self.assertEquals(None, line.peek_key())

  def test_escapes(self):
    """
    Checks that we can parse quoted values with escaped quotes in it. This
    explicitely comes up with the COOKIEFILE attribute of PROTOCOLINFO
    responses.
    """

    auth_line = PROTOCOLINFO_RESPONSE[1]
    line = stem.response.ControlLine(auth_line)
    self.assertEquals(line, auth_line)
    self.assertEquals(line.remainder(), auth_line)

    self.assertEquals(line.pop(), 'AUTH')
    self.assertEquals(line.pop_mapping(), ('METHODS', 'COOKIE'))

    self.assertEquals(line.remainder(), r'COOKIEFILE="/tmp/my data\\\"dir//control_auth_cookie"')
    self.assertTrue(line.is_next_mapping())
    self.assertTrue(line.is_next_mapping(key = 'COOKIEFILE'))
    self.assertTrue(line.is_next_mapping(quoted = True))
    self.assertTrue(line.is_next_mapping(quoted = True, escaped = True))
    cookie_file_entry = line.remainder()

    # try a general pop
    self.assertEquals(line.pop(), 'COOKIEFILE="/tmp/my')
    self.assertEquals(line.pop(), r'data\\\"dir//control_auth_cookie"')
    self.assertTrue(line.is_empty())

    # try a general pop with escapes
    line = stem.response.ControlLine(cookie_file_entry)
    self.assertEquals(line.pop(escaped = True), 'COOKIEFILE="/tmp/my')
    self.assertEquals(line.pop(escaped = True), r'data\"dir//control_auth_cookie"')
    self.assertTrue(line.is_empty())

    # try a mapping pop
    line = stem.response.ControlLine(cookie_file_entry)
    self.assertEquals(line.pop_mapping(), ('COOKIEFILE', '"/tmp/my'))
    self.assertEquals(line.remainder(), r'data\\\"dir//control_auth_cookie"')
    self.assertFalse(line.is_empty())

    # try a quoted mapping pop (this should trip up on the escaped quote)
    line = stem.response.ControlLine(cookie_file_entry)
    self.assertEquals(line.pop_mapping(True), ('COOKIEFILE', '/tmp/my data\\\\\\'))
    self.assertEquals(line.remainder(), 'dir//control_auth_cookie"')
    self.assertFalse(line.is_empty())

    # try an escaped quoted mapping pop
    line = stem.response.ControlLine(cookie_file_entry)
    self.assertEquals(line.pop_mapping(True, True), ('COOKIEFILE', r'/tmp/my data\"dir//control_auth_cookie'))
    self.assertTrue(line.is_empty())

    # try an escaped slash followed by a character that could be part of an
    # escape sequence

    line = stem.response.ControlLine(r'COOKIEFILE="C:\\Users\\Atagar\\AppData\\tor\\control_auth_cookie"')
    self.assertEquals(line.pop_mapping(True, True), ('COOKIEFILE', r'C:\Users\Atagar\AppData\tor\control_auth_cookie'))
    self.assertTrue(line.is_empty())