def test_remove_should_acquire_lock_on_parent_nodes(self): parent1 = Node((1, 2)) parent2 = Node((2, 3)) node = Node((3, 4), parents=set([(1, 2), (2, 3)])) parent1.children = set([(3, 4)]) parent2.children = set([(3, 4)]) leaf_queue = Mock() parent1.lock = Mock() parent1.lock.aquire.side_effect = lambda: self.assertTrue(node in parent1.children) parent1.lock.release.side_effect = lambda: self.assertFalse(node in parent1.children) parent2.lock = Mock() parent2.lock.aquire.side_effect = lambda: self.assertTrue(node in parent2.children) parent2.lock.release.side_effect = lambda: self.assertFalse(node in parent2.children) node.remove_from_parents([parent1, parent2], leaf_queue) self.assertTrue(parent1.lock.acquire.called) self.assertTrue(parent1.lock.release.called) self.assertTrue(parent2.lock.acquire.called) self.assertTrue(parent2.lock.release.called) self.assertEquals( leaf_queue.put.call_args_list, [call((1, 2)), call((2, 3))] )
def test_equality(self): n1 = Node((1, 2), children=set([1])) n1.parents = set([2]) n2 = Node((1, 2), children=set([1])) n2.parents = set([2]) self.assertTrue(n1 == n2) self.assertFalse(n1 != n2) n2.location = (3, 4) self.assertFalse(n1 == n2) self.assertTrue(n1 != n2) n2.location = (1, 2) n2.parents = set([3]) self.assertFalse(n1 == n2) self.assertTrue(n1 != n2) n2.children = set([3]) self.assertFalse(n1 == n2) self.assertTrue(n1 != n2) n2.parents = set([2]) self.assertFalse(n1 == n2) self.assertTrue(n1 != n2)
def test_returns_graph_and_leaf_nodes(self): worksheet = Worksheet() worksheet[1, 1].formula = '=A2 + B2' worksheet[1, 2].formula = '=A3' worksheet[2, 2].formula = '=B3' worksheet[1, 3].formula = '=1' worksheet[2, 3].formula = '1' worksheet[3, 3].python_formula = '1' graph, leaves = build_dependency_graph(worksheet) self.maxDiff = None self.assertEquals( graph, { (1, 1): Node( (1, 1), children=set([(1, 2), (2, 2)]), parents=set()), (1, 2): Node( (1, 2), children=set([(1, 3)]), parents=set([(1, 1)])), (2, 2): Node((2, 2), children=set(), parents=set([(1, 1)])), (1, 3): Node((1, 3), children=set(), parents=set([(1, 2)])), (3, 3): Node((3, 3), children=set(), parents=set()), }) self.assertEquals(set(leaves), set([(1, 3), (2, 2), (3, 3)])) worksheet[1, 2].formula = '=A3 + B3' graph, leaves = build_dependency_graph(worksheet) self.assertEquals( graph, { (1, 1): Node( (1, 1), children=set([(1, 2), (2, 2)]), parents=set(), ), (1, 2): Node( (1, 2), children=set([(1, 3)]), parents=set([(1, 1)]), ), (2, 2): Node((2, 2), children=set(), parents=set([(1, 1)])), (1, 3): Node((1, 3), children=set(), parents=set([(1, 2)])), (3, 3): Node((3, 3), children=set(), parents=set()), }) self.assertEquals(set(leaves), set([(1, 3), (2, 2), (3, 3)]))
def test_constructor(self): self.assertRaises(TypeError, lambda: Node()) n1 = Node((1, 2)) self.assertEquals(n1.location, (1, 2)) self.assertEquals(n1.children, set()) self.assertEquals(n1.parents, set()) n2 = Node((2, 3), children=set([1, 2, 3])) self.assertEquals(n2.location, (2, 3)) self.assertEquals(n2.children, set([1, 2, 3])) self.assertEquals(n2.parents, set()) n3 = Node((4, 5), parents=set([1, 2, 3])) self.assertEquals(n3.location, (4, 5)) self.assertEquals(n3.children, set()) self.assertEquals(n3.parents, set([1, 2, 3]))
def test_remove_should_add_new_leaves_to_queue(self): parent = Node((1, 2)) child1 = Node((2, 3), parents=set([parent.location])) child2 = Node((3, 4), parents=set([parent.location])) parent.children = set([child1.location, child2.location]) leaf_queue = Mock() child1.remove_from_parents([parent], leaf_queue) self.assertFalse(leaf_queue.put.called) child2.remove_from_parents([parent], leaf_queue) self.assertEquals(leaf_queue.put.call_args, ((parent.location,), {}))
def test_is_robust_against_references_to_empty_cells(self): worksheet = Worksheet() worksheet[1, 1].formula = '=A2' # NB we're making sure that this call doesn't raise an error # because the cell A2 is created in the dictionary while we're # iterating over it. graph, leaves = build_dependency_graph(worksheet) self.maxDiff = None self.assertEquals( graph, {(1, 1): Node((1, 1), children=set(), parents=set())}) self.assertEquals(leaves, [(1, 1)])
def test_does_not_include_discovered_cycle_in_deps_of_current_cell( self): # worksheet = Worksheet() worksheet[1, 1].formula = '=A2' worksheet[1, 2].formula = '=A1' worksheet[1, 3].formula = '=A1' visited = set() graph = {} _generate_cell_subgraph(worksheet, graph, (1, 3), visited, []) self.assertEquals(graph, {(1, 3): Node((1, 3), set())}) self.assertEquals(visited, set([(1, 2), (1, 3), (1, 1)]))
def test_puts_errors_on_cells_in_cycles_and_omits_them_from_graph( self, mock_report_cell_error): mock_report_cell_error.side_effect = report_cell_error worksheet = Worksheet() worksheet[1, 1].formula = '=A2' worksheet[1, 2].formula = '=A1' worksheet[1, 3].formula = '=A1' worksheet[1, 4].formula = '=A5' worksheet[1, 5].formula = '=5' graph, leaves = build_dependency_graph(worksheet) self.assertEquals( graph, { (1, 3): Node((1, 3), children=set(), parents=set()), (1, 4): Node((1, 4), children=set([(1, 5)]), parents=set()), (1, 5): Node((1, 5), children=set(), parents=set([(1, 4)])), }) self.assertEquals(leaves, [(1, 5), (1, 3)]) a1_cycle_error = CycleError([(1, 2), (1, 1), (1, 2)]) self.assertEquals(mock_report_cell_error.call_args_list, [ call(worksheet, (1, 2), a1_cycle_error), call(worksheet, (1, 1), a1_cycle_error), ])
def test_should_not_recurse_into_existing_cycle_errors_or_include_them_in_its_deps( self, mock_recursive_call): cycle_error = CycleError([(1, 2), (3, 4), (1, 2)]) worksheet = Worksheet() worksheet[1, 2].error = cycle_error worksheet[3, 4].error = cycle_error worksheet[1, 3].formula = "=foo" worksheet[1, 3].dependencies = [(3, 4)] visited = set([(1, 2), (3, 4)]) graph = {} _generate_cell_subgraph(worksheet, graph, (1, 3), visited, []) dep_cell_calls = [c[0][2] for c in mock_recursive_call.call_args_list] self.assertNotIn(dep_cell_calls, (3, 4)) self.assertEquals(visited, set([(1, 2), (1, 3), (3, 4)])) self.assertEquals(graph, {(1, 3): Node((1, 3), set())})
def test_add_location_dependencies_also_adds_reverse_dependencies(self): graph = {} parent_loc = (1, 2) child1_loc = (2, 3) child2_loc = (3, 4) grandchild_loc = (4, 5) _add_location_dependencies(graph, parent_loc, set([child1_loc, child2_loc])) expected = { parent_loc: Node(parent_loc, children=set([child1_loc, child2_loc])), child1_loc: Node(child1_loc, parents=set([parent_loc])), child2_loc: Node(child2_loc, parents=set([parent_loc])), } self.assertEquals(expected, graph) _add_location_dependencies(graph, grandchild_loc, set()) expected = { parent_loc: Node(parent_loc, children=set([child1_loc, child2_loc])), child1_loc: Node(child1_loc, parents=set([parent_loc])), child2_loc: Node(child2_loc, parents=set([parent_loc])), grandchild_loc: Node(grandchild_loc), } self.assertEquals(expected, graph) _add_location_dependencies(graph, child1_loc, set([grandchild_loc])) expected = { parent_loc: Node(parent_loc, children=set([child1_loc, child2_loc])), child1_loc: Node(child1_loc, children=set([grandchild_loc]), parents=set([parent_loc])), child2_loc: Node(child2_loc, parents=set([parent_loc])), grandchild_loc: Node(grandchild_loc, parents=set([child1_loc])), } self.assertEquals(expected, graph)
def test_remove_should_add_new_leaves_to_queue(self): parent = Node((1, 2)) child1 = Node((2, 3), parents=set([parent.location])) child2 = Node((3, 4), parents=set([parent.location])) parent.children = set([child1.location, child2.location]) leaf_queue = Mock() child1.remove_from_parents([parent], leaf_queue) self.assertFalse(leaf_queue.put.called) child2.remove_from_parents([parent], leaf_queue) self.assertEquals(leaf_queue.put.call_args, ((parent.location, ), {}))
def test_remove_should_acquire_lock_on_parent_nodes(self): parent1 = Node((1, 2)) parent2 = Node((2, 3)) node = Node((3, 4), parents=set([(1, 2), (2, 3)])) parent1.children = set([(3, 4)]) parent2.children = set([(3, 4)]) leaf_queue = Mock() parent1.lock = Mock() parent1.lock.aquire.side_effect = lambda: self.assertTrue( node in parent1.children) parent1.lock.release.side_effect = lambda: self.assertFalse( node in parent1.children) parent2.lock = Mock() parent2.lock.aquire.side_effect = lambda: self.assertTrue( node in parent2.children) parent2.lock.release.side_effect = lambda: self.assertFalse( node in parent2.children) node.remove_from_parents([parent1, parent2], leaf_queue) self.assertTrue(parent1.lock.acquire.called) self.assertTrue(parent1.lock.release.called) self.assertTrue(parent2.lock.acquire.called) self.assertTrue(parent2.lock.release.called) self.assertEquals(leaf_queue.put.call_args_list, [call((1, 2)), call((2, 3))])
def test_repr(self): self.assertEquals(str(Node((1, 2), children=set([1, 2, 3]))), "<Node 1,2 children={1, 2, 3} parents={}>")
def test_nodes_should_have_a_lock(self): node = Node((1, 2)) self.assertIsNotNone(node.lock.acquire) self.assertIsNotNone(node.lock.release)