Example #1
0
def test_cached_history_function():
    
    def changes(history_browser):
        '''
        Return how many cells changed between most recent state and its parent.
        '''
        changes.called_flag = True
        try:
            state = history_browser[-1]
            last_state = history_browser[-2]
        except IndexError:
            return None
        board, last_board = state.board, last_state.board
        board_size = len(board._Board__list)
        counter = 0
        for i in xrange(board_size):
            if board._Board__list[i] != last_board._Board__list[i]:
                counter += 1
        return counter
    
    cached_changes = caching.history_cache(changes)
    
    cute_testing.assert_polite_wrapper(cached_changes, changes,
                                       same_signature=False)
    
    s = life.State.create_messy_root(5, 5)
    
    p = garlicsim.Project(life)
    
    r = p.root_this_state(s)
    
    leaf = p.simulate(r, 10)
    
    path = leaf.make_containing_path()
        
    result_1 = [cached_changes(node) for node in list(path)[0:5]]
        
    assert changes.called_flag is True
    changes.called_flag = False
    
    
    result_2 = [cached_changes(node) for node in list(path)[0:5]]
    
    assert changes.called_flag is False
    
    assert result_1 == result_2
    
    
    result_1 = [cached_changes(node) for node in list(path)]
        
    assert changes.called_flag is True
    changes.called_flag = False
    
    
    result_2 = [cached_changes(node) for node in list(path)]
    
    assert changes.called_flag is False
    
    assert result_1 == result_2
Example #2
0
 def test_project(self):
     project = garlicsim.Project(lightbulb)
     root = project.root_this_state(self.state)
     project.begin_crunching(root, 4)
     print project.sync_crunchers()
     print project.sync_crunchers()
     print project.tree
     (path, ) = project.tree.all_possible_paths()
     print path
Example #3
0
def check(simpack, cruncher_type):

    my_simpack_grokker = garlicsim.misc.SimpackGrokker(simpack)

    assert my_simpack_grokker is garlicsim.misc.SimpackGrokker(simpack)
    # Ensuring caching works.

    assert garlicsim.misc.simpack_grokker.step_type.StepType.get_step_type(
        my_simpack_grokker.default_step_function
    ) == simpack._test_settings.DEFAULT_STEP_FUNCTION_TYPE

    step_profile = my_simpack_grokker.build_step_profile()
    deterministic = \
        my_simpack_grokker.settings.DETERMINISM_FUNCTION(step_profile)

    state = simpack.State.create_root()

    project = garlicsim.Project(simpack)

    project.crunching_manager.cruncher_type = cruncher_type

    assert project.tree.lock._ReadWriteLock__writer is None

    root = project.root_this_state(state)

    def run_sync_crunchers_until_we_get_at_least_one_node():
        while not project.sync_crunchers():
            time.sleep(0.1)

    ### Test changing clock target on the fly: ################################
    #                                                                         #

    huge_number = 10**20
    different_huge_number = huge_number + 1
    assert different_huge_number - huge_number == 1

    job = project.begin_crunching(root, huge_number)
    run_sync_crunchers_until_we_get_at_least_one_node()
    (cruncher, ) = project.crunching_manager.crunchers.values()

    ## An interlude to test `__repr__` methods: ###############################

    step_profile_description = repr(job.crunching_profile.step_profile)
    assert step_profile_description == \
        'StepProfile(%s)' % simpack._test_settings.DEFAULT_STEP_FUNCTION

    short_step_profile_description = \
            job.crunching_profile.step_profile.__repr__(short_form=True)
    assert short_step_profile_description == \
        '%s(<state>)' % address_tools.describe(
            simpack._test_settings.DEFAULT_STEP_FUNCTION,
            shorten=True,
            root=simpack,
        )

    crunching_profile_description = repr(job.crunching_profile)
    assert crunching_profile_description == \
           'CrunchingProfile(clock_target=%d, step_profile=%s)' % \
           (huge_number, short_step_profile_description)

    job_description = repr(job)
    assert job_description == 'Job(node=%s, crunching_profile=%s)' % \
           (repr(job.node), crunching_profile_description)

    crunching_manager_description = repr(project.crunching_manager)
    assert re.match(
        ('^<.*?CrunchingManager currently employing 1 crunchers to '
         'handle 1 jobs at .*?>$'), crunching_manager_description)

    project_description = repr(project)
    assert re.match(
        '<.*?Project containing .*? nodes and employing 1 crunchers at .*?>',
        project_description)

    # Assert the job cruncher is not unequal to itself:
    assert not job.crunching_profile.__ne__(job.crunching_profile)

    ## Finished interlude to test `__repr__` methods. #########################

    job.crunching_profile.raise_clock_target(different_huge_number)
    # Letting our crunching manager update our cruncher about the new clock
    # target:
    project.sync_crunchers()
    assert not job.is_done()
    (same_cruncher, ) = project.crunching_manager.crunchers.values()
    # todo: On slow machines cruncher doesn't get created fast enough for the
    # above assert to work. Probably make some function that waits for it.
    assert same_cruncher is cruncher

    # Deleting jobs so the cruncher will stop:
    del project.crunching_manager.jobs[:]
    project.sync_crunchers()
    assert not project.crunching_manager.jobs
    assert not project.crunching_manager.crunchers

    #                                                                         #
    ### Finish testing changing clock target on the fly. ######################

    ### Test changing step profile on the fly: ################################
    #                                                                         #

    # For simpacks providing more than one step function, we'll test changing
    # between them. This will exercise the crunching manager's policy of
    # switching crunchers immediately when the step profile for a job gets
    # changed.
    if simpack._test_settings.N_STEP_FUNCTIONS >= 2:
        default_step_function, alternate_step_function = \
            my_simpack_grokker.all_step_functions[:2]
        job = project.begin_crunching(root, infinity)
        assert job.crunching_profile.step_profile.step_function == \
               default_step_function
        run_sync_crunchers_until_we_get_at_least_one_node()
        (cruncher, ) = project.crunching_manager.crunchers.values()
        alternate_step_profile = \
            garlicsim.misc.StepProfile(alternate_step_function)
        job.crunching_profile.step_profile = alternate_step_profile
        # Letting our crunching manager get a new cruncher for our new step
        # profile:
        project.sync_crunchers()
        (new_cruncher, ) = project.crunching_manager.crunchers.values()
        assert new_cruncher is not cruncher
        last_node_with_default_step_profile = job.node
        assert not last_node_with_default_step_profile.children  # It's a leaf
        assert last_node_with_default_step_profile.\
               step_profile.step_function == default_step_function
        # Another `sync_crunchers`:
        run_sync_crunchers_until_we_get_at_least_one_node()
        # And now we have some new nodes with the alternate step profile.
        (first_node_with_alternate_step_profile,) = \
            last_node_with_default_step_profile.children
        path = last_node_with_default_step_profile.make_containing_path()

        nodes_with_alternate_step_profile = list(
            path.__iter__(head=first_node_with_alternate_step_profile))
        for node in nodes_with_alternate_step_profile:
            assert node.step_profile == alternate_step_profile

        # Deleting jobs so the cruncher will stop:
        del project.crunching_manager.jobs[:]
        project.sync_crunchers()
        assert not project.crunching_manager.jobs
        assert not project.crunching_manager.crunchers

    #                                                                         #
    ### Finished testing changing step profile on the fly. ####################

    ### Testing cruncher type switching: ######################################
    #                                                                         #

    job_1 = project.begin_crunching(root, clock_buffer=infinity)
    job_2 = project.begin_crunching(root, clock_buffer=infinity)

    assert len(project.crunching_manager.crunchers) == 0
    assert project.sync_crunchers() == 0
    assert len(project.crunching_manager.crunchers) == 2
    (cruncher_1, cruncher_2) = project.crunching_manager.crunchers.values()
    assert type(cruncher_1) is cruncher_type
    assert type(cruncher_2) is cruncher_type

    time.sleep(0.2)  # Letting the crunchers start working

    project.crunching_manager.cruncher_type = MustachedThreadCruncher
    project.sync_crunchers()
    assert len(project.crunching_manager.crunchers) == 2
    (cruncher_1, cruncher_2) = project.crunching_manager.crunchers.values()
    assert type(cruncher_1) is MustachedThreadCruncher
    assert type(cruncher_2) is MustachedThreadCruncher

    project.crunching_manager.cruncher_type = cruncher_type
    project.sync_crunchers()
    assert len(project.crunching_manager.crunchers) == 2
    (cruncher_1, cruncher_2) = project.crunching_manager.crunchers.values()
    assert type(cruncher_1) is cruncher_type
    assert type(cruncher_2) is cruncher_type

    # Deleting jobs so the crunchers will stop:
    del project.crunching_manager.jobs[:]
    project.sync_crunchers()
    assert not project.crunching_manager.jobs
    assert not project.crunching_manager.crunchers
