mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 03:18:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			135 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2012 Aaron Jacobs. All Rights Reserved.
 | |
| // Author: aaronjjacobs@gmail.com (Aaron Jacobs)
 | |
| //
 | |
| // 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
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| package oglematchers
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"reflect"
 | |
| )
 | |
| 
 | |
| // Is the type comparable according to the definition here?
 | |
| //
 | |
| //     http://weekly.golang.org/doc/go_spec.html#Comparison_operators
 | |
| //
 | |
| func isComparable(t reflect.Type) bool {
 | |
| 	switch t.Kind() {
 | |
| 	case reflect.Array:
 | |
| 		return isComparable(t.Elem())
 | |
| 
 | |
| 	case reflect.Struct:
 | |
| 		for i := 0; i < t.NumField(); i++ {
 | |
| 			if !isComparable(t.Field(i).Type) {
 | |
| 				return false
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return true
 | |
| 
 | |
| 	case reflect.Slice, reflect.Map, reflect.Func:
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| // Should the supplied type be allowed as an argument to IdenticalTo?
 | |
| func isLegalForIdenticalTo(t reflect.Type) (bool, error) {
 | |
| 	// Allow the zero type.
 | |
| 	if t == nil {
 | |
| 		return true, nil
 | |
| 	}
 | |
| 
 | |
| 	// Reference types are always okay; we compare pointers.
 | |
| 	switch t.Kind() {
 | |
| 	case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan:
 | |
| 		return true, nil
 | |
| 	}
 | |
| 
 | |
| 	// Reject other non-comparable types.
 | |
| 	if !isComparable(t) {
 | |
| 		return false, errors.New(fmt.Sprintf("%v is not comparable", t))
 | |
| 	}
 | |
| 
 | |
| 	return true, nil
 | |
| }
 | |
| 
 | |
| // IdenticalTo(x) returns a matcher that matches values v with type identical
 | |
| // to x such that:
 | |
| //
 | |
| //  1. If v and x are of a reference type (slice, map, function, channel), then
 | |
| //     they are either both nil or are references to the same object.
 | |
| //
 | |
| //  2. Otherwise, if v and x are not of a reference type but have a valid type,
 | |
| //     then v == x.
 | |
| //
 | |
| // If v and x are both the invalid type (which results from the predeclared nil
 | |
| // value, or from nil interface variables), then the matcher is satisfied.
 | |
| //
 | |
| // This function will panic if x is of a value type that is not comparable. For
 | |
| // example, x cannot be an array of functions.
 | |
| func IdenticalTo(x interface{}) Matcher {
 | |
| 	t := reflect.TypeOf(x)
 | |
| 
 | |
| 	// Reject illegal arguments.
 | |
| 	if ok, err := isLegalForIdenticalTo(t); !ok {
 | |
| 		panic("IdenticalTo: " + err.Error())
 | |
| 	}
 | |
| 
 | |
| 	return &identicalToMatcher{x}
 | |
| }
 | |
| 
 | |
| type identicalToMatcher struct {
 | |
| 	x interface{}
 | |
| }
 | |
| 
 | |
| func (m *identicalToMatcher) Description() string {
 | |
| 	t := reflect.TypeOf(m.x)
 | |
| 	return fmt.Sprintf("identical to <%v> %v", t, m.x)
 | |
| }
 | |
| 
 | |
| func (m *identicalToMatcher) Matches(c interface{}) error {
 | |
| 	// Make sure the candidate's type is correct.
 | |
| 	t := reflect.TypeOf(m.x)
 | |
| 	if ct := reflect.TypeOf(c); t != ct {
 | |
| 		return NewFatalError(fmt.Sprintf("which is of type %v", ct))
 | |
| 	}
 | |
| 
 | |
| 	// Special case: two values of the invalid type are always identical.
 | |
| 	if t == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	// Handle reference types.
 | |
| 	switch t.Kind() {
 | |
| 	case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan:
 | |
| 		xv := reflect.ValueOf(m.x)
 | |
| 		cv := reflect.ValueOf(c)
 | |
| 		if xv.Pointer() == cv.Pointer() {
 | |
| 			return nil
 | |
| 		}
 | |
| 
 | |
| 		return errors.New("which is not an identical reference")
 | |
| 	}
 | |
| 
 | |
| 	// Are the values equal?
 | |
| 	if m.x == c {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	return errors.New("")
 | |
| }
 |