| // Copyright 2018 The Fuchsia 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 catapult_test |
| |
| import ( |
| "math" |
| "reflect" |
| "testing" |
| |
| "fuchsia.googlesource.com/infra/infra/catapult" |
| ) |
| |
| // Expects NewLinearBoundaries to return an error when called with the given |
| // arguments. |
| func expectCreationFailure(t *testing.T, centralBinCount uint, min float64, max float64) { |
| if _, err := catapult.NewLinearBinBoundaries(centralBinCount, min, max); err == nil { |
| t.Errorf("expected an error, given (centralBinCount,min,max)=(%v,%v,%v). "+ |
| "Error was nil.", centralBinCount, min, max) |
| } |
| } |
| |
| // Expects GetBinIndex to return the given index for the given value. |
| func expectBinIndex(t *testing.T, bb *catapult.BinBoundaries, index uint, value float64) { |
| if actualBin := bb.GetBinIndex(value); actualBin != index { |
| t.Errorf("expected bin %v for %v with boundaries: %v Got bin %v", |
| index, value, bb.GetBoundaries(), actualBin) |
| } |
| } |
| |
| // Expects BinBoundaries created from the given centralBinCount, min, and max to have |
| // the given boundaries. |
| func expectBoundaries(t *testing.T, centralBinCount uint, min float64, max float64, boundaries []float64) { |
| bb, err := catapult.NewLinearBinBoundaries(centralBinCount, min, max) |
| if err != nil { |
| t.Errorf("failed to create BinBoundaries %v", err) |
| } |
| |
| actualBoundaries := bb.GetBoundaries() |
| if !reflect.DeepEqual(actualBoundaries, boundaries) { |
| t.Errorf("expected boundaries %v. Got %v", boundaries, actualBoundaries) |
| } |
| } |
| |
| func TestNewLinearBinBoundaries(t *testing.T) { |
| t.Run("should err when given centralBinCount < 1", func(t *testing.T) { |
| expectCreationFailure(t, 0, math.Inf(1), math.Inf(-1)) |
| }) |
| |
| t.Run("should err when min >= max", func(t *testing.T) { |
| centralBinCount := uint(10) |
| expectCreationFailure(t, centralBinCount, 4, 4) |
| expectCreationFailure(t, centralBinCount, 5, 4) |
| }) |
| |
| t.Run("should return BinBoundaries", func(t *testing.T) { |
| bb, err := catapult.NewLinearBinBoundaries(10, 20, 30) |
| if err != nil || bb == nil { |
| t.Errorf("expected BinBoundaries. Got %v and error: %v", |
| bb, err) |
| } |
| }) |
| } |
| |
| func TestBinBoundaries_GetBin_Linear(t *testing.T) { |
| t.Run("centralBinCount=1", func(t *testing.T) { |
| // We're using 1 central bin with a min and max of 0 and 10. Our bins |
| // should consist of an underflow bin, a central bin and an overflow bin |
| // with the following shape: |
| // |
| // 0 10 |
| // | | |
| // | | |
| // -Inf <-------|---------|--------> Inf |
| // : underflow : central : overflow : |
| // : bin : bin : bin : |
| bb, err := catapult.NewLinearBinBoundaries(1, 0, 10) |
| if err != nil { |
| t.Errorf("failed to create BinBoundaries %v", err) |
| } |
| |
| // Constant bin indices for our boundaries. |
| const underflow, central, overflow uint = 0, 1, 2 |
| |
| // Values <0 belong in underflow bin |
| t.Run("underflow bin", func(t *testing.T) { |
| expectBinIndex(t, bb, underflow, -100) |
| expectBinIndex(t, bb, underflow, -1) |
| expectBinIndex(t, bb, underflow, -1e-10) |
| }) |
| // Values >=0 and <10 belong in central bin |
| t.Run("central bin", func(t *testing.T) { |
| expectBinIndex(t, bb, central, 0) |
| expectBinIndex(t, bb, central, 7) |
| expectBinIndex(t, bb, central, 9.9999) |
| }) |
| // Values >=10 belong in overflow bin |
| t.Run("overflow bin", func(t *testing.T) { |
| expectBinIndex(t, bb, overflow, 10) |
| expectBinIndex(t, bb, overflow, 10.000000001) |
| expectBinIndex(t, bb, overflow, 100) |
| }) |
| }) |
| |
| t.Run("centralBinCount>1", func(t *testing.T) { |
| // We're using 2 central bins with a min and max of 7 and 14. Our bins |
| // should consist of an underflow bin, a central bin and an overflow bin |
| // bin with the following shape: |
| // |
| // 7 10.5 14 |
| // | | | |
| // | | | |
| // -Inf <-------|---------|--------|--------> Inf |
| // : underflow : central :central : overflow : |
| // : bin : bin0 : bin1 : bin : |
| bb, err := catapult.NewLinearBinBoundaries(2, 7, 14) |
| if err != nil { |
| t.Errorf("failed to create BinBoundaries %v", err) |
| } |
| |
| // Constant bin indices for our boundaries. |
| const underflow, central0, central1, overflow uint = 0, 1, 2, 3 |
| |
| // Values <7 belong in underflow bin |
| t.Run("underflow bin", func(t *testing.T) { |
| expectBinIndex(t, bb, underflow, -99999) |
| expectBinIndex(t, bb, underflow, 0) |
| expectBinIndex(t, bb, underflow, 4) |
| expectBinIndex(t, bb, underflow, 6.999999999) |
| }) |
| // Values >=7 and <10.5 belong in first central bin |
| t.Run("first central bin", func(t *testing.T) { |
| expectBinIndex(t, bb, central0, 7) |
| expectBinIndex(t, bb, central0, 7.0000000001) |
| expectBinIndex(t, bb, central0, 9) |
| expectBinIndex(t, bb, central0, 10.499999999999) |
| }) |
| // Values >=10.5 and < 14 belong in second central bin |
| t.Run("second central bin", func(t *testing.T) { |
| expectBinIndex(t, bb, central1, 10.5) |
| expectBinIndex(t, bb, central1, 10.500000000001) |
| expectBinIndex(t, bb, central1, 12) |
| expectBinIndex(t, bb, central1, 13.99999999999) |
| }) |
| // Values >=14 belong in overflow bin |
| t.Run("third central bin", func(t *testing.T) { |
| expectBinIndex(t, bb, overflow, 14) |
| expectBinIndex(t, bb, overflow, 14.000000001) |
| expectBinIndex(t, bb, overflow, 10000) |
| }) |
| }) |
| } |
| |
| func TestBinBoundaries_GetBoundaries(t *testing.T) { |
| t.Run("centralBinCount==1", func(t *testing.T) { |
| expectBoundaries(t, 1, -3, 3, []float64{-3, 3}) |
| expectBoundaries(t, 1, 1e-5, 1e-4, []float64{1e-5, 1e-4}) |
| }) |
| t.Run("centralBinCount>1", func(t *testing.T) { |
| expectBoundaries(t, 2, -100, 10, []float64{-100, -45, 10}) |
| expectBoundaries(t, 3, 0, 20, []float64{0, 20.0 / 3, 40.0 / 3, 20}) |
| }) |
| } |
| |
| func TestBinBoundaries_BinCount(t *testing.T) { |
| centralBinCount := uint(123) |
| bb, err := catapult.NewLinearBinBoundaries(centralBinCount, 0, 1) |
| if err != nil { |
| t.Errorf("failed to create BinBoundaries %v", err) |
| } |
| |
| actualCount := bb.BinCount() |
| if actualCount != centralBinCount+2 { |
| t.Errorf("expect bin count %v. Got %v", centralBinCount, actualCount) |
| } |
| } |