mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-04 13:28:25 +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("")
 | 
						|
}
 |