rlsm 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,66 @@
1
+ #Setting up the testing environment
2
+ require "rubygems"
3
+ require "minitest/unit"
4
+ require "minitest/autorun"
5
+
6
+ #Add the lib dir to the load path
7
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
8
+
9
+ #Defining some convinience methods for tests (doesn't want to load the minitest/spec)
10
+ #Basically copied from minitest/spec and removed nested describe feature and renamed things
11
+ module Kernel
12
+ def context desc, &block
13
+ name = desc.to_s.split(/\W+/).map { |s| s.capitalize }.join + "Spec"
14
+ cls = Object.class_eval "class #{name} < MiniTest::Spec; end; #{name}"
15
+
16
+ cls.class_eval(&block)
17
+ end
18
+ private :context
19
+ end
20
+
21
+ class MiniTest::Spec < MiniTest::Unit::TestCase
22
+ def initialize name
23
+ super
24
+ end
25
+
26
+ def self.before(type = :each, &block)
27
+ raise "unsupported before type: #{type}" unless type == :each
28
+ define_method :setup, &block
29
+ end
30
+
31
+ def self.after(type = :each, &block)
32
+ raise "unsupported after type: #{type}" unless type == :each
33
+ define_method :teardown, &block
34
+ end
35
+
36
+ def self.test desc, &block
37
+ default_block = lambda { skip "Pending: #{desc}" }
38
+ block = default_block unless block_given?
39
+
40
+ define_method "test_#{desc.gsub(/\W+/, '_').downcase}", &block
41
+ end
42
+ end
43
+
44
+ #Adding two IMHO missing assertions.
45
+ module MiniTest::Assertions
46
+ def assert_nothing_raised msg = nil, &block
47
+ begin
48
+ yield
49
+ rescue Exception => exception
50
+ msg = message(msg) { exception_details exception, "Expected nothing raises, but" }
51
+ assert false, msg
52
+ else
53
+ pass
54
+ end
55
+ end
56
+
57
+ def assert_same_elements expected, actual, msg = nil
58
+ msg = message(msg) { "Expected that #{p expected} and #{p actual} have same elements" }
59
+ assert_equal expected.size, actual.size, msg
60
+ refute expected.uniq!, "assert_same_elements expects unique elements."
61
+ refute actual.uniq!, "assert_same_elements expects unique elements."
62
+ expected.each do |element|
63
+ assert actual.include?(element), msg
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,119 @@
1
+ require 'rubygems'
2
+ require 'shoulda'
3
+
4
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
5
+
6
+ require 'rlsm/binary_operation'
7
+
8
+ class BinaryOperationTest < Test::Unit::TestCase
9
+ context "BinaryOperation::new" do
10
+ should "Require argument" do
11
+ assert_raises ArgumentError do
12
+ RLSM::BinaryOperation.new
13
+ end
14
+ end
15
+
16
+ should "Parse a valid description with elements" do
17
+ binop = RLSM::BinaryOperation.new "012:000 000 000"
18
+
19
+ assert_equal Hash['0', 0, '1', 1, '2', 2], binop.mapping
20
+ assert_equal %w(0 1 2), binop.elements
21
+ assert_equal 3, binop.order
22
+ assert_equal [0]*9, binop.table
23
+ end
24
+
25
+ should "Ignore whitspaces between element seperators" do
26
+ binop = RLSM::BinaryOperation.new "0, 1,2:0,0,0 0,0, 0 0, 0,0"
27
+
28
+ assert_equal Hash['0', 0, '1', 1, '2', 2], binop.mapping
29
+ assert_equal %w(0 1 2), binop.elements
30
+ assert_equal 3, binop.order
31
+ assert_equal [0]*9, binop.table
32
+ end
33
+
34
+ should "Raise ParseError if some commas are missing" do
35
+ assert_raises ParseError do
36
+ RLSM::BinaryOperation.new "012:0,1,2 210 2,2,2"
37
+ end
38
+ end
39
+
40
+ should "Parse commas in the elements part, no commas in table part" do
41
+ binop = RLSM::BinaryOperation.new "0,1,2:000 000 000"
42
+
43
+ assert_equal Hash['0', 0, '1', 1, '2', 2], binop.mapping
44
+ assert_equal %w(0 1 2), binop.elements
45
+ assert_equal 3, binop.order
46
+ assert_equal [0]*9, binop.table
47
+ end
48
+
49
+ should "Parse commas in the table part, no commas in elements part" do
50
+ binop = RLSM::BinaryOperation.new "012:0,0,0 0,0,0 0,0,0"
51
+
52
+ assert_equal Hash['0', 0, '1', 1, '2', 2], binop.mapping
53
+ assert_equal %w(0 1 2), binop.elements
54
+ assert_equal 3, binop.order
55
+ assert_equal [0]*9, binop.table
56
+ end
57
+
58
+ should "Raise ParseError if too many elements are given." do
59
+ assert_raises ParseError do
60
+ RLSM::BinaryOperation.new "012:0,1,3 210 2,2,2"
61
+ end
62
+ end
63
+
64
+ should "Raise ParseError if too few elements are given." do
65
+ assert_raises ParseError do
66
+ RLSM::BinaryOperation.new "000 000 000"
67
+ end
68
+ end
69
+
70
+ should "Raise ParseError if table format is wrong." do
71
+ assert_raises ParseError do
72
+ RLSM::BinaryOperation.new "012:0,1,2 2,1 2,2,2"
73
+ end
74
+ end
75
+
76
+ should "Parse a monoid with neutral element in first row." do
77
+ binop = RLSM::BinaryOperation.new "0123 1230 2301 3012"
78
+
79
+ assert_equal Hash['0', 0, '1', 1, '2', 2, '3', 3], binop.mapping
80
+ assert_equal %w(0 1 2 3), binop.elements
81
+ assert_equal 4, binop.order
82
+ assert_equal [0,1,2,3,1,2,3,0,2,3,0,1,3,0,1,2], binop.table
83
+ end
84
+ end
85
+
86
+ context "BinaryOperation#associative?" do
87
+ should "Return true if binary operation is associative." do
88
+ assert_equal true, RLSM::BinaryOperation.new("01:00 00").associative?
89
+ end
90
+
91
+ should "Return false if binary operation is not associative." do
92
+ assert_equal false, RLSM::BinaryOperation.new("01 00").associative?
93
+ end
94
+ end
95
+
96
+ context "BinaryOperation#commutative?" do
97
+ should "Return true if binary operation is commutative." do
98
+ assert_equal true, RLSM::BinaryOperation.new("012 111 211").commutative?
99
+ end
100
+
101
+ should "Return false if binary operation is not commutative." do
102
+ assert_equal false, RLSM::BinaryOperation.new("012 111 222").commutative?
103
+ end
104
+ end
105
+
106
+ context "BinaryOperation#enforce_associativity" do
107
+ should "Raise BinOpError for nonassociative binary operation." do
108
+ assert_raises BinOpError do
109
+ RLSM::BinaryOperation.new("01 00").enforce_associativity
110
+ end
111
+ end
112
+
113
+ should "Do nothing for assovityive binary operation." do
114
+ assert_nothing_raised do
115
+ RLSM::BinaryOperation.new("01 10").enforce_associativity
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,435 @@
1
+ require File.join(File.dirname(__FILE__), 'helpers')
2
+
3
+ require "rlsm/dfa"
4
+ require "rlsm/monoid"
5
+
6
+ context "Parsing the description of a DFA." do
7
+ test "A description of the DFA is required." do
8
+ assert_raises ArgumentError do
9
+ RLSM::DFA.new
10
+ end
11
+ end
12
+
13
+ test "The empty string is not accepted" do
14
+ assert_raises DFAError do
15
+ RLSM::DFA.new ""
16
+ end
17
+ end
18
+
19
+ test "A valid description should be parsed" do
20
+ assert_nothing_raised do
21
+ RLSM::DFA.new "}s1-a->*s2 s2-b->s1"
22
+ end
23
+ end
24
+
25
+ test "The description must include an initial state indicator." do
26
+ assert_raises DFAError do
27
+ RLSM::DFA.new "s1"
28
+ end
29
+ end
30
+
31
+ test "The description may not include more than one initial state." do
32
+ assert_raises DFAError do
33
+ RLSM::DFA.new "}s1-a->}s2"
34
+ end
35
+ end
36
+
37
+ test "A DFA without transitions is allowed." do
38
+ assert_nothing_raised do
39
+ RLSM::DFA.new "}s1"
40
+ end
41
+ end
42
+
43
+ test "A transition arrow must have a starting dash." do
44
+ assert_raises DFAError do
45
+ RLSM::DFA.new "}s1 a-> s2"
46
+ end
47
+ end
48
+
49
+ test "A transition arrow must have a closing arrow." do
50
+ assert_raises DFAError do
51
+ RLSM::DFA.new "}s1 -a> s2"
52
+ end
53
+
54
+ assert_raises DFAError do
55
+ RLSM::DFA.new "}s1 -a- s2"
56
+ end
57
+ end
58
+
59
+ test "A transition must have at least one label." do
60
+ assert_raises DFAError do
61
+ RLSM::DFA.new "}s1 --> s2"
62
+ end
63
+ end
64
+
65
+ test "Multiple labels must be seperated by a comma." do
66
+ assert_raises DFAError do
67
+ RLSM::DFA.new "}s1 -a;b-> s2"
68
+ end
69
+ end
70
+
71
+ test "Trailing and leading whitspaces will be ignored." do
72
+ assert_nothing_raised do
73
+ RLSM::DFA.new " }s1 -a, b-> *s2 "
74
+ end
75
+ end
76
+
77
+ test "A transition must start with a state." do
78
+ assert_raises DFAError do
79
+ RLSM::DFA.new " -a-> }s2"
80
+ end
81
+ end
82
+
83
+ test "A transition must end with a state." do
84
+ assert_raises DFAError do
85
+ RLSM::DFA.new "}s1 -a-> "
86
+ end
87
+ end
88
+ end
89
+
90
+ context "Creation of a DFA." do
91
+ test "A DFA must have an initial state." do
92
+ dfa = RLSM::DFA.new "}s1"
93
+
94
+ assert_equal 's1', dfa.initial_state
95
+
96
+ dfa = RLSM::DFA.new "}s2"
97
+
98
+ assert_equal 's2', dfa.initial_state
99
+ end
100
+
101
+ test "A DFA without final states is allowed." do
102
+ assert_equal [], RLSM::DFA.new("}s1").final_states
103
+ end
104
+
105
+ test "A DFA may have final states." do
106
+ assert_equal ['s2'], RLSM::DFA.new("}s1-a->*s2").final_states
107
+ end
108
+
109
+ test "The initial state may be a final state" do
110
+ assert_equal ['s1'], RLSM::DFA.new("}*s1-a->s2").final_states
111
+ assert_equal ['s1'], RLSM::DFA.new("*}s1-a->s2").final_states
112
+ end
113
+
114
+ test "A DFA may have one state" do
115
+ assert_equal ['s1'], RLSM::DFA.new("}*s1-a->s1").states
116
+ end
117
+
118
+ test "A DFA may have more than one state" do
119
+ assert_equal ['s1','s2'], RLSM::DFA.new("}s1-a->*s2").states
120
+ end
121
+
122
+ test "A DFA may have more than one state without transitions." do
123
+ assert_equal ['s1','s2'], RLSM::DFA.new("}s1 s2").states
124
+ end
125
+
126
+ test "A DFA must have an alphabet." do
127
+ assert_equal ['1','a'], RLSM::DFA.new("}s1-a,1->*s1").alphabet
128
+ assert_equal ['a','b'], RLSM::DFA.new("}s1-a,b->*s1").alphabet
129
+ end
130
+
131
+ test "A DFA may have none transitions." do
132
+ assert_equal [], RLSM::DFA.new("}s1").transitions
133
+ end
134
+
135
+ test "A DFA may have transitions." do
136
+ assert_equal [ %w(s1 s2 a) ], RLSM::DFA.new("}s1-a->s2").transitions
137
+ assert_equal( [ %w(s1 s2 a), %w(s1 s2 b) ],
138
+ RLSM::DFA.new("}s1-a,b->s2").transitions)
139
+ end
140
+
141
+ test "Transition labels out from one state must be unique" do
142
+ assert_raises DFAError do
143
+ RLSM::DFA.new "}s1 -a-> s2 s1-a->s3"
144
+ end
145
+ end
146
+
147
+ test "Duplications of transitions are allowed." do
148
+ assert_nothing_raised do
149
+ RLSM::DFA.new "}s1 -a-> s1 s1 -a->s1 s2 -a,a,a->s2"
150
+ end
151
+ end
152
+ end
153
+
154
+ context "Properties of a state" do
155
+ test "There may be unreachable states." do
156
+ dfa = RLSM::DFA.new "}s1 s2"
157
+
158
+ assert dfa.reachable?('s1')
159
+ refute dfa.reachable?('s2')
160
+ end
161
+
162
+ test "A DFA may be connected." do
163
+ dfa1 = RLSM::DFA.new "}s1 -a-> *s2 s3 -a-> s2"
164
+ dfa2 = RLSM::DFA.new "}s1 -a-> *s2 s2 -a-> s3"
165
+
166
+ refute dfa1.connected?
167
+ assert dfa2.connected?
168
+ end
169
+
170
+ test "A DFA may be complete." do
171
+ dfa1 = RLSM::DFA.new "}s1 -a-> s1"
172
+ dfa2 = RLSM::DFA.new "}s1 s2"
173
+
174
+ assert dfa1.complete?
175
+ assert dfa2.complete?
176
+ end
177
+
178
+ test "A DFA may be not complete." do
179
+ dfa1 = RLSM::DFA.new "}s1 -a-> s2"
180
+ dfa2 = RLSM::DFA.new "}s1 -a,b-> s2 s2 -a-> s1"
181
+
182
+ refute dfa1.complete?
183
+ refute dfa2.complete?
184
+ end
185
+
186
+ test "Dead States: Initial state is never dead." do
187
+ dfa1 = RLSM::DFA.new "}s1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a,b-> s3"
188
+ dfa2 = RLSM::DFA.new "}s1"
189
+ dfa3 = RLSM::DFA.new "}s1 s2 s3"
190
+
191
+ refute dfa1.dead?('s1')
192
+ refute dfa2.dead?('s1')
193
+ refute dfa3.dead?('s1')
194
+ end
195
+
196
+ test "Dead States: Final states are never dead." do
197
+ dfa = RLSM::DFA.new "}s1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a,b-> s3"
198
+
199
+ refute dfa.dead?('s3')
200
+ end
201
+
202
+ test "Dead States: A state may be dead." do
203
+ dfa = RLSM::DFA.new "}s1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a,b-> s3"
204
+
205
+ assert dfa.dead?('s2')
206
+ end
207
+
208
+ test "Arguments for state properties must be states of the DFA." do
209
+ dfa = RLSM::DFA.new "}s1"
210
+ assert_raises DFAError do
211
+ dfa.dead? "s3"
212
+ end
213
+
214
+ assert_raises DFAError do
215
+ dfa.reachable? "s3"
216
+ end
217
+ end
218
+ end
219
+
220
+ context "Transformations of a DFA" do
221
+ test "DFA#== : Equal DFAs must have same alphabet." do
222
+ dfa1 = RLSM::DFA.new "}s1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a,b-> s3"
223
+ dfa2 = RLSM::DFA.new "}s1 -c-> s2 s1 -b-> *s3 s2 -c,b-> s2 s3 -c,b-> s3"
224
+
225
+ refute_equal dfa1, dfa2
226
+ end
227
+
228
+ test "DFA#== : Equal DFAs must have same initial state." do
229
+ dfa1 = RLSM::DFA.new "}s1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a,b-> s3"
230
+ dfa2 = RLSM::DFA.new "}t1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a,b-> s3"
231
+
232
+ refute_equal dfa1, dfa2
233
+ end
234
+
235
+ test "DFA#== : Equal DFAs must have same final_states." do
236
+ dfa1 = RLSM::DFA.new "}s1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a,b-> s3"
237
+ dfa2 = RLSM::DFA.new "}*s1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a,b-> s3"
238
+
239
+ refute_equal dfa1, dfa2
240
+ end
241
+
242
+ test "DFA#== : Equal DFAs must have same states." do
243
+ dfa1 = RLSM::DFA.new "}s1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a,b-> s3"
244
+ dfa2 = RLSM::DFA.new "}s1 -a-> t2 s1 -b-> *s3 t2 -a,b-> t2 s3 -a,b-> s3"
245
+
246
+ refute_equal dfa1, dfa2
247
+ end
248
+
249
+ test "DFA#== : Equal DFAs must have same transitions." do
250
+ dfa1 = RLSM::DFA.new "}s1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a,b-> s3"
251
+ dfa2 = RLSM::DFA.new "}s1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a-> s3"
252
+
253
+ refute_equal dfa1, dfa2
254
+ end
255
+
256
+ test "DFA#== : Equal monoids must be equal." do
257
+ dfa1 = RLSM::DFA.new "}s1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a,b-> s3"
258
+ dfa2 = RLSM::DFA.new "}s1 -a-> s2 s1 -b-> *s3 s2 -a,b-> s2 s3 -a,b-> s3"
259
+
260
+ assert_equal dfa1, dfa2
261
+ end
262
+
263
+ test "DFA#minimize! : Minimizing a connected complete DFA." do
264
+ dfa = RLSM::DFA.new "}i -a-> 1 i -b-> 2 1 -b-> 2 2-b->1 1-a->3 2-a->*3 3 -a,b-> trap trap -a,b-> trap"
265
+
266
+ dfa.minimize!
267
+
268
+ expected = RLSM::DFA.new "}i-a,b-> 1 1 -b-> 1 1-a->*3"
269
+ assert_equal expected, dfa
270
+ end
271
+
272
+ test "DFA#minimize! : Minimizing a connected DFA." do
273
+ dfa = RLSM::DFA.new "}i -a-> 1 i -b-> 2 1 -b-> 2 2-b->1 1-a->3 2-a->*3"
274
+
275
+ dfa.minimize!
276
+
277
+ expected = RLSM::DFA.new "}i-a,b-> 1 1 -b-> 1 1-a->*3"
278
+ assert_equal expected, dfa
279
+ end
280
+
281
+ test "DFA#minimize! : Minimizing a unconnected DFA." do
282
+ dfa = RLSM::DFA.new "}i -a-> 1 i -b-> 2 1 -b-> 2 2-b->1 1-a->3 2-a->*3 s4-a->s5 *s5-a,b-> 3"
283
+
284
+ dfa.minimize!
285
+
286
+ expected = RLSM::DFA.new "}i-a,b-> 1 1 -b-> 1 1-a->*3"
287
+ assert_equal expected, dfa
288
+ end
289
+
290
+ test "DFA#minimal? : Recognizing a minimal DFA." do
291
+ assert RLSM::DFA.new("}i-a,b-> 1 1 -b-> 1 1-a->*3").minimal?
292
+ end
293
+
294
+ test "DFA#minimal? : Recognizing a nonminimal DFA." do
295
+ refute RLSM::DFA.new("}i -a-> 1 i -b-> 2 1 -b-> 2 2-b->1 1-a->3 2-a->*3").minimal?
296
+ end
297
+
298
+ test "DFA#=~ : A DFA is isomorph with itself" do
299
+ dfa = RLSM::DFA.new "}s1 -a-> *s1"
300
+ assert dfa =~ dfa
301
+ end
302
+
303
+ test "DFA#=~ : A DFA is not isomorph to other things than DFAs." do
304
+ dfa = RLSM::DFA.new "}s1 -a-> *s1"
305
+ refute dfa =~ :dfa
306
+ end
307
+
308
+ test "DFA#=~ : A DFA is isomorph with another if only state names differs" do
309
+ dfa1 = RLSM::DFA.new "}s1 -a-> *s1"
310
+ dfa2 = RLSM::DFA.new "}t1 -a-> *t1"
311
+ assert dfa1 =~ dfa2
312
+ end
313
+
314
+ test "DFA#=~ : A DFA is not isomorph with another if alphabet differs" do
315
+ dfa1 = RLSM::DFA.new "}s1 -a-> *s1"
316
+ dfa2 = RLSM::DFA.new "}s1 -b-> *s1"
317
+ refute dfa1 =~ dfa2
318
+ end
319
+
320
+ test "DFA#=~ : A DFA is isomorph with another if number of state differs" do
321
+ dfa1 = RLSM::DFA.new "}s1 -a-> *s1 s3"
322
+ dfa2 = RLSM::DFA.new "}t1 -a-> *t1"
323
+ refute dfa1 =~ dfa2
324
+ end
325
+
326
+ test "DFA#=~ : DFA not isomorph with other if number of final state differs" do
327
+ dfa1 = RLSM::DFA.new "}s1 -a-> *s1 *s3"
328
+ dfa2 = RLSM::DFA.new "}t1 -a-> *t1 s3"
329
+ refute dfa1 =~ dfa2
330
+ end
331
+
332
+ test "DFA#=~ : DFA not isomorph with other if transition number differs" do
333
+ dfa1 = RLSM::DFA.new "}s1 -a-> *s1 s1-b->*s3"
334
+ dfa2 = RLSM::DFA.new "}s1 -a,b-> *s1 *s3-a->s3"
335
+ refute dfa1 =~ dfa2
336
+ end
337
+
338
+ test "DFA#=~ : DFA not isomorph with other if transitions differs" do
339
+ dfa1 = RLSM::DFA.new "}s1 -a-> *s1 s1-b->*s3"
340
+ dfa2 = RLSM::DFA.new "}s1 -a,b-> *s1 *s3"
341
+ refute dfa1 =~ dfa2
342
+ end
343
+
344
+
345
+ test "DFA#equivalent_to : Recognising equivalent DFAs." do
346
+ dfa1 = RLSM::DFA.new "}i -a-> 1 i -b-> 2 1 -b-> 2 2-b->1 1-a->3 2-a->*3"
347
+ dfa2 = RLSM::DFA.new "}i-a,b-> 1 1 -b-> 1 1-a->*3"
348
+
349
+ assert dfa1.equivalent_to(dfa2)
350
+ end
351
+
352
+ test "DFA#equivalent_to : Recognising nonequivalent DFAs." do
353
+ dfa1 = RLSM::DFA.new "}i -a-> 1 i -b-> 2 1 -b-> 2 2-b->1 1-a->3 2-a->*3"
354
+ dfa2 = RLSM::DFA.new "}i-a,b-> 1 1-a->*3"
355
+
356
+ refute dfa1.equivalent_to(dfa2)
357
+ end
358
+ end
359
+
360
+ context "Accepting of words, transition monoid" do
361
+ test "Following the transitions from an arbitrary state." do
362
+ dfa = RLSM::DFA.new "}s1-a->s2 s2 -a-> *s3 s3 -b-> s2"
363
+
364
+ assert_equal "s2", dfa['s3', 'b']
365
+ assert_equal "s2", dfa['s1', 'a']
366
+ assert_equal "s2", dfa['s3', 'bab']
367
+ end
368
+
369
+ test "Following the transitions from the initial state." do
370
+ dfa = RLSM::DFA.new "}s1-a->s2 s2 -a-> *s3 s3 -b-> s2"
371
+
372
+ assert_equal "s2", dfa << "a"
373
+ assert_equal "s2", dfa << "aabab"
374
+ assert_equal "s3", dfa << "aa"
375
+ end
376
+
377
+ test "Requesting a nonexistent transition." do
378
+ dfa = RLSM::DFA.new "}s1-a->s2 s2 -a-> *s3 s3 -b-> s2 s4"
379
+
380
+ assert_nil dfa << "b"
381
+ assert_nil dfa['s4','a']
382
+ end
383
+
384
+ test "Requesting a transition from a nonexistant state." do
385
+ assert_raises DFAError do
386
+ RLSM::DFA.new("}s1")['s2', 'a']
387
+ end
388
+ end
389
+
390
+ test "Accepting words." do
391
+ dfa = RLSM::DFA.new "}s1-a->s2 s2 -a-> *s3 s3 -b-> s2"
392
+
393
+ assert dfa.accepts?("aa")
394
+ assert dfa.accepts?("aaba")
395
+ end
396
+
397
+ test "Rejecting words." do
398
+ dfa = RLSM::DFA.new "}s1-a->s2 s2 -a-> *s3 s3 -b-> s2"
399
+
400
+ refute dfa.accepts?("a")
401
+ refute dfa.accepts?("aab")
402
+ end
403
+
404
+ test "Calculating the transition monoid." do
405
+ dfa = RLSM::DFA.new "}s1-a->s2 s2 -a-> *s3 s3 -b-> s2"
406
+ expected_monoid = RLSM::Monoid[ <<MONOID
407
+ id, a, b, aa, ab, ba, bb,aab,aba
408
+ a, aa, ab, bb,aab,aba, bb, bb, aa
409
+ b, ba, bb, bb, b, bb, bb, bb, ba
410
+ aa, bb,aab, bb, bb, aa, bb, bb, bb
411
+ ab,aba, bb, bb, ab, bb, bb, bb,aba
412
+ ba, bb, b, bb, bb, ba, bb, bb, bb
413
+ bb, bb, bb, bb, bb, bb, bb, bb, bb
414
+ aab, aa, bb, bb,aab, bb, bb, bb, aa
415
+ aba, bb, ab, bb, bb,aba, bb, bb, bb
416
+ MONOID
417
+ ]
418
+ assert_equal expected_monoid, dfa.transition_monoid
419
+ end
420
+
421
+ end
422
+
423
+ context "DFA#to_regexp" do
424
+ test "Should return emptyset for DFA['}s1']" do
425
+ assert_equal RLSM::RegExp.empty_set, RLSM::DFA['}s1'].to_regexp
426
+ end
427
+
428
+ test "Should return empty word for DFA['}*s1']" do
429
+ assert_equal RLSM::RegExp.empty_word, RLSM::DFA['}*s1'].to_regexp
430
+ end
431
+
432
+ test "Should return a* for DFA['}*s1-a->s1']" do
433
+ assert_equal RLSM::RegExp['a*'], RLSM::DFA['}*s1-a->s1'].to_regexp
434
+ end
435
+ end