...

Source file src/github.com/growthbook/growthbook-golang/test_utils.go

Documentation: github.com/growthbook/growthbook-golang

     1  package growthbook
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"strings"
     7  	"testing"
     8  )
     9  
    10  // Some test functions generate warnings in the log. We need to check
    11  // the expected ones, and not miss any unexpected ones.
    12  
    13  func handleExpectedWarnings(
    14  	t *testing.T, test []interface{}, expectedWarnings map[string]int) {
    15  	name, ok := test[0].(string)
    16  	if !ok {
    17  		t.Errorf("can't extract test name!")
    18  	}
    19  	warnings, ok := expectedWarnings[name]
    20  	if ok {
    21  		if len(testLog.errors) == 0 && len(testLog.warnings) == warnings {
    22  			testLog.reset()
    23  		} else {
    24  			t.Errorf("expected log warning")
    25  		}
    26  	}
    27  }
    28  
    29  // Helper to round variation ranges for comparison with fixed test
    30  // values.
    31  func roundRanges(ranges []Range) []Range {
    32  	result := make([]Range, len(ranges))
    33  	for i, r := range ranges {
    34  		rmin := math.Round(r.Min*1000000) / 1000000
    35  		rmax := math.Round(r.Max*1000000) / 1000000
    36  		result[i] = Range{rmin, rmax}
    37  	}
    38  	return result
    39  }
    40  
    41  // Helper to round floating point arrays for test comparison.
    42  func round(vals []float64) []float64 {
    43  	result := make([]float64, len(vals))
    44  	for i, v := range vals {
    45  		result[i] = math.Round(v*1000000) / 1000000
    46  	}
    47  	return result
    48  }
    49  
    50  // Logger to capture error and log messages.
    51  type testLogger struct {
    52  	errors   []string
    53  	warnings []string
    54  	info     []string
    55  }
    56  
    57  var testLog = testLogger{}
    58  
    59  func (log *testLogger) allErrors() string {
    60  	return strings.Join(log.errors, ", ")
    61  }
    62  
    63  func (log *testLogger) allWarnings() string {
    64  	return strings.Join(log.warnings, ", ")
    65  }
    66  
    67  func (log *testLogger) allInfo() string {
    68  	return strings.Join(log.info, ", ")
    69  }
    70  
    71  func (log *testLogger) reset() {
    72  	log.errors = []string{}
    73  	log.warnings = []string{}
    74  	log.info = []string{}
    75  }
    76  
    77  func formatArgs(args ...interface{}) string {
    78  	s := ""
    79  	for i, a := range args {
    80  		if i != 0 {
    81  			s += " "
    82  		}
    83  		s += fmt.Sprint(a)
    84  	}
    85  	return s
    86  }
    87  
    88  func (log *testLogger) Error(msg string, args ...interface{}) {
    89  	s := msg
    90  	if len(args) > 0 {
    91  		s += ": " + formatArgs(args...)
    92  	}
    93  	log.errors = append(log.errors, s)
    94  }
    95  
    96  func (log *testLogger) Errorf(format string, args ...interface{}) {
    97  	s := fmt.Sprintf(format, args...)
    98  	log.errors = append(log.errors, s)
    99  }
   100  
   101  func (log *testLogger) Warn(msg string, args ...interface{}) {
   102  	s := msg
   103  	if len(args) > 0 {
   104  		s += ": " + formatArgs(args...)
   105  	}
   106  	log.warnings = append(log.warnings, s)
   107  }
   108  
   109  func (log *testLogger) Warnf(format string, args ...interface{}) {
   110  	s := fmt.Sprintf(format, args...)
   111  	log.warnings = append(log.warnings, s)
   112  }
   113  
   114  func (log *testLogger) Info(msg string, args ...interface{}) {
   115  	s := msg
   116  	if len(args) > 0 {
   117  		s += ": " + fmt.Sprint(args...)
   118  	}
   119  	log.info = append(log.info, s)
   120  }
   121  
   122  func (log *testLogger) Infof(format string, args ...interface{}) {
   123  	s := fmt.Sprintf(format, args...)
   124  	log.info = append(log.info, s)
   125  }
   126  
   127  // Polyfill from Go v1.20 sort.
   128  
   129  func sortFind(n int, cmp func(int) int) (i int, found bool) {
   130  	// The invariants here are similar to the ones in Search.
   131  	// Define cmp(-1) > 0 and cmp(n) <= 0
   132  	// Invariant: cmp(i-1) > 0, cmp(j) <= 0
   133  	i, j := 0, n
   134  	for i < j {
   135  		h := int(uint(i+j) >> 1) // avoid overflow when computing h
   136  		// i ≤ h < j
   137  		if cmp(h) > 0 {
   138  			i = h + 1 // preserves cmp(i-1) > 0
   139  		} else {
   140  			j = h // preserves cmp(j) <= 0
   141  		}
   142  	}
   143  	// i == j, cmp(i-1) > 0 and cmp(j) <= 0
   144  	return i, i < n && cmp(i) == 0
   145  }
   146  

View as plain text