def test_linked_choices__linked_option_with_processed_choice(self):
        is_raised = False

        for i in xrange(100):
            kb = KnowledgeBase()
            start = facts.Start(uid='start', type='test', nesting=0)
            choice_1 = facts.Choice(uid='choice_1')
            choice_2 = facts.Choice(uid='choice_2')
            finish_1 = facts.Finish(uid='finish_1',
                                    results={},
                                    nesting=0,
                                    start='start')
            finish_2 = facts.Finish(uid='finish_2',
                                    results={},
                                    nesting=0,
                                    start='start')

            option_1 = facts.Option(state_from=choice_1.uid,
                                    state_to=finish_1.uid,
                                    type='opt_1',
                                    markers=())
            option_2 = facts.Option(state_from=choice_1.uid,
                                    state_to=choice_2.uid,
                                    type='opt_2',
                                    markers=())

            option_2_1 = facts.Option(state_from=choice_2.uid,
                                      state_to=finish_1.uid,
                                      type='opt_2_1',
                                      markers=())
            option_2_2 = facts.Option(state_from=choice_2.uid,
                                      state_to=finish_2.uid,
                                      type='opt_2_2',
                                      markers=())

            facts_list = [
                start,
                facts.Jump(state_from=start.uid,
                           state_to=choice_1.uid), choice_1, choice_2,
                finish_1, finish_2, option_1, option_2, option_2_1, option_2_2,
                facts.OptionsLink(options=(option_2.uid, option_2_2.uid))
            ]

            kb += facts_list

            try:
                transformators.determine_default_choices(kb)
            except exceptions.LinkedOptionWithProcessedChoiceError:
                is_raised = True
                self.assertEqual(len(list(kb.filter(facts.ChoicePath))), 1)
                self.assertEqual(
                    [path.choice for path in kb.filter(facts.ChoicePath)],
                    [choice_2.uid])
                self.assertEqual(
                    [path.option for path in kb.filter(facts.ChoicePath)],
                    [option_2_1.uid])
                break

        self.assertFalse(is_raised)
Esempio n. 2
0
    def test_linked_choices__linked_option_with_processed_choice(self):
        is_raised = False

        for i in xrange(100):
            kb = KnowledgeBase()
            start = facts.Start(uid="start", type="test", nesting=0)
            choice_1 = facts.Choice(uid="choice_1")
            choice_2 = facts.Choice(uid="choice_2")
            finish_1 = facts.Finish(uid="finish_1", results={}, nesting=0, start="start")
            finish_2 = facts.Finish(uid="finish_2", results={}, nesting=0, start="start")

            option_1 = facts.Option(state_from=choice_1.uid, state_to=finish_1.uid, type="opt_1", markers=())
            option_2 = facts.Option(state_from=choice_1.uid, state_to=choice_2.uid, type="opt_2", markers=())

            option_2_1 = facts.Option(state_from=choice_2.uid, state_to=finish_1.uid, type="opt_2_1", markers=())
            option_2_2 = facts.Option(state_from=choice_2.uid, state_to=finish_2.uid, type="opt_2_2", markers=())

            facts_list = [
                start,
                facts.Jump(state_from=start.uid, state_to=choice_1.uid),
                choice_1,
                choice_2,
                finish_1,
                finish_2,
                option_1,
                option_2,
                option_2_1,
                option_2_2,
                facts.OptionsLink(options=(option_2.uid, option_2_2.uid)),
            ]

            kb += facts_list

            try:
                transformators.determine_default_choices(kb)
            except exceptions.LinkedOptionWithProcessedChoiceError:
                is_raised = True
                self.assertEqual(len(list(kb.filter(facts.ChoicePath))), 1)
                self.assertEqual([path.choice for path in kb.filter(facts.ChoicePath)], [choice_2.uid])
                self.assertEqual([path.option for path in kb.filter(facts.ChoicePath)], [option_2_1.uid])
                break

        self.assertFalse(is_raised)
Esempio n. 3
0
class LogicTestsBase(testcase.TestCase):
    def setUp(self):
        super(LogicTestsBase, self).setUp()

        self.place_1, self.place_2, self.place_3 = create_test_map()

        account = self.accounts_factory.create_account(is_fast=True)

        self.storage = LogicStorage()
        self.storage.load_account_data(account)
        self.hero = self.storage.accounts_to_heroes[account.id]

        self.hero_uid = uids.hero(self.hero.id)

        self.knowledge_base = KnowledgeBase()

    def get_hero_info(self):
        return logic.create_hero_info(self.hero)

    def check_uids(self, left, right):
        self.assertEqual(set(f.uid for f in left), set(f.uid for f in right))

    def check_facts(self,
                    places=[],
                    persons=[],
                    locations=[],
                    mobs=[],
                    prefered_mobs=[],
                    hometowns=[],
                    friends=[],
                    bad_branches=[],
                    enemies=[],
                    good_branches=[],
                    equipment_slots=[],
                    social_connections=[]):
        self.check_uids(self.knowledge_base.filter(facts.Place), places)
        self.check_uids(self.knowledge_base.filter(facts.Person), persons)
        self.check_uids(self.knowledge_base.filter(facts.LocatedIn), locations)
        self.check_uids(self.knowledge_base.filter(facts.Mob), mobs)
        self.check_uids(self.knowledge_base.filter(facts.PreferenceMob),
                        prefered_mobs)
        self.check_uids(self.knowledge_base.filter(facts.PreferenceHometown),
                        hometowns)
        self.check_uids(self.knowledge_base.filter(facts.PreferenceFriend),
                        friends)
        self.check_uids(self.knowledge_base.filter(facts.ExceptBadBranches),
                        bad_branches)
        self.check_uids(self.knowledge_base.filter(facts.PreferenceEnemy),
                        enemies)
        self.check_uids(self.knowledge_base.filter(facts.ExceptGoodBranches),
                        good_branches)
        self.check_uids(
            self.knowledge_base.filter(facts.PreferenceEquipmentSlot),
            equipment_slots)
        self.check_uids(self.knowledge_base.filter(facts.SocialConnection),
                        social_connections)
Esempio n. 4
0
class KnowledgeBaseTests(unittest.TestCase):
    def setUp(self):
        self.kb = KnowledgeBase()

        self.fact = Fact(uid='fact')
        self.fact_2 = Fact(uid='fact_2', description='cba')

        self.kb += [self.fact, self.fact_2]

    def test_serialize(self):
        self.assertEqual(
            self.kb.serialize(),
            KnowledgeBase.deserialize(self.kb.serialize(), FACTS).serialize())
        self.assertEqual(
            self.kb.serialize(short=True),
            KnowledgeBase.deserialize(self.kb.serialize(short=True),
                                      FACTS).serialize())
        self.assertNotEqual(
            self.kb.serialize(),
            KnowledgeBase.deserialize(self.kb.serialize(short=True),
                                      FACTS).serialize())

    def test_contains__for_child(self):
        self.assertTrue('fact' in self.kb)
        self.assertFalse('wrong uid' in self.kb)

    def test_getitem__for_child(self):
        self.assertEqual(self.kb['fact'].uid, 'fact')
        self.assertRaises(exceptions.NoFactError, self.kb.__getitem__,
                          'wrong uid')

    def test_get__for_child(self):
        self.assertEqual(self.kb.get('fact').uid, 'fact')
        self.assertEqual(self.kb.get('wrong uid'), None)

    def test_delitem__no_item(self):
        self.assertRaises(exceptions.NoFactError, self.kb.__delitem__,
                          'wrong_fact')

    def test_delitem(self):
        del self.kb['fact']
        self.assertFalse('fact' in self.kb)

    def test_add_fact__list(self):
        self.kb += [Fact(uid='fact 1'), Fact(uid='fact 2')]
        self.assertTrue('fact 1' in self.kb)
        self.assertTrue('fact 2' in self.kb)

    def test_add_fact__duplicate_fact(self):
        self.assertRaises(exceptions.DuplicatedFactError, self.kb.__iadd__,
                          self.fact)

    def test_add_fact__wrong_type(self):
        self.assertRaises(exceptions.WrongFactTypeError, self.kb.__iadd__,
                          'some string')

    def test_add_fact__wrong_type_for_nested_lists(self):
        self.assertRaises(exceptions.WrongFactTypeError, self.kb.__iadd__,
                          [[Fact(uid='some fact')]])

    def test_remove_fact__no_fact(self):
        self.assertRaises(exceptions.NoFactError, self.kb.__isub__,
                          Fact(uid='some fact'))

    def test_remove_fact__wrong_type(self):
        self.assertRaises(exceptions.WrongFactTypeError, self.kb.__isub__,
                          'some string')

    def test_remove_fact__wrong_type_for_nested_lists(self):
        self.assertRaises(exceptions.WrongFactTypeError, self.kb.__isub__,
                          [[self.fact]])

    def test_validate_consistency__success(self):
        self.kb.validate_consistency([])
        self.kb.validate_consistency([restrictions.AlwaysSuccess()])

    def test_validate_consistency__error(self):
        self.assertRaises(restrictions.AlwaysError.Error,
                          self.kb.validate_consistency,
                          [restrictions.AlwaysError()])

    def test_uids(self):
        self.assertEqual(self.kb.uids(), set(self.kb._facts.keys()))

    def test_facts(self):
        self.assertEqual(set(fact.uid for fact in self.kb.facts()),
                         set(self.kb._facts.keys()))

    def test_filter__no_facts(self):
        self.assertEqual(list(self.kb.filter(Person)), [])

    def test_filter(self):
        self.assertEqual(len(list(self.kb.filter(Fact))), 2)

        person_1 = Person(uid='person_1')
        person_2 = Person(uid='person_2')
        place_1 = Place(uid='place_1')

        self.kb += [person_1, person_2, place_1]

        self.assertEqual(len(list(self.kb.filter(Fact))), 5)
        self.assertEqual(set(fact.uid for fact in self.kb.filter(Person)),
                         set([person_1.uid, person_2.uid]))
        self.assertEqual(set(fact.uid for fact in self.kb.filter(Place)),
                         set([place_1.uid]))
