bson/internal/assert/assertion_mongo.go
2025-03-17 20:58:26 +01:00

127 lines
3.2 KiB
Go

// Copyright (C) MongoDB, Inc. 2023-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// assertion_mongo.go contains MongoDB-specific extensions to the "assert"
// package.
package assert
import (
"context"
"fmt"
"reflect"
"time"
"unsafe"
)
// DifferentAddressRanges asserts that two byte slices reference distinct memory
// address ranges, meaning they reference different underlying byte arrays.
func DifferentAddressRanges(t TestingT, a, b []byte) (ok bool) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if len(a) == 0 || len(b) == 0 {
return true
}
// Find the start and end memory addresses for the underlying byte array for
// each input byte slice.
sliceAddrRange := func(b []byte) (uintptr, uintptr) {
sh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
return sh.Data, sh.Data + uintptr(sh.Cap-1)
}
aStart, aEnd := sliceAddrRange(a)
bStart, bEnd := sliceAddrRange(b)
// If "b" starts after "a" ends or "a" starts after "b" ends, there is no
// overlap.
if bStart > aEnd || aStart > bEnd {
return true
}
// Otherwise, calculate the overlap start and end and print the memory
// overlap error message.
min := func(a, b uintptr) uintptr {
if a < b {
return a
}
return b
}
max := func(a, b uintptr) uintptr {
if a > b {
return a
}
return b
}
overlapLow := max(aStart, bStart)
overlapHigh := min(aEnd, bEnd)
t.Errorf("Byte slices point to the same underlying byte array:\n"+
"\ta addresses:\t%d ... %d\n"+
"\tb addresses:\t%d ... %d\n"+
"\toverlap:\t%d ... %d",
aStart, aEnd,
bStart, bEnd,
overlapLow, overlapHigh)
return false
}
// EqualBSON asserts that the expected and actual BSON binary values are equal.
// If the values are not equal, it prints both the binary and Extended JSON diff
// of the BSON values. The provided BSON value types must implement the
// fmt.Stringer interface.
func EqualBSON(t TestingT, expected, actual interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Equal(t,
expected,
actual,
`expected and actual BSON values do not match
As Extended JSON:
Expected: %s
Actual : %s`,
expected.(fmt.Stringer).String(),
actual.(fmt.Stringer).String())
}
// Soon runs the provided callback and fails the passed-in test if the callback
// does not complete within timeout. The provided callback should respect the
// passed-in context and cease execution when it has expired.
//
// Deprecated: This function will be removed with GODRIVER-2667, use
// assert.Eventually instead.
func Soon(t TestingT, callback func(ctx context.Context), timeout time.Duration) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
// Create context to manually cancel callback after Soon assertion.
callbackCtx, cancel := context.WithCancel(context.Background())
defer cancel()
done := make(chan struct{})
fullCallback := func() {
callback(callbackCtx)
done <- struct{}{}
}
timer := time.NewTimer(timeout)
defer timer.Stop()
go fullCallback()
select {
case <-done:
return
case <-timer.C:
t.Errorf("timed out in %s waiting for callback", timeout)
}
}