golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/src/cmd/vendor/github.com/google/pprof/internal/graph/graph_test.go (about)

     1  package graph
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  )
     7  
     8  func edgeDebugString(edge *Edge) string {
     9  	debug := ""
    10  	debug += fmt.Sprintf("\t\tSrc: %p\n", edge.Src)
    11  	debug += fmt.Sprintf("\t\tDest: %p\n", edge.Dest)
    12  	debug += fmt.Sprintf("\t\tWeight: %d\n", edge.Weight)
    13  	debug += fmt.Sprintf("\t\tResidual: %t\n", edge.Residual)
    14  	debug += fmt.Sprintf("\t\tInline: %t\n", edge.Inline)
    15  	return debug
    16  }
    17  
    18  func edgeMapsDebugString(in, out EdgeMap) string {
    19  	debug := ""
    20  	debug += "In Edges:\n"
    21  	for parent, edge := range in {
    22  		debug += fmt.Sprintf("\tParent: %p\n", parent)
    23  		debug += edgeDebugString(edge)
    24  	}
    25  	debug += "Out Edges:\n"
    26  	for child, edge := range out {
    27  		debug += fmt.Sprintf("\tChild: %p\n", child)
    28  		debug += edgeDebugString(edge)
    29  	}
    30  	return debug
    31  }
    32  
    33  func graphDebugString(graph *Graph) string {
    34  	debug := ""
    35  	for i, node := range graph.Nodes {
    36  		debug += fmt.Sprintf("Node %d: %p\n", i, node)
    37  	}
    38  
    39  	for i, node := range graph.Nodes {
    40  		debug += "\n"
    41  		debug += fmt.Sprintf("===  Node %d: %p  ===\n", i, node)
    42  		debug += edgeMapsDebugString(node.In, node.Out)
    43  	}
    44  	return debug
    45  }
    46  
    47  func expectedNodesDebugString(expected []expectedNode) string {
    48  	debug := ""
    49  	for i, node := range expected {
    50  		debug += fmt.Sprintf("Node %d: %p\n", i, node.node)
    51  	}
    52  
    53  	for i, node := range expected {
    54  		debug += "\n"
    55  		debug += fmt.Sprintf("===  Node %d: %p  ===\n", i, node.node)
    56  		debug += edgeMapsDebugString(node.in, node.out)
    57  	}
    58  	return debug
    59  }
    60  
    61  // edgeMapsEqual checks if all the edges in this equal all the edges in that.
    62  func edgeMapsEqual(this, that EdgeMap) bool {
    63  	if len(this) != len(that) {
    64  		return false
    65  	}
    66  	for node, thisEdge := range this {
    67  		if *thisEdge != *that[node] {
    68  			return false
    69  		}
    70  	}
    71  	return true
    72  }
    73  
    74  // nodesEqual checks if node is equal to expected.
    75  func nodesEqual(node *Node, expected expectedNode) bool {
    76  	return node == expected.node && edgeMapsEqual(node.In, expected.in) &&
    77  		edgeMapsEqual(node.Out, expected.out)
    78  }
    79  
    80  // graphsEqual checks if graph is equivalent to the graph templated by expected.
    81  func graphsEqual(graph *Graph, expected []expectedNode) bool {
    82  	if len(graph.Nodes) != len(expected) {
    83  		return false
    84  	}
    85  	expectedSet := make(map[*Node]expectedNode)
    86  	for i := range expected {
    87  		expectedSet[expected[i].node] = expected[i]
    88  	}
    89  
    90  	for _, node := range graph.Nodes {
    91  		expectedNode, found := expectedSet[node]
    92  		if !found || !nodesEqual(node, expectedNode) {
    93  			return false
    94  		}
    95  	}
    96  	return true
    97  }
    98  
    99  type expectedNode struct {
   100  	node    *Node
   101  	in, out EdgeMap
   102  }
   103  
   104  type trimTreeTestcase struct {
   105  	initial  *Graph
   106  	expected []expectedNode
   107  	keep     NodePtrSet
   108  }
   109  
   110  // makeExpectedEdgeResidual makes the edge from parent to child residual.
   111  func makeExpectedEdgeResidual(parent, child expectedNode) {
   112  	parent.out[child.node].Residual = true
   113  	child.in[parent.node].Residual = true
   114  }
   115  
   116  func makeEdgeInline(edgeMap EdgeMap, node *Node) {
   117  	edgeMap[node].Inline = true
   118  }
   119  
   120  func setEdgeWeight(edgeMap EdgeMap, node *Node, weight int64) {
   121  	edgeMap[node].Weight = weight
   122  }
   123  
   124  // createEdges creates directed edges from the parent to each of the children.
   125  func createEdges(parent *Node, children ...*Node) {
   126  	for _, child := range children {
   127  		edge := &Edge{
   128  			Src:  parent,
   129  			Dest: child,
   130  		}
   131  		parent.Out[child] = edge
   132  		child.In[parent] = edge
   133  	}
   134  }
   135  
   136  // createEmptyNode creates a node without any edges.
   137  func createEmptyNode() *Node {
   138  	return &Node{
   139  		In:  make(EdgeMap),
   140  		Out: make(EdgeMap),
   141  	}
   142  }
   143  
   144  // createExpectedNodes creates a slice of expectedNodes from nodes.
   145  func createExpectedNodes(nodes ...*Node) ([]expectedNode, NodePtrSet) {
   146  	expected := make([]expectedNode, len(nodes))
   147  	keep := make(NodePtrSet, len(nodes))
   148  
   149  	for i, node := range nodes {
   150  		expected[i] = expectedNode{
   151  			node: node,
   152  			in:   make(EdgeMap),
   153  			out:  make(EdgeMap),
   154  		}
   155  		keep[node] = true
   156  	}
   157  
   158  	return expected, keep
   159  }
   160  
   161  // createExpectedEdges creates directed edges from the parent to each of the
   162  // children.
   163  func createExpectedEdges(parent expectedNode, children ...expectedNode) {
   164  	for _, child := range children {
   165  		edge := &Edge{
   166  			Src:  parent.node,
   167  			Dest: child.node,
   168  		}
   169  		parent.out[child.node] = edge
   170  		child.in[parent.node] = edge
   171  	}
   172  }
   173  
   174  // createTestCase1 creates a test case that initally looks like:
   175  //     0
   176  //     |(5)
   177  //     1
   178  // (3)/ \(4)
   179  //   2   3.
   180  //
   181  // After keeping 0, 2, and 3, it expects the graph:
   182  //     0
   183  // (3)/ \(4)
   184  //   2   3.
   185  func createTestCase1() trimTreeTestcase {
   186  	// Create initial graph
   187  	graph := &Graph{make(Nodes, 4)}
   188  	nodes := graph.Nodes
   189  	for i := range nodes {
   190  		nodes[i] = createEmptyNode()
   191  	}
   192  	createEdges(nodes[0], nodes[1])
   193  	createEdges(nodes[1], nodes[2], nodes[3])
   194  	makeEdgeInline(nodes[0].Out, nodes[1])
   195  	makeEdgeInline(nodes[1].Out, nodes[2])
   196  	setEdgeWeight(nodes[0].Out, nodes[1], 5)
   197  	setEdgeWeight(nodes[1].Out, nodes[2], 3)
   198  	setEdgeWeight(nodes[1].Out, nodes[3], 4)
   199  
   200  	// Create expected graph
   201  	expected, keep := createExpectedNodes(nodes[0], nodes[2], nodes[3])
   202  	createExpectedEdges(expected[0], expected[1], expected[2])
   203  	makeEdgeInline(expected[0].out, expected[1].node)
   204  	makeExpectedEdgeResidual(expected[0], expected[1])
   205  	makeExpectedEdgeResidual(expected[0], expected[2])
   206  	setEdgeWeight(expected[0].out, expected[1].node, 3)
   207  	setEdgeWeight(expected[0].out, expected[2].node, 4)
   208  	return trimTreeTestcase{
   209  		initial:  graph,
   210  		expected: expected,
   211  		keep:     keep,
   212  	}
   213  }
   214  
   215  // createTestCase2 creates a test case that initially looks like:
   216  //   3
   217  //   | (12)
   218  //   1
   219  //   | (8)
   220  //   2
   221  //   | (15)
   222  //   0
   223  //   | (10)
   224  //   4.
   225  //
   226  // After keeping 3 and 4, it expects the graph:
   227  //   3
   228  //   | (10)
   229  //   4.
   230  func createTestCase2() trimTreeTestcase {
   231  	// Create initial graph
   232  	graph := &Graph{make(Nodes, 5)}
   233  	nodes := graph.Nodes
   234  	for i := range nodes {
   235  		nodes[i] = createEmptyNode()
   236  	}
   237  	createEdges(nodes[3], nodes[1])
   238  	createEdges(nodes[1], nodes[2])
   239  	createEdges(nodes[2], nodes[0])
   240  	createEdges(nodes[0], nodes[4])
   241  	setEdgeWeight(nodes[3].Out, nodes[1], 12)
   242  	setEdgeWeight(nodes[1].Out, nodes[2], 8)
   243  	setEdgeWeight(nodes[2].Out, nodes[0], 15)
   244  	setEdgeWeight(nodes[0].Out, nodes[4], 10)
   245  
   246  	// Create expected graph
   247  	expected, keep := createExpectedNodes(nodes[3], nodes[4])
   248  	createExpectedEdges(expected[0], expected[1])
   249  	makeExpectedEdgeResidual(expected[0], expected[1])
   250  	setEdgeWeight(expected[0].out, expected[1].node, 10)
   251  	return trimTreeTestcase{
   252  		initial:  graph,
   253  		expected: expected,
   254  		keep:     keep,
   255  	}
   256  }
   257  
   258  // createTestCase3 creates an initally empty graph and expects an empty graph
   259  // after trimming.
   260  func createTestCase3() trimTreeTestcase {
   261  	graph := &Graph{make(Nodes, 0)}
   262  	expected, keep := createExpectedNodes()
   263  	return trimTreeTestcase{
   264  		initial:  graph,
   265  		expected: expected,
   266  		keep:     keep,
   267  	}
   268  }
   269  
   270  // createTestCase4 creates a test case that initially looks like:
   271  //   0.
   272  //
   273  // After keeping 0, it expects the graph:
   274  //   0.
   275  func createTestCase4() trimTreeTestcase {
   276  	graph := &Graph{make(Nodes, 1)}
   277  	nodes := graph.Nodes
   278  	for i := range nodes {
   279  		nodes[i] = createEmptyNode()
   280  	}
   281  	expected, keep := createExpectedNodes(nodes[0])
   282  	return trimTreeTestcase{
   283  		initial:  graph,
   284  		expected: expected,
   285  		keep:     keep,
   286  	}
   287  }
   288  
   289  func createTrimTreeTestCases() []trimTreeTestcase {
   290  	caseGenerators := []func() trimTreeTestcase{
   291  		createTestCase1,
   292  		createTestCase2,
   293  		createTestCase3,
   294  		createTestCase4,
   295  	}
   296  	cases := make([]trimTreeTestcase, len(caseGenerators))
   297  	for i, gen := range caseGenerators {
   298  		cases[i] = gen()
   299  	}
   300  	return cases
   301  }
   302  
   303  func TestTrimTree(t *testing.T) {
   304  	tests := createTrimTreeTestCases()
   305  	for _, test := range tests {
   306  		graph := test.initial
   307  		graph.TrimTree(test.keep)
   308  		if !graphsEqual(graph, test.expected) {
   309  			t.Fatalf("Graphs do not match.\nExpected: %s\nFound: %s\n",
   310  				expectedNodesDebugString(test.expected),
   311  				graphDebugString(graph))
   312  		}
   313  	}
   314  }