-
Notifications
You must be signed in to change notification settings - Fork 103
/
dependency_order_test.go
99 lines (86 loc) · 2.87 KB
/
dependency_order_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package graph
import (
"errors"
"strings"
"testing"
)
const (
lineBreak = "\n"
delimiter = ","
)
/*
TestDependencyOrder tests solution(s) with the following signature and problem description:
func DependencyOrder(graph []*VertexWithIngress) []*VertexWithIngress
Given a multiline input, each line starting with an element and followed by a comma separated
list of dependent elements, output the elements in the order in which the dependencies are met.
In real world this is similar to courses and their prerequisite where a prerequisite must be
taken before a course can be taken. This is also similar to the dependencies of a software,
where there are dependencies of dependencies and a software can only built when all of its
dependencies are built.
For example the following input:
a,b,c,d
b,c
d,e,f
Means that a depends on b, c, d; b depends on c; d depends on e, f.
The output should be f,e,c,d,b,a. Note that the order of the elements in the output is not
important, but the order of the dependencies is important.
*/
func TestDependencyOrder(t *testing.T) {
tests := []struct {
input string
order string
expectedErr error
}{
{"", "", nil},
{"a,b", "b,a", nil},
{"a,b,c\nc,a", "", ErrNotADAG},
{"a,b,c,d\nb,c\nd,e,f", "f,e,c,d,b,a", nil},
{"a,f\nb,f\nc,f\nd,f\ne,f", "f,e,d,c,b,a", nil},
{"a,f\nb,f\nc,f\nd,f\ne,f\nf,g\ng,h", "h,g,f,e,d,c,b,a", nil},
{"a,f\nb,f\nc,f\nd,f\ne,f\nf,g\ng,h\nd,h", "h,g,f,e,d,c,b,a", nil},
}
for i, test := range tests {
orderedGraph, err := DependencyOrder(toDependencyGraph(test.input))
got := ""
for i := range orderedGraph {
got += orderedGraph[i].Val.(string) + delimiter
}
if len(orderedGraph) > 0 {
got = strings.TrimSuffix(got, delimiter)
}
if err != nil {
if test.expectedErr == nil {
t.Fatalf("Failed test case #%d. Unexpected error. Error :%s", i, err)
}
if !errors.Is(err, test.expectedErr) {
t.Fatalf("Failed test case #%d. Unexpected error. Want %s, Got Error :%s", i, test.expectedErr, err)
}
}
if err == nil && test.expectedErr != nil {
t.Fatalf("Failed test case #%d. Expected error %s did not occur", i, test.expectedErr)
}
if got != test.order {
t.Fatalf("Failed test case #%d. Want %s got %s", i, test.order, got)
}
}
}
func toDependencyGraph(input string) []*VertexWithIngress {
graph := []*VertexWithIngress{}
graphMap := make(map[string]*VertexWithIngress)
for _, line := range strings.Split(input, lineBreak) {
firstElement := ""
for _, element := range strings.Split(line, delimiter) {
if _, ok := graphMap[element]; !ok {
vertex := &VertexWithIngress{Val: element, Edges: []*VertexWithIngress{}}
graphMap[element] = vertex
graph = append(graph, vertex)
}
if firstElement == "" {
firstElement = element
continue
}
graphMap[firstElement].Edges = append(graphMap[firstElement].Edges, graphMap[element])
}
}
return graph
}