blob: 9fce3cf10efed656f608779910459429212f6456 [file] [log] [blame]
// 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{
{100, "ns/op", 100e-9, "sec/op"},
{100, "B/op", 0, ""},
}
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)
}