github.com/dolthub/go-mysql-server@v0.18.0/sql/transform/node_test.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package transform 16 17 import ( 18 "fmt" 19 "testing" 20 21 "github.com/dolthub/go-mysql-server/sql" 22 23 "github.com/stretchr/testify/require" 24 ) 25 26 // todo(max): more tests 27 func TestTransformUp(t *testing.T) { 28 require := require.New(t) 29 30 tests := []struct { 31 inp sql.Node 32 cmp sql.Node 33 visit NodeFunc 34 same TreeIdentity 35 }{ 36 { 37 inp: a(a(a(), a(), a(b())), c()), 38 cmp: b(b(b(), b(), b(c())), c()), 39 same: NewTree, 40 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 41 switch n := node.(type) { 42 case *nodeA: 43 return b(n.children...), NewTree, nil 44 case *nodeB: 45 return c(n.children...), NewTree, nil 46 default: 47 return n, SameTree, nil 48 } 49 }, 50 }, 51 { 52 inp: a(a(a(), a(), a(b())), c()), 53 cmp: b(b(b(), b(), b(b())), b()), 54 same: NewTree, 55 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 56 switch n := node.(type) { 57 case *nodeA, *nodeB, *nodeC: 58 return b(n.Children()...), NewTree, nil 59 default: 60 return n, SameTree, nil 61 } 62 }, 63 }, 64 { 65 inp: a(a(a(), a(), a(b())), c()), 66 cmp: a(a(a(), a(), a(b())), b()), 67 same: NewTree, 68 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 69 switch n := node.(type) { 70 case *nodeC: 71 return b(n.Children()...), NewTree, nil 72 default: 73 return n, SameTree, nil 74 } 75 }, 76 }, 77 { 78 inp: a(b(b(), c(), b(b())), c()), 79 cmp: c(b(b(), c(), b(b())), c()), 80 same: NewTree, 81 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 82 switch n := node.(type) { 83 case *nodeA: 84 return c(n.Children()...), NewTree, nil 85 default: 86 return n, SameTree, nil 87 } 88 }, 89 }, 90 { 91 inp: a(b(b())), 92 cmp: c(b(b())), 93 same: NewTree, 94 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 95 switch n := node.(type) { 96 case *nodeA: 97 return c(n.Children()...), NewTree, nil 98 default: 99 return n, SameTree, nil 100 } 101 }, 102 }, 103 { 104 inp: a(b(a())), 105 cmp: c(b(c())), 106 same: NewTree, 107 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 108 switch n := node.(type) { 109 case *nodeA: 110 return c(n.Children()...), NewTree, nil 111 default: 112 return n, SameTree, nil 113 } 114 }, 115 }, 116 { 117 inp: a(b(b(b(b(b(b(b(b(b()))))))))), 118 cmp: c(b(b(b(b(b(b(b(b(b()))))))))), 119 same: NewTree, 120 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 121 switch n := node.(type) { 122 case *nodeA: 123 return c(n.Children()...), NewTree, nil 124 default: 125 return n, SameTree, nil 126 } 127 }, 128 }, 129 { 130 inp: a(), 131 cmp: c(), 132 same: NewTree, 133 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 134 switch n := node.(type) { 135 case *nodeA: 136 return c(n.Children()...), NewTree, nil 137 default: 138 return n, SameTree, nil 139 } 140 }, 141 }, 142 { 143 inp: a(a(a(), a(), a(b())), b()), 144 cmp: a(a(a(), a(), a(b())), b()), 145 same: SameTree, 146 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 147 switch n := node.(type) { 148 case *nodeC: 149 return a(n.children...), NewTree, nil 150 default: 151 return n, SameTree, nil 152 } 153 }, 154 }, 155 { 156 inp: a(a(a(), a(), a(b())), b()), 157 cmp: a(a(a(), a(), a(b())), b()), 158 same: SameTree, 159 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 160 switch n := node.(type) { 161 case *nodeC: 162 return a(n.children...), NewTree, nil 163 default: 164 return n, SameTree, nil 165 } 166 }, 167 }, 168 { 169 inp: c(b(b(), c(), b(b())), c()), 170 cmp: c(b(b(), c(), b(b())), c()), 171 same: SameTree, 172 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 173 switch n := node.(type) { 174 case *nodeA: 175 return c(n.Children()...), NewTree, nil 176 default: 177 return n, SameTree, nil 178 } 179 }, 180 }, 181 { 182 inp: a(b(b())), 183 cmp: a(b(b())), 184 same: SameTree, 185 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 186 switch n := node.(type) { 187 case *nodeC: 188 return c(n.Children()...), NewTree, nil 189 default: 190 return n, SameTree, nil 191 } 192 }, 193 }, 194 { 195 inp: a(b(a())), 196 cmp: a(b(a())), 197 same: SameTree, 198 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 199 switch n := node.(type) { 200 case *nodeC: 201 return c(n.Children()...), NewTree, nil 202 default: 203 return n, SameTree, nil 204 } 205 }, 206 }, 207 { 208 inp: a(b(b(b(b(b(b(b(b(b()))))))))), 209 cmp: a(b(b(b(b(b(b(b(b(b()))))))))), 210 same: SameTree, 211 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 212 switch n := node.(type) { 213 case *nodeC: 214 return c(n.Children()...), NewTree, nil 215 default: 216 return n, SameTree, nil 217 } 218 }, 219 }, 220 { 221 inp: a(), 222 cmp: a(), 223 same: SameTree, 224 visit: func(node sql.Node) (sql.Node, TreeIdentity, error) { 225 switch n := node.(type) { 226 case *nodeC: 227 return c(n.Children()...), NewTree, nil 228 default: 229 return n, SameTree, nil 230 } 231 }, 232 }, 233 } 234 235 for i, tt := range tests { 236 var name string 237 if tt.same { 238 name = fmt.Sprintf("same tree #%d", i) 239 } else { 240 name = fmt.Sprintf("new tree #%d", i) 241 } 242 243 t.Run(name, func(t *testing.T) { 244 res, same, err := Node(tt.inp, tt.visit) 245 require.NoError(err) 246 require.Equal(tt.cmp, res) 247 require.Equal(same, tt.same) 248 }) 249 } 250 } 251 252 type nodeA struct { 253 testNode 254 } 255 type nodeB struct { 256 testNode 257 } 258 type nodeC struct { 259 testNode 260 } 261 262 var _ sql.Node = (*nodeA)(nil) 263 var _ sql.CollationCoercible = (*nodeA)(nil) 264 265 func a(nodes ...sql.Node) *nodeA { 266 return &nodeA{testNode{children: nodes}} 267 } 268 269 func b(nodes ...sql.Node) *nodeB { 270 return &nodeB{testNode{children: nodes}} 271 } 272 273 func c(nodes ...sql.Node) *nodeC { 274 return &nodeC{testNode{children: nodes}} 275 } 276 277 func (n *nodeA) WithChildren(nodes ...sql.Node) (sql.Node, error) { 278 nn := *n 279 nn.children = nodes 280 return &nn, nil 281 } 282 283 func (n *nodeB) WithChildren(nodes ...sql.Node) (sql.Node, error) { 284 nn := *n 285 nn.children = nodes 286 return &nn, nil 287 } 288 289 func (n *nodeC) WithChildren(nodes ...sql.Node) (sql.Node, error) { 290 nn := *n 291 nn.children = nodes 292 return &nn, nil 293 } 294 295 func NewTestNode(nodes ...sql.Node) *testNode { 296 return &testNode{ 297 children: nodes, 298 } 299 } 300 301 type testNode struct { 302 children []sql.Node 303 } 304 305 var _ sql.Node = (*testNode)(nil) 306 var _ sql.CollationCoercible = (*testNode)(nil) 307 308 func (n *testNode) Resolved() bool { 309 return true 310 } 311 312 func (n *testNode) String() string { 313 return "" 314 } 315 316 func (n *testNode) Schema() sql.Schema { 317 return nil 318 } 319 320 func (n *testNode) IsReadOnly() bool { 321 return true 322 } 323 324 func (n *testNode) Children() []sql.Node { 325 return n.children 326 } 327 328 func (n *testNode) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { 329 return nil, nil 330 } 331 332 func (n *testNode) WithChildren(nodes ...sql.Node) (sql.Node, error) { 333 nn := *n 334 nn.children = nodes 335 return &nn, nil 336 } 337 338 func (n *testNode) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 339 return true 340 } 341 342 // CollationCoercibility implements the interface sql.CollationCoercible. 343 func (*testNode) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 344 return sql.Collation_binary, 7 345 }