1package assertions 2 3import ( 4 "fmt" 5 "reflect" 6 7 "github.com/smartystreets/assertions/internal/oglematchers" 8) 9 10// ShouldContain receives exactly two parameters. The first is a slice and the 11// second is a proposed member. Membership is determined using ShouldEqual. 12func ShouldContain(actual interface{}, expected ...interface{}) string { 13 if fail := need(1, expected); fail != success { 14 return fail 15 } 16 17 if matchError := oglematchers.Contains(expected[0]).Matches(actual); matchError != nil { 18 typeName := reflect.TypeOf(actual) 19 20 if fmt.Sprintf("%v", matchError) == "which is not a slice or array" { 21 return fmt.Sprintf(shouldHaveBeenAValidCollection, typeName) 22 } 23 return fmt.Sprintf(shouldHaveContained, typeName, expected[0]) 24 } 25 return success 26} 27 28// ShouldNotContain receives exactly two parameters. The first is a slice and the 29// second is a proposed member. Membership is determinied using ShouldEqual. 30func ShouldNotContain(actual interface{}, expected ...interface{}) string { 31 if fail := need(1, expected); fail != success { 32 return fail 33 } 34 typeName := reflect.TypeOf(actual) 35 36 if matchError := oglematchers.Contains(expected[0]).Matches(actual); matchError != nil { 37 if fmt.Sprintf("%v", matchError) == "which is not a slice or array" { 38 return fmt.Sprintf(shouldHaveBeenAValidCollection, typeName) 39 } 40 return success 41 } 42 return fmt.Sprintf(shouldNotHaveContained, typeName, expected[0]) 43} 44 45// ShouldContainKey receives exactly two parameters. The first is a map and the 46// second is a proposed key. Keys are compared with a simple '=='. 47func ShouldContainKey(actual interface{}, expected ...interface{}) string { 48 if fail := need(1, expected); fail != success { 49 return fail 50 } 51 52 keys, isMap := mapKeys(actual) 53 if !isMap { 54 return fmt.Sprintf(shouldHaveBeenAValidMap, reflect.TypeOf(actual)) 55 } 56 57 if !keyFound(keys, expected[0]) { 58 return fmt.Sprintf(shouldHaveContainedKey, reflect.TypeOf(actual), expected) 59 } 60 61 return "" 62} 63 64// ShouldNotContainKey receives exactly two parameters. The first is a map and the 65// second is a proposed absent key. Keys are compared with a simple '=='. 66func ShouldNotContainKey(actual interface{}, expected ...interface{}) string { 67 if fail := need(1, expected); fail != success { 68 return fail 69 } 70 71 keys, isMap := mapKeys(actual) 72 if !isMap { 73 return fmt.Sprintf(shouldHaveBeenAValidMap, reflect.TypeOf(actual)) 74 } 75 76 if keyFound(keys, expected[0]) { 77 return fmt.Sprintf(shouldNotHaveContainedKey, reflect.TypeOf(actual), expected) 78 } 79 80 return "" 81} 82 83func mapKeys(m interface{}) ([]reflect.Value, bool) { 84 value := reflect.ValueOf(m) 85 if value.Kind() != reflect.Map { 86 return nil, false 87 } 88 return value.MapKeys(), true 89} 90func keyFound(keys []reflect.Value, expectedKey interface{}) bool { 91 found := false 92 for _, key := range keys { 93 if key.Interface() == expectedKey { 94 found = true 95 } 96 } 97 return found 98} 99 100// ShouldBeIn receives at least 2 parameters. The first is a proposed member of the collection 101// that is passed in either as the second parameter, or of the collection that is comprised 102// of all the remaining parameters. This assertion ensures that the proposed member is in 103// the collection (using ShouldEqual). 104func ShouldBeIn(actual interface{}, expected ...interface{}) string { 105 if fail := atLeast(1, expected); fail != success { 106 return fail 107 } 108 109 if len(expected) == 1 { 110 return shouldBeIn(actual, expected[0]) 111 } 112 return shouldBeIn(actual, expected) 113} 114func shouldBeIn(actual interface{}, expected interface{}) string { 115 if matchError := oglematchers.Contains(actual).Matches(expected); matchError != nil { 116 return fmt.Sprintf(shouldHaveBeenIn, actual, reflect.TypeOf(expected)) 117 } 118 return success 119} 120 121// ShouldNotBeIn receives at least 2 parameters. The first is a proposed member of the collection 122// that is passed in either as the second parameter, or of the collection that is comprised 123// of all the remaining parameters. This assertion ensures that the proposed member is NOT in 124// the collection (using ShouldEqual). 125func ShouldNotBeIn(actual interface{}, expected ...interface{}) string { 126 if fail := atLeast(1, expected); fail != success { 127 return fail 128 } 129 130 if len(expected) == 1 { 131 return shouldNotBeIn(actual, expected[0]) 132 } 133 return shouldNotBeIn(actual, expected) 134} 135func shouldNotBeIn(actual interface{}, expected interface{}) string { 136 if matchError := oglematchers.Contains(actual).Matches(expected); matchError == nil { 137 return fmt.Sprintf(shouldNotHaveBeenIn, actual, reflect.TypeOf(expected)) 138 } 139 return success 140} 141 142// ShouldBeEmpty receives a single parameter (actual) and determines whether or not 143// calling len(actual) would return `0`. It obeys the rules specified by the len 144// function for determining length: http://golang.org/pkg/builtin/#len 145func ShouldBeEmpty(actual interface{}, expected ...interface{}) string { 146 if fail := need(0, expected); fail != success { 147 return fail 148 } 149 150 if actual == nil { 151 return success 152 } 153 154 value := reflect.ValueOf(actual) 155 switch value.Kind() { 156 case reflect.Slice: 157 if value.Len() == 0 { 158 return success 159 } 160 case reflect.Chan: 161 if value.Len() == 0 { 162 return success 163 } 164 case reflect.Map: 165 if value.Len() == 0 { 166 return success 167 } 168 case reflect.String: 169 if value.Len() == 0 { 170 return success 171 } 172 case reflect.Ptr: 173 elem := value.Elem() 174 kind := elem.Kind() 175 if (kind == reflect.Slice || kind == reflect.Array) && elem.Len() == 0 { 176 return success 177 } 178 } 179 180 return fmt.Sprintf(shouldHaveBeenEmpty, actual) 181} 182 183// ShouldNotBeEmpty receives a single parameter (actual) and determines whether or not 184// calling len(actual) would return a value greater than zero. It obeys the rules 185// specified by the `len` function for determining length: http://golang.org/pkg/builtin/#len 186func ShouldNotBeEmpty(actual interface{}, expected ...interface{}) string { 187 if fail := need(0, expected); fail != success { 188 return fail 189 } 190 191 if empty := ShouldBeEmpty(actual, expected...); empty != success { 192 return success 193 } 194 return fmt.Sprintf(shouldNotHaveBeenEmpty, actual) 195} 196 197// ShouldHaveLength receives 2 parameters. The first is a collection to check 198// the length of, the second being the expected length. It obeys the rules 199// specified by the len function for determining length: 200// http://golang.org/pkg/builtin/#len 201func ShouldHaveLength(actual interface{}, expected ...interface{}) string { 202 if fail := need(1, expected); fail != success { 203 return fail 204 } 205 206 var expectedLen int64 207 lenValue := reflect.ValueOf(expected[0]) 208 switch lenValue.Kind() { 209 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 210 expectedLen = lenValue.Int() 211 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 212 expectedLen = int64(lenValue.Uint()) 213 default: 214 return fmt.Sprintf(shouldHaveBeenAValidInteger, reflect.TypeOf(expected[0])) 215 } 216 217 if expectedLen < 0 { 218 return fmt.Sprintf(shouldHaveBeenAValidLength, expected[0]) 219 } 220 221 value := reflect.ValueOf(actual) 222 switch value.Kind() { 223 case reflect.Slice: 224 if int64(value.Len()) == expectedLen { 225 return success 226 } 227 case reflect.Chan: 228 if int64(value.Len()) == expectedLen { 229 return success 230 } 231 case reflect.Map: 232 if int64(value.Len()) == expectedLen { 233 return success 234 } 235 case reflect.String: 236 if int64(value.Len()) == expectedLen { 237 return success 238 } 239 case reflect.Ptr: 240 elem := value.Elem() 241 kind := elem.Kind() 242 if (kind == reflect.Slice || kind == reflect.Array) && int64(elem.Len()) == expectedLen { 243 return success 244 } 245 default: 246 return fmt.Sprintf(shouldHaveBeenAValidCollection, reflect.TypeOf(actual)) 247 } 248 249 return fmt.Sprintf(shouldHaveHadLength, actual, expectedLen) 250} 251