SafeString._str__ must not return a binary string with Python 3.x.
[docutils.git] / test / test_statemachine.py
blob2422adcda1b7e39a25792fa124efa3ed952ad1a4
1 #! /usr/bin/env python
3 # $Id$
4 # Author: David Goodger <goodger@python.org>
5 # Copyright: This module has been placed in the public domain.
7 """
8 Test module for statemachine.py.
9 """
11 import unittest
12 import sys
13 import re
14 from DocutilsTestSupport import statemachine
17 debug = False
18 testtext = statemachine.string2lines("""\
19 First paragraph.
21 - This is a bullet list. First list item.
22 Second line of first para.
24 Second para.
26 block quote
28 - Second list item. Example::
31 literal
32 block
34 Last paragraph.""")
35 expected = ('StateMachine1 text1 blank1 bullet1 known_indent1 '
36 'StateMachine2 text2 text2 blank2 text2 blank2 indent2 '
37 'StateMachine3 text3 blank3 finished3 finished2 '
38 'bullet1 known_indent1 '
39 'StateMachine2 text2 blank2 literalblock2(4) finished2 '
40 'text1 finished1').split()
41 para1 = testtext[:2]
42 item1 = [line[2:] for line in testtext[2:9]]
43 item2 = [line[2:] for line in testtext[9:-1]]
44 lbindent = 6
45 literalblock = [line[lbindent:] for line in testtext[11:-1]]
46 para2 = testtext[-1]
49 class MockState(statemachine.StateWS):
51 patterns = {'bullet': re.compile(r'- '),
52 'text': ''}
53 initial_transitions = ['bullet', ['text']]
54 levelholder = [0]
56 def bof(self, context):
57 self.levelholder[0] += 1
58 self.level = self.levelholder[0]
59 if self.debug: print >>sys.stderr, 'StateMachine%s' % self.level
60 return [], ['StateMachine%s' % self.level]
62 def blank(self, match, context, next_state):
63 result = ['blank%s' % self.level]
64 if self.debug: print >>sys.stderr, 'blank%s' % self.level
65 if context and context[-1] and context[-1][-2:] == '::':
66 result.extend(self.literalblock())
67 return [], None, result
69 def indent(self, match, context, next_state):
70 if self.debug: print >>sys.stderr, 'indent%s' % self.level
71 context, next_state, result = statemachine.StateWS.indent(
72 self, match, context, next_state)
73 return context, next_state, ['indent%s' % self.level] + result
75 def known_indent(self, match, context, next_state):
76 if self.debug: print >>sys.stderr, 'known_indent%s' % self.level
77 context, next_state, result = statemachine.StateWS.known_indent(
78 self, match, context, next_state)
79 return context, next_state, ['known_indent%s' % self.level] + result
81 def bullet(self, match, context, next_state):
82 if self.debug: print >>sys.stderr, 'bullet%s' % self.level
83 context, next_state, result \
84 = self.known_indent(match, context, next_state)
85 return [], next_state, ['bullet%s' % self.level] + result
87 def text(self, match, context, next_state):
88 if self.debug: print >>sys.stderr, 'text%s' % self.level
89 return [match.string], next_state, ['text%s' % self.level]
91 def literalblock(self):
92 indented, indent, offset, good = self.state_machine.get_indented()
93 if self.debug: print >>sys.stderr, 'literalblock%s(%s)' % (self.level,
94 indent)
95 return ['literalblock%s(%s)' % (self.level, indent)]
97 def eof(self, context):
98 self.levelholder[0] -= 1
99 if self.debug: print >>sys.stderr, 'finished%s' % self.level
100 return ['finished%s' % self.level]
103 class EmptySMTests(unittest.TestCase):
105 def setUp(self):
106 self.sm = statemachine.StateMachine(
107 state_classes=[], initial_state='State')
108 self.sm.debug = debug
110 def test_add_state(self):
111 self.sm.add_state(statemachine.State)
112 self.assertTrue(len(self.sm.states) == 1)
113 self.assertRaises(statemachine.DuplicateStateError, self.sm.add_state,
114 statemachine.State)
115 self.sm.add_state(statemachine.StateWS)
116 self.assertTrue(len(self.sm.states) == 2)
118 def test_add_states(self):
119 self.sm.add_states((statemachine.State, statemachine.StateWS))
120 self.assertEqual(len(self.sm.states), 2)
122 def test_get_state(self):
123 self.assertRaises(statemachine.UnknownStateError, self.sm.get_state)
124 self.sm.add_states((statemachine.State, statemachine.StateWS))
125 self.assertRaises(statemachine.UnknownStateError, self.sm.get_state,
126 'unknownState')
127 self.assertTrue(isinstance(self.sm.get_state('State'),
128 statemachine.State))
129 self.assertTrue(isinstance(self.sm.get_state('StateWS'),
130 statemachine.State))
131 self.assertEqual(self.sm.current_state, 'StateWS')
134 class EmptySMWSTests(EmptySMTests):
136 def setUp(self):
137 self.sm = statemachine.StateMachineWS(
138 state_classes=[], initial_state='State')
139 self.sm.debug = debug
142 class SMWSTests(unittest.TestCase):
144 def setUp(self):
145 self.sm = statemachine.StateMachineWS([MockState], 'MockState',
146 debug=debug)
147 self.sm.debug = debug
148 self.sm.states['MockState'].levelholder[0] = 0
150 def tearDown(self):
151 self.sm.unlink()
153 def test___init__(self):
154 self.assertEqual(self.sm.states.keys(), ['MockState'])
155 self.assertEqual(len(self.sm.states['MockState'].transitions), 4)
157 def test_get_indented(self):
158 self.sm.input_lines = statemachine.StringList(testtext)
159 self.sm.line_offset = -1
160 self.sm.next_line(3)
161 indented, offset, good = self.sm.get_known_indented(2)
162 self.assertEqual(indented, item1)
163 self.assertEqual(offset, len(para1))
164 self.assertTrue(good)
165 self.sm.next_line()
166 indented, offset, good = self.sm.get_known_indented(2)
167 self.assertEqual(indented, item2)
168 self.assertEqual(offset, len(para1) + len(item1))
169 self.assertTrue(good)
170 self.sm.previous_line(3)
171 if self.sm.debug:
172 print '\ntest_get_indented: self.sm.line:\n', self.sm.line
173 indented, indent, offset, good = self.sm.get_indented()
174 if self.sm.debug:
175 print '\ntest_get_indented: indented:\n', indented
176 self.assertEqual(indent, lbindent)
177 self.assertEqual(indented, literalblock)
178 self.assertEqual(offset, (len(para1) + len(item1) + len(item2)
179 - len(literalblock)))
180 self.assertTrue(good)
182 def test_get_text_block(self):
183 self.sm.input_lines = statemachine.StringList(testtext)
184 self.sm.line_offset = -1
185 self.sm.next_line()
186 textblock = self.sm.get_text_block()
187 self.assertEqual(textblock, testtext[:1])
188 self.sm.next_line(2)
189 textblock = self.sm.get_text_block()
190 self.assertEqual(textblock, testtext[2:4])
192 def test_get_text_block_flush_left(self):
193 self.sm.input_lines = statemachine.StringList(testtext)
194 self.sm.line_offset = -1
195 self.sm.next_line()
196 textblock = self.sm.get_text_block(flush_left=1)
197 self.assertEqual(textblock, testtext[:1])
198 self.sm.next_line(2)
199 self.assertRaises(statemachine.UnexpectedIndentationError,
200 self.sm.get_text_block, flush_left=1)
202 def test_run(self):
203 self.assertEqual(self.sm.run(testtext), expected)
206 class EmptyClass:
207 pass
210 class EmptyStateTests(unittest.TestCase):
212 def setUp(self):
213 self.state = statemachine.State(EmptyClass(), debug=debug)
214 self.state.patterns = {'nop': 'dummy',
215 'nop2': 'dummy',
216 'nop3': 'dummy',
217 'bogus': 'dummy'}
218 self.state.nop2 = self.state.nop3 = self.state.nop
220 def test_add_transitions(self):
221 self.assertEqual(len(self.state.transitions), 0)
222 self.state.add_transitions(['None'], {'None': None})
223 self.assertEqual(len(self.state.transitions), 1)
224 self.assertRaises(statemachine.UnknownTransitionError,
225 self.state.add_transitions, ['bogus'], {})
226 self.assertRaises(statemachine.DuplicateTransitionError,
227 self.state.add_transitions, ['None'],
228 {'None': None})
230 def test_add_transition(self):
231 self.assertEqual(len(self.state.transitions), 0)
232 self.state.add_transition('None', None)
233 self.assertEqual(len(self.state.transitions), 1)
234 self.assertRaises(statemachine.DuplicateTransitionError,
235 self.state.add_transition, 'None', None)
237 def test_remove_transition(self):
238 self.assertEqual(len(self.state.transitions), 0)
239 self.state.add_transition('None', None)
240 self.assertEqual(len(self.state.transitions), 1)
241 self.state.remove_transition('None')
242 self.assertEqual(len(self.state.transitions), 0)
243 self.assertRaises(statemachine.UnknownTransitionError,
244 self.state.remove_transition, 'None')
246 def test_make_transition(self):
247 dummy = re.compile('dummy')
248 self.assertEqual(self.state.make_transition('nop', 'bogus'),
249 (dummy, self.state.nop, 'bogus'))
250 self.assertEqual(self.state.make_transition('nop'),
251 (dummy, self.state.nop,
252 self.state.__class__.__name__))
253 self.assertRaises(statemachine.TransitionPatternNotFound,
254 self.state.make_transition, 'None')
255 self.assertRaises(statemachine.TransitionMethodNotFound,
256 self.state.make_transition, 'bogus')
258 def test_make_transitions(self):
259 dummy = re.compile('dummy')
260 self.assertEqual(self.state.make_transitions(('nop', ['nop2'],
261 ('nop3', 'bogus'))),
262 (['nop', 'nop2', 'nop3'],
263 {'nop': (dummy, self.state.nop,
264 self.state.__class__.__name__),
265 'nop2': (dummy, self.state.nop2,
266 self.state.__class__.__name__),
267 'nop3': (dummy, self.state.nop3, 'bogus')}))
270 class MiscTests(unittest.TestCase):
272 s2l_string = "hello\tthere\thow are\tyou?\n\tI'm fine\tthanks.\n"
273 s2l_expected = ['hello there how are you?',
274 " I'm fine thanks."]
275 def test_string2lines(self):
276 self.assertEqual(statemachine.string2lines(self.s2l_string),
277 self.s2l_expected)
280 if __name__ == '__main__':
281 unittest.main()