github.com/ves/terraform@v0.8.0-beta2/dag/marshal_test.go (about) 1 package dag 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "strings" 7 "testing" 8 ) 9 10 func TestGraphDot_empty(t *testing.T) { 11 var g Graph 12 g.Add(1) 13 g.Add(2) 14 g.Add(3) 15 16 actual := strings.TrimSpace(string(g.Dot(nil))) 17 expected := strings.TrimSpace(testGraphDotEmptyStr) 18 if actual != expected { 19 t.Fatalf("bad: %s", actual) 20 } 21 } 22 23 func TestGraphDot_basic(t *testing.T) { 24 var g Graph 25 g.Add(1) 26 g.Add(2) 27 g.Add(3) 28 g.Connect(BasicEdge(1, 3)) 29 30 actual := strings.TrimSpace(string(g.Dot(nil))) 31 expected := strings.TrimSpace(testGraphDotBasicStr) 32 if actual != expected { 33 t.Fatalf("bad: %s", actual) 34 } 35 } 36 37 const testGraphDotBasicStr = `digraph { 38 compound = "true" 39 newrank = "true" 40 subgraph "root" { 41 "[root] 1" -> "[root] 3" 42 } 43 } 44 ` 45 46 const testGraphDotEmptyStr = `digraph { 47 compound = "true" 48 newrank = "true" 49 subgraph "root" { 50 } 51 }` 52 53 func TestGraphJSON_empty(t *testing.T) { 54 var g Graph 55 g.Add(1) 56 g.Add(2) 57 g.Add(3) 58 59 js, err := g.MarshalJSON() 60 if err != nil { 61 t.Fatal(err) 62 } 63 64 actual := strings.TrimSpace(string(js)) 65 expected := strings.TrimSpace(testGraphJSONEmptyStr) 66 if actual != expected { 67 t.Fatalf("bad: %s", actual) 68 } 69 } 70 71 func TestGraphJSON_basic(t *testing.T) { 72 var g Graph 73 g.Add(1) 74 g.Add(2) 75 g.Add(3) 76 g.Connect(BasicEdge(1, 3)) 77 78 js, err := g.MarshalJSON() 79 if err != nil { 80 t.Fatal(err) 81 } 82 actual := strings.TrimSpace(string(js)) 83 expected := strings.TrimSpace(testGraphJSONBasicStr) 84 if actual != expected { 85 t.Fatalf("bad: %s", actual) 86 } 87 } 88 89 // record some graph transformations, and make sure we get the same graph when 90 // they're replayed 91 func TestGraphJSON_basicRecord(t *testing.T) { 92 var g Graph 93 var buf bytes.Buffer 94 g.SetDebugWriter(&buf) 95 96 g.Add(1) 97 g.Add(2) 98 g.Add(3) 99 g.Connect(BasicEdge(1, 2)) 100 g.Connect(BasicEdge(1, 3)) 101 g.Connect(BasicEdge(2, 3)) 102 (&AcyclicGraph{g}).TransitiveReduction() 103 104 recorded := buf.Bytes() 105 // the Walk doesn't happen in a determined order, so just count operations 106 // for now to make sure we wrote stuff out. 107 if len(bytes.Split(recorded, []byte{'\n'})) != 17 { 108 t.Fatalf("bad: %s", recorded) 109 } 110 111 original, err := g.MarshalJSON() 112 if err != nil { 113 t.Fatal(err) 114 } 115 116 // replay the logs, and marshal the graph back out again 117 m, err := decodeGraph(bytes.NewReader(buf.Bytes())) 118 if err != nil { 119 t.Fatal(err) 120 } 121 122 replayed, err := json.MarshalIndent(m, "", " ") 123 if err != nil { 124 t.Fatal(err) 125 } 126 127 if !bytes.Equal(original, replayed) { 128 t.Fatalf("\noriginal: %s\nreplayed: %s", original, replayed) 129 } 130 } 131 132 // Verify that Vertex and Edge annotations appear in the debug output 133 func TestGraphJSON_debugInfo(t *testing.T) { 134 var g Graph 135 var buf bytes.Buffer 136 g.SetDebugWriter(&buf) 137 138 g.Add(1) 139 g.Add(2) 140 g.Add(3) 141 g.Connect(BasicEdge(1, 2)) 142 143 g.DebugVertexInfo(2, "2") 144 g.DebugVertexInfo(3, "3") 145 g.DebugEdgeInfo(BasicEdge(1, 2), "1|2") 146 147 dec := json.NewDecoder(bytes.NewReader(buf.Bytes())) 148 149 var found2, found3, foundEdge bool 150 for dec.More() { 151 var d streamDecode 152 153 err := dec.Decode(&d) 154 if err != nil { 155 t.Fatal(err) 156 } 157 158 switch d.Type { 159 case "VertexDebugInfo": 160 va := &vertexDebugInfo{} 161 err := json.Unmarshal(d.JSON, va) 162 if err != nil { 163 t.Fatal(err) 164 } 165 166 switch va.Info { 167 case "2": 168 if va.Vertex.Name != "2" { 169 t.Fatalf("wrong vertex annotated 2: %#v", va) 170 } 171 found2 = true 172 case "3": 173 if va.Vertex.Name != "3" { 174 t.Fatalf("wrong vertex annotated 3: %#v", va) 175 } 176 found3 = true 177 default: 178 t.Fatalf("unexpected annotation: %#v", va) 179 } 180 case "EdgeDebugInfo": 181 ea := &edgeDebugInfo{} 182 err := json.Unmarshal(d.JSON, ea) 183 if err != nil { 184 t.Fatal(err) 185 } 186 187 switch ea.Info { 188 case "1|2": 189 if ea.Edge.Name != "1|2" { 190 t.Fatalf("incorrect edge annotation: %#v\n", ea) 191 } 192 foundEdge = true 193 default: 194 t.Fatalf("unexpected edge Info: %#v", ea) 195 } 196 } 197 } 198 199 if !found2 { 200 t.Fatal("annotation 2 not found") 201 } 202 if !found3 { 203 t.Fatal("annotation 3 not found") 204 } 205 if !foundEdge { 206 t.Fatal("edge annotation not found") 207 } 208 } 209 210 // Verify that debug operations appear in the debug output 211 func TestGraphJSON_debugOperations(t *testing.T) { 212 var g Graph 213 var buf bytes.Buffer 214 g.SetDebugWriter(&buf) 215 216 debugOp := g.DebugOperation("AddOne", "adding node 1") 217 g.Add(1) 218 debugOp.End("done adding node 1") 219 220 // use an immediate closure to test defers 221 func() { 222 defer g.DebugOperation("AddTwo", "adding nodes 2 and 3").End("done adding 2 and 3") 223 g.Add(2) 224 defer g.DebugOperation("NestedAddThree", "second defer").End("done adding node 3") 225 g.Add(3) 226 }() 227 228 g.Connect(BasicEdge(1, 2)) 229 230 dec := json.NewDecoder(bytes.NewReader(buf.Bytes())) 231 232 var ops []string 233 for dec.More() { 234 var d streamDecode 235 236 err := dec.Decode(&d) 237 if err != nil { 238 t.Fatal(err) 239 } 240 241 if d.Type != "Operation" { 242 continue 243 } 244 245 o := &marshalOperation{} 246 err = json.Unmarshal(d.JSON, o) 247 if err != nil { 248 t.Fatal(err) 249 } 250 251 switch { 252 case o.Begin == "AddOne": 253 ops = append(ops, "BeginAddOne") 254 case o.End == "AddOne": 255 ops = append(ops, "EndAddOne") 256 case o.Begin == "AddTwo": 257 ops = append(ops, "BeginAddTwo") 258 case o.End == "AddTwo": 259 ops = append(ops, "EndAddTwo") 260 case o.Begin == "NestedAddThree": 261 ops = append(ops, "BeginAddThree") 262 case o.End == "NestedAddThree": 263 ops = append(ops, "EndAddThree") 264 } 265 } 266 267 expectedOps := []string{ 268 "BeginAddOne", 269 "EndAddOne", 270 "BeginAddTwo", 271 "BeginAddThree", 272 "EndAddThree", 273 "EndAddTwo", 274 } 275 276 if strings.Join(ops, ",") != strings.Join(expectedOps, ",") { 277 t.Fatalf("incorrect order of operations: %v", ops) 278 } 279 } 280 281 const testGraphJSONEmptyStr = `{ 282 "Type": "Graph", 283 "Name": "root", 284 "Vertices": [ 285 { 286 "ID": "1", 287 "Name": "1" 288 }, 289 { 290 "ID": "2", 291 "Name": "2" 292 }, 293 { 294 "ID": "3", 295 "Name": "3" 296 } 297 ] 298 }` 299 300 const testGraphJSONBasicStr = `{ 301 "Type": "Graph", 302 "Name": "root", 303 "Vertices": [ 304 { 305 "ID": "1", 306 "Name": "1" 307 }, 308 { 309 "ID": "2", 310 "Name": "2" 311 }, 312 { 313 "ID": "3", 314 "Name": "3" 315 } 316 ], 317 "Edges": [ 318 { 319 "Name": "1|3", 320 "Source": "1", 321 "Target": "3" 322 } 323 ] 324 }`