Example #4
0
def check(simpack, cruncher_type):

    assert simpack._test_settings.ENDABLE is True
    assert simpack._test_settings.CONSTANT_CLOCK_INTERVAL == 1

    my_simpack_grokker = garlicsim.misc.SimpackGrokker(simpack)

    assert my_simpack_grokker is garlicsim.misc.SimpackGrokker(simpack)
    # Ensuring caching works.

    assert garlicsim.misc.simpack_grokker.step_type.StepType.get_step_type(
        my_simpack_grokker.default_step_function
    ) == simpack._test_settings.DEFAULT_STEP_FUNCTION_TYPE

    step_profile = my_simpack_grokker.build_step_profile()
    deterministic = \
        my_simpack_grokker.settings.DETERMINISM_FUNCTION(step_profile)

    state = simpack.State.create_root()

    ### Running for short periods synchronically so it doesn't end: ###########
    #                                                                         #

    # Whether we run the simulation for one, two, three, or four iterations,
    # the simulation doesn't end.
    prev_state = state
    for i in [1, 2, 3, 4]:
        new_state = garlicsim.simulate(state, i)
        assert new_state.clock >= getattr(prev_state, 'clock', 0)
        prev_state = new_state

    result = garlicsim.list_simulate(state, 4)
    for item in result:
        assert isinstance(item, garlicsim.data_structures.State)
        assert isinstance(item, simpack.State)

    assert isinstance(result, list)
    assert len(result) == 5

    iter_result = garlicsim.iter_simulate(state, 4)

    assert not hasattr(iter_result, '__getitem__')
    assert hasattr(iter_result, '__iter__')
    iter_result_in_list = list(iter_result)
    del iter_result
    assert len(iter_result_in_list) == len(result) == 5

    #                                                                         #
    ### Done running for short periods synchronically so it doesn't end. ######

    ### Now, let's run it for longer periods synchronically to make it end: ###
    #                                                                         #

    for i in [5, 6, 7]:
        new_state = garlicsim.simulate(state, i)
        assert new_state.clock == 4

    result = garlicsim.list_simulate(state, 7)

    assert isinstance(result, list)
    assert len(result) == 5

    iter_result = garlicsim.iter_simulate(state, 7)

    assert not hasattr(iter_result, '__getitem__')
    assert hasattr(iter_result, '__iter__')
    iter_result_in_list = list(iter_result)
    del iter_result
    assert len(iter_result_in_list) == len(result) == 5

    #                                                                         #
    ### Done running for longer periods synchronically to make it end. ########

    ### Setting up a project to run asynchronous tests:

    project = garlicsim.Project(simpack)

    project.crunching_manager.cruncher_type = cruncher_type

    assert project.tree.lock._ReadWriteLock__writer is None

    root = project.root_this_state(state)

    def get_all_ends():
        return [
            member for member in project.tree.iterate_tree_members()
            if isinstance(member, garlicsim.data_structures.End)
        ]

    assert len(get_all_ends()) == 0

    ### Running for short periods asynchronically so it doesn't end: ##########
    #                                                                         #

    project.begin_crunching(root, 4)

    total_nodes_added = 0
    while project.crunching_manager.jobs:
        time.sleep(0.1)
        total_nodes_added += project.sync_crunchers()

    assert total_nodes_added == 4

    assert len(project.tree.nodes) == 5
    assert len(project.tree.roots) == 1

    paths = project.tree.all_possible_paths()

    assert len(paths) == 1

    (my_path, ) = paths

    assert len(my_path) == 5

    node_1 = my_path[1]
    assert node_1.state.clock == 1

    node_2 = project.simulate(node_1, 3)

    assert len(project.tree.nodes) == 8
    assert len(project.tree.roots) == 1

    assert len(project.tree.all_possible_paths()) == 2

    assert len(get_all_ends()) == 0

    #                                                                         #
    ### Done running for short periods asynchronically so it doesn't end. #####

    ### Now, let's run it for longer periods asynchronically to make it end: ##
    #                                                                         #

    node_3 = my_path.next_node(node_1)
    assert node_3.state.clock == 2
    project.begin_crunching(node_3, 3)

    total_nodes_added = 0
    while project.crunching_manager.jobs:
        time.sleep(0.1)
        total_nodes_added += project.sync_crunchers()
    assert total_nodes_added == 2  # Would have been 3 without the end!

    assert len(get_all_ends()) == 1

    # So now `node_3`'s newer path has an end:
    ended_path = node_3.all_possible_paths()[1]
    isinstance(ended_path, garlicsim.data_structures.Path)
    (end,
     ) = ended_path.get_ends_of_last_node()  # (Asserting there's one end.)
    assert isinstance(end, garlicsim.data_structures.End)

    assert len(project.tree.nodes) == 10

    paths = project.tree.all_possible_paths()
    assert len(paths) == 3

    assert [len(p) for p in paths] == [5, 5, 5]

    # Ensuring buffer on `ended_path` from `node_3` won't cause a new job to be
    # created since we have a path to an existing end:
    project.ensure_buffer_on_path(node_3, ended_path, 10)
    project.ensure_buffer_on_path(node_3, ended_path, 1000)
    project.ensure_buffer_on_path(node_3, ended_path, infinity)
    total_nodes_added = 0
    assert not project.crunching_manager.jobs
    assert len(project.tree.nodes) == 10

    # These `ensure_buffer_on_path` calls shouldn't have added any ends:
    assert len(get_all_ends()) == 1

    # But `node_3` has the older path coming out of it which goes all the way to
    # clock 4 but doesn't terminate in an `End`:
    other_path = node_3.all_possible_paths()[0]
    assert other_path.get_ends_of_last_node() == []

    # And when we `ensure_buffer` from `node_3`, it will ensure a buffer on that
    # path also, and cause an `End` to be created there:
    project.ensure_buffer(node_3, 1000)
    total_nodes_added = 0
    while project.crunching_manager.jobs:
        time.sleep(0.1)
        total_nodes_added += project.sync_crunchers()
    assert len(project.tree.nodes) == 10
    assert len(get_all_ends()) == 2

    plain_root = project.create_root()

    assert len(project.tree.roots) == 2
    assert len(project.tree.all_possible_paths()) == 4
    assert len(project.tree.nodes) == 11

    iterator = project.iter_simulate(node_1, 10)
    new_node = iterator.next()
    assert new_node is node_1
    assert len(project.tree.nodes) == 11

    assert project.tree.lock._ReadWriteLock__writer is None

    new_node = iterator.next()
    assert new_node is not node_1
    assert new_node.parent is node_1
    assert len(project.tree.nodes) == 12

    bunch_of_new_nodes = tuple(iterator)
    consecutive_pairs = cute_iter_tools.consecutive_pairs(bunch_of_new_nodes)
    for parent_node, kid_node in consecutive_pairs:
        assert project.tree.lock._ReadWriteLock__writer is None
        assert isinstance(parent_node, garlicsim.data_structures.Node)
        assert isinstance(kid_node, garlicsim.data_structures.Node)
        assert parent_node.children == [kid_node]
        assert kid_node.parent is parent_node

    assert len(project.tree.nodes) == 14

    assert len(get_all_ends()) == 3


    tree_members_iterator = \
        project.tree.iterate_tree_members(include_blockful_nodes=False)
    assert tree_members_iterator.__iter__() is tree_members_iterator
    tree_members = list(tree_members_iterator)
    for tree_member in tree_members:
        if isinstance(tree_member, garlicsim.data_structures.Node):
            assert tree_member.block is None

    tree_members_iterator_including_blockful_nodes = \
        project.tree.iterate_tree_members()
    assert tree_members_iterator_including_blockful_nodes.__iter__() is \
        tree_members_iterator_including_blockful_nodes
    tree_members_including_blockful_nodes = \
        list(tree_members_iterator_including_blockful_nodes)


    blockful_nodes = \
        [member for member in tree_members_including_blockful_nodes if
         member not in tree_members]
    assert len(blockful_nodes) >= 1
    for blockful_node in blockful_nodes:
        assert isinstance(blockful_node, garlicsim.data_structures.Node)
        assert isinstance(blockful_node.block, garlicsim.data_structures.Block)
        assert blockful_node.block is blockful_node.soft_get_block()
    assert set(tree_members).\
        issubset(set(tree_members_including_blockful_nodes))

    tree_step_profiles = project.tree.get_step_profiles()
    assert isinstance(tree_step_profiles, OrderedSet)
    assert tree_step_profiles == [step_profile]

    ends = [
        member for member in tree_members
        if isinstance(member, garlicsim.data_structures.End)
    ]
    assert len(ends) == 3
    for end in ends:
        assert end in tree_members_including_blockful_nodes

    ### Testing `Project.simulate`: ###########################################
    #                                                                         #

    project.simulate(root, 4)
    assert len(get_all_ends()) == 3

    project.simulate(root, 5)
    assert len(get_all_ends()) == 4

    #                                                                         #
    ### Finished testing `Project.simulate`. ##################################

    ### Testing end creation in middle of block: ##############################
    #                                                                         #

    my_non_ending_step = non_ending_history_step if \
        my_simpack_grokker.history_dependent else non_ending_inplace_step

    nodes_in_tree = len(project.tree.nodes)
    nodes = list(project.iter_simulate(root, 8, my_non_ending_step))
    assert len(project.tree.nodes) == nodes_in_tree + 8

    middle_node = nodes[-4]
    assert middle_node.state.clock == 5
    assert nodes[1].block == middle_node.block == nodes[-1].block
    assert len(middle_node.block) == 8

    project.begin_crunching(middle_node, infinity, step_profile)
    total_nodes_added = 0
    assert project.crunching_manager.jobs
    while project.crunching_manager.jobs:
        time.sleep(0.1)
        total_nodes_added += project.sync_crunchers()
    assert total_nodes_added == 0

    assert len(middle_node.ends) == 1
    assert middle_node.block is not nodes[-1].block
    assert len(middle_node.block) == 5
    assert len(nodes[-1].block) == 3
