forked from dagoof/sqlalchemy-fsm
-
Notifications
You must be signed in to change notification settings - Fork 1
/
tests.py
170 lines (128 loc) · 5.07 KB
/
tests.py
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
import unittest, sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy_fsm import FSMField, transition, can_proceed
engine = sqlalchemy.create_engine('sqlite:///:memory:', echo = True)
session = sessionmaker(bind = engine)
Base = declarative_base()
class BlogPost(Base):
__tablename__ = 'blogpost'
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key = True)
state = sqlalchemy.Column(FSMField)
def __init__(self, *args, **kwargs):
self.state = 'new'
super(BlogPost, self).__init__(*args, **kwargs)
@transition(source='new', target='published')
def publish(self):
pass
@transition(source='published', target='hidden')
def hide(self):
pass
@transition(source='new', target='removed')
def remove(self):
raise Exception('No rights to delete %s' % self)
@transition(source=['published','hidden'], target='stolen')
def steal(self):
pass
@transition(source='*', target='moderated')
def moderate(self):
pass
class FSMFieldTest(unittest.TestCase):
def setUp(self):
self.model = BlogPost()
def test_initial_state_instatiated(self):
self.assertEqual(self.model.state, 'new')
def test_known_transition_should_succeed(self):
self.assertTrue(can_proceed(self.model.publish))
self.model.publish()
self.assertEqual(self.model.state, 'published')
self.assertTrue(can_proceed(self.model.hide))
self.model.hide()
self.assertEqual(self.model.state, 'hidden')
def test_unknow_transition_fails(self):
self.assertFalse(can_proceed(self.model.hide))
self.assertRaises(NotImplementedError, self.model.hide)
def test_state_non_changed_after_fail(self):
self.assertRaises(Exception, self.model.remove)
self.assertTrue(can_proceed(self.model.remove))
self.assertEqual(self.model.state, 'new')
def test_mutiple_source_support_path_1_works(self):
self.model.publish()
self.model.steal()
self.assertEqual(self.model.state, 'stolen')
def test_mutiple_source_support_path_2_works(self):
self.model.publish()
self.model.hide()
self.model.steal()
self.assertEqual(self.model.state, 'stolen')
def test_star_shortcut_succeed(self):
self.assertTrue(can_proceed(self.model.moderate))
self.model.moderate()
self.assertEqual(self.model.state, 'moderated')
class InvalidModel(Base):
__tablename__ = 'invalidmodel'
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key = True)
state = sqlalchemy.Column(FSMField)
action = sqlalchemy.Column(FSMField)
def __init__(self, *args, **kwargs):
self.state = 'new'
self.action = 'no'
super(InvalidModel, self).__init__(*args, **kwargs)
@transition(source='new', target='no')
def validate(self):
pass
class InvalidModelTest(unittest.TestCase):
def test_two_fsmfields_in_one_model_not_allowed(self):
model = InvalidModel()
self.assertRaises(TypeError, model.validate)
class Document(Base):
__tablename__ = 'document'
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key = True)
status = sqlalchemy.Column(FSMField)
def __init__(self, *args, **kwargs):
self.status = 'new'
super(Document, self).__init__(*args, **kwargs)
@transition(source='new', target='published')
def publish(self):
pass
class DocumentTest(unittest.TestCase):
def test_any_state_field_name_allowed(self):
model = Document()
model.publish()
self.assertEqual(model.status, 'published')
def condition_func(instance):
return True
class BlogPostWithConditions(Base):
__tablename__ = 'BlogPostWithConditions'
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key = True)
state = sqlalchemy.Column(FSMField)
def __init__(self, *args, **kwargs):
self.state = 'new'
super(BlogPostWithConditions, self).__init__(*args, **kwargs)
def model_condition(self):
return True
def unmet_condition(self):
return False
@transition(source='new', target='published', conditions=[condition_func, model_condition])
def publish(self):
pass
@transition(source='published', target='destroyed', conditions=[condition_func, unmet_condition])
def destroy(self):
pass
class ConditionalTest(unittest.TestCase):
def setUp(self):
self.model = BlogPostWithConditions()
def test_initial_staet(self):
self.assertEqual(self.model.state, 'new')
def test_known_transition_should_succeed(self):
self.assertTrue(can_proceed(self.model.publish))
self.model.publish()
self.assertEqual(self.model.state, 'published')
def test_unmet_condition(self):
self.model.publish()
self.assertEqual(self.model.state, 'published')
self.assertFalse(can_proceed(self.model.destroy))
self.model.destroy()
self.assertEqual(self.model.state, 'published')
if __name__ == '__main__':
unittest.main()