go.temporal.io/server@v1.23.0/common/testing/protoassert/testify_assert.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 // MIT License 26 // 27 // Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. 28 // 29 // Permission is hereby granted, free of charge, to any person obtaining a copy 30 // of this software and associated documentation files (the "Software"), to deal 31 // in the Software without restriction, including without limitation the rights 32 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 33 // copies of the Software, and to permit persons to whom the Software is 34 // furnished to do so, subject to the following conditions: 35 // 36 // The above copyright notice and this permission notice shall be included in all 37 // copies or substantial portions of the Software. 38 // 39 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 40 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 41 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 42 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 43 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 44 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 45 // SOFTWARE. 46 47 // The following helpers are slightly modified versions of those found in testify's assert package 48 package protoassert 49 50 import ( 51 "bytes" 52 "fmt" 53 "reflect" 54 55 "github.com/stretchr/testify/assert" 56 "go.temporal.io/api/temporalproto" 57 ) 58 59 func formatListDiff(listA, listB any, extraA, extraB any) string { 60 var msg bytes.Buffer 61 62 msg.WriteString("elements differ") 63 if !isEmpty(extraA) { 64 msg.WriteString("\n\nextra elements in list A:\n") 65 msg.WriteString(prettyPrint(extraA)) 66 } 67 if !isEmpty(extraB) { 68 msg.WriteString("\n\nextra elements in list B:\n") 69 msg.WriteString(prettyPrint(extraB)) 70 } 71 msg.WriteString("\n\nlistA:\n") 72 msg.WriteString(prettyPrint(listA)) 73 msg.WriteString("\n\nlistB:\n") 74 msg.WriteString(prettyPrint(listB)) 75 76 return msg.String() 77 } 78 79 func diffLists(listA, listB interface{}) (extraA, extraB []interface{}) { 80 aValue := reflect.ValueOf(listA) 81 bValue := reflect.ValueOf(listB) 82 83 aLen := aValue.Len() 84 bLen := bValue.Len() 85 86 // Mark indexes in bValue that we already used 87 visited := make([]bool, bLen) 88 for i := 0; i < aLen; i++ { 89 element := aValue.Index(i).Interface() 90 found := false 91 for j := 0; j < bLen; j++ { 92 if visited[j] { 93 continue 94 } 95 if temporalproto.DeepEqual(bValue.Index(j).Interface(), element) { 96 visited[j] = true 97 found = true 98 break 99 } 100 } 101 if !found { 102 extraA = append(extraA, element) 103 } 104 } 105 106 for j := 0; j < bLen; j++ { 107 if visited[j] { 108 continue 109 } 110 extraB = append(extraB, bValue.Index(j).Interface()) 111 } 112 113 return 114 } 115 116 func isEmpty(object interface{}) bool { 117 118 // get nil case out of the way 119 if object == nil { 120 return true 121 } 122 123 objValue := reflect.ValueOf(object) 124 125 switch objValue.Kind() { 126 // collection types are empty when they have no element 127 case reflect.Chan, reflect.Map, reflect.Slice: 128 return objValue.Len() == 0 129 // pointers are empty if nil or if the value they point to is empty 130 case reflect.Ptr: 131 if objValue.IsNil() { 132 return true 133 } 134 deref := objValue.Elem().Interface() 135 return isEmpty(deref) 136 // for all other types, compare against the zero value 137 // array types are empty when they match their zero-initialized state 138 default: 139 zero := reflect.Zero(objValue.Type()) 140 return reflect.DeepEqual(object, zero.Interface()) 141 } 142 } 143 144 // isList checks that the provided value is array or slice. 145 func isList(t assert.TestingT, list interface{}, msgAndArgs ...interface{}) (ok bool) { 146 kind := reflect.TypeOf(list).Kind() 147 if kind != reflect.Array && kind != reflect.Slice { 148 return assert.Fail(t, fmt.Sprintf("%q has an unsupported type %s, expecting array or slice", list, kind), 149 msgAndArgs...) 150 } 151 return true 152 }