...

Source file src/github.com/onsi/gomega/internal/assertion.go

Documentation: github.com/onsi/gomega/internal

     1  package internal
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  
     7  	"github.com/onsi/gomega/format"
     8  	"github.com/onsi/gomega/types"
     9  )
    10  
    11  type Assertion struct {
    12  	actuals     []interface{} // actual value plus all extra values
    13  	actualIndex int           // value to pass to the matcher
    14  	vet         vetinari      // the vet to call before calling Gomega matcher
    15  	offset      int
    16  	g           *Gomega
    17  }
    18  
    19  // ...obligatory discworld reference, as "vetineer" doesn't sound ... quite right.
    20  type vetinari func(assertion *Assertion, optionalDescription ...interface{}) bool
    21  
    22  func NewAssertion(actualInput interface{}, g *Gomega, offset int, extra ...interface{}) *Assertion {
    23  	return &Assertion{
    24  		actuals:     append([]interface{}{actualInput}, extra...),
    25  		actualIndex: 0,
    26  		vet:         (*Assertion).vetActuals,
    27  		offset:      offset,
    28  		g:           g,
    29  	}
    30  }
    31  
    32  func (assertion *Assertion) WithOffset(offset int) types.Assertion {
    33  	assertion.offset = offset
    34  	return assertion
    35  }
    36  
    37  func (assertion *Assertion) Error() types.Assertion {
    38  	return &Assertion{
    39  		actuals:     assertion.actuals,
    40  		actualIndex: len(assertion.actuals) - 1,
    41  		vet:         (*Assertion).vetError,
    42  		offset:      assertion.offset,
    43  		g:           assertion.g,
    44  	}
    45  }
    46  
    47  func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
    48  	assertion.g.THelper()
    49  	vetOptionalDescription("Assertion", optionalDescription...)
    50  	return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
    51  }
    52  
    53  func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
    54  	assertion.g.THelper()
    55  	vetOptionalDescription("Assertion", optionalDescription...)
    56  	return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
    57  }
    58  
    59  func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
    60  	assertion.g.THelper()
    61  	vetOptionalDescription("Assertion", optionalDescription...)
    62  	return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
    63  }
    64  
    65  func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
    66  	assertion.g.THelper()
    67  	vetOptionalDescription("Assertion", optionalDescription...)
    68  	return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
    69  }
    70  
    71  func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
    72  	assertion.g.THelper()
    73  	vetOptionalDescription("Assertion", optionalDescription...)
    74  	return assertion.vet(assertion, optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
    75  }
    76  
    77  func (assertion *Assertion) buildDescription(optionalDescription ...interface{}) string {
    78  	switch len(optionalDescription) {
    79  	case 0:
    80  		return ""
    81  	case 1:
    82  		if describe, ok := optionalDescription[0].(func() string); ok {
    83  			return describe() + "\n"
    84  		}
    85  	}
    86  	return fmt.Sprintf(optionalDescription[0].(string), optionalDescription[1:]...) + "\n"
    87  }
    88  
    89  func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
    90  	actualInput := assertion.actuals[assertion.actualIndex]
    91  	matches, err := matcher.Match(actualInput)
    92  	assertion.g.THelper()
    93  	if err != nil {
    94  		description := assertion.buildDescription(optionalDescription...)
    95  		assertion.g.Fail(description+err.Error(), 2+assertion.offset)
    96  		return false
    97  	}
    98  	if matches != desiredMatch {
    99  		var message string
   100  		if desiredMatch {
   101  			message = matcher.FailureMessage(actualInput)
   102  		} else {
   103  			message = matcher.NegatedFailureMessage(actualInput)
   104  		}
   105  		description := assertion.buildDescription(optionalDescription...)
   106  		assertion.g.Fail(description+message, 2+assertion.offset)
   107  		return false
   108  	}
   109  
   110  	return true
   111  }
   112  
   113  // vetActuals vets the actual values, with the (optional) exception of a
   114  // specific value, such as the first value in case non-error assertions, or the
   115  // last value in case of Error()-based assertions.
   116  func (assertion *Assertion) vetActuals(optionalDescription ...interface{}) bool {
   117  	success, message := vetActuals(assertion.actuals, assertion.actualIndex)
   118  	if success {
   119  		return true
   120  	}
   121  
   122  	description := assertion.buildDescription(optionalDescription...)
   123  	assertion.g.THelper()
   124  	assertion.g.Fail(description+message, 2+assertion.offset)
   125  	return false
   126  }
   127  
   128  // vetError vets the actual values, except for the final error value, in case
   129  // the final error value is non-zero. Otherwise, it doesn't vet the actual
   130  // values, as these are allowed to take on any values unless there is a non-zero
   131  // error value.
   132  func (assertion *Assertion) vetError(optionalDescription ...interface{}) bool {
   133  	if err := assertion.actuals[assertion.actualIndex]; err != nil {
   134  		// Go error result idiom: all other actual values must be zero values.
   135  		return assertion.vetActuals(optionalDescription...)
   136  	}
   137  	return true
   138  }
   139  
   140  // vetActuals vets a slice of actual values, optionally skipping a particular
   141  // value slice element, such as the first or last value slice element.
   142  func vetActuals(actuals []interface{}, skipIndex int) (bool, string) {
   143  	for i, actual := range actuals {
   144  		if i == skipIndex {
   145  			continue
   146  		}
   147  		if actual != nil {
   148  			zeroValue := reflect.Zero(reflect.TypeOf(actual)).Interface()
   149  			if !reflect.DeepEqual(zeroValue, actual) {
   150  				var message string
   151  				if err, ok := actual.(error); ok {
   152  					message = fmt.Sprintf("Unexpected error: %s\n%s", err, format.Object(err, 1))
   153  				} else {
   154  					message = fmt.Sprintf("Unexpected non-nil/non-zero argument at index %d:\n\t<%T>: %#v", i, actual, actual)
   155  				}
   156  				return false, message
   157  			}
   158  		}
   159  	}
   160  	return true, ""
   161  }
   162  

View as plain text