| // 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" | |
| "testing" | |
| "golang.org/x/perf/benchfmt" | |
| ) | |
| func TestFilter(t *testing.T) { | |
| res := r(t, "Name/n1=v3", "f1", "v1", "f2", "v2") | |
| res.Values = []benchfmt.Value{ | |
| {Value: 100, Unit: "ns/op", OrigValue: 100e-9, OrigUnit: "sec/op"}, | |
| {Value: 100, Unit: "B/op", OrigValue: 0, OrigUnit: ""}, | |
| } | |
| const ALL = 0b11 | |
| const NONE = 0 | |
| check := func(t *testing.T, query string, want uint) { | |
| t.Helper() | |
| f, err := NewFilter(query) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| m, _ := f.Match(res) | |
| var got uint | |
| for i := 0; i < 2; i++ { | |
| if m.Test(i) { | |
| got |= 1 << i | |
| } | |
| } | |
| if got != want { | |
| t.Errorf("%s: got %02b, want %02b", query, got, want) | |
| } else if want == ALL && !m.All() { | |
| t.Errorf("%s: want All", query) | |
| } else if want == 0 && m.Any() { | |
| t.Errorf("%s: want !Any", query) | |
| } | |
| } | |
| t.Run("basic", func(t *testing.T) { | |
| // File keys | |
| check(t, "f1:v1", ALL) | |
| check(t, "f1:v2", NONE) | |
| // Name keys | |
| check(t, "/n1:v3", ALL) | |
| // Special keys | |
| check(t, ".name:Name", ALL) | |
| check(t, ".fullname:Name/n1=v3", ALL) | |
| }) | |
| t.Run("units", func(t *testing.T) { | |
| check(t, ".unit:ns/op", 0b01) // Base unit | |
| check(t, ".unit:sec/op", 0b01) // Tidied unit | |
| check(t, ".unit:B/op", 0b10) | |
| check(t, ".unit:foo", 0b00) | |
| }) | |
| t.Run("boolean", func(t *testing.T) { | |
| check(t, "*", ALL) | |
| check(t, "f1:v1 OR f1:v2", ALL) | |
| check(t, "f1:v1 AND f1:v2", NONE) | |
| check(t, "f1:v1 f1:v2", NONE) | |
| check(t, "f1:v1 f2:v2", ALL) | |
| check(t, "-f1:v1", NONE) | |
| check(t, "--f1:v1", ALL) | |
| check(t, ".unit:(ns/op OR B/op)", 0b11) | |
| }) | |
| t.Run("manyUnits", func(t *testing.T) { | |
| res := res.Clone() | |
| res.Values = make([]benchfmt.Value, 100) | |
| for i := range res.Values { | |
| res.Values[i].Unit = fmt.Sprintf("u%d", i) | |
| } | |
| // Test large unit matches through all operators. | |
| f, err := NewFilter("f1:v1 AND --(f1:v2 OR .unit:(u0 OR u99))") | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| m, _ := f.Match(res) | |
| for i := 0; i < 100; i++ { | |
| got := m.Test(i) | |
| want := i == 0 || i == 99 | |
| if got != want { | |
| t.Errorf("for unit u%d, got %v, want %v", i, got, want) | |
| } | |
| } | |
| }) | |
| } | |
| func TestMatch(t *testing.T) { | |
| check := func(m Match, all, any bool) { | |
| t.Helper() | |
| if m.All() != all { | |
| t.Errorf("match %+v: All should be %v, got %v", m, all, !all) | |
| } | |
| if m.Any() != any { | |
| t.Errorf("match %+v: Any should be %v, got %v", m, any, !any) | |
| } | |
| if m.Test(-1) { | |
| t.Errorf("match %+v: Test(-1) should be false, got true", m) | |
| } | |
| if m.Test(m.n + 1) { | |
| t.Errorf("match %+v: Test(%v) should be false, got true", m, m.n+1) | |
| } | |
| } | |
| // Check nil mask. | |
| m := Match{n: 4, x: false} | |
| check(m, false, false) | |
| m = Match{n: 4, x: true} | |
| check(m, true, true) | |
| // Check mask with some bits set. | |
| m = Match{n: 4, m: []uint32{0x1}} | |
| check(m, false, true) | |
| m = Match{n: 1, m: []uint32{0x1}} | |
| check(m, true, true) | |
| // Check that we ignore zeroed bits above n. | |
| m = Match{n: 4, m: []uint32{0xf}} | |
| check(m, true, true) | |
| // Check that we ignore set bits above n. | |
| m = Match{n: 4, m: []uint32{0xfffffff0}} | |
| check(m, false, false) | |
| } |