Path: blob/main/vendor/github.com/onsi/gomega/matchers/have_exact_elements.go
2880 views
package matchers12import (3"fmt"4"reflect"56"github.com/onsi/gomega/format"7"github.com/onsi/gomega/matchers/internal/miter"8)910type mismatchFailure struct {11failure string12index int13}1415type HaveExactElementsMatcher struct {16Elements []any17mismatchFailures []mismatchFailure18missingIndex int19extraIndex int20}2122func (matcher *HaveExactElementsMatcher) Match(actual any) (success bool, err error) {23matcher.resetState()2425if isMap(actual) || miter.IsSeq2(actual) {26return false, fmt.Errorf("HaveExactElements matcher doesn't work on map or iter.Seq2. Got:\n%s", format.Object(actual, 1))27}2829matchers := matchers(matcher.Elements)30lenMatchers := len(matchers)3132success = true3334if miter.IsIter(actual) {35// In the worst case, we need to see everything before we can give our36// verdict. The only exception is fast fail.37i := 038miter.IterateV(actual, func(v reflect.Value) bool {39if i >= lenMatchers {40// the iterator produces more values than we got matchers: this41// is not good.42matcher.extraIndex = i43success = false44return false45}4647elemMatcher := matchers[i].(omegaMatcher)48match, err := elemMatcher.Match(v.Interface())49if err != nil {50matcher.mismatchFailures = append(matcher.mismatchFailures, mismatchFailure{51index: i,52failure: err.Error(),53})54success = false55} else if !match {56matcher.mismatchFailures = append(matcher.mismatchFailures, mismatchFailure{57index: i,58failure: elemMatcher.FailureMessage(v.Interface()),59})60success = false61}62i++63return true64})65if i < len(matchers) {66// the iterator produced less values than we got matchers: this is67// no good, no no no.68matcher.missingIndex = i69success = false70}71return success, nil72}7374values := valuesOf(actual)75lenValues := len(values)7677for i := 0; i < lenMatchers || i < lenValues; i++ {78if i >= lenMatchers {79matcher.extraIndex = i80success = false81continue82}8384if i >= lenValues {85matcher.missingIndex = i86success = false87return88}8990elemMatcher := matchers[i].(omegaMatcher)91match, err := elemMatcher.Match(values[i])92if err != nil {93matcher.mismatchFailures = append(matcher.mismatchFailures, mismatchFailure{94index: i,95failure: err.Error(),96})97success = false98} else if !match {99matcher.mismatchFailures = append(matcher.mismatchFailures, mismatchFailure{100index: i,101failure: elemMatcher.FailureMessage(values[i]),102})103success = false104}105}106107return success, nil108}109110func (matcher *HaveExactElementsMatcher) FailureMessage(actual any) (message string) {111message = format.Message(actual, "to have exact elements with", presentable(matcher.Elements))112if matcher.missingIndex > 0 {113message = fmt.Sprintf("%s\nthe missing elements start from index %d", message, matcher.missingIndex)114}115if matcher.extraIndex > 0 {116message = fmt.Sprintf("%s\nthe extra elements start from index %d", message, matcher.extraIndex)117}118if len(matcher.mismatchFailures) != 0 {119message = fmt.Sprintf("%s\nthe mismatch indexes were:", message)120}121for _, mismatch := range matcher.mismatchFailures {122message = fmt.Sprintf("%s\n%d: %s", message, mismatch.index, mismatch.failure)123}124return125}126127func (matcher *HaveExactElementsMatcher) NegatedFailureMessage(actual any) (message string) {128return format.Message(actual, "not to contain elements", presentable(matcher.Elements))129}130131func (matcher *HaveExactElementsMatcher) resetState() {132matcher.mismatchFailures = nil133matcher.missingIndex = 0134matcher.extraIndex = 0135}136137138