def test_bug_36(): etc1 = FSM(alphabet={unspecified}, states={0}, initial=0, accepting={0}, transition={0: { unspecified: 0 }}) etc2 = FSM(alphabet={'s', unspecified}, states={0, 1}, initial=0, accepting={1}, transition={ 0: { 's': 1 }, 1: { 's': 1, unspecified: 1 } }) both = etc1 & etc2 assert etc1.accepts(["s"]) assert etc2.accepts(["s"]) assert both.alphabet == {unspecified, "s"} assert both.accepts(["s"])
def test_accepts_basic_3(self): f = FSM() f.addstate('freshman') f.addstate('sophmore') f.addstate('junior') f.addstate('senior') f.setstartstate('freshman') f.addtransition('freshman','freshman','F') f.addtransition('sophmore','sophmore','F') f.addtransition('junior','junior','F') f.addtransition('senior','senior','F') f.addtransition('freshman','sophmore','A') f.addtransition('sophmore','junior','A') f.addtransition('junior','senior','A') f.addtransition('senior','freshman','F') f.addtransition('junior','freshman','F') f.addtransition('sophmore','freshman','F') f.setacceptstate('senior') self.assertTrue(f.accepts('AAA')) # True self.assertTrue(f.accepts('AAAF')) # True self.assertTrue(f.accepts('AAAFAAA')) # True self.assertTrue(f.accepts('FAFAAFAAA')) # True self.assertTrue(f.accepts('FAFAAFA')) # True self.assertTrue(f.accepts('AFAA')) self.assertFalse(f.accepts('AA')) self.assertFalse(f.accepts('FAFF')) self.assertFalse(f.accepts('AAAA')) self.assertFalse(f.accepts('AFFFFF')) self.assertFalse(f.accepts('AFAAFAFA'))
def test_new_fsm(self): M = FSM() M.addstate('open') M.addstate('closed') M.addtransition('open', 'closed', 'a') M.addtransition('closed', 'open', 'b') M.setstartstate('closed') assert(M.accepts('a') == False) M.setacceptstate('open') assert(M.accepts('a') == False) assert(M.accepts('b') == True) assert(M.accepts('bab') == True) assert(M.accepts('ba') == False)
def test_accepts_noTransitions(self): f = FSM() f.addstate('a') f.addstate('b') f.addstate('c') f.addstate('d') f.setstartstate('a') self.assertFalse(f.accepts("thereisnopath")) f.addtransition('d', 'b', '0') f.addtransition('d', 'b', '1') f.addtransition('d', 'c', '0') f.addtransition('d', 'c', '1') self.assertFalse(f.accepts("thereisnopath"))
def test_addbug(): # Odd bug with fsm.__add__(), exposed by "[bc]*c" int5A = FSM(alphabet={"a", "b", "c", unspecified}, states={0, 1}, initial=1, accepting={1}, transition={ 0: { unspecified: 0, "a": 0, "b": 0, "c": 0 }, 1: { unspecified: 0, "a": 0, "b": 1, "c": 1 }, }) assert int5A.accepts("") int5B = FSM(alphabet={"a", "b", "c", unspecified}, states={0, 1, 2}, initial=1, accepting={0}, transition={ 0: { unspecified: 2, "a": 2, "b": 2, "c": 2 }, 1: { unspecified: 2, "a": 2, "b": 2, "c": 0 }, 2: { unspecified: 2, "a": 2, "b": 2, "c": 2 }, }) assert int5B.accepts("c") int5C = int5A + int5B print(int5C) assert int5C.accepts("c")
def test_star_advanced(): # This is (a*ba)*. Naively connecting the final states to the initial state # gives the incorrect result here. starred = FSM(alphabet={"a", "b"}, states={0, 1, 2, "oblivion"}, initial=0, accepting={2}, transition={ 0: { "a": 0, "b": 1 }, 1: { "a": 2, "b": "oblivion" }, 2: { "a": "oblivion", "b": "oblivion" }, "oblivion": { "a": "oblivion", "b": "oblivion" }, }).star() assert starred.alphabet == frozenset(["a", "b"]) assert starred.accepts("") assert not starred.accepts("a") assert not starred.accepts("b") assert not starred.accepts("aa") assert starred.accepts("ba") assert starred.accepts("aba") assert starred.accepts("aaba") assert not starred.accepts("aabb") assert starred.accepts("abababa")
def test_multiple_accept_states(self): M =FSM() for i in range(5): M.addstate(str(i)) for i in range(4): M.addtransition(str(i), str(i+1), 'a') M.setstartstate('0') assert(M.accepts('aaa') == False) M.setacceptstate('4') assert(M.accepts('aaa') == False) assert(M.accepts('aaaa') == True) M.setacceptstate('3') assert(M.accepts('aaa') == True) assert(M.accepts('aaaa') == True)
def test_accepts_basic_2(self): a = FSM() a.setstartstate('q1') a.addstate('q2') a.addstate('q3') a.addstate('q4') a.addstate('q5') a.addstate('q6') a.setacceptstate('q2') a.setacceptstate('q5') a.addtransition('q1','q2','1') a.addtransition('q2','q1','0') a.addtransition('q1','q1','0') a.addtransition('q2','q3','0') a.addtransition('q3','q4','0') a.addtransition('q4','q5','0') a.addtransition('q5','q6','0') a.addtransition('q6','q3','1') self.assertFalse(a.accepts('0010')) # False self.assertFalse(a.accepts('10')) # False self.assertFalse(a.accepts('100')) # False self.assertTrue(a.accepts('1000')) # True self.assertTrue(a.accepts('0101')) # True self.assertTrue(a.accepts('100001')) # True a.addtransition('q3','q2','0') self.assertTrue(a.accepts('1000010')) # True self.assertTrue(a.accepts('101000001000')) # True self.assertFalse(a.accepts('1010000011')) # This depends on the case of invalid alphabets
def test_all_ones(self): M = FSM() M.addstate('allones') M.addstate('fail') M.addtransition('allones', 'allones', '1') M.addtransition('allones', 'fail', '0') M.addtransition('fail', 'fail', '0') M.addtransition('fail', 'fail', '1') M.setstartstate('allones') M.setacceptstate('allones') assert(M.accepts('')) assert(M.accepts('1')) assert(M.accepts('11111111')) assert(not M.accepts('11111110')) assert(not M.accepts('0'))
def test_accepts_noStates(self): f = FSM() # testing accepts without given a startstate self.assertRaises(ValueError,f.accepts,'10121') # given non-existent states f.setstartstate("pie") self.assertRaises(KeyError,f.addtransition,'fail','this','1') self.assertFalse(f.accepts("thereisnothing"))
def test_dead_default(): ''' You may now omit a transition, or even an entire state, from the transition. This affects every usage of `fsm.transition`. ''' blockquote = FSM(alphabet={"/", "*", unspecified}, states={0, 1, 2, 3, 4, 5}, initial=0, accepting={4}, transition={ 0: { "/": 1 }, 1: { "*": 2 }, 2: { "/": 2, unspecified: 2, "*": 3 }, 3: { "/": 4, unspecified: 2, "*": 3 }, }) assert blockquote.accepts(["/", "*", "whatever", "*", "/"]) assert not blockquote.accepts(["*", "*", "whatever", "*", "/"]) str(blockquote) # test stringification blockquote | blockquote blockquote & blockquote blockquote ^ blockquote reversed(blockquote) assert not blockquote.everythingbut().accepts( ["/", "*", "whatever", "*", "/"]) assert blockquote.everythingbut().accepts(["*" ]) # deliberately seek oblivion assert blockquote.islive(3) assert blockquote.islive(4) assert not blockquote.islive(5) gen = blockquote.strings() assert next(gen) == ["/", "*", "*", "/"]
def test_accepts_invalidInput(self): f = FSM() f.addstate("python") f.addstate("java") f.addstate("c") f.addstate("c++") f.addstate("scheme") f.setstartstate("java") # transitions longer than length 1 f.addtransition("java","scheme","1729") f.addtransition("scheme","python","2050") f.addtransition("python","c++","4095") f.addtransition("c++","c","4095") self.assertFalse(f.accepts("1729")) self.assertFalse(f.accepts("17292050")) self.assertFalse(f.accepts("172920504095")) self.assertFalse(f.accepts("1729205040954095")) # invalid paramter type self.assertRaises(TypeError,f.accepts,1729205040954095)
def test_unspecified_acceptance(): a = FSM( alphabet={"a", "b", "c", unspecified}, states={1}, initial=1, accepting={1}, transition={1: { "a": 1, "b": 1, "c": 1, unspecified: 1 }}, ) assert a.accepts("d")
def test_bug_28(): # This is (ab*)* and it caused some defects. abstar = FSM(alphabet={'a', 'b'}, states={0, 1}, initial=0, accepting={1}, transition={ 0: { 'a': 1 }, 1: { 'b': 1 } }) assert abstar.accepts("a") assert not abstar.accepts("b") assert abstar.accepts("ab") assert abstar.accepts("abb") abstarstar = abstar.star() assert abstarstar.accepts("a") assert not abstarstar.accepts("b") assert abstarstar.accepts("ab") assert not abstar.star().accepts("bb")
def test_highly_connected(self): m = FSM() m.addstate('a') m.addstate('b') m.addstate('c') m.addstate('d') m.addtransition('a', 'b', '0') m.addtransition('a', 'b', '1') m.addtransition('a', 'c', '0') m.addtransition('a', 'c', '1') m.addtransition('a', 'd', '0') m.addtransition('a', 'd', '1') m.addtransition('b', 'a', '0') m.addtransition('b', 'a', '1') m.addtransition('b', 'c', '0') m.addtransition('b', 'c', '1') m.addtransition('b', 'd', '0') m.addtransition('b', 'd', '1') m.addtransition('c', 'a', '0') m.addtransition('c', 'a', '1') m.addtransition('c', 'b', '0') m.addtransition('c', 'b', '1') m.addtransition('c', 'd', '0') m.addtransition('c', 'd', '1') m.addtransition('d', 'a', '0') m.addtransition('d', 'a', '1') m.addtransition('d', 'b', '0') m.addtransition('d', 'b', '1') m.addtransition('d', 'c', '0') m.addtransition('d', 'c', '1') m.setstartstate('a') assert(m.accepts('00000') == False) m.setacceptstate('b') assert(m.accepts('00000') == True) assert(m.accepts('01010101010') == True) assert(m.accepts('010101010120') == False) assert(m.accepts('010101010000000000000000000000000011100010') == True)
def test_odd_number_of_zeros(self): M = FSM() M.addstate('oddzeros') M.addstate('evenzeros') M.addtransition('evenzeros', 'evenzeros', '1') M.addtransition('evenzeros', 'oddzeros', '0') M.addtransition('oddzeros', 'oddzeros', '1') M.addtransition('oddzeros', 'evenzeros', '0') M.setstartstate('evenzeros') M.setacceptstate('oddzeros') assert(M.accepts('0')) assert(M.accepts('10010')) assert(M.accepts('11101010111')) assert(not M.accepts('00')) assert(not M.accepts('0000')) assert(not M.accepts('1110101010111111'))
def test_accepts_basic(self): a = FSM() a.setstartstate('q1') a.addstate('q2') a.setacceptstate('q2') a.addtransition('q1','q2','1') a.addtransition('q2','q1','0') self.assertTrue(a.accepts('1')) # True self.assertFalse(a.accepts('10')) # False self.assertTrue(a.accepts('101')) # True self.assertFalse(a.accepts('1010')) # False self.assertFalse(a.accepts('1010101110001110101')) # This depends on how you handle invalid letters self.assertFalse(a.accepts('10101010101010101010')) # False a.addstate('q3') a.addtransition('q2','q3','1') a.addtransition('q3','q1','1') self.assertFalse(a.accepts('11')) # False self.assertTrue(a.accepts('1111')) # True self.assertFalse(a.accepts('10101111011')) # False a.addtransition('q3','q2','1') self.assertTrue(a.accepts('111')) # True - this fails bc this is deterministic self.assertFalse(a.accepts('')) # False self.assertFalse(a.accepts('14')) # # This depends on how you handle invalid letters self.assertTrue(a.accepts('1')) # True
def test_reverse_brzozowski(): # This is (a|b)*a(a|b) brzozowski = FSM( alphabet={"a", "b"}, states={"A", "B", "C", "D", "E"}, initial="A", accepting={"C", "E"}, transition={ "A": { "a": "B", "b": "D" }, "B": { "a": "C", "b": "E" }, "C": { "a": "C", "b": "E" }, "D": { "a": "B", "b": "D" }, "E": { "a": "B", "b": "D" }, }, ) assert brzozowski.accepts("aa") assert brzozowski.accepts("ab") assert brzozowski.accepts("aab") assert brzozowski.accepts("bab") assert brzozowski.accepts("abbbbbbbab") assert not brzozowski.accepts("") assert not brzozowski.accepts("a") assert not brzozowski.accepts("b") assert not brzozowski.accepts("ba") assert not brzozowski.accepts("bb") assert not brzozowski.accepts("bbbbbbbbbbbb") # So this is (a|b)a(a|b)* b2 = reversed(brzozowski) assert b2.accepts("aa") assert b2.accepts("ba") assert b2.accepts("baa") assert b2.accepts("bab") assert b2.accepts("babbbbbbba") assert not b2.accepts("") assert not b2.accepts("a") assert not b2.accepts("b") assert not b2.accepts("ab") assert not b2.accepts("bb") assert not b2.accepts("bbbbbbbbbbbb") # Test string generator functionality. gen = b2.strings() assert next(gen) == ["a", "a"] assert next(gen) == ["b", "a"] assert next(gen) == ["a", "a", "a"] assert next(gen) == ["a", "a", "b"] assert next(gen) == ["b", "a", "a"] assert next(gen) == ["b", "a", "b"] assert next(gen) == ["a", "a", "a", "a"]
def test_binary_3(): # Binary numbers divisible by 3. # Disallows the empty string # Allows "0" on its own, but not leading zeroes. div3 = FSM( alphabet={"0", "1"}, states={"initial", "zero", 0, 1, 2, None}, initial="initial", accepting={"zero", 0}, transition={ "initial": { "0": "zero", "1": 1 }, "zero": { "0": None, "1": None }, 0: { "0": 0, "1": 1 }, 1: { "0": 2, "1": 0 }, 2: { "0": 1, "1": 2 }, None: { "0": None, "1": None }, }, ) assert not div3.accepts("") assert div3.accepts("0") assert not div3.accepts("1") assert not div3.accepts("00") assert not div3.accepts("01") assert not div3.accepts("10") assert div3.accepts("11") assert not div3.accepts("000") assert not div3.accepts("001") assert not div3.accepts("010") assert not div3.accepts("011") assert not div3.accepts("100") assert not div3.accepts("101") assert div3.accepts("110") assert not div3.accepts("111") assert not div3.accepts("0000") assert not div3.accepts("0001") assert not div3.accepts("0010") assert not div3.accepts("0011") assert not div3.accepts("0100") assert not div3.accepts("0101") assert not div3.accepts("0110") assert not div3.accepts("0111") assert not div3.accepts("1000") assert div3.accepts("1001")