1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
package assertly
import (
"fmt"
"github.com/viant/toolbox"
"strings"
"unicode"
)
//Failure represents a validation failre
type Failure struct {
Source string
Path string
Expected interface{}
Actual interface{}
Args []interface{}
Reason string
Message string
}
func (f *Failure) Index() int {
pair := strings.SplitN(f.Path, ":", 2)
if len(pair) != 2 {
return -1
}
var index = ""
var expectIndex = false
outer:
for _, r := range pair[1] {
switch r {
case '[':
expectIndex = true
case ']':
expectIndex = false
if len(index) > 0 {
break outer
}
default:
if expectIndex && unicode.IsNumber(r) {
index += string(r)
}
}
}
if len(index) == 0 {
return -1
}
return toolbox.AsInt(index)
}
func (f *Failure) LeafKey() string {
leafIndex := strings.LastIndex(f.Path, ".")
if leafIndex == -1 {
return ""
}
return string(f.Path[leafIndex+1:])
}
func removeDirectives(aMap map[string]interface{}) map[string]interface{} {
var result = make(map[string]interface{})
for k, v := range aMap {
if strings.HasPrefix(k, "@") {
continue
}
result[k] = v
}
return result
}
//NewFailure creates a new failure
func NewFailure(source, path string, reason string, expected, actual interface{}, args ...interface{}) *Failure {
if expected != nil && toolbox.IsMap(expected) {
expected = removeDirectives(toolbox.AsMap(expected))
}
if actual != nil && toolbox.IsMap(actual) {
actual = removeDirectives(toolbox.AsMap(actual))
}
var result = &Failure{
Source: source,
Path: path,
Reason: reason,
Expected: expected,
Actual: actual,
Args: args,
}
result.Message = FormatMessage(result)
return result
}
func FormatMessage(failure *Failure) string {
switch failure.Reason {
case MissingEntryViolation:
return fmt.Sprintf("entry for %v was missing, expected: %v, actual keys: %v", failure.Args[0], failure.Expected, failure.Actual)
case MissingItemViolation:
return fmt.Sprintf("item was missing, expected: %v, actual: %v", failure.Expected, failure.Actual)
case ItemMismatchViolation:
return fmt.Sprintf("item was mismatched, key1: %v, key2: %v", failure.Expected, failure.Actual)
case IncompatibleDataTypeViolation:
return fmt.Sprintf("actual was %T, but expected %T(%v)", failure.Actual, failure.Expected, failure.Expected)
case KeyExistsViolation:
return fmt.Sprintf("key '%v' should exists", failure.Expected)
case KeyDoesNotExistViolation:
return fmt.Sprintf("'%v' should not exists", failure.Expected)
case EqualViolation:
return fmt.Sprintf("actual(%T): '%v' was not equal (%T) '%v'", failure.Actual, failure.Actual, failure.Expected, failure.Expected)
case NotEqualViolation:
return fmt.Sprintf("actual(%T): '%v' was equal (%T) '%v'", failure.Actual, failure.Actual, failure.Expected, failure.Expected)
case LengthViolation:
return fmt.Sprintf("actual length %v was not equal: %v", failure.Actual, failure.Expected)
case MissingCaseViolation:
switchBy := failure.Args[0].([]string)
caseValue := toolbox.AsString(failure.Args[1])
var availableKeys = toolbox.MapKeysToStringSlice(failure.Expected)
return fmt.Sprintf("actual case %v => %v, was missing in expected set: available keys: [%v]",
strings.Join(switchBy, ","), caseValue, strings.Join(availableKeys, ","))
case RegExprMatchesViolation:
return fmt.Sprintf("actual: '%v' should matched %v", failure.Actual, failure.Expected)
case RegExprDoesNotMatchViolation:
return fmt.Sprintf("actual: '%v' should not be matched %v", failure.Actual, failure.Expected)
case RangeViolation:
return fmt.Sprintf("actual '%v' is not in: '%v'", failure.Actual, failure.Expected)
case RangeNotViolation:
return fmt.Sprintf("actual '%v' should not be in: '%v'", failure.Actual, failure.Expected)
case ContainsViolation:
return fmt.Sprintf("actual '%v' does not contain: '%v'", failure.Actual, failure.Expected)
case DoesNotContainViolation:
return fmt.Sprintf("actual '%v' should not not contain: '%v'", failure.Actual, failure.Expected)
case PredicateViolation:
return fmt.Sprintf("actual '%v' should pass predicate: '%v'", failure.Actual, failure.Expected)
}
return failure.Reason
}
|