Esempio n. 5
0
class QuestsTests(unittest.TestCase):

    def setUp(self):
        self.qb = QuestsBase()
        self.qb += [Simple]

        self.kb = KnowledgeBase()

        self.kb += [ facts.Hero(uid='hero'),

            facts.Place(uid='place_1', terrains=(1,)),
            facts.Place(uid='place_2', terrains=(0,)),
            facts.Place(uid='place_3', terrains=(0,)),
            facts.Place(uid='place_4', terrains=(1,)),
            facts.Place(uid='place_5', terrains=(2,)),
            facts.Place(uid='place_6', terrains=(1,)),
            facts.Place(uid='place_7', terrains=(2,)),
            facts.Place(uid='place_8', terrains=(2,)),
            facts.Place(uid='place_9', terrains=(1,)),
            facts.Place(uid='place_10', terrains=(2,)),

            facts.Person(uid='person_1', profession=PROFESSION.NONE),
            facts.Person(uid='person_2', profession=PROFESSION.BLACKSMITH),
            facts.Person(uid='person_3', profession=PROFESSION.NONE),
            facts.Person(uid='person_4', profession=PROFESSION.NONE),
            facts.Person(uid='person_5', profession=PROFESSION.NONE),
            facts.Person(uid='person_6', profession=PROFESSION.NONE),
            facts.Person(uid='person_7', profession=PROFESSION.NONE),
            facts.Person(uid='person_8', profession=PROFESSION.NONE),
            facts.Person(uid='person_9', profession=PROFESSION.NONE),
            facts.Person(uid='person_10', profession=PROFESSION.NONE),

            facts.LocatedIn(object='person_1', place='place_1'),
            facts.LocatedIn(object='person_2', place='place_2'),
            facts.LocatedIn(object='person_3', place='place_3'),
            facts.LocatedIn(object='person_4', place='place_4'),
            facts.LocatedIn(object='person_5', place='place_5'),
            facts.LocatedIn(object='person_6', place='place_6'),
            facts.LocatedIn(object='person_7', place='place_7'),
            facts.LocatedIn(object='person_8', place='place_8'),
            facts.LocatedIn(object='person_9', place='place_9'),
            facts.LocatedIn(object='person_10', place='place_10'),

            facts.LocatedIn(object='hero', place='place_1'),

            facts.Mob(uid='mob_1', terrains=(0,)),
            facts.PreferenceMob(object='hero', mob='mob_1'),
            facts.PreferenceHometown(object='hero', place='place_2'),
            facts.PreferenceFriend(object='hero', person='person_4'),
            facts.PreferenceEnemy(object='hero', person='person_5'),
            facts.UpgradeEquipmentCost(money=777)
            ]

        self.selector = Selector(self.kb, self.qb)


    def check_quest(self, quest_class):
        self.kb += quest_class.construct_from_place(nesting=0, selector=self.selector, start_place=self.selector.new_place(candidates=('place_1',)))

        self.kb.validate_consistency([restrictions.SingleStartStateWithNoEnters(),
                                      restrictions.FinishStateExists(),
                                      restrictions.AllStatesHasJumps(),
                                      restrictions.SingleLocationForObject(),
                                      restrictions.ReferencesIntegrity(),
                                      restrictions.ConnectedStateJumpGraph(),
                                      restrictions.NoCirclesInStateJumpGraph(),
                                      # restrictions.MultipleJumpsFromNormalState(),
                                      restrictions.ChoicesConsistency(),
                                      restrictions.QuestionsConsistency(),
                                      restrictions.FinishResultsConsistency(),
                                      restrictions.RequirementsConsistency(),
                                      restrictions.ActionsConsistency()])

    def check_linked_options_has_similar_markers(self, quest_class):
        self.kb += quest_class.construct_from_place(nesting=0, selector=self.selector, start_place=self.selector.new_place(candidates=('place_1',)))

        for options_link in self.kb.filter(facts.OptionsLink):

            makrers = None

            for option_uid in options_link.options:
                option = self.kb[option_uid]

                if makrers is None:
                    makrers = set(option.markers)

                self.assertEqual(makrers, set(option.markers))
Esempio n. 6
0
class LogicTestsBase(testcase.TestCase):

    def setUp(self):
        super(LogicTestsBase, self).setUp()

        self.place_1, self.place_2, self.place_3 = create_test_map()

        result, account_id, bundle_id = register_user('test_user')

        self.storage = LogicStorage()
        self.storage.load_account_data(AccountPrototype.get_by_id(account_id))
        self.hero = self.storage.accounts_to_heroes[account_id]

        self.hero_uid = uids.hero(self.hero.id)

        self.knowledge_base = KnowledgeBase()


    def get_hero_info(self):
        return logic.create_hero_info(self.hero)


    def check_uids(self, left, right):
        self.assertEqual(set(f.uid for f in left), set(f.uid for f in right))

    def check_facts(self,
                    places=[],
                    persons=[],
                    locations=[],
                    mobs=[],
                    prefered_mobs=[],
                    hometowns=[],
                    friends=[],
                    bad_branches=[],
                    enemies=[],
                    good_branches=[],
                    equipment_slots=[],
                    social_connections=[]):
        self.check_uids(self.knowledge_base.filter(facts.Place), places)
        self.check_uids(self.knowledge_base.filter(facts.Person), persons)
        self.check_uids(self.knowledge_base.filter(facts.LocatedIn), locations)
        self.check_uids(self.knowledge_base.filter(facts.Mob), mobs)
        self.check_uids(self.knowledge_base.filter(facts.PreferenceMob), prefered_mobs)
        self.check_uids(self.knowledge_base.filter(facts.PreferenceHometown), hometowns)
        self.check_uids(self.knowledge_base.filter(facts.PreferenceFriend), friends)
        self.check_uids(self.knowledge_base.filter(facts.ExceptBadBranches), bad_branches)
        self.check_uids(self.knowledge_base.filter(facts.PreferenceEnemy), enemies)
        self.check_uids(self.knowledge_base.filter(facts.ExceptGoodBranches), good_branches)
        self.check_uids(self.knowledge_base.filter(facts.PreferenceEquipmentSlot), equipment_slots)
        self.check_uids(self.knowledge_base.filter(facts.SocialConnection), social_connections)
