golang.org/x/arch@v0.17.0/internal/unify/unify_test.go (about) 1 // Copyright 2025 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package unify 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "os" 12 "path/filepath" 13 "slices" 14 "strings" 15 "testing" 16 17 "gopkg.in/yaml.v3" 18 ) 19 20 func TestUnify(t *testing.T) { 21 paths, err := filepath.Glob("testdata/*") 22 if err != nil { 23 t.Fatal(err) 24 } 25 if len(paths) == 0 { 26 t.Fatal("no testdata found") 27 } 28 for _, path := range paths { 29 // Skip paths starting with _ so experimental files can be added. 30 base := filepath.Base(path) 31 if base[0] == '_' { 32 continue 33 } 34 if !strings.HasSuffix(base, ".yaml") { 35 t.Errorf("non-.yaml file in testdata: %s", base) 36 continue 37 } 38 base = strings.TrimSuffix(base, ".yaml") 39 40 t.Run(base, func(t *testing.T) { 41 testUnify(t, path) 42 }) 43 } 44 } 45 46 func testUnify(t *testing.T, path string) { 47 f, err := os.Open(path) 48 if err != nil { 49 t.Fatal(err) 50 } 51 defer f.Close() 52 53 type testCase struct { 54 Skip bool 55 Name string 56 Unify []Closure 57 Want yaml.Node 58 All yaml.Node 59 } 60 dec := yaml.NewDecoder(f) 61 62 for i := 0; ; i++ { 63 var tc testCase 64 err := dec.Decode(&tc) 65 if err == io.EOF { 66 break 67 } 68 if err != nil { 69 t.Fatal(err) 70 } 71 72 name := tc.Name 73 if name == "" { 74 name = fmt.Sprint(i) 75 } 76 77 t.Run(name, func(t *testing.T) { 78 if tc.Skip { 79 t.Skip("skip: true set in test case") 80 } 81 82 defer func() { 83 p := recover() 84 if p != nil || t.Failed() { 85 // Redo with a trace 86 // 87 // TODO: Use t.Output() in Go 1.25. 88 var buf bytes.Buffer 89 Debug.UnifyLog = &buf 90 func() { 91 defer func() { 92 // If the original unify panicked, the second one 93 // probably will, too. Ignore it and let the first panic 94 // bubble. 95 recover() 96 }() 97 Unify(tc.Unify...) 98 }() 99 Debug.UnifyLog = nil 100 t.Logf("Trace:\n%s", buf.String()) 101 } 102 if p != nil { 103 panic(p) 104 } 105 }() 106 107 // Unify the test cases 108 // 109 // TODO: Try reordering the inputs also 110 c, err := Unify(tc.Unify...) 111 if err != nil { 112 // TODO: Tests of errors 113 t.Fatal(err) 114 } 115 116 // Encode the result back to YAML so we can check if it's structurally 117 // equal. 118 clean := func(val any) *yaml.Node { 119 var node yaml.Node 120 node.Encode(val) 121 for n := range allYamlNodes(&node) { 122 // Canonicalize the style. There may be other style flags we need to 123 // muck with. 124 n.Style &^= yaml.FlowStyle 125 n.HeadComment = "" 126 n.LineComment = "" 127 n.FootComment = "" 128 } 129 return &node 130 } 131 check := func(gotVal any, wantNode *yaml.Node) { 132 got, err := yaml.Marshal(clean(gotVal)) 133 if err != nil { 134 t.Fatalf("Encoding Value back to yaml failed: %s", err) 135 } 136 want, err := yaml.Marshal(clean(wantNode)) 137 if err != nil { 138 t.Fatalf("Encoding Want back to yaml failed: %s", err) 139 } 140 141 if !bytes.Equal(got, want) { 142 t.Errorf("%s:%d:\nwant:\n%sgot\n%s", f.Name(), wantNode.Line, want, got) 143 } 144 } 145 if tc.Want.Kind != 0 { 146 check(c.val, &tc.Want) 147 } 148 if tc.All.Kind != 0 { 149 fVal := slices.Collect(c.All()) 150 check(fVal, &tc.All) 151 } 152 }) 153 } 154 }