1 #! /usr/bin/env python3
4 # Author: David Goodger <goodger@python.org>
5 # Copyright: This module has been placed in the public domain.
8 Test module for statemachine.py.
11 from pathlib
import Path
16 if __name__
== '__main__':
17 # prepend the "docutils root" to the Python library path
18 # so we import the local `docutils` package.
19 sys
.path
.insert(0, str(Path(__file__
).resolve().parents
[1]))
21 from docutils
import statemachine
25 testtext
= statemachine
.string2lines("""\
28 - This is a bullet list. First list item.
29 Second line of first para.
35 - Second list item. Example::
42 expected
= ('StateMachine1 text1 blank1 bullet1 known_indent1 '
43 'StateMachine2 text2 text2 blank2 text2 blank2 indent2 '
44 'StateMachine3 text3 blank3 finished3 finished2 '
45 'bullet1 known_indent1 '
46 'StateMachine2 text2 blank2 literalblock2(4) finished2 '
47 'text1 finished1').split()
49 item1
= [line
[2:] for line
in testtext
[2:9]]
50 item2
= [line
[2:] for line
in testtext
[9:-1]]
52 literalblock
= [line
[lbindent
:] for line
in testtext
[11:-1]]
56 class MockState(statemachine
.StateWS
):
58 patterns
= {'bullet': re
.compile(r
'- '),
60 initial_transitions
= ['bullet', ['text']]
63 def bof(self
, context
):
64 self
.levelholder
[0] += 1
65 self
.level
= self
.levelholder
[0]
67 print('StateMachine%s' % self
.level
, file=sys
.stderr
)
68 return [], ['StateMachine%s' % self
.level
]
70 def blank(self
, match
, context
, next_state
):
71 result
= ['blank%s' % self
.level
]
73 print('blank%s' % self
.level
, file=sys
.stderr
)
74 if context
and context
[-1] and context
[-1][-2:] == '::':
75 result
.extend(self
.literalblock())
76 return [], None, result
78 def indent(self
, match
, context
, next_state
):
80 print('indent%s' % self
.level
, file=sys
.stderr
)
81 context
, next_state
, result
= statemachine
.StateWS
.indent(
82 self
, match
, context
, next_state
)
83 return context
, next_state
, ['indent%s' % self
.level
] + result
85 def known_indent(self
, match
, context
, next_state
):
87 print('known_indent%s' % self
.level
, file=sys
.stderr
)
88 context
, next_state
, result
= statemachine
.StateWS
.known_indent(
89 self
, match
, context
, next_state
)
90 return context
, next_state
, ['known_indent%s' % self
.level
] + result
92 def bullet(self
, match
, context
, next_state
):
94 print('bullet%s' % self
.level
, file=sys
.stderr
)
95 context
, next_state
, result \
96 = self
.known_indent(match
, context
, next_state
)
97 return [], next_state
, ['bullet%s' % self
.level
] + result
99 def text(self
, match
, context
, next_state
):
101 print('text%s' % self
.level
, file=sys
.stderr
)
102 return [match
.string
], next_state
, ['text%s' % self
.level
]
104 def literalblock(self
):
105 indented
, indent
, offset
, good
= self
.state_machine
.get_indented()
107 print('literalblock%s(%s)' % (self
.level
, indent
), file=sys
.stderr
)
108 return ['literalblock%s(%s)' % (self
.level
, indent
)]
110 def eof(self
, context
):
111 self
.levelholder
[0] -= 1
113 print('finished%s' % self
.level
, file=sys
.stderr
)
114 return ['finished%s' % self
.level
]
117 class EmptySMTests(unittest
.TestCase
):
120 self
.sm
= statemachine
.StateMachine(
121 state_classes
=[], initial_state
='State')
122 self
.sm
.debug
= debug
124 def test_add_state(self
):
125 self
.sm
.add_state(statemachine
.State
)
126 self
.assertTrue(len(self
.sm
.states
) == 1)
127 with self
.assertRaises(statemachine
.DuplicateStateError
):
128 self
.sm
.add_state(statemachine
.State
)
129 self
.sm
.add_state(statemachine
.StateWS
)
130 self
.assertTrue(len(self
.sm
.states
) == 2)
132 def test_add_states(self
):
133 self
.sm
.add_states((statemachine
.State
, statemachine
.StateWS
))
134 self
.assertEqual(len(self
.sm
.states
), 2)
136 def test_get_state(self
):
137 self
.assertRaises(statemachine
.UnknownStateError
, self
.sm
.get_state
)
138 self
.sm
.add_states((statemachine
.State
, statemachine
.StateWS
))
139 with self
.assertRaises(statemachine
.UnknownStateError
):
140 self
.sm
.get_state('unknownState')
141 self
.assertTrue(isinstance(self
.sm
.get_state('State'),
143 self
.assertTrue(isinstance(self
.sm
.get_state('StateWS'),
145 self
.assertEqual(self
.sm
.current_state
, 'StateWS')
148 class EmptySMWSTests(EmptySMTests
):
151 self
.sm
= statemachine
.StateMachineWS(
152 state_classes
=[], initial_state
='State')
153 self
.sm
.debug
= debug
156 class SMWSTests(unittest
.TestCase
):
159 self
.sm
= statemachine
.StateMachineWS([MockState
], 'MockState',
161 self
.sm
.debug
= debug
162 self
.sm
.states
['MockState'].levelholder
[0] = 0
167 def test___init__(self
):
168 self
.assertEqual(list(self
.sm
.states
.keys()), ['MockState'])
169 self
.assertEqual(len(self
.sm
.states
['MockState'].transitions
), 4)
171 def test_get_indented(self
):
172 self
.sm
.input_lines
= statemachine
.StringList(testtext
)
173 self
.sm
.line_offset
= -1
175 indented
, offset
, good
= self
.sm
.get_known_indented(2)
176 self
.assertEqual(indented
, item1
)
177 self
.assertEqual(offset
, len(para1
))
178 self
.assertTrue(good
)
180 indented
, offset
, good
= self
.sm
.get_known_indented(2)
181 self
.assertEqual(indented
, item2
)
182 self
.assertEqual(offset
, len(para1
) + len(item1
))
183 self
.assertTrue(good
)
184 self
.sm
.previous_line(3)
186 print('\ntest_get_indented: self.sm.line:\n', self
.sm
.line
)
187 indented
, indent
, offset
, good
= self
.sm
.get_indented()
189 print('\ntest_get_indented: indented:\n', indented
)
190 self
.assertEqual(indent
, lbindent
)
191 self
.assertEqual(indented
, literalblock
)
192 self
.assertEqual(offset
, (len(para1
) + len(item1
) + len(item2
)
193 - len(literalblock
)))
194 self
.assertTrue(good
)
196 def test_get_text_block(self
):
197 self
.sm
.input_lines
= statemachine
.StringList(testtext
)
198 self
.sm
.line_offset
= -1
200 textblock
= self
.sm
.get_text_block()
201 self
.assertEqual(textblock
, testtext
[:1])
203 textblock
= self
.sm
.get_text_block()
204 self
.assertEqual(textblock
, testtext
[2:4])
206 def test_get_text_block_flush_left(self
):
207 self
.sm
.input_lines
= statemachine
.StringList(testtext
)
208 self
.sm
.line_offset
= -1
210 textblock
= self
.sm
.get_text_block(flush_left
=1)
211 self
.assertEqual(textblock
, testtext
[:1])
213 with self
.assertRaises(statemachine
.UnexpectedIndentationError
):
214 self
.sm
.get_text_block(flush_left
=1)
217 self
.assertEqual(self
.sm
.run(testtext
), expected
)
224 class EmptyStateTests(unittest
.TestCase
):
227 self
.state
= statemachine
.State(EmptyClass(), debug
=debug
)
228 self
.state
.patterns
= {'nop': 'dummy',
232 self
.state
.nop2
= self
.state
.nop3
= self
.state
.nop
234 def test_add_transitions(self
):
235 self
.assertEqual(len(self
.state
.transitions
), 0)
236 self
.state
.add_transitions(['None'], {'None': None})
237 self
.assertEqual(len(self
.state
.transitions
), 1)
238 with self
.assertRaises(statemachine
.UnknownTransitionError
):
239 self
.state
.add_transitions(['bogus'], {})
240 with self
.assertRaises(statemachine
.DuplicateTransitionError
):
241 self
.state
.add_transitions(['None'], {'None': None})
243 def test_add_transition(self
):
244 self
.assertEqual(len(self
.state
.transitions
), 0)
245 self
.state
.add_transition('None', None)
246 self
.assertEqual(len(self
.state
.transitions
), 1)
247 with self
.assertRaises(statemachine
.DuplicateTransitionError
):
248 self
.state
.add_transition('None', None)
250 def test_remove_transition(self
):
251 self
.assertEqual(len(self
.state
.transitions
), 0)
252 self
.state
.add_transition('None', None)
253 self
.assertEqual(len(self
.state
.transitions
), 1)
254 self
.state
.remove_transition('None')
255 self
.assertEqual(len(self
.state
.transitions
), 0)
256 with self
.assertRaises(statemachine
.UnknownTransitionError
):
257 self
.state
.remove_transition('None')
259 def test_make_transition(self
):
260 dummy
= re
.compile('dummy')
261 self
.assertEqual(self
.state
.make_transition('nop', 'bogus'),
262 (dummy
, self
.state
.nop
, 'bogus'))
263 self
.assertEqual(self
.state
.make_transition('nop'),
264 (dummy
, self
.state
.nop
,
265 self
.state
.__class
__.__name
__))
266 with self
.assertRaises(statemachine
.TransitionPatternNotFound
):
267 self
.state
.make_transition('None')
268 with self
.assertRaises(statemachine
.TransitionMethodNotFound
):
269 self
.state
.make_transition('bogus')
271 def test_make_transitions(self
):
272 dummy
= re
.compile('dummy')
273 self
.assertEqual(self
.state
.make_transitions(('nop', ['nop2'],
275 (['nop', 'nop2', 'nop3'],
276 {'nop': (dummy
, self
.state
.nop
,
277 self
.state
.__class
__.__name
__),
278 'nop2': (dummy
, self
.state
.nop2
,
279 self
.state
.__class
__.__name
__),
280 'nop3': (dummy
, self
.state
.nop3
, 'bogus')}))
283 class MiscTests(unittest
.TestCase
):
285 s2l_string
= "hello\tthere\thow are\tyou?\n\tI'm fine\tthanks.\n"
286 s2l_expected
= ['hello there how are you?',
289 def test_string2lines(self
):
290 self
.assertEqual(statemachine
.string2lines(self
.s2l_string
),
294 if __name__
== '__main__':