| // Copyright 2022 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package benchproc |
| |
| import ( |
| "fmt" |
| "strings" |
| "testing" |
| ) |
| |
| func checkKeyHeader(t *testing.T, tree *KeyHeader, want string) { |
| t.Helper() |
| got := renderKeyHeader(tree) |
| if got != want { |
| t.Errorf("want %s\ngot %s", want, got) |
| } |
| |
| // Check the structure of the tree. |
| prevEnd := make([]int, len(tree.Levels)) |
| var walk func(int, *KeyHeaderNode) |
| walk = func(level int, n *KeyHeaderNode) { |
| if n.Field != level { |
| t.Errorf("want level %d, got %d", level, n.Field) |
| } |
| if n.Start != prevEnd[level] { |
| t.Errorf("want start %d, got %d", prevEnd[level], n.Start) |
| } |
| prevEnd[level] = n.Start + n.Len |
| for _, sub := range n.Children { |
| walk(level+1, sub) |
| } |
| } |
| for _, n := range tree.Top { |
| walk(0, n) |
| } |
| // Check that we walked the full span of keys on each level. |
| for level, width := range prevEnd { |
| if width != len(tree.Keys) { |
| t.Errorf("want width %d, got %d at level %d", len(tree.Keys), width, level) |
| } |
| } |
| } |
| |
| func renderKeyHeader(t *KeyHeader) string { |
| buf := new(strings.Builder) |
| var walk func([]*KeyHeaderNode) |
| walk = func(ns []*KeyHeaderNode) { |
| for _, n := range ns { |
| fmt.Fprintf(buf, "\n%s%s:%s", strings.Repeat("\t", n.Field), t.Levels[n.Field], n.Value) |
| walk(n.Children) |
| } |
| } |
| walk(t.Top) |
| return buf.String() |
| } |
| |
| func TestKeyHeader(t *testing.T) { |
| // Test basic merging. |
| t.Run("basic", func(t *testing.T) { |
| s, _ := mustParse(t, ".config") |
| c1 := p(t, s, "", "a", "a1", "b", "b1") |
| c2 := p(t, s, "", "a", "a1", "b", "b2") |
| tree := NewKeyHeader([]Key{c1, c2}) |
| checkKeyHeader(t, tree, ` |
| a:a1 |
| b:b1 |
| b:b2`) |
| }) |
| |
| // Test that higher level differences prevent lower levels |
| // from being merged, even if the lower levels match. |
| t.Run("noMerge", func(t *testing.T) { |
| s, _ := mustParse(t, ".config") |
| c1 := p(t, s, "", "a", "a1", "b", "b1") |
| c2 := p(t, s, "", "a", "a2", "b", "b1") |
| tree := NewKeyHeader([]Key{c1, c2}) |
| checkKeyHeader(t, tree, ` |
| a:a1 |
| b:b1 |
| a:a2 |
| b:b1`) |
| }) |
| |
| // Test mismatched tuple lengths. |
| t.Run("missingValues", func(t *testing.T) { |
| s, _ := mustParse(t, ".config") |
| c1 := p(t, s, "", "a", "a1") |
| c2 := p(t, s, "", "a", "a1", "b", "b1") |
| c3 := p(t, s, "", "a", "a1", "b", "b1", "c", "c1") |
| tree := NewKeyHeader([]Key{c1, c2, c3}) |
| checkKeyHeader(t, tree, ` |
| a:a1 |
| b: |
| c: |
| b:b1 |
| c: |
| c:c1`) |
| }) |
| |
| // Test no Keys. |
| t.Run("none", func(t *testing.T) { |
| tree := NewKeyHeader([]Key{}) |
| if len(tree.Top) != 0 { |
| t.Fatalf("wanted empty tree, got %v", tree) |
| } |
| }) |
| |
| // Test empty Keys. |
| t.Run("empty", func(t *testing.T) { |
| s, _ := mustParse(t, ".config") |
| c1 := p(t, s, "") |
| c2 := p(t, s, "") |
| tree := NewKeyHeader([]Key{c1, c2}) |
| checkKeyHeader(t, tree, "") |
| }) |
| } |