Example #5
0
    def __init_general(self, simpack, frame, project=None):
        '''General initialization.'''

        self.frame = frame
        '''The frame that this gui project lives in.'''

        assert isinstance(self.frame, garlicsim_wx.Frame)

        if isinstance(simpack, garlicsim.misc.SimpackGrokker):
            simpack_grokker = simpack
            simpack = simpack_grokker.simpack
        else:
            simpack_grokker = garlicsim.misc.SimpackGrokker(simpack)

        self.simpack = simpack
        '''The simpack used for this gui project.'''

        self.simpack_grokker = simpack_grokker
        '''The simpack grokker used for this gui project.'''

        self.simpack_wx_grokker = garlicsim_wx.misc.SimpackWxGrokker(simpack)
        '''The simpack_wx used for this gui project.'''

        self.project = project or garlicsim.Project(simpack_grokker)
        '''The project encapsulated in this gui project.'''

        assert isinstance(self.project, garlicsim.Project)

        ### If it's a new project, use `ProcessCruncher` if available: ########
        #                                                                     #

        if (not project):  # Note this is the project given as an argument
            if (crunchers.ProcessCruncher
                    in simpack_grokker.available_cruncher_types):

                self.project.crunching_manager.cruncher_type = \
                    crunchers.ProcessCruncher
        #                                                                     #
        #######################################################################

        self.path = None
        '''The active path.'''

        self.active_node = None
        '''The node that is currently displayed onscreen.'''

        self.is_playing = False
        '''Says whether the simulation is currently playing.'''

        self.infinity_job = None
        '''
        The job of the playing leaf, which should be crunched to infinity.
        '''

        self.default_buffer = 100
        '''
        The default clock buffer to crunch from an active node.

        For the user it is called "Autocrunch".
        '''

        self._default_buffer_before_cancellation = None
        '''
        The value of the default buffer before buffering was cancelled.

        When buffering will be enabled again, it will be set to this value.
        '''

        self.timer_for_playing = thread_timer.ThreadTimer(self.frame)
        '''Contains the timer object used when playing the simulation.'''

        self.frame.Bind(thread_timer.EVT_THREAD_TIMER, self.__play_next,
                        self.timer_for_playing)

        self.defacto_playing_speed = 4
        '''The playing speed that we are actually playing in.'''

        self.official_playing_speed = 4
        '''
        The playing speed that we're "officially" playing in.
        
        The defacto playing speed may deviate from this.
        '''

        self.standard_playing_speed = 4
        '''The reference playing speed. This speed is considered "normal".'''

        self.last_tracked_real_time = None
        '''
        The last tracked time point (real time, not simulation), for playback.
        '''

        self.pseudoclock = 0
        '''
        The current pseudoclock.
        
        The pseudoclock is *something like* the clock of the current active
        node. But not exactly. We're letting the pseudoclock slide more
        smoothly from one node to its neighbor, instead of jumping. This is in
        order to make some things smoother in the program. This is also why
        it's called "pseudo".
        '''

        self.default_step_profile = garlicsim.misc.StepProfile(
            self.simpack_grokker.default_step_function)
        '''The step profile that will be used be default.'''

        self.step_profiles = EmittingOrderedSet(
            emitter=None, items=(self.default_step_profile, ))
        '''An ordered set of step profiles that the user may use.'''

        self.step_profiles_to_hues = EmittingWeakKeyDefaultDict(
            emitter=None,
            default_factory=StepProfileHueDefaultFactory(self),
        )
        '''Mapping from step profile to hue that represents it in GUI.'''

        self._tracked_step_profile = None
        self._temp_shell_history = None
        self._temp_shell_command_history = None
        self._job_and_node_of_recent_fork_by_crunching = None

        ### Setting up namespace: #############################################
        #                                                                     #

        self.namespace = {
            '__name__': '__garlicsim_shell__',
            # This will become `.__module__` of classes and functions.
            'f': frame,
            'frame': frame,
            'gp': self,
            'gui_project': self,
            'p': self.project,
            'project': self.project,
            't': self.project.tree,
            'tree': self.project.tree,
            'gs': garlicsim,
            'garlicsim': garlicsim,
            'gs_wx': garlicsim_wx,
            'garlicsim_wx': garlicsim_wx,
            'wx': wx,
            'simpack': self.simpack,
            self.simpack.__name__.rsplit('.', 1)[-1]: self.simpack,
        }
        '''Namespace that will be used in shell and other places.'''

        garlicsim_lib = import_tools.import_if_exists('garlicsim_lib',
                                                      silent_fail=True)
        if garlicsim_lib:
            self.namespace.update({
                'gs_lib': garlicsim_lib,
                'garlicsim_lib': garlicsim_lib,
            })

        #                                                                     #
        ### Finished setting up namespace. ####################################

        self.__init_emitters()
        self.__init_menu_enablings()

        self.emitter_system.top_emitter.emit()
