package evaltest

import (
	
	
	
	

	
)

// ApproximatelyThreshold defines the threshold for matching float64 values when
// using Approximately.
const ApproximatelyThreshold = 1e-15

// Approximately can be passed to TestCase.Puts to match a float64 within the
// threshold defined by ApproximatelyThreshold.
type Approximately struct{ F float64 }

func (, ,  float64) bool {
	if math.IsNaN() && math.IsNaN() {
		return true
	}
	if math.IsInf(, 0) && math.IsInf(, 0) &&
		math.Signbit() == math.Signbit() {
		return true
	}
	return math.Abs(-) <= 
}

// MatchingRegexp can be passed to TestCase.Puts to match a any string that
// matches a regexp pattern. If the pattern is not a valid regexp, the test will
// panic.
type MatchingRegexp struct{ Pattern string }

func (,  string) bool {
	,  := regexp.MatchString(, )
	if  != nil {
		panic()
	}
	return 
}

type errorMatcher interface{ matchError(error) bool }

// AnyError is an error that can be passed to TestCase.Throws to match any
// non-nil error.
var AnyError = anyError{}

// An errorMatcher for any error.
type anyError struct{}

func (anyError) () string { return "any error" }

func (anyError) ( error) bool { return  != nil }

// An errorMatcher for exceptions.
type exc struct {
	reason error
	stacks []string
}

func ( exc) () string {
	if len(.stacks) == 0 {
		return fmt.Sprintf("exception with reason %v", .reason)
	}
	return fmt.Sprintf("exception with reason %v and stacks %v", .reason, .stacks)
}

func ( exc) ( error) bool {
	if ,  := .(eval.Exception);  {
		return matchErr(.reason, .Reason()) &&
			(len(.stacks) == 0 ||
				reflect.DeepEqual(.stacks, getStackTexts(.StackTrace())))
	}
	return false
}

func ( *eval.StackTrace) []string {
	 := []string{}
	for  != nil {
		 := .Head
		 = append(, .Source[.From:.To])
		 = .Next
	}
	return 
}

// ErrorWithType returns an error that can be passed to the TestCase.Throws
// to match any error with the same type as the argument.
func ( error) error { return errWithType{} }

// An errorMatcher for any error with the given type.
type errWithType struct{ v error }

func ( errWithType) () string { return fmt.Sprintf("error with type %T", .v) }

func ( errWithType) ( error) bool {
	return reflect.TypeOf(.v) == reflect.TypeOf()
}

// ErrorWithMessage returns an error that can be passed to TestCase.Throws to
// match any error with the given message.
func ( string) error { return errWithMessage{} }

// An errorMatcher for any error with the given message.
type errWithMessage struct{ msg string }

func ( errWithMessage) () string { return "error with message " + .msg }

func ( errWithMessage) ( error) bool {
	return  != nil && .msg == .Error()
}

// CmdExit returns an error that can be passed to TestCase.Throws to match an
// eval.ExternalCmdExit ignoring the Pid field.
func ( eval.ExternalCmdExit) error { return errCmdExit{} }

// An errorMatcher for an ExternalCmdExit error that ignores the `Pid` member.
// We only match the command name and exit status because at run time we
// cannot know the correct value for `Pid`.
type errCmdExit struct{ v eval.ExternalCmdExit }

func ( errCmdExit) () string {
	return .v.Error()
}

func ( errCmdExit) ( error) bool {
	if  == nil {
		return false
	}
	 := .(eval.ExternalCmdExit)
	return .v.CmdName == .CmdName && .v.WaitStatus == .WaitStatus
}