//go:build validatedebug package validate import ( "fmt" "runtime" "sync" "testing" "github.com/go-openapi/spec" ) // This version of the pools is to be used for debugging and testing, with build tag "validatedebug". // // In this mode, the pools are tracked for allocation and redemption of borrowed objects, so we can // verify a few behaviors of the validators. The debug pools panic when an invalid usage pattern is detected. var pools allPools func init() { resetPools() } func resetPools() { // NOTE: for testing purpose, we might want to reset pools after calling Validate twice. // The pool is corrupted in that case: calling Put twice inserts a duplicate in the pool // and further calls to Get are mishandled. pools = allPools{ poolOfSchemaValidators: schemaValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &SchemaValidator{} return s }, }, debugMap: make(map[*SchemaValidator]status), allocMap: make(map[*SchemaValidator]string), redeemMap: make(map[*SchemaValidator]string), }, poolOfObjectValidators: objectValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &objectValidator{} return s }, }, debugMap: make(map[*objectValidator]status), allocMap: make(map[*objectValidator]string), redeemMap: make(map[*objectValidator]string), }, poolOfSliceValidators: sliceValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &schemaSliceValidator{} return s }, }, debugMap: make(map[*schemaSliceValidator]status), allocMap: make(map[*schemaSliceValidator]string), redeemMap: make(map[*schemaSliceValidator]string), }, poolOfItemsValidators: itemsValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &itemsValidator{} return s }, }, debugMap: make(map[*itemsValidator]status), allocMap: make(map[*itemsValidator]string), redeemMap: make(map[*itemsValidator]string), }, poolOfBasicCommonValidators: basicCommonValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &basicCommonValidator{} return s }, }, debugMap: make(map[*basicCommonValidator]status), allocMap: make(map[*basicCommonValidator]string), redeemMap: make(map[*basicCommonValidator]string), }, poolOfHeaderValidators: headerValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &HeaderValidator{} return s }, }, debugMap: make(map[*HeaderValidator]status), allocMap: make(map[*HeaderValidator]string), redeemMap: make(map[*HeaderValidator]string), }, poolOfParamValidators: paramValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &ParamValidator{} return s }, }, debugMap: make(map[*ParamValidator]status), allocMap: make(map[*ParamValidator]string), redeemMap: make(map[*ParamValidator]string), }, poolOfBasicSliceValidators: basicSliceValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &basicSliceValidator{} return s }, }, debugMap: make(map[*basicSliceValidator]status), allocMap: make(map[*basicSliceValidator]string), redeemMap: make(map[*basicSliceValidator]string), }, poolOfNumberValidators: numberValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &numberValidator{} return s }, }, debugMap: make(map[*numberValidator]status), allocMap: make(map[*numberValidator]string), redeemMap: make(map[*numberValidator]string), }, poolOfStringValidators: stringValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &stringValidator{} return s }, }, debugMap: make(map[*stringValidator]status), allocMap: make(map[*stringValidator]string), redeemMap: make(map[*stringValidator]string), }, poolOfSchemaPropsValidators: schemaPropsValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &schemaPropsValidator{} return s }, }, debugMap: make(map[*schemaPropsValidator]status), allocMap: make(map[*schemaPropsValidator]string), redeemMap: make(map[*schemaPropsValidator]string), }, poolOfFormatValidators: formatValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &formatValidator{} return s }, }, debugMap: make(map[*formatValidator]status), allocMap: make(map[*formatValidator]string), redeemMap: make(map[*formatValidator]string), }, poolOfTypeValidators: typeValidatorsPool{ Pool: &sync.Pool{ New: func() any { s := &typeValidator{} return s }, }, debugMap: make(map[*typeValidator]status), allocMap: make(map[*typeValidator]string), redeemMap: make(map[*typeValidator]string), }, poolOfSchemas: schemasPool{ Pool: &sync.Pool{ New: func() any { s := &spec.Schema{} return s }, }, debugMap: make(map[*spec.Schema]status), allocMap: make(map[*spec.Schema]string), redeemMap: make(map[*spec.Schema]string), }, poolOfResults: resultsPool{ Pool: &sync.Pool{ New: func() any { s := &Result{} return s }, }, debugMap: make(map[*Result]status), allocMap: make(map[*Result]string), redeemMap: make(map[*Result]string), }, } } const ( statusFresh status = iota + 1 statusRecycled statusRedeemed ) func (s status) String() string { switch s { case statusFresh: return "fresh" case statusRecycled: return "recycled" case statusRedeemed: return "redeemed" default: panic(fmt.Errorf("invalid status: %d", s)) } } type ( // Debug status uint8 allPools struct { // memory pools for all validator objects. // // Each pool can be borrowed from and redeemed to. poolOfSchemaValidators schemaValidatorsPool poolOfObjectValidators objectValidatorsPool poolOfSliceValidators sliceValidatorsPool poolOfItemsValidators itemsValidatorsPool poolOfBasicCommonValidators basicCommonValidatorsPool poolOfHeaderValidators headerValidatorsPool poolOfParamValidators paramValidatorsPool poolOfBasicSliceValidators basicSliceValidatorsPool poolOfNumberValidators numberValidatorsPool poolOfStringValidators stringValidatorsPool poolOfSchemaPropsValidators schemaPropsValidatorsPool poolOfFormatValidators formatValidatorsPool poolOfTypeValidators typeValidatorsPool poolOfSchemas schemasPool poolOfResults resultsPool } schemaValidatorsPool struct { *sync.Pool debugMap map[*SchemaValidator]status allocMap map[*SchemaValidator]string redeemMap map[*SchemaValidator]string mx sync.Mutex } objectValidatorsPool struct { *sync.Pool debugMap map[*objectValidator]status allocMap map[*objectValidator]string redeemMap map[*objectValidator]string mx sync.Mutex } sliceValidatorsPool struct { *sync.Pool debugMap map[*schemaSliceValidator]status allocMap map[*schemaSliceValidator]string redeemMap map[*schemaSliceValidator]string mx sync.Mutex } itemsValidatorsPool struct { *sync.Pool debugMap map[*itemsValidator]status allocMap map[*itemsValidator]string redeemMap map[*itemsValidator]string mx sync.Mutex } basicCommonValidatorsPool struct { *sync.Pool debugMap map[*basicCommonValidator]status allocMap map[*basicCommonValidator]string redeemMap map[*basicCommonValidator]string mx sync.Mutex } headerValidatorsPool struct { *sync.Pool debugMap map[*HeaderValidator]status allocMap map[*HeaderValidator]string redeemMap map[*HeaderValidator]string mx sync.Mutex } paramValidatorsPool struct { *sync.Pool debugMap map[*ParamValidator]status allocMap map[*ParamValidator]string redeemMap map[*ParamValidator]string mx sync.Mutex } basicSliceValidatorsPool struct { *sync.Pool debugMap map[*basicSliceValidator]status allocMap map[*basicSliceValidator]string redeemMap map[*basicSliceValidator]string mx sync.Mutex } numberValidatorsPool struct { *sync.Pool debugMap map[*numberValidator]status allocMap map[*numberValidator]string redeemMap map[*numberValidator]string mx sync.Mutex } stringValidatorsPool struct { *sync.Pool debugMap map[*stringValidator]status allocMap map[*stringValidator]string redeemMap map[*stringValidator]string mx sync.Mutex } schemaPropsValidatorsPool struct { *sync.Pool debugMap map[*schemaPropsValidator]status allocMap map[*schemaPropsValidator]string redeemMap map[*schemaPropsValidator]string mx sync.Mutex } formatValidatorsPool struct { *sync.Pool debugMap map[*formatValidator]status allocMap map[*formatValidator]string redeemMap map[*formatValidator]string mx sync.Mutex } typeValidatorsPool struct { *sync.Pool debugMap map[*typeValidator]status allocMap map[*typeValidator]string redeemMap map[*typeValidator]string mx sync.Mutex } schemasPool struct { *sync.Pool debugMap map[*spec.Schema]status allocMap map[*spec.Schema]string redeemMap map[*spec.Schema]string mx sync.Mutex } resultsPool struct { *sync.Pool debugMap map[*Result]status allocMap map[*Result]string redeemMap map[*Result]string mx sync.Mutex } ) func (p *schemaValidatorsPool) BorrowValidator() *SchemaValidator { s := p.Get().(*SchemaValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled schema should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *schemaValidatorsPool) RedeemValidator(s *SchemaValidator) { // NOTE: s might be nil. In that case, Put is a noop. p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed schema should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed schema should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *objectValidatorsPool) BorrowValidator() *objectValidator { s := p.Get().(*objectValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled object should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *objectValidatorsPool) RedeemValidator(s *objectValidator) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed object should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed object should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *sliceValidatorsPool) BorrowValidator() *schemaSliceValidator { s := p.Get().(*schemaSliceValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled schemaSliceValidator should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *sliceValidatorsPool) RedeemValidator(s *schemaSliceValidator) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed schemaSliceValidator should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed schemaSliceValidator should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *itemsValidatorsPool) BorrowValidator() *itemsValidator { s := p.Get().(*itemsValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled itemsValidator should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *itemsValidatorsPool) RedeemValidator(s *itemsValidator) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed itemsValidator should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed itemsValidator should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *basicCommonValidatorsPool) BorrowValidator() *basicCommonValidator { s := p.Get().(*basicCommonValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled basicCommonValidator should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *basicCommonValidatorsPool) RedeemValidator(s *basicCommonValidator) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed basicCommonValidator should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed basicCommonValidator should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *headerValidatorsPool) BorrowValidator() *HeaderValidator { s := p.Get().(*HeaderValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled HeaderValidator should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *headerValidatorsPool) RedeemValidator(s *HeaderValidator) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed header should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed header should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *paramValidatorsPool) BorrowValidator() *ParamValidator { s := p.Get().(*ParamValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled param should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *paramValidatorsPool) RedeemValidator(s *ParamValidator) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed param should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed param should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *basicSliceValidatorsPool) BorrowValidator() *basicSliceValidator { s := p.Get().(*basicSliceValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled basicSliceValidator should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *basicSliceValidatorsPool) RedeemValidator(s *basicSliceValidator) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed basicSliceValidator should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed basicSliceValidator should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *numberValidatorsPool) BorrowValidator() *numberValidator { s := p.Get().(*numberValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled number should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *numberValidatorsPool) RedeemValidator(s *numberValidator) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed number should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed number should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *stringValidatorsPool) BorrowValidator() *stringValidator { s := p.Get().(*stringValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled string should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *stringValidatorsPool) RedeemValidator(s *stringValidator) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed string should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed string should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *schemaPropsValidatorsPool) BorrowValidator() *schemaPropsValidator { s := p.Get().(*schemaPropsValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled param should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *schemaPropsValidatorsPool) RedeemValidator(s *schemaPropsValidator) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed schemaProps should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed schemaProps should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *formatValidatorsPool) BorrowValidator() *formatValidator { s := p.Get().(*formatValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled format should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *formatValidatorsPool) RedeemValidator(s *formatValidator) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed format should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed format should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *typeValidatorsPool) BorrowValidator() *typeValidator { s := p.Get().(*typeValidator) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled type should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *typeValidatorsPool) RedeemValidator(s *typeValidator) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed type should have been allocated") } if x != statusRecycled && x != statusFresh { panic(fmt.Errorf("redeemed type should have been allocated from a fresh or recycled pointer. Got status %s, already redeamed at: %s", x, p.redeemMap[s])) } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *schemasPool) BorrowSchema() *spec.Schema { s := p.Get().(*spec.Schema) p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled spec.Schema should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *schemasPool) RedeemSchema(s *spec.Schema) { p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed spec.Schema should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed spec.Schema should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *resultsPool) BorrowResult() *Result { s := p.Get().(*Result).cleared() p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { p.debugMap[s] = statusFresh } else { if x != statusRedeemed { panic("recycled result should have been redeemed") } p.debugMap[s] = statusRecycled } p.allocMap[s] = caller() return s } func (p *resultsPool) RedeemResult(s *Result) { if s == emptyResult { if len(s.Errors) > 0 || len(s.Warnings) > 0 { panic("empty result should not mutate") } return } p.mx.Lock() defer p.mx.Unlock() x, ok := p.debugMap[s] if !ok { panic("redeemed Result should have been allocated") } if x != statusRecycled && x != statusFresh { panic("redeemed Result should have been allocated from a fresh or recycled pointer") } p.debugMap[s] = statusRedeemed p.redeemMap[s] = caller() p.Put(s) } func (p *allPools) allIsRedeemed(t testing.TB) bool { outcome := true for k, v := range p.poolOfSchemaValidators.debugMap { if v == statusRedeemed { continue } t.Logf("schemaValidator should be redeemed. Allocated by: %s", p.poolOfSchemaValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfObjectValidators.debugMap { if v == statusRedeemed { continue } t.Logf("objectValidator should be redeemed. Allocated by: %s", p.poolOfObjectValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfSliceValidators.debugMap { if v == statusRedeemed { continue } t.Logf("sliceValidator should be redeemed. Allocated by: %s", p.poolOfSliceValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfItemsValidators.debugMap { if v == statusRedeemed { continue } t.Logf("itemsValidator should be redeemed. Allocated by: %s", p.poolOfItemsValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfBasicCommonValidators.debugMap { if v == statusRedeemed { continue } t.Logf("basicCommonValidator should be redeemed. Allocated by: %s", p.poolOfBasicCommonValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfHeaderValidators.debugMap { if v == statusRedeemed { continue } t.Logf("headerValidator should be redeemed. Allocated by: %s", p.poolOfHeaderValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfParamValidators.debugMap { if v == statusRedeemed { continue } t.Logf("paramValidator should be redeemed. Allocated by: %s", p.poolOfParamValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfBasicSliceValidators.debugMap { if v == statusRedeemed { continue } t.Logf("basicSliceValidator should be redeemed. Allocated by: %s", p.poolOfBasicSliceValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfNumberValidators.debugMap { if v == statusRedeemed { continue } t.Logf("numberValidator should be redeemed. Allocated by: %s", p.poolOfNumberValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfStringValidators.debugMap { if v == statusRedeemed { continue } t.Logf("stringValidator should be redeemed. Allocated by: %s", p.poolOfStringValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfSchemaPropsValidators.debugMap { if v == statusRedeemed { continue } t.Logf("schemaPropsValidator should be redeemed. Allocated by: %s", p.poolOfSchemaPropsValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfFormatValidators.debugMap { if v == statusRedeemed { continue } t.Logf("formatValidator should be redeemed. Allocated by: %s", p.poolOfFormatValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfTypeValidators.debugMap { if v == statusRedeemed { continue } t.Logf("typeValidator should be redeemed. Allocated by: %s", p.poolOfTypeValidators.allocMap[k]) outcome = false } for k, v := range p.poolOfSchemas.debugMap { if v == statusRedeemed { continue } t.Logf("schemas should be redeemed. Allocated by: %s", p.poolOfSchemas.allocMap[k]) outcome = false } for k, v := range p.poolOfResults.debugMap { if v == statusRedeemed { continue } t.Logf("result should be redeemed. Allocated by: %s", p.poolOfResults.allocMap[k]) outcome = false } return outcome } func caller() string { pc, _, _, _ := runtime.Caller(3) //nolint:dogsled from, line := runtime.FuncForPC(pc).FileLine(pc) return fmt.Sprintf("%s:%d", from, line) }