Example #6
0
def check(simpack, cruncher_type):

    my_simpack_grokker = garlicsim.misc.SimpackGrokker(simpack)

    assert my_simpack_grokker is garlicsim.misc.SimpackGrokker(simpack)
    # Ensuring caching works.

    assert not simpack._test_settings.ENDABLE

    assert garlicsim.misc.simpack_grokker.step_type.StepType.get_step_type(
        my_simpack_grokker.default_step_function
    ) == simpack._test_settings.DEFAULT_STEP_FUNCTION_TYPE

    step_profile = my_simpack_grokker.build_step_profile()
    deterministic = \
        my_simpack_grokker.settings.DETERMINISM_FUNCTION(step_profile)

    state = simpack.State.create_root()

    prev_state = state
    for i in [1, 2, 3, 4]:
        new_state = garlicsim.simulate(state, i)
        assert new_state.clock >= getattr(prev_state, 'clock', 0)
        prev_state = new_state

    result = garlicsim.list_simulate(state, 4)
    for item in result:
        assert isinstance(item, garlicsim.data_structures.State)
        assert isinstance(item, simpack.State)

    assert isinstance(result, list)
    assert len(result) == 5

    iter_result = garlicsim.iter_simulate(state, 4)

    assert not hasattr(iter_result, '__getitem__')
    assert hasattr(iter_result, '__iter__')
    iter_result_in_list = list(iter_result)
    del iter_result
    assert len(iter_result_in_list) == len(result) == 5

    ### Setting up a project to run asynchronous tests:

    project = garlicsim.Project(simpack)

    project.crunching_manager.cruncher_type = cruncher_type

    assert project.tree.lock._ReadWriteLock__writer is None

    root = project.root_this_state(state)

    project.begin_crunching(root, 4)

    total_nodes_added = 0
    while project.crunching_manager.jobs:
        time.sleep(0.1)
        total_nodes_added += project.sync_crunchers()

    assert total_nodes_added == 4

    assert len(project.tree.nodes) == 5
    assert len(project.tree.roots) == 1

    paths = project.tree.all_possible_paths()

    assert len(paths) == 1

    (my_path, ) = paths

    assert len(my_path) == 5

    node_1 = my_path[1]
    assert node_1.state.clock == 1

    node_2 = project.simulate(node_1, 3)

    assert len(project.tree.nodes) == 8
    assert len(project.tree.roots) == 1

    assert len(project.tree.all_possible_paths()) == 2

    block_1, block_2 = [node.block for node in node_1.children]
    assert isinstance(block_1, garlicsim.data_structures.Block)
    assert isinstance(block_2, garlicsim.data_structures.Block)
    assert block_1.soft_get_block() is block_1
    assert block_2.soft_get_block() is block_2
    assert block_1.is_overlapping(block_1)
    assert block_2.is_overlapping(block_2)
    assert not block_1.is_overlapping(block_2)
    assert not block_2.is_overlapping(block_1)
    block_path_1 = block_1.make_containing_path()
    block_path_2 = block_2.make_containing_path()
    assert block_path_1 == block_path_1
    assert block_path_1 != block_path_2
    assert (block_1[0] in block_path_1) and (block_1[-1] in block_path_1)
    assert (block_2[0] in block_path_2) and (block_2[-1] in block_path_2)
    assert block_1.get_root() is block_2.get_root()



    tree_members_iterator = \
        project.tree.iterate_tree_members(include_blockful_nodes=False)
    assert tree_members_iterator.__iter__() is tree_members_iterator
    tree_members = list(tree_members_iterator)
    assert (block_1 in tree_members) and (block_2 in tree_members)
    for tree_member in tree_members:
        if isinstance(tree_member, garlicsim.data_structures.Node):
            assert tree_member.block is None

    tree_members_iterator_including_blockful_nodes = \
        project.tree.iterate_tree_members(include_blockful_nodes=True)
    assert tree_members_iterator_including_blockful_nodes.__iter__() is \
        tree_members_iterator_including_blockful_nodes
    tree_members_including_blockful_nodes = \
        list(tree_members_iterator_including_blockful_nodes)

    blockful_nodes = \
        [member for member in tree_members_including_blockful_nodes if
         member not in tree_members]
    for blockful_node in blockful_nodes:
        assert isinstance(blockful_node, garlicsim.data_structures.Node)
        assert isinstance(blockful_node.block, garlicsim.data_structures.Block)
        assert blockful_node.block is blockful_node.soft_get_block()
    assert set(tree_members).\
        issubset(set(tree_members_including_blockful_nodes))

    tree_step_profiles = project.tree.get_step_profiles()
    assert isinstance(tree_step_profiles, OrderedSet)
    assert tree_step_profiles == [step_profile]