Esempio n. 7
0
class KnowledgeBaseTests(unittest.TestCase):

    def setUp(self):
        self.kb = KnowledgeBase()

        self.fact = Fact(uid='fact')
        self.fact_2 = Fact(uid='fact_2', description='cba')

        self.kb += [ self.fact,
                     self.fact_2 ]

    def test_serialize(self):
        self.assertEqual(self.kb.serialize(), KnowledgeBase.deserialize(self.kb.serialize(), FACTS).serialize())
        self.assertEqual(self.kb.serialize(short=True), KnowledgeBase.deserialize(self.kb.serialize(short=True), FACTS).serialize())
        self.assertNotEqual(self.kb.serialize(), KnowledgeBase.deserialize(self.kb.serialize(short=True), FACTS).serialize())

    def test_contains__for_child(self):
        self.assertTrue('fact' in self.kb)
        self.assertFalse('wrong uid' in self.kb)

    def test_getitem__for_child(self):
        self.assertEqual(self.kb['fact'].uid, 'fact')
        self.assertRaises(exceptions.NoFactError, self.kb.__getitem__, 'wrong uid')

    def test_get__for_child(self):
        self.assertEqual(self.kb.get('fact').uid, 'fact')
        self.assertEqual(self.kb.get('wrong uid'), None)

    def test_delitem__no_item(self):
        self.assertRaises(exceptions.NoFactError, self.kb.__delitem__, 'wrong_fact')

    def test_delitem(self):
        del self.kb['fact']
        self.assertFalse('fact' in self.kb)

    def test_add_fact__list(self):
        self.kb += [Fact(uid='fact 1'), Fact(uid='fact 2')]
        self.assertTrue('fact 1' in self.kb)
        self.assertTrue('fact 2' in self.kb)

    def test_add_fact__duplicate_fact(self):
        self.assertRaises(exceptions.DuplicatedFactError,
                          self.kb.__iadd__, self.fact)

    def test_add_fact__wrong_type(self):
        self.assertRaises(exceptions.WrongFactTypeError,
                          self.kb.__iadd__, 'some string')

    def test_add_fact__wrong_type_for_nested_lists(self):
        self.assertRaises(exceptions.WrongFactTypeError,
                          self.kb.__iadd__, [[Fact(uid='some fact')]])

    def test_remove_fact__no_fact(self):
        self.assertRaises(exceptions.NoFactError,
                          self.kb.__isub__, Fact(uid='some fact'))

    def test_remove_fact__wrong_type(self):
        self.assertRaises(exceptions.WrongFactTypeError,
                          self.kb.__isub__, 'some string')

    def test_remove_fact__wrong_type_for_nested_lists(self):
        self.assertRaises(exceptions.WrongFactTypeError,
                          self.kb.__isub__, [[self.fact]])

    def test_validate_consistency__success(self):
        self.kb.validate_consistency([])
        self.kb.validate_consistency([restrictions.AlwaysSuccess()])

    def test_validate_consistency__error(self):
        self.assertRaises(restrictions.AlwaysError.Error, self.kb.validate_consistency, [restrictions.AlwaysError()])

    def test_uids(self):
        self.assertEqual(self.kb.uids(),
                         set(self.kb._facts.keys()))

    def test_facts(self):
        self.assertEqual(set(fact.uid for fact in self.kb.facts()),
                         set(self.kb._facts.keys()))

    def test_filter__no_facts(self):
        self.assertEqual(list(self.kb.filter(Person)), [])

    def test_filter(self):
        self.assertEqual(len(list(self.kb.filter(Fact))), 2)

        person_1 = Person(uid='person_1')
        person_2 = Person(uid='person_2')
        place_1 = Place(uid='place_1')

        self.kb += [ person_1, person_2, place_1]

        self.assertEqual(len(list(self.kb.filter(Fact))), 5)
        self.assertEqual(set(fact.uid for fact in self.kb.filter(Person)),
                         set([person_1.uid, person_2.uid]))
        self.assertEqual(set(fact.uid for fact in self.kb.filter(Place)),
                         set([place_1.uid]))
Esempio n. 8
0
class QuestsTests(unittest.TestCase):
    def setUp(self):
        self.qb = QuestsBase()
        self.qb += [Simple]

        self.kb = KnowledgeBase()

        self.kb += [
            facts.Hero(uid='hero'),
            facts.Place(uid='place_1', terrains=(1, )),
            facts.Place(uid='place_2', terrains=(0, )),
            facts.Place(uid='place_3', terrains=(0, )),
            facts.Place(uid='place_4', terrains=(1, )),
            facts.Place(uid='place_5', terrains=(2, )),
            facts.Place(uid='place_6', terrains=(1, )),
            facts.Place(uid='place_7', terrains=(2, )),
            facts.Place(uid='place_8', terrains=(2, )),
            facts.Place(uid='place_9', terrains=(1, )),
            facts.Place(uid='place_10', terrains=(2, )),
            facts.Person(uid='person_1', profession=PROFESSION.NONE),
            facts.Person(uid='person_2', profession=PROFESSION.BLACKSMITH),
            facts.Person(uid='person_3', profession=PROFESSION.NONE),
            facts.Person(uid='person_4', profession=PROFESSION.NONE),
            facts.Person(uid='person_5', profession=PROFESSION.NONE),
            facts.Person(uid='person_6', profession=PROFESSION.NONE),
            facts.Person(uid='person_7', profession=PROFESSION.NONE),
            facts.Person(uid='person_8', profession=PROFESSION.NONE),
            facts.Person(uid='person_9', profession=PROFESSION.NONE),
            facts.Person(uid='person_10', profession=PROFESSION.NONE),
            facts.LocatedIn(object='person_1', place='place_1'),
            facts.LocatedIn(object='person_2', place='place_2'),
            facts.LocatedIn(object='person_3', place='place_3'),
            facts.LocatedIn(object='person_4', place='place_4'),
            facts.LocatedIn(object='person_5', place='place_5'),
            facts.LocatedIn(object='person_6', place='place_6'),
            facts.LocatedIn(object='person_7', place='place_7'),
            facts.LocatedIn(object='person_8', place='place_8'),
            facts.LocatedIn(object='person_9', place='place_9'),
            facts.LocatedIn(object='person_10', place='place_10'),
            facts.LocatedIn(object='hero', place='place_1'),
            facts.Mob(uid='mob_1', terrains=(0, )),
            facts.PreferenceMob(object='hero', mob='mob_1'),
            facts.PreferenceHometown(object='hero', place='place_2'),
            facts.PreferenceFriend(object='hero', person='person_4'),
            facts.PreferenceEnemy(object='hero', person='person_5'),
            facts.UpgradeEquipmentCost(money=777)
        ]

        self.selector = Selector(self.kb, self.qb)

    def check_quest(self, quest_class):
        self.kb += quest_class.construct_from_place(
            nesting=0,
            selector=self.selector,
            start_place=self.selector.new_place(candidates=('place_1', )))

        self.kb.validate_consistency([
            restrictions.SingleStartStateWithNoEnters(),
            restrictions.FinishStateExists(),
            restrictions.AllStatesHasJumps(),
            restrictions.SingleLocationForObject(),
            restrictions.ReferencesIntegrity(),
            restrictions.ConnectedStateJumpGraph(),
            restrictions.NoCirclesInStateJumpGraph(),
            # restrictions.MultipleJumpsFromNormalState(),
            restrictions.ChoicesConsistency(),
            restrictions.QuestionsConsistency(),
            restrictions.FinishResultsConsistency(),
            restrictions.RequirementsConsistency(),
            restrictions.ActionsConsistency()
        ])

    def check_linked_options_has_similar_markers(self, quest_class):
        self.kb += quest_class.construct_from_place(
            nesting=0,
            selector=self.selector,
            start_place=self.selector.new_place(candidates=('place_1', )))

        for options_link in self.kb.filter(facts.OptionsLink):

            makrers = None

            for option_uid in options_link.options:
                option = self.kb[option_uid]

                if makrers is None:
                    makrers = set(option.markers)

                self.assertEqual(makrers, set(option.markers))