Example #7
0
def test_node_selection_and_range():
    '''Test `node_selection` and `node_range`.'''
    root_state = life.State.create_root(2, 2)
    project = garlicsim.Project(life)
    tree = project.tree
    root = project.root_this_state(root_state)
    leaf1 = project.simulate(root, 10)
    temp_path = root.make_containing_path()
    middle_node = temp_path[5]
    leaf2 = project.simulate(middle_node, 10)

    # Now we have a tree with a fork in it, in `middle_node`

    path1 = leaf1.make_containing_path()  # creating only after leaf2
    path2 = leaf2.make_containing_path()

    range1 = ds.NodeRange(root, leaf1)
    assert path1 == range1.make_path()
    range2 = ds.NodeRange(root, leaf2)
    assert path2 == range2.make_path()

    ns1 = ds.NodeSelection([range1, range2])
    ns2 = ns1.copy()
    assert ns1 == ns2

    ns2.compact()
    assert ns1 == ns2

    range1blocky = ds.NodeRange(root, leaf1.block)
    range2blocky = ds.NodeRange(root, leaf2.block)
    ns3 = ds.NodeSelection([range1blocky, range2blocky])

    ns4 = ns3.copy()
    ns4.compact()

    logic_tools.all_equal((ns1, ns2, ns3, ns4), exhaustive=True)

    all_ranges = sum((ns.ranges for ns in (ns1, ns2, ns3, ns4)), [])

    for range in all_ranges:
        assert range == range.clone_with_blocks_dissolved()

    assert len(tree.nodes) == 21

    #####################
    alt_tree, alt_ns1 = copy.deepcopy((tree, ns1))
    alt_tree.delete_node_selection(alt_ns1)
    assert len(alt_tree.nodes) == 0
    assert len(alt_tree.roots) == 0
    #####################

    assert len(tree.nodes) == 21

    middle_node_grandparent = middle_node.parent.parent

    middle_node_grandchild_1 = path1.next_node(path1.next_node(middle_node))
    middle_node_grandchild_2 = path2.next_node(path2.next_node(middle_node))

    assert middle_node_grandchild_1 is not middle_node_grandchild_2

    small_range_1 = ds.NodeRange(middle_node_grandparent,
                                 middle_node_grandchild_1)
    small_range_2 = ds.NodeRange(middle_node_grandparent,
                                 middle_node_grandchild_2)

    assert small_range_1 != small_range_2

    small_ns = ds.NodeSelection((small_range_1, small_range_2))

    #####################
    alt_tree, alt_small_range_1 = copy.deepcopy((tree, small_range_1))
    alt_tree.delete_node_range(alt_small_range_1)
    assert len(alt_tree.roots) == 3
    assert len(alt_tree.nodes) == 16
    #####################

    #####################
    alt_tree, alt_small_range_2 = copy.deepcopy((tree, small_range_2))
    alt_tree.delete_node_range(alt_small_range_2)
    assert len(alt_tree.roots) == 3
    assert len(alt_tree.nodes) == 16
    #####################

    #####################
    alt_tree, alt_small_ns = copy.deepcopy((tree, small_ns))
    alt_tree.delete_node_selection(alt_small_ns)
    assert len(alt_tree.roots) == 3
    assert len(alt_tree.nodes) == 14
    #####################

    assert len(tree.nodes) == 21