Esempio n. 9
0
class MachineTests(unittest.TestCase):

    def setUp(self):
        self.kb = KnowledgeBase()

        self.hero = facts.Hero(uid='hero')

        self.start = facts.Start(uid='start', type='test', nesting=0)
        self.state_1 = facts.State(uid='state_1')
        self.state_2 = facts.State(uid='state_2')
        self.finish_1 = facts.Finish(start='start', uid='finish_1', results={}, nesting=0)

        self.kb += [ self.start, self.state_1, self.state_2, self.finish_1, self.hero]

        self.machine = Machine(knowledge_base=self.kb, interpreter=FakeInterpreter())

    def test_get_pointer(self):
        self.assertEqual(list(self.kb.filter(facts.Pointer)), [])
        pointer = self.machine.pointer
        self.assertEqual(list(self.kb.filter(facts.Pointer)), [pointer])

    def test_get_available_jumps__no_jumps(self):
        self.assertEqual(self.machine.get_available_jumps(self.start), [])

    def test_get_available_jumps__all_jumps(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        jump_2 = facts.Jump(state_from=self.start.uid, state_to=self.state_2.uid)
        self.kb += [jump_1, jump_2]

        self.assertEqual(set(jump.uid for jump in self.machine.get_available_jumps(self.start)),
                         set([jump_1.uid, jump_2.uid]))

    def test_get_available_jumps__for_choice_state(self):
        choice = facts.Choice(uid='choice')
        option_1 = facts.Option(state_from=choice.uid, state_to=self.state_1.uid, type='opt_1', markers=())
        option_2 = facts.Option(state_from=choice.uid, state_to=self.state_2.uid, type='opt_2', markers=())
        path = facts.ChoicePath(choice=choice.uid, option=option_2.uid, default=True)
        self.kb += (choice, option_1, option_2, path)

        for i in range(100):
            self.assertEqual(self.machine.get_available_jumps(choice), [option_2])

    def test_get_available_jumps__for_question_state(self):
        condition = requirements.LocatedIn(object='object', place='place')

        question = facts.Question(uid='choice', condition=[condition])
        answer_1 = facts.Answer(state_from=question.uid, state_to=self.state_1.uid, condition=True)
        answer_2 = facts.Answer(state_from=question.uid, state_to=self.state_2.uid, condition=False)
        self.kb += (question, answer_1, answer_2)

        with mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=False)):
            for i in range(100):
                self.assertEqual(self.machine.get_available_jumps(question), [answer_2])

        with mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=True)):
            for i in range(100):
                self.assertEqual(self.machine.get_available_jumps(question), [answer_1])

    def test_get_next_jump__no_jumps(self):
        self.assertRaises(exceptions.NoJumpsAvailableError,
                          self.machine.get_next_jump, self.start)

    def test_get_next_jump__all_jumps(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        jump_2 = facts.Jump(state_from=self.start.uid, state_to=self.state_2.uid)
        self.kb += [jump_1, jump_2]

        jumps = set()

        for i in range(100):
            jumps.add(self.machine.get_next_jump(self.start, single=False).uid)

        self.assertEqual(jumps, set([jump_1.uid, jump_2.uid]))

    def test_get_next_jump__require_one_jump__exception(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        jump_2 = facts.Jump(state_from=self.start.uid, state_to=self.state_2.uid)
        self.kb += [jump_1, jump_2]

        self.assertRaises(exceptions.MoreThenOneJumpsAvailableError, self.machine.get_next_jump, self.start, single=True)

    def test_get_next_jump__require_one_jump(self):
        jump = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        self.kb += jump
        self.assertEqual(self.machine.get_next_jump(self.start, single=True).uid, jump.uid)

    def test_can_do_step__no_pointer(self):
        self.assertEqual(list(self.kb.filter(facts.Pointer)), [])
        self.assertTrue(self.machine.can_do_step())

    @mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_is_alive=False))
    def test_can_do_step__requirement_failed(self):
        state_3 = facts.State(uid='state_3', require=[requirements.IsAlive(object='hero')])
        jump_3 = facts.Jump(state_from=self.start.uid, state_to=state_3.uid)
        self.kb += [ state_3, jump_3]

        pointer = self.machine.pointer
        self.kb -= pointer
        self.kb += pointer.change(state=self.start.uid, jump=jump_3.uid)

        self.assertFalse(self.machine.can_do_step())

    def test_can_do_step__success(self):
        state_3 = facts.State(uid='state_3', require=[requirements.IsAlive(object='hero')])
        jump_3 = facts.Jump(state_from=self.start.uid, state_to=state_3.uid)
        self.kb += [ state_3, jump_3]

        pointer = self.machine.pointer
        self.kb -= pointer
        self.kb += pointer.change(state=self.start.uid, jump=jump_3.uid)

        with mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_is_alive=True)):
            self.assertTrue(self.machine.can_do_step())


    def test_do_step__no_pointer(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        jump_2 = facts.Jump(state_from=self.state_1.uid, state_to=self.state_2.uid)
        self.kb += [jump_1, jump_2]

        calls_manager = mock.MagicMock()

        with mock.patch.object(self.machine.interpreter, 'on_state__before_actions') as on_state__before_actions:
            with mock.patch.object(self.machine.interpreter, 'on_state__after_actions') as on_state__after_actions:
                with mock.patch.object(self.machine.interpreter, 'on_jump_start__before_actions') as on_jump_start__before_actions:
                    with mock.patch.object(self.machine.interpreter, 'on_jump_start__after_actions') as on_jump_start__after_actions:
                        with mock.patch.object(self.machine.interpreter, 'on_jump_end__before_actions') as on_jump_end__before_actions:
                            with mock.patch.object(self.machine.interpreter, 'on_jump_end__after_actions') as on_jump_end__after_actions:

                                calls_manager.attach_mock(on_state__before_actions, 'on_state__before_actions')
                                calls_manager.attach_mock(on_state__after_actions, 'on_state__after_actions')
                                calls_manager.attach_mock(on_jump_start__before_actions, 'on_jump_start__before_actions')
                                calls_manager.attach_mock(on_jump_start__after_actions, 'on_jump_start__after_actions')
                                calls_manager.attach_mock(on_jump_end__before_actions, 'on_jump_end__before_actions')
                                calls_manager.attach_mock(on_jump_end__after_actions, 'on_jump_end__after_actions')

                                self.assertEqual(list(self.kb.filter(facts.Pointer)), [])
                                self.machine.step()
                                self.assertEqual(len(list(self.kb.filter(facts.Pointer))), 1)

                                self.assertEqual(calls_manager.mock_calls, [mock.call.on_state__before_actions(state=self.start),
                                                                            mock.call.on_state__after_actions(state=self.start)])

        pointer = self.machine.pointer
        self.assertEqual(pointer.state, self.start.uid)
        self.assertEqual(pointer.jump, None)


    def test_do_step__finish(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.finish_1.uid)
        self.kb += jump_1

        self.machine.step()
        self.machine.step()

        calls_manager = mock.MagicMock()

        with mock.patch.object(self.machine.interpreter, 'on_state__before_actions') as on_state__before_actions:
            with mock.patch.object(self.machine.interpreter, 'on_state__after_actions') as on_state__after_actions:
                with mock.patch.object(self.machine.interpreter, 'on_jump_start__before_actions') as on_jump_start__before_actions:
                    with mock.patch.object(self.machine.interpreter, 'on_jump_start__after_actions') as on_jump_start__after_actions:
                        with mock.patch.object(self.machine.interpreter, 'on_jump_end__before_actions') as on_jump_end__before_actions:
                            with mock.patch.object(self.machine.interpreter, 'on_jump_end__after_actions') as on_jump_end__after_actions:

                                calls_manager.attach_mock(on_state__before_actions, 'on_state__before_actions')
                                calls_manager.attach_mock(on_state__after_actions, 'on_state__after_actions')
                                calls_manager.attach_mock(on_jump_start__before_actions, 'on_jump_start__before_actions')
                                calls_manager.attach_mock(on_jump_start__after_actions, 'on_jump_start__after_actions')
                                calls_manager.attach_mock(on_jump_end__before_actions, 'on_jump_end__before_actions')
                                calls_manager.attach_mock(on_jump_end__after_actions, 'on_jump_end__after_actions')

                                self.machine.step()

                                self.assertEqual(calls_manager.mock_calls, [mock.call.on_jump_end__before_actions(jump=jump_1),
                                                                            mock.call.on_jump_end__after_actions(jump=jump_1),
                                                                            mock.call.on_state__before_actions(state=self.finish_1),
                                                                            mock.call.on_state__after_actions(state=self.finish_1)])

        pointer = self.machine.pointer
        self.assertEqual(pointer.state, self.finish_1.uid)
        self.assertEqual(pointer.jump, None)

    def test_do_step__step_after_finish(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.finish_1.uid)
        self.kb += jump_1

        self.machine.step()
        self.machine.step()
        self.machine.step()

        self.assertRaises(exceptions.NoJumpsFromLastStateError, self.machine.step)

    def test_do_step__next_jump(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        jump_2 = facts.Jump(state_from=self.state_1.uid, state_to=self.state_2.uid)
        self.kb += [jump_1, jump_2]

        self.machine.step()

        calls_manager = mock.MagicMock()

        pointer = self.machine.pointer
        self.assertEqual(pointer.state, self.start.uid)
        self.assertEqual(pointer.jump, None)

        with mock.patch.object(self.machine.interpreter, 'on_state__before_actions') as on_state__before_actions:
            with mock.patch.object(self.machine.interpreter, 'on_state__after_actions') as on_state__after_actions:
                with mock.patch.object(self.machine.interpreter, 'on_jump_start__before_actions') as on_jump_start__before_actions:
                    with mock.patch.object(self.machine.interpreter, 'on_jump_start__after_actions') as on_jump_start__after_actions:
                        with mock.patch.object(self.machine.interpreter, 'on_jump_end__before_actions') as on_jump_end__before_actions:
                            with mock.patch.object(self.machine.interpreter, 'on_jump_end__after_actions') as on_jump_end__after_actions:

                                calls_manager.attach_mock(on_state__before_actions, 'on_state__before_actions')
                                calls_manager.attach_mock(on_state__after_actions, 'on_state__after_actions')
                                calls_manager.attach_mock(on_jump_start__before_actions, 'on_jump_start__before_actions')
                                calls_manager.attach_mock(on_jump_start__after_actions, 'on_jump_start__after_actions')
                                calls_manager.attach_mock(on_jump_end__before_actions, 'on_jump_end__before_actions')
                                calls_manager.attach_mock(on_jump_end__after_actions, 'on_jump_end__after_actions')

                                self.machine.step()

                                self.assertEqual(calls_manager.mock_calls, [mock.call.on_jump_start__before_actions(jump=jump_1),
                                                                            mock.call.on_jump_start__after_actions(jump=jump_1)])

        pointer = self.machine.pointer
        self.assertEqual(pointer.state, self.start.uid)
        self.assertEqual(pointer.jump, jump_1.uid)

    def test_do_step__next_state(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        jump_2 = facts.Jump(state_from=self.state_1.uid, state_to=self.state_2.uid)
        self.kb += [jump_1, jump_2]

        self.machine.step()
        self.machine.step()
        self.machine.step()

        pointer = self.machine.pointer
        self.assertEqual(pointer.state, self.state_1.uid)
        self.assertEqual(pointer.jump, None)

        calls_manager = mock.MagicMock()

        with mock.patch.object(self.machine.interpreter, 'on_state__before_actions') as on_state__before_actions:
            with mock.patch.object(self.machine.interpreter, 'on_state__after_actions') as on_state__after_actions:
                with mock.patch.object(self.machine.interpreter, 'on_jump_start__before_actions') as on_jump_start__before_actions:
                    with mock.patch.object(self.machine.interpreter, 'on_jump_start__after_actions') as on_jump_start__after_actions:
                        with mock.patch.object(self.machine.interpreter, 'on_jump_end__before_actions') as on_jump_end__before_actions:
                            with mock.patch.object(self.machine.interpreter, 'on_jump_end__after_actions') as on_jump_end__after_actions:

                                calls_manager.attach_mock(on_state__before_actions, 'on_state__before_actions')
                                calls_manager.attach_mock(on_state__after_actions, 'on_state__after_actions')
                                calls_manager.attach_mock(on_jump_start__before_actions, 'on_jump_start__before_actions')
                                calls_manager.attach_mock(on_jump_start__after_actions, 'on_jump_start__after_actions')
                                calls_manager.attach_mock(on_jump_end__before_actions, 'on_jump_end__before_actions')
                                calls_manager.attach_mock(on_jump_end__after_actions, 'on_jump_end__after_actions')

                                self.machine.step()

                                self.assertEqual(calls_manager.mock_calls, [mock.call.on_jump_start__before_actions(jump=jump_2),
                                                                            mock.call.on_jump_start__after_actions(jump=jump_2)])

        pointer = self.machine.pointer
        self.assertEqual(pointer.state, self.state_1.uid)
        self.assertEqual(pointer.jump, jump_2.uid)

    def test_sync_pointer(self):
        choice = facts.Choice(uid='choice')
        option_1 = facts.Option(state_from=choice.uid, state_to=self.state_1.uid, type='opt_1', markers=())
        option_2 = facts.Option(state_from=choice.uid, state_to=self.state_2.uid, type='opt_2', markers=())
        path = facts.ChoicePath(choice=choice.uid, option=option_2.uid, default=True)
        pointer = facts.Pointer(state=choice.uid, jump=option_1.uid)

        self.kb += (choice, option_1, option_2, path, pointer)

        calls_manager = mock.MagicMock()

        with mock.patch.object(self.machine.interpreter, 'on_state__before_actions') as on_state__before_actions:
            with mock.patch.object(self.machine.interpreter, 'on_state__after_actions') as on_state__after_actions:
                with mock.patch.object(self.machine.interpreter, 'on_jump_start__before_actions') as on_jump_start__before_actions:
                    with mock.patch.object(self.machine.interpreter, 'on_jump_start__after_actions') as on_jump_start__after_actions:
                        with mock.patch.object(self.machine.interpreter, 'on_jump_end__before_actions') as on_jump_end__before_actions:
                            with mock.patch.object(self.machine.interpreter, 'on_jump_end__after_actions') as on_jump_end__after_actions:

                                calls_manager.attach_mock(on_state__before_actions, 'on_state__before_actions')
                                calls_manager.attach_mock(on_state__after_actions, 'on_state__after_actions')
                                calls_manager.attach_mock(on_jump_start__before_actions, 'on_jump_start__before_actions')
                                calls_manager.attach_mock(on_jump_start__after_actions, 'on_jump_start__after_actions')
                                calls_manager.attach_mock(on_jump_end__before_actions, 'on_jump_end__before_actions')
                                calls_manager.attach_mock(on_jump_end__after_actions, 'on_jump_end__after_actions')

                                self.machine.sync_pointer()

                                self.assertEqual(calls_manager.mock_calls, [mock.call.on_jump_start__before_actions(jump=option_2),
                                                                            mock.call.on_jump_start__after_actions(jump=option_2)])

        self.assertEqual(self.machine.pointer.jump, option_2.uid)
        self.assertEqual(self.machine.pointer.state, choice.uid)

    def test_get_start_state(self):
        start_2 = facts.Start(uid='s2', type='test', nesting=0)
        start_3 = facts.Start(uid='start_3', type='test', nesting=0)


        self.kb += [ start_2,
                     start_3,
                     facts.Jump(state_from=self.start.uid, state_to=start_2.uid),
                     facts.Jump(state_from=start_3.uid, state_to=self.start.uid) ]

        self.assertEqual(self.machine.get_start_state().uid, start_3.uid)

    def test_get_nearest_choice__no_choice(self):
        self.kb += facts.Jump(state_from=self.start.uid, state_to=self.finish_1.uid)
        self.assertEqual(self.machine.get_nearest_choice(), (None, None, None))

    def test_get_nearest_choice__choice(self):
        choice = facts.Choice(uid='choice')
        option_1 = facts.Option(state_from=choice.uid, state_to=self.state_1.uid, type='opt_1', markers=())
        option_2 = facts.Option(state_from=choice.uid, state_to=self.state_2.uid, type='opt_2', markers=())
        path = facts.ChoicePath(choice=choice.uid, option=option_2.uid, default=True)
        self.kb += (choice,
                    option_1,
                    option_2,
                    path,
                    facts.Jump(state_from=self.start.uid, state_to=choice.uid)    )

        choice_, options_, path_ = self.machine.get_nearest_choice()
        self.assertEqual(choice_.uid, choice.uid)
        self.assertEqual(set(o.uid for o in options_), set([option_1.uid, option_2.uid]))
        self.assertEqual([p.uid for p in path_], [path.uid])

    def test_get_nearest_choice__2_choices(self):
        choice_1 = facts.Choice(uid='choice_1')

        choice_2 = facts.Choice(uid='choice_2')
        option_2_1 = facts.Option(state_from=choice_2.uid, state_to=self.state_1.uid, type='opt_2_1', markers=())
        option_2_2 = facts.Option(state_from=choice_2.uid, state_to=self.state_2.uid, type='opt_2_2', markers=())
        path_2 = facts.ChoicePath(choice=choice_2.uid, option=option_2_2.uid, default=True)

        option_1_1 = facts.Option(state_from=choice_1.uid, state_to=self.state_1.uid, type='opt_1_1', markers=())
        option_1_2 = facts.Option(state_from=choice_1.uid, state_to=choice_2.uid, type='opt_1_2', markers=())
        path_1 = facts.ChoicePath(choice=choice_1.uid, option=option_1_2.uid, default=True)

        self.kb += (choice_1,
                    option_1_1,
                    option_1_2,
                    path_1,

                    choice_2,
                    option_2_1,
                    option_2_2,
                    path_2,
                    facts.Jump(state_from=self.start.uid, state_to=choice_1.uid),
            )

        choice_, options_, path_ = self.machine.get_nearest_choice()
        self.assertEqual(choice_.uid, choice_1.uid)
        self.assertEqual(set(o.uid for o in options_), set([option_1_1.uid, option_1_2.uid]))
        self.assertEqual([p.uid for p in path_], [path_1.uid])

    def test_get_nearest_choice__2_choices__second_choice(self):
        choice_1 = facts.Choice(uid='choice_1')

        choice_2 = facts.Choice(uid='choice_2')
        option_2_1 = facts.Option(state_from=choice_2.uid, state_to=self.state_1.uid, type='opt_2_1', markers=())
        option_2_2 = facts.Option(state_from=choice_2.uid, state_to=self.state_2.uid, type='opt_2_2', markers=())
        path_2 = facts.ChoicePath(choice=choice_2.uid, option=option_2_2.uid, default=True)

        option_1_1 = facts.Option(state_from=choice_1.uid, state_to=self.state_1.uid, type='opt_1_1', markers=())
        option_1_2 = facts.Option(state_from=choice_1.uid, state_to=choice_2.uid, type='opt_1_2', markers=())
        path_1 = facts.ChoicePath(choice=choice_1.uid, option=option_1_2.uid, default=True)

        self.kb += (choice_1,
                    option_1_1,
                    option_1_2,
                    path_1,

                    choice_2,
                    option_2_1,
                    option_2_2,
                    path_2,
                    facts.Jump(state_from=self.start.uid, state_to=choice_1.uid),

                    facts.Pointer(state=choice_2.uid)
            )

        choice_, options_, path_ = self.machine.get_nearest_choice()
        self.assertEqual(choice_.uid, choice_2.uid)
        self.assertEqual(set(o.uid for o in options_), set([option_2_1.uid, option_2_2.uid]))
        self.assertEqual([p.uid for p in path_], [path_2.uid])

    def test_get_nearest_choice__choice_after_finish(self):
        choice = facts.Choice(uid='choice')
        option_1 = facts.Option(state_from=choice.uid, state_to=self.state_1.uid, type='opt_1', markers=())
        option_2 = facts.Option(state_from=choice.uid, state_to=self.state_2.uid, type='opt_2', markers=())
        path = facts.ChoicePath(choice=choice.uid, option=option_2.uid, default=True)
        self.kb += (choice,
                    option_1,
                    option_2,
                    path,
                    facts.Jump(state_from=self.start.uid, state_to=self.finish_1.uid),
                    facts.Jump(state_from=self.finish_1.uid, state_to=choice.uid))

        self.assertEqual(self.machine.get_nearest_choice(), (None, None, None))

    def test_get_nearest_choice__choice_after_question(self):
        choice = facts.Choice(uid='choice')
        option_1 = facts.Option(state_from=choice.uid, state_to=self.state_1.uid, type='opt_1', markers=())
        option_2 = facts.Option(state_from=choice.uid, state_to=self.state_2.uid, type='opt_2', markers=())
        path = facts.ChoicePath(choice=choice.uid, option=option_2.uid, default=True)

        question = facts.Question(uid='question', condition=())

        self.kb += (choice,
                    option_1,
                    option_2,
                    path,
                    question,
                    facts.Jump(state_from=self.start.uid, state_to=question.uid),
                    facts.Jump(state_from=question.uid, state_to=choice.uid))

        self.assertEqual(self.machine.get_nearest_choice(), (None, None, None))

    def test_get_nearest_choice__choice_after_start(self):
        choice = facts.Choice(uid='choice')
        option_1 = facts.Option(state_from=choice.uid, state_to=self.state_1.uid, type='opt_1', markers=())
        option_2 = facts.Option(state_from=choice.uid, state_to=self.state_2.uid, type='opt_2', markers=())
        path = facts.ChoicePath(choice=choice.uid, option=option_2.uid, default=True)
        start_2 = facts.Start(uid='start_2', type='test', nesting=0)
        self.kb += (choice,
                    option_1,
                    option_2,
                    path,
                    start_2,
                    facts.Jump(state_from=self.start.uid, state_to=start_2.uid),
                    facts.Jump(state_from=start_2.uid, state_to=choice.uid))

        self.assertEqual(self.machine.get_nearest_choice(), (None, None, None))


    @mock.patch('questgen.machine.Machine.can_do_step', lambda self: True)
    def test_do_step__step_done(self):
        with mock.patch('questgen.machine.Machine.step') as step:
            self.assertTrue(self.machine.do_step())

        self.assertEqual(step.call_args_list, [mock.call()])

    @mock.patch('questgen.machine.Machine.can_do_step', lambda self: False)
    @mock.patch('questgen.machine.Machine.is_processed', True)
    def test_do_step__quest_processed(self):
        with mock.patch('questgen.machine.Machine.step') as step:
            self.assertFalse(self.machine.do_step())

        self.assertEqual(step.call_args_list, [])

    @mock.patch('questgen.machine.Machine.can_do_step', lambda self: False)
    @mock.patch('questgen.machine.Machine.is_processed', False)
    @mock.patch('questgen.machine.Machine.next_state', 'next-state')
    def test_do_step__satisfy_requirements(self):
        with mock.patch('questgen.machine.Machine.step') as step:
            with mock.patch('questgen.machine.Machine.satisfy_requirements') as satisfy_requirements:
                self.assertTrue(self.machine.do_step())

        self.assertEqual(step.call_args_list, [])
        self.assertEqual(satisfy_requirements.call_args_list, [mock.call('next-state')])
Esempio n. 10
0
class MachineTests(unittest.TestCase):

    def setUp(self):
        self.kb = KnowledgeBase()

        self.hero = facts.Hero(uid='hero')

        self.start = facts.Start(uid='start', type='test', nesting=0)
        self.state_1 = facts.State(uid='state_1')
        self.state_2 = facts.State(uid='state_2')
        self.finish_1 = facts.Finish(start='start', uid='finish_1', results={}, nesting=0)

        self.kb += [ self.start, self.state_1, self.state_2, self.finish_1, self.hero]

        self.machine = Machine(knowledge_base=self.kb, interpreter=FakeInterpreter())

    def test_get_pointer(self):
        self.assertEqual(list(self.kb.filter(facts.Pointer)), [])
        pointer = self.machine.pointer
        self.assertEqual(list(self.kb.filter(facts.Pointer)), [pointer])

    def test_get_available_jumps__no_jumps(self):
        self.assertEqual(self.machine.get_available_jumps(self.start), [])

    def test_get_available_jumps__all_jumps(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        jump_2 = facts.Jump(state_from=self.start.uid, state_to=self.state_2.uid)
        self.kb += [jump_1, jump_2]

        self.assertEqual(set(jump.uid for jump in self.machine.get_available_jumps(self.start)),
                         set([jump_1.uid, jump_2.uid]))

    def test_get_available_jumps__for_choice_state(self):
        choice = facts.Choice(uid='choice')
        option_1 = facts.Option(state_from=choice.uid, state_to=self.state_1.uid, type='opt_1', markers=())
        option_2 = facts.Option(state_from=choice.uid, state_to=self.state_2.uid, type='opt_2', markers=())
        path = facts.ChoicePath(choice=choice.uid, option=option_2.uid, default=True)
        self.kb += (choice, option_1, option_2, path)

        for i in xrange(100):
            self.assertEqual(self.machine.get_available_jumps(choice), [option_2])

    def test_get_available_jumps__for_question_state(self):
        condition = requirements.LocatedIn(object='object', place='place')

        question = facts.Question(uid='choice', condition=[condition])
        answer_1 = facts.Answer(state_from=question.uid, state_to=self.state_1.uid, condition=True)
        answer_2 = facts.Answer(state_from=question.uid, state_to=self.state_2.uid, condition=False)
        self.kb += (question, answer_1, answer_2)

        with mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=False)):
            for i in xrange(100):
                self.assertEqual(self.machine.get_available_jumps(question), [answer_2])

        with mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=True)):
            for i in xrange(100):
                self.assertEqual(self.machine.get_available_jumps(question), [answer_1])

    def test_get_next_jump__no_jumps(self):
        self.assertRaises(exceptions.NoJumpsAvailableError,
                          self.machine.get_next_jump, self.start)

    def test_get_next_jump__all_jumps(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        jump_2 = facts.Jump(state_from=self.start.uid, state_to=self.state_2.uid)
        self.kb += [jump_1, jump_2]

        jumps = set()

        for i in xrange(100):
            jumps.add(self.machine.get_next_jump(self.start, single=False).uid)

        self.assertEqual(jumps, set([jump_1.uid, jump_2.uid]))

    def test_get_next_jump__require_one_jump__exception(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        jump_2 = facts.Jump(state_from=self.start.uid, state_to=self.state_2.uid)
        self.kb += [jump_1, jump_2]

        self.assertRaises(exceptions.MoreThenOneJumpsAvailableError, self.machine.get_next_jump, self.start, single=True)

    def test_get_next_jump__require_one_jump(self):
        jump = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        self.kb += jump
        self.assertEqual(self.machine.get_next_jump(self.start, single=True).uid, jump.uid)

    def test_can_do_step__no_pointer(self):
        self.assertEqual(list(self.kb.filter(facts.Pointer)), [])
        self.assertTrue(self.machine.can_do_step())

    @mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_is_alive=False))
    def test_can_do_step__requirement_failed(self):
        state_3 = facts.State(uid='state_3', require=[requirements.IsAlive(object='hero')])
        jump_3 = facts.Jump(state_from=self.start.uid, state_to=state_3.uid)
        self.kb += [ state_3, jump_3]

        pointer = self.machine.pointer
        self.kb -= pointer
        self.kb += pointer.change(state=self.start.uid, jump=jump_3.uid)

        self.assertFalse(self.machine.can_do_step())

    def test_can_do_step__success(self):
        state_3 = facts.State(uid='state_3', require=[requirements.IsAlive(object='hero')])
        jump_3 = facts.Jump(state_from=self.start.uid, state_to=state_3.uid)
        self.kb += [ state_3, jump_3]

        pointer = self.machine.pointer
        self.kb -= pointer
        self.kb += pointer.change(state=self.start.uid, jump=jump_3.uid)

        with mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_is_alive=True)):
            self.assertTrue(self.machine.can_do_step())


    def test_do_step__no_pointer(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        jump_2 = facts.Jump(state_from=self.state_1.uid, state_to=self.state_2.uid)
        self.kb += [jump_1, jump_2]

        calls_manager = mock.MagicMock()

        with mock.patch.object(self.machine.interpreter, 'on_state__before_actions') as on_state__before_actions:
            with mock.patch.object(self.machine.interpreter, 'on_state__after_actions') as on_state__after_actions:
                with mock.patch.object(self.machine.interpreter, 'on_jump_start__before_actions') as on_jump_start__before_actions:
                    with mock.patch.object(self.machine.interpreter, 'on_jump_start__after_actions') as on_jump_start__after_actions:
                        with mock.patch.object(self.machine.interpreter, 'on_jump_end__before_actions') as on_jump_end__before_actions:
                            with mock.patch.object(self.machine.interpreter, 'on_jump_end__after_actions') as on_jump_end__after_actions:

                                calls_manager.attach_mock(on_state__before_actions, 'on_state__before_actions')
                                calls_manager.attach_mock(on_state__after_actions, 'on_state__after_actions')
                                calls_manager.attach_mock(on_jump_start__before_actions, 'on_jump_start__before_actions')
                                calls_manager.attach_mock(on_jump_start__after_actions, 'on_jump_start__after_actions')
                                calls_manager.attach_mock(on_jump_end__before_actions, 'on_jump_end__before_actions')
                                calls_manager.attach_mock(on_jump_end__after_actions, 'on_jump_end__after_actions')

                                self.assertEqual(list(self.kb.filter(facts.Pointer)), [])
                                self.machine.step()
                                self.assertEqual(len(list(self.kb.filter(facts.Pointer))), 1)

                                self.assertEqual(calls_manager.mock_calls, [mock.call.on_state__before_actions(state=self.start),
                                                                            mock.call.on_state__after_actions(state=self.start)])

        pointer = self.machine.pointer
        self.assertEqual(pointer.state, self.start.uid)
        self.assertEqual(pointer.jump, None)


    def test_do_step__finish(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.finish_1.uid)
        self.kb += jump_1

        self.machine.step()
        self.machine.step()

        calls_manager = mock.MagicMock()

        with mock.patch.object(self.machine.interpreter, 'on_state__before_actions') as on_state__before_actions:
            with mock.patch.object(self.machine.interpreter, 'on_state__after_actions') as on_state__after_actions:
                with mock.patch.object(self.machine.interpreter, 'on_jump_start__before_actions') as on_jump_start__before_actions:
                    with mock.patch.object(self.machine.interpreter, 'on_jump_start__after_actions') as on_jump_start__after_actions:
                        with mock.patch.object(self.machine.interpreter, 'on_jump_end__before_actions') as on_jump_end__before_actions:
                            with mock.patch.object(self.machine.interpreter, 'on_jump_end__after_actions') as on_jump_end__after_actions:

                                calls_manager.attach_mock(on_state__before_actions, 'on_state__before_actions')
                                calls_manager.attach_mock(on_state__after_actions, 'on_state__after_actions')
                                calls_manager.attach_mock(on_jump_start__before_actions, 'on_jump_start__before_actions')
                                calls_manager.attach_mock(on_jump_start__after_actions, 'on_jump_start__after_actions')
                                calls_manager.attach_mock(on_jump_end__before_actions, 'on_jump_end__before_actions')
                                calls_manager.attach_mock(on_jump_end__after_actions, 'on_jump_end__after_actions')

                                self.machine.step()

                                self.assertEqual(calls_manager.mock_calls, [mock.call.on_jump_end__before_actions(jump=jump_1),
                                                                            mock.call.on_jump_end__after_actions(jump=jump_1),
                                                                            mock.call.on_state__before_actions(state=self.finish_1),
                                                                            mock.call.on_state__after_actions(state=self.finish_1)])

        pointer = self.machine.pointer
        self.assertEqual(pointer.state, self.finish_1.uid)
        self.assertEqual(pointer.jump, None)

    def test_do_step__step_after_finish(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.finish_1.uid)
        self.kb += jump_1

        self.machine.step()
        self.machine.step()
        self.machine.step()

        self.assertRaises(exceptions.NoJumpsFromLastStateError, self.machine.step)

    def test_do_step__next_jump(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        jump_2 = facts.Jump(state_from=self.state_1.uid, state_to=self.state_2.uid)
        self.kb += [jump_1, jump_2]

        self.machine.step()

        calls_manager = mock.MagicMock()

        pointer = self.machine.pointer
        self.assertEqual(pointer.state, self.start.uid)
        self.assertEqual(pointer.jump, None)

        with mock.patch.object(self.machine.interpreter, 'on_state__before_actions') as on_state__before_actions:
            with mock.patch.object(self.machine.interpreter, 'on_state__after_actions') as on_state__after_actions:
                with mock.patch.object(self.machine.interpreter, 'on_jump_start__before_actions') as on_jump_start__before_actions:
                    with mock.patch.object(self.machine.interpreter, 'on_jump_start__after_actions') as on_jump_start__after_actions:
                        with mock.patch.object(self.machine.interpreter, 'on_jump_end__before_actions') as on_jump_end__before_actions:
                            with mock.patch.object(self.machine.interpreter, 'on_jump_end__after_actions') as on_jump_end__after_actions:

                                calls_manager.attach_mock(on_state__before_actions, 'on_state__before_actions')
                                calls_manager.attach_mock(on_state__after_actions, 'on_state__after_actions')
                                calls_manager.attach_mock(on_jump_start__before_actions, 'on_jump_start__before_actions')
                                calls_manager.attach_mock(on_jump_start__after_actions, 'on_jump_start__after_actions')
                                calls_manager.attach_mock(on_jump_end__before_actions, 'on_jump_end__before_actions')
                                calls_manager.attach_mock(on_jump_end__after_actions, 'on_jump_end__after_actions')

                                self.machine.step()

                                self.assertEqual(calls_manager.mock_calls, [mock.call.on_jump_start__before_actions(jump=jump_1),
                                                                            mock.call.on_jump_start__after_actions(jump=jump_1)])

        pointer = self.machine.pointer
        self.assertEqual(pointer.state, self.start.uid)
        self.assertEqual(pointer.jump, jump_1.uid)

    def test_do_step__next_state(self):
        jump_1 = facts.Jump(state_from=self.start.uid, state_to=self.state_1.uid)
        jump_2 = facts.Jump(state_from=self.state_1.uid, state_to=self.state_2.uid)
        self.kb += [jump_1, jump_2]

        self.machine.step()
        self.machine.step()
        self.machine.step()

        pointer = self.machine.pointer
        self.assertEqual(pointer.state, self.state_1.uid)
        self.assertEqual(pointer.jump, None)

        calls_manager = mock.MagicMock()

        with mock.patch.object(self.machine.interpreter, 'on_state__before_actions') as on_state__before_actions:
            with mock.patch.object(self.machine.interpreter, 'on_state__after_actions') as on_state__after_actions:
                with mock.patch.object(self.machine.interpreter, 'on_jump_start__before_actions') as on_jump_start__before_actions:
                    with mock.patch.object(self.machine.interpreter, 'on_jump_start__after_actions') as on_jump_start__after_actions:
                        with mock.patch.object(self.machine.interpreter, 'on_jump_end__before_actions') as on_jump_end__before_actions:
                            with mock.patch.object(self.machine.interpreter, 'on_jump_end__after_actions') as on_jump_end__after_actions:

                                calls_manager.attach_mock(on_state__before_actions, 'on_state__before_actions')
                                calls_manager.attach_mock(on_state__after_actions, 'on_state__after_actions')
                                calls_manager.attach_mock(on_jump_start__before_actions, 'on_jump_start__before_actions')
                                calls_manager.attach_mock(on_jump_start__after_actions, 'on_jump_start__after_actions')
                                calls_manager.attach_mock(on_jump_end__before_actions, 'on_jump_end__before_actions')
                                calls_manager.attach_mock(on_jump_end__after_actions, 'on_jump_end__after_actions')

                                self.machine.step()

                                self.assertEqual(calls_manager.mock_calls, [mock.call.on_jump_start__before_actions(jump=jump_2),
                                                                            mock.call.on_jump_start__after_actions(jump=jump_2)])

        pointer = self.machine.pointer
        self.assertEqual(pointer.state, self.state_1.uid)
        self.assertEqual(pointer.jump, jump_2.uid)

    def test_sync_pointer(self):
        choice = facts.Choice(uid='choice')
        option_1 = facts.Option(state_from=choice.uid, state_to=self.state_1.uid, type='opt_1', markers=())
        option_2 = facts.Option(state_from=choice.uid, state_to=self.state_2.uid, type='opt_2', markers=())
        path = facts.ChoicePath(choice=choice.uid, option=option_2.uid, default=True)
        pointer = facts.Pointer(state=choice.uid, jump=option_1.uid)

        self.kb += (choice, option_1, option_2, path, pointer)

        calls_manager = mock.MagicMock()

        with mock.patch.object(self.machine.interpreter, 'on_state__before_actions') as on_state__before_actions:
            with mock.patch.object(self.machine.interpreter, 'on_state__after_actions') as on_state__after_actions:
                with mock.patch.object(self.machine.interpreter, 'on_jump_start__before_actions') as on_jump_start__before_actions:
                    with mock.patch.object(self.machine.interpreter, 'on_jump_start__after_actions') as on_jump_start__after_actions:
                        with mock.patch.object(self.machine.interpreter, 'on_jump_end__before_actions') as on_jump_end__before_actions:
                            with mock.patch.object(self.machine.interpreter, 'on_jump_end__after_actions') as on_jump_end__after_actions:

                                calls_manager.attach_mock(on_state__before_actions, 'on_state__before_actions')
                                calls_manager.attach_mock(on_state__after_actions, 'on_state__after_actions')
                                calls_manager.attach_mock(on_jump_start__before_actions, 'on_jump_start__before_actions')
                                calls_manager.attach_mock(on_jump_start__after_actions, 'on_jump_start__after_actions')
                                calls_manager.attach_mock(on_jump_end__before_actions, 'on_jump_end__before_actions')
                                calls_manager.attach_mock(on_jump_end__after_actions, 'on_jump_end__after_actions')

                                self.machine.sync_pointer()

                                self.assertEqual(calls_manager.mock_calls, [mock.call.on_jump_start__before_actions(jump=option_2),
                                                                            mock.call.on_jump_start__after_actions(jump=option_2)])

        self.assertEqual(self.machine.pointer.jump, option_2.uid)
        self.assertEqual(self.machine.pointer.state, choice.uid)

    def test_get_start_state(self):
        start_2 = facts.Start(uid='s2', type='test', nesting=0)
        start_3 = facts.Start(uid='start_3', type='test', nesting=0)


        self.kb += [ start_2,
                     start_3,
                     facts.Jump(state_from=self.start.uid, state_to=start_2.uid),
                     facts.Jump(state_from=start_3.uid, state_to=self.start.uid) ]

        self.assertEqual(self.machine.get_start_state().uid, start_3.uid)

    def test_get_nearest_choice__no_choice(self):
        self.kb += facts.Jump(state_from=self.start.uid, state_to=self.finish_1.uid)
        self.assertEqual(self.machine.get_nearest_choice(), (None, None, None))

    def test_get_nearest_choice__choice(self):
        choice = facts.Choice(uid='choice')
        option_1 = facts.Option(state_from=choice.uid, state_to=self.state_1.uid, type='opt_1', markers=())
        option_2 = facts.Option(state_from=choice.uid, state_to=self.state_2.uid, type='opt_2', markers=())
        path = facts.ChoicePath(choice=choice.uid, option=option_2.uid, default=True)
        self.kb += (choice,
                    option_1,
                    option_2,
                    path,
                    facts.Jump(state_from=self.start.uid, state_to=choice.uid)    )

        choice_, options_, path_ = self.machine.get_nearest_choice()
        self.assertEqual(choice_.uid, choice.uid)
        self.assertEqual(set(o.uid for o in options_), set([option_1.uid, option_2.uid]))
        self.assertEqual([p.uid for p in path_], [path.uid])

    def test_get_nearest_choice__2_choices(self):
        choice_1 = facts.Choice(uid='choice_1')

        choice_2 = facts.Choice(uid='choice_2')
        option_2_1 = facts.Option(state_from=choice_2.uid, state_to=self.state_1.uid, type='opt_2_1', markers=())
        option_2_2 = facts.Option(state_from=choice_2.uid, state_to=self.state_2.uid, type='opt_2_2', markers=())
        path_2 = facts.ChoicePath(choice=choice_2.uid, option=option_2_2.uid, default=True)

        option_1_1 = facts.Option(state_from=choice_1.uid, state_to=self.state_1.uid, type='opt_1_1', markers=())
        option_1_2 = facts.Option(state_from=choice_1.uid, state_to=choice_2.uid, type='opt_1_2', markers=())
        path_1 = facts.ChoicePath(choice=choice_1.uid, option=option_1_2.uid, default=True)

        self.kb += (choice_1,
                    option_1_1,
                    option_1_2,
                    path_1,

                    choice_2,
                    option_2_1,
                    option_2_2,
                    path_2,
                    facts.Jump(state_from=self.start.uid, state_to=choice_1.uid),
            )

        choice_, options_, path_ = self.machine.get_nearest_choice()
        self.assertEqual(choice_.uid, choice_1.uid)
        self.assertEqual(set(o.uid for o in options_), set([option_1_1.uid, option_1_2.uid]))
        self.assertEqual([p.uid for p in path_], [path_1.uid])

    def test_get_nearest_choice__2_choices__second_choice(self):
        choice_1 = facts.Choice(uid='choice_1')

        choice_2 = facts.Choice(uid='choice_2')
        option_2_1 = facts.Option(state_from=choice_2.uid, state_to=self.state_1.uid, type='opt_2_1', markers=())
        option_2_2 = facts.Option(state_from=choice_2.uid, state_to=self.state_2.uid, type='opt_2_2', markers=())
        path_2 = facts.ChoicePath(choice=choice_2.uid, option=option_2_2.uid, default=True)

        option_1_1 = facts.Option(state_from=choice_1.uid, state_to=self.state_1.uid, type='opt_1_1', markers=())
        option_1_2 = facts.Option(state_from=choice_1.uid, state_to=choice_2.uid, type='opt_1_2', markers=())
        path_1 = facts.ChoicePath(choice=choice_1.uid, option=option_1_2.uid, default=True)

        self.kb += (choice_1,
                    option_1_1,
                    option_1_2,
                    path_1,

                    choice_2,
                    option_2_1,
                    option_2_2,
                    path_2,
                    facts.Jump(state_from=self.start.uid, state_to=choice_1.uid),

                    facts.Pointer(state=choice_2.uid)
            )

        choice_, options_, path_ = self.machine.get_nearest_choice()
        self.assertEqual(choice_.uid, choice_2.uid)
        self.assertEqual(set(o.uid for o in options_), set([option_2_1.uid, option_2_2.uid]))
        self.assertEqual([p.uid for p in path_], [path_2.uid])

    def test_get_nearest_choice__choice_after_finish(self):
        choice = facts.Choice(uid='choice')
        option_1 = facts.Option(state_from=choice.uid, state_to=self.state_1.uid, type='opt_1', markers=())
        option_2 = facts.Option(state_from=choice.uid, state_to=self.state_2.uid, type='opt_2', markers=())
        path = facts.ChoicePath(choice=choice.uid, option=option_2.uid, default=True)
        self.kb += (choice,
                    option_1,
                    option_2,
                    path,
                    facts.Jump(state_from=self.start.uid, state_to=self.finish_1.uid),
                    facts.Jump(state_from=self.finish_1.uid, state_to=choice.uid))

        self.assertEqual(self.machine.get_nearest_choice(), (None, None, None))

    def test_get_nearest_choice__choice_after_question(self):
        choice = facts.Choice(uid='choice')
        option_1 = facts.Option(state_from=choice.uid, state_to=self.state_1.uid, type='opt_1', markers=())
        option_2 = facts.Option(state_from=choice.uid, state_to=self.state_2.uid, type='opt_2', markers=())
        path = facts.ChoicePath(choice=choice.uid, option=option_2.uid, default=True)

        question = facts.Question(uid='question', condition=())

        self.kb += (choice,
                    option_1,
                    option_2,
                    path,
                    question,
                    facts.Jump(state_from=self.start.uid, state_to=question.uid),
                    facts.Jump(state_from=question.uid, state_to=choice.uid))

        self.assertEqual(self.machine.get_nearest_choice(), (None, None, None))

    def test_get_nearest_choice__choice_after_start(self):
        choice = facts.Choice(uid='choice')
        option_1 = facts.Option(state_from=choice.uid, state_to=self.state_1.uid, type='opt_1', markers=())
        option_2 = facts.Option(state_from=choice.uid, state_to=self.state_2.uid, type='opt_2', markers=())
        path = facts.ChoicePath(choice=choice.uid, option=option_2.uid, default=True)
        start_2 = facts.Start(uid='start_2', type='test', nesting=0)
        self.kb += (choice,
                    option_1,
                    option_2,
                    path,
                    start_2,
                    facts.Jump(state_from=self.start.uid, state_to=start_2.uid),
                    facts.Jump(state_from=start_2.uid, state_to=choice.uid))

        self.assertEqual(self.machine.get_nearest_choice(), (None, None, None))


    @mock.patch('questgen.machine.Machine.can_do_step', lambda self: True)
    def test_do_step__step_done(self):
        with mock.patch('questgen.machine.Machine.step') as step:
            self.assertTrue(self.machine.do_step())

        self.assertEqual(step.call_args_list, [mock.call()])

    @mock.patch('questgen.machine.Machine.can_do_step', lambda self: False)
    @mock.patch('questgen.machine.Machine.is_processed', True)
    def test_do_step__quest_processed(self):
        with mock.patch('questgen.machine.Machine.step') as step:
            self.assertFalse(self.machine.do_step())

        self.assertEqual(step.call_args_list, [])

    @mock.patch('questgen.machine.Machine.can_do_step', lambda self: False)
    @mock.patch('questgen.machine.Machine.is_processed', False)
    @mock.patch('questgen.machine.Machine.next_state', 'next-state')
    def test_do_step__satisfy_requirements(self):
        with mock.patch('questgen.machine.Machine.step') as step:
            with mock.patch('questgen.machine.Machine.satisfy_requirements') as satisfy_requirements:
                self.assertTrue(self.machine.do_step())

        self.assertEqual(step.call_args_list, [])
        self.assertEqual(satisfy_requirements.call_args_list, [mock.call('next-state')])