Example #8
0
def test():
    '''Test tutorial-1.'''
    life_board_pattern = re.compile('^(([ #]{45}\n){24})([ #]{45})$')
    import garlicsim
    from garlicsim_lib.simpacks import life
    state = life.State.create_messy_root()
    assert life_board_pattern.match(repr(state))
    assert repr(type(state)) == \
        "<class 'garlicsim_lib.simpacks.life.state.State'>"
    new_state = garlicsim.simulate(state)
    assert life_board_pattern.match(repr(new_state))
    new_state = garlicsim.simulate(state, 20)
    assert life_board_pattern.match(repr(new_state))
    result = garlicsim.list_simulate(state, 20)
    assert repr(type(result)) == "<type 'list'>"
    assert len(result) == 21
    assert life_board_pattern.match(repr(result[0]))
    assert result[0] == state
    assert life_board_pattern.match(repr(result[-1]))
    assert life_board_pattern.match(repr(result[7]))
    repr(garlicsim.iter_simulate(state, 5))  # Not testing cause of pypy et al.
    assert (list(garlicsim.iter_simulate(state, 5)) == \
            garlicsim.list_simulate(state, 5))

    project = garlicsim.Project(life)
    state = life.State.create_diehard()
    assert life_board_pattern.match(repr(state))
    assert repr(state).count('#') == 7
    root = project.root_this_state(state)
    assert repr(root) == \
        ('<garlicsim.data_structures.Node with clock 0, '
         'root, leaf, touched, blockless, at %s>' % hex(id(root)))
    project.begin_crunching(root, 50)
    _result = project.sync_crunchers()
    assert repr(_result) == '<0 nodes were added to the tree>'
    (cruncher, ) = project.crunching_manager.crunchers.values()
    while cruncher.is_alive():
        time.sleep(0.1)
    _result = project.sync_crunchers()
    assert repr(_result) == '<50 nodes were added to the tree>'
    assert repr(
        project.tree) == ('<garlicsim.data_structures.Tree with 1 roots, '
                          '51 nodes and 1 possible paths at %s>' %
                          hex(id(project.tree)))
    (path, ) = project.tree.all_possible_paths()
    assert repr(path) == ('<garlicsim.data_structures.Path of length 51 '
                          'at %s>' % hex(id(path)))
    assert repr(path[-1]) == (
        '<garlicsim.data_structures.Node with clock 50, leaf, untouched, '
        'blockful, crunched with life.State.step_generator(<state>), at '
        '%s>' % hex(id(path[-1])))
    _state = path[-1].state
    assert repr(_state).count('#') == 24
    assert life_board_pattern.match(repr(_state))
    node = path[27]
    assert repr(node.state).count('#') == 20
    assert life_board_pattern.match(repr(node.state))
    new_node = project.fork_to_edit(node)
    new_node.state.board.set(28, 13, True)
    assert repr(new_node.state).count('#') == 21
    assert life_board_pattern.match(repr(new_node.state))
    new_node.finalize()
    assert repr(
        project.tree) == ('<garlicsim.data_structures.Tree with 1 roots, '
                          '52 nodes and 2 possible paths at %s>' %
                          hex(id(project.tree)))
    project.ensure_buffer(root, 50)
    _result = project.sync_crunchers()
    assert repr(_result) == '<0 nodes were added to the tree>'
    (cruncher, ) = project.crunching_manager.crunchers.values()
    while cruncher.is_alive():
        time.sleep(0.1)
    _result = project.sync_crunchers()
    assert repr(_result) == '<23 nodes were added to the tree>'
    new_path = new_node.make_containing_path()
    assert repr(new_path[-1].state).count('#') == 49
    assert life_board_pattern.match(repr(new_path[-1].state))
Example #9
0
def check(simpack, cruncher_type):
    '''
    Run checks on a simpack that uses inplace step functions.
    '''
    my_simpack_grokker = garlicsim.misc.SimpackGrokker(simpack)

    assert simpack._test_settings.DEFAULT_STEP_FUNCTION_TYPE in \
           [garlicsim.misc.simpack_grokker.step_types.InplaceStep,
            garlicsim.misc.simpack_grokker.step_types.InplaceStepGenerator]

    assert garlicsim.misc.simpack_grokker.step_type.StepType.get_step_type(
        my_simpack_grokker.default_step_function
    ) == simpack._test_settings.DEFAULT_STEP_FUNCTION_TYPE

    assert simpack._test_settings.CONSTANT_CLOCK_INTERVAL == 1

    step_profile = my_simpack_grokker.build_step_profile()

    state = simpack.State.create_root()
    assert state.clock == 0

    with StateDeepcopyCounter() as state_deepcopy_counter:
        state_1 = garlicsim.simulate(state)
    assert state.clock == 0
    assert state_1.clock == 1
    assert state_1 is not state
    assert state_1.list is not state.list
    assert state_1.cross_process_persistent is state.cross_process_persistent
    n_state_deepcopy_operations = state_deepcopy_counter.call_count
    assert 1 <= n_state_deepcopy_operations <= 2

    with StateDeepcopyCounter() as state_deepcopy_counter:
        state_2 = garlicsim.simulate(state, 2)
    assert state.clock == 0
    assert state_1.clock == 1
    assert state_2.clock == 2
    assert state_2 is not state
    assert state_2.list is not state.list
    assert state_2.cross_process_persistent is state.cross_process_persistent
    assert n_state_deepcopy_operations == state_deepcopy_counter.call_count

    with StateDeepcopyCounter() as state_deepcopy_counter:
        state_10 = garlicsim.simulate(state, 10)
    assert state.clock == 0
    assert state_1.clock == 1
    assert state_2.clock == 2
    assert state_10.clock == 10
    assert state_10 is not state
    assert state_10 is not state_2
    assert state_10.list is not state.list
    assert state_10.list is not state_2.list
    assert state_10.cross_process_persistent is state.cross_process_persistent
    assert n_state_deepcopy_operations == state_deepcopy_counter.call_count

    ###########################################################################
    #                                                                         #

    with StateDeepcopyCounter() as state_deepcopy_counter:
        garlicsim.list_simulate(state, 3)
    n_state_deepcopy_operations_for_3_in_list = \
        state_deepcopy_counter.call_count

    with StateDeepcopyCounter() as state_deepcopy_counter:
        garlicsim.list_simulate(state, 4)
    n_state_deepcopy_operations_for_4_in_list = \
        state_deepcopy_counter.call_count

    assert n_state_deepcopy_operations_for_4_in_list > \
           n_state_deepcopy_operations_for_3_in_list

    #                                                                         #
    ###########################################################################

    prev_state = state
    for i in [1, 2, 3, 4]:
        new_state = garlicsim.simulate(state, i)
        assert new_state.clock >= getattr(prev_state, 'clock', 0)
        assert new_state is not prev_state
        assert new_state.list is not prev_state.list
        assert new_state.cross_process_persistent is \
               prev_state.cross_process_persistent
        prev_state = new_state

    result = garlicsim.list_simulate(state, 4)
    for item in result:
        assert isinstance(item, garlicsim.data_structures.State)
        assert isinstance(item, simpack.State)

    assert isinstance(result, list)
    assert len(result) == 5

    iter_result = garlicsim.iter_simulate(state, 4)

    assert not hasattr(iter_result, '__getitem__')
    assert hasattr(iter_result, '__iter__')
    iter_result_in_list = list(iter_result)
    del iter_result
    assert len(iter_result_in_list) == len(result) == 5

    ### Setting up a project to run asynchronous tests:

    project = garlicsim.Project(simpack)

    project.crunching_manager.cruncher_type = cruncher_type

    assert project.tree.lock._ReadWriteLock__writer is None

    root = project.root_this_state(state)

    project.begin_crunching(root, 4)

    total_nodes_added = 0
    while project.crunching_manager.jobs:
        time.sleep(0.1)
        total_nodes_added += project.sync_crunchers()

    assert total_nodes_added == 4

    assert len(project.tree.nodes) == 5
    assert len(project.tree.roots) == 1

    paths = project.tree.all_possible_paths()

    assert len(paths) == 1

    (my_path, ) = paths

    assert len(my_path) == 5

    node_1 = my_path[1]
    assert node_1.state.clock == 1

    node_2 = project.simulate(node_1, 3)

    assert len(project.tree.nodes) == 8
    assert len(project.tree.roots) == 1

    assert len(project.tree.all_possible_paths()) == 2

    block_1, block_2 = [node.block for node in node_1.children]
    assert isinstance(block_1, garlicsim.data_structures.Block)
    assert isinstance(block_2, garlicsim.data_structures.Block)
    assert block_1.soft_get_block() is block_1
    assert block_2.soft_get_block() is block_2
    assert block_1.is_overlapping(block_1)
    assert block_2.is_overlapping(block_2)
    assert not block_1.is_overlapping(block_2)
    assert not block_2.is_overlapping(block_1)
    block_path_1 = block_1.make_containing_path()
    block_path_2 = block_2.make_containing_path()
    assert block_path_1 == block_path_1
    assert block_path_1 != block_path_2
    assert (block_1[0] in block_path_1) and (block_1[-1] in block_path_1)
    assert (block_2[0] in block_path_2) and (block_2[-1] in block_path_2)
    assert block_1.get_root() is block_2.get_root()



    tree_members_iterator = \
        project.tree.iterate_tree_members(include_blockful_nodes=False)
    assert tree_members_iterator.__iter__() is tree_members_iterator
    tree_members = list(tree_members_iterator)
    assert (block_1 in tree_members) and (block_2 in tree_members)
    for tree_member in tree_members:
        if isinstance(tree_member, garlicsim.data_structures.Node):
            assert tree_member.block is None

    tree_members_iterator_including_blockful_nodes = \
        project.tree.iterate_tree_members(include_blockful_nodes=True)
    assert tree_members_iterator_including_blockful_nodes.__iter__() is \
        tree_members_iterator_including_blockful_nodes
    tree_members_including_blockful_nodes = \
        list(tree_members_iterator_including_blockful_nodes)

    blockful_nodes = \
        [member for member in tree_members_including_blockful_nodes if
         member not in tree_members]
    for blockful_node in blockful_nodes:
        assert isinstance(blockful_node, garlicsim.data_structures.Node)
        assert isinstance(blockful_node.block, garlicsim.data_structures.Block)
        assert blockful_node.block is blockful_node.soft_get_block()
    assert set(tree_members).\
        issubset(set(tree_members_including_blockful_nodes))

    tree_step_profiles = project.tree.get_step_profiles()
    assert isinstance(tree_step_profiles, OrderedSet)
    assert tree_step_profiles == [step_profile]
Example #10
0
def check(simpack, cruncher_type):

    my_simpack_grokker = garlicsim.misc.SimpackGrokker(simpack)

    assert my_simpack_grokker is garlicsim.misc.SimpackGrokker(simpack)
    # Ensuring caching works.

    empty_step_profile = garlicsim.misc.StepProfile(
        my_simpack_grokker.default_step_function)

    state = simpack.State.create_messy_root() if \
          simpack.State.create_messy_root else \
          simpack.State.create_root()

    new_state = garlicsim.simulate(state, 3)

    result = garlicsim.list_simulate(state, 3)
    for item in result:
        assert isinstance(item, garlicsim.data_structures.State)
        assert isinstance(item, simpack.State)

    assert isinstance(result, list)
    assert len(result) == 4

    if _is_deterministic(simpack):
        for old, new in cute_iter_tools.consecutive_pairs(result):
            assert new == my_simpack_grokker.step(old, empty_step_profile)

    iter_result = garlicsim.iter_simulate(state, 3)

    assert not hasattr(iter_result, '__getitem__')
    assert hasattr(iter_result, '__iter__')
    iter_result_in_list = list(iter_result)
    del iter_result
    assert len(iter_result_in_list) == len(result) == 4
    if _is_deterministic(simpack):
        assert iter_result_in_list == result
        assert iter_result_in_list[-1] == new_state == result[-1]

    project = garlicsim.Project(simpack)

    # Ensure that `Project.__init__` can take simpack grokker:
    alterante_project = garlicsim.Project(my_simpack_grokker)
    project.simpack is alterante_project.simpack
    project.simpack_grokker is alterante_project.simpack_grokker

    project.crunching_manager.cruncher_type = cruncher_type

    assert project.tree.lock._ReadWriteLock__writer is None

    root = project.root_this_state(state)

    project.begin_crunching(root, 4)

    total_nodes_added = 0
    while project.crunching_manager.jobs:
        time.sleep(0.1)
        total_nodes_added += project.sync_crunchers()

    x = total_nodes_added

    if x < 4:
        # For simpacks with long time intervals, we make sure at least 4 nodes
        # were created.
        path = root.make_containing_path()
        leaf = path[-1]
        project.simulate(leaf, math_tools.round_to_int(4 - x, up=True))
        x += path.__len__(head=path.next_node(leaf))

    assert len(project.tree.nodes) == x + 1
    assert len(project.tree.roots) == 1

    paths = project.tree.all_possible_paths()

    assert len(paths) == 1

    (my_path, ) = paths

    assert len(my_path) == x + 1

    node_1 = my_path[1]

    node_2 = project.simulate(node_1, 3)

    assert len(project.tree.nodes) == x + 1 + 3
    assert len(project.tree.roots) == 1

    assert len(project.tree.all_possible_paths()) == 2

    ### Testing project pickling and unpickling: ##############################
    #                                                                         #
    pickled_project = pickle.dumps(project, protocol=2)

    unpickled_project = cPickle.loads(pickled_project)
    path_pairs = itertools.izip(project.tree.all_possible_paths(),
                                unpickled_project.tree.all_possible_paths())

    if simpack.State.__eq__ != garlicsim.data_structures.State.__eq__:

        for path_of_original, path_of_duplicate in path_pairs:

            state_pairs = itertools.izip(path_of_original.states(),
                                         path_of_duplicate.states())
            for state_of_original, state_of_duplicate in state_pairs:

                assert state_of_original == state_of_duplicate
    #                                                                         #
    ### Finished testing project pickling and unpickling. #####################

    node_3 = my_path.next_node(node_1)

    project.begin_crunching(node_3, 3)

    total_nodes_added = 0
    while project.crunching_manager.jobs:
        time.sleep(0.1)
        total_nodes_added += project.sync_crunchers()
    y = total_nodes_added

    if y < 3:
        # For simpacks with long time intervals, we make sure at least 3 nodes
        # were created.
        path = node_3.children[1].make_containing_path()
        leaf = path[-1]
        project.simulate(leaf, math_tools.round_to_int(3 - y, up=True))
        y += path.__len__(head=path.next_node(leaf))

    assert len(project.tree.nodes) == x + y + 4

    paths = project.tree.all_possible_paths()
    assert len(paths) == 3

    assert [len(p) for p in paths] == [x + 1, 3 + y, 5]

    for (_path_1, _path_2) in cute_iter_tools.consecutive_pairs(paths):
        assert _path_1._get_higher_path(node=root) == _path_2

    for _path in paths:
        assert _path.copy() == _path

    project.ensure_buffer(node_3, 3)

    total_nodes_added = 0
    while project.crunching_manager.jobs:
        time.sleep(0.1)
        total_nodes_added += project.sync_crunchers()

    assert len(project.tree.nodes) == x + y + 4 + total_nodes_added
    assert len(project.tree.all_possible_paths()) == 3

    assert project.tree.lock._ReadWriteLock__writer is None

    two_paths = node_3.all_possible_paths()

    assert len(two_paths) == 2
    (path_1, path_2) = two_paths
    get_clock_buffer = lambda path: (path[-1].state.clock - node_3.state.clock)
    (clock_buffer_1, clock_buffer_2) = [get_clock_buffer(p) for p in two_paths]

    project.ensure_buffer_on_path(node_3, path_1,
                                  get_clock_buffer(path_1) * 1.2)

    total_nodes_added = 0
    while project.crunching_manager.jobs:
        time.sleep(0.1)
        total_nodes_added += project.sync_crunchers()

    (old_clock_buffer_1, old_clock_buffer_2) = (clock_buffer_1, clock_buffer_2)
    (clock_buffer_1, clock_buffer_2) = [get_clock_buffer(p) for p in two_paths]

    assert clock_buffer_1 / old_clock_buffer_1 >= 1.2 - FUZZ
    assert clock_buffer_2 == old_clock_buffer_2

    project.ensure_buffer_on_path(node_3, path_2,
                                  get_clock_buffer(path_2) * 1.3)

    total_nodes_added = 0
    while project.crunching_manager.jobs:
        time.sleep(0.1)
        total_nodes_added += project.sync_crunchers()

    (old_clock_buffer_1, old_clock_buffer_2) = (clock_buffer_1, clock_buffer_2)
    (clock_buffer_1, clock_buffer_2) = [get_clock_buffer(p) for p in two_paths]

    assert clock_buffer_1 == old_clock_buffer_1
    assert clock_buffer_2 / old_clock_buffer_2 >= 1.3 - FUZZ

    plain_root = project.create_root()

    assert len(project.tree.roots) == 2

    assert len(project.tree.all_possible_paths()) == 4

    assert project.tree.lock._ReadWriteLock__writer is None

    number_of_nodes = len(project.tree.nodes)
    iterator = project.iter_simulate(plain_root, 5)

    assert project.tree.lock._ReadWriteLock__writer is None

    new_node = iterator.next()
    assert new_node is plain_root
    assert len(project.tree.nodes) == number_of_nodes

    assert project.tree.lock._ReadWriteLock__writer is None

    new_node = iterator.next()
    assert new_node is not plain_root
    assert new_node.parent is plain_root
    assert len(project.tree.nodes) == number_of_nodes + 1

    bunch_of_new_nodes = tuple(iterator)
    consecutive_nodes = cute_iter_tools.consecutive_pairs(bunch_of_new_nodes)
    for parent_node, kid_node in consecutive_nodes:
        assert project.tree.lock._ReadWriteLock__writer is None
        assert isinstance(parent_node, garlicsim.data_structures.Node)
        assert isinstance(kid_node, garlicsim.data_structures.Node)
        assert parent_node.children == [kid_node]
        assert kid_node.parent is parent_node

    assert len(project.tree.nodes) == number_of_nodes + 5

    (alternate_path, ) = plain_root.all_possible_paths()
    assert isinstance(alternate_path, garlicsim.data_structures.Path)
    assert alternate_path == plain_root.make_containing_path()
    assert len(alternate_path) == 6
    all_except_root = list(alternate_path)[1:]

    ((_key, _value), ) = plain_root.get_all_leaves().items()
    assert _key is alternate_path[-1]
    assert _value['nodes_distance'] == 5
    assert 'clock_distance' in _value  # Can't know the value of that.

    block = all_except_root[0].block
    assert isinstance(block, garlicsim.data_structures.Block)
    for node in all_except_root:
        assert isinstance(node, garlicsim.data_structures.Node)
        assert node.block is node.soft_get_block() is block
        nose.tools.assert_raises(garlicsim.data_structures.NodeError,
                                 node.finalize)
        assert node.get_root() is plain_root
        assert node.get_ancestor(generations=0) is node
        assert node.get_ancestor(generations=infinity, round=True) is \
            plain_root
        nose.tools.assert_raises(
            garlicsim.data_structures.node.NodeLookupError,
            lambda: node.get_ancestor(generations=infinity, round=False))
        nose.tools.assert_raises(
            garlicsim.data_structures.node.NodeLookupError,
            lambda: node.get_ancestor(generations=100, round=False))
        if node.is_last_on_block():
            assert block[-1] is node
            assert node.get_ancestor(generations=2, round=False) is \
                block[-3]
            assert node.get_ancestor(generations=1, round=True) is \
                block[-2] is node.parent
        if node.is_first_on_block():
            assert block[0] is node

    assert set(all_except_root) == set(block)

    second_on_block = block[1]
    second_to_last_on_block = block[-2]
    assert second_to_last_on_block.state.clock > second_on_block.state.clock
    assert list(
        alternate_path.iterate_blockwise(
            second_on_block, second_to_last_on_block)) == list(block[1:-1])
    assert list(
        alternate_path.iterate_blockwise_reversed(
            second_on_block, second_to_last_on_block)) == list(block[-2:0:-1])

    ### Testing path methods: #################################################
    #                                                                         #

    empty_path = garlicsim.data_structures.Path(project.tree)
    assert len(empty_path) == 0
    assert list(empty_path) == []
    assert list(reversed(empty_path)) == []
    assert list(empty_path.iterate_blockwise()) == []
    assert list(empty_path.iterate_blockwise_reversed()) == []

    for (path, other_path) in [(path_1, path_2), (path_2, path_1)]:
        assert isinstance(path, garlicsim.data_structures.Path)
        assert path[-1] is path.get_last_node()
        node_list = list(path)
        reversed_node_list = list(reversed(path))
        assert node_list == list(reversed(reversed_node_list))
        assert list(path.iterate_blockwise()) == \
            list(reversed(list(path.iterate_blockwise_reversed(tail=path[-1]))))
        stranger_node = other_path[-1]
        assert stranger_node not in path
        nose.tools.assert_raises(
            garlicsim.data_structures.path.TailNotReached,
            lambda: list(path.__iter__(tail=stranger_node)))

    #                                                                         #
    ### Finished testing path methods. ########################################

    if simpack.State.create_messy_root is not None:
        messy_root = project.create_messy_root()
        assert len(project.tree.roots) == 3
        assert messy_root is project.tree.roots[-1]
        assert isinstance(messy_root.state, simpack.State)