vitess.io/vitess@v0.16.2/go/tools/asthelpergen/integration/integration_rewriter_test.go (about) 1 /* 2 Copyright 2021 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package integration 18 19 import ( 20 "fmt" 21 "reflect" 22 "testing" 23 24 "github.com/stretchr/testify/require" 25 26 "github.com/stretchr/testify/assert" 27 ) 28 29 func TestRewriteVisitRefContainer(t *testing.T) { 30 leaf1 := &Leaf{1} 31 leaf2 := &Leaf{2} 32 container := &RefContainer{ASTType: leaf1, ASTImplementationType: leaf2} 33 containerContainer := &RefContainer{ASTType: container} 34 35 tv := &rewriteTestVisitor{} 36 37 _ = Rewrite(containerContainer, tv.pre, tv.post) 38 39 expected := []step{ 40 Pre{containerContainer}, 41 Pre{container}, 42 Pre{leaf1}, 43 Post{leaf1}, 44 Pre{leaf2}, 45 Post{leaf2}, 46 Post{container}, 47 Post{containerContainer}, 48 } 49 tv.assertEquals(t, expected) 50 } 51 52 func TestRewriteVisitValueContainer(t *testing.T) { 53 leaf1 := &Leaf{1} 54 leaf2 := &Leaf{2} 55 container := ValueContainer{ASTType: leaf1, ASTImplementationType: leaf2} 56 containerContainer := ValueContainer{ASTType: container} 57 58 tv := &rewriteTestVisitor{} 59 60 _ = Rewrite(containerContainer, tv.pre, tv.post) 61 62 expected := []step{ 63 Pre{containerContainer}, 64 Pre{container}, 65 Pre{leaf1}, 66 Post{leaf1}, 67 Pre{leaf2}, 68 Post{leaf2}, 69 Post{container}, 70 Post{containerContainer}, 71 } 72 tv.assertEquals(t, expected) 73 } 74 75 func TestRewriteVisitRefSliceContainer(t *testing.T) { 76 leaf1 := &Leaf{1} 77 leaf2 := &Leaf{2} 78 leaf3 := &Leaf{3} 79 leaf4 := &Leaf{4} 80 container := &RefSliceContainer{ASTElements: []AST{leaf1, leaf2}, ASTImplementationElements: []*Leaf{leaf3, leaf4}} 81 containerContainer := &RefSliceContainer{ASTElements: []AST{container}} 82 83 tv := &rewriteTestVisitor{} 84 85 _ = Rewrite(containerContainer, tv.pre, tv.post) 86 87 tv.assertEquals(t, []step{ 88 Pre{containerContainer}, 89 Pre{container}, 90 Pre{leaf1}, 91 Post{leaf1}, 92 Pre{leaf2}, 93 Post{leaf2}, 94 Pre{leaf3}, 95 Post{leaf3}, 96 Pre{leaf4}, 97 Post{leaf4}, 98 Post{container}, 99 Post{containerContainer}, 100 }) 101 } 102 103 func TestRewriteVisitValueSliceContainer(t *testing.T) { 104 leaf1 := &Leaf{1} 105 leaf2 := &Leaf{2} 106 leaf3 := &Leaf{3} 107 leaf4 := &Leaf{4} 108 container := ValueSliceContainer{ASTElements: []AST{leaf1, leaf2}, ASTImplementationElements: []*Leaf{leaf3, leaf4}} 109 containerContainer := ValueSliceContainer{ASTElements: []AST{container}} 110 111 tv := &rewriteTestVisitor{} 112 113 _ = Rewrite(containerContainer, tv.pre, tv.post) 114 115 tv.assertEquals(t, []step{ 116 Pre{containerContainer}, 117 Pre{container}, 118 Pre{leaf1}, 119 Post{leaf1}, 120 Pre{leaf2}, 121 Post{leaf2}, 122 Pre{leaf3}, 123 Post{leaf3}, 124 Pre{leaf4}, 125 Post{leaf4}, 126 Post{container}, 127 Post{containerContainer}, 128 }) 129 } 130 131 func TestRewriteVisitInterfaceSlice(t *testing.T) { 132 leaf1 := &Leaf{2} 133 astType := &RefContainer{NotASTType: 12} 134 implementationType := &Leaf{2} 135 136 leaf2 := &Leaf{3} 137 refContainer := &RefContainer{ 138 ASTType: astType, 139 ASTImplementationType: implementationType, 140 } 141 ast := InterfaceSlice{ 142 refContainer, 143 leaf1, 144 leaf2, 145 } 146 147 tv := &rewriteTestVisitor{} 148 149 _ = Rewrite(ast, tv.pre, tv.post) 150 151 tv.assertEquals(t, []step{ 152 Pre{ast}, 153 Pre{refContainer}, 154 Pre{astType}, 155 Post{astType}, 156 Pre{implementationType}, 157 Post{implementationType}, 158 Post{refContainer}, 159 Pre{leaf1}, 160 Post{leaf1}, 161 Pre{leaf2}, 162 Post{leaf2}, 163 Post{ast}, 164 }) 165 } 166 167 func TestRewriteAndRevisitInterfaceSlice(t *testing.T) { 168 leaf1 := &Leaf{2} 169 leaf2 := &Leaf{3} 170 ast := InterfaceSlice{ 171 leaf1, 172 leaf2, 173 } 174 ast2 := InterfaceSlice{ 175 leaf2, 176 leaf1, 177 } 178 179 tv := &rewriteTestVisitor{} 180 181 a := false 182 _ = Rewrite(ast, func(cursor *Cursor) bool { 183 tv.pre(cursor) 184 switch cursor.node.(type) { 185 case InterfaceSlice: 186 if a { 187 break 188 } 189 a = true 190 cursor.ReplaceAndRevisit(ast2) 191 } 192 return true 193 }, tv.post) 194 195 tv.assertEquals(t, []step{ 196 Pre{ast}, // when we visit ast, we want to replace and revisit, 197 // which means that we don't do a post on this node, or visit the children 198 Pre{ast2}, 199 Pre{leaf2}, 200 Post{leaf2}, 201 Pre{leaf1}, 202 Post{leaf1}, 203 Post{ast2}, 204 }) 205 } 206 207 func TestRewriteVisitRefContainerReplace(t *testing.T) { 208 ast := &RefContainer{ 209 ASTType: &RefContainer{NotASTType: 12}, 210 ASTImplementationType: &Leaf{2}, 211 } 212 213 // rewrite field of type AST 214 _ = Rewrite(ast, func(cursor *Cursor) bool { 215 leaf, ok := cursor.node.(*RefContainer) 216 if ok && leaf.NotASTType == 12 { 217 cursor.Replace(&Leaf{99}) 218 } 219 return true 220 }, nil) 221 222 assert.Equal(t, &RefContainer{ 223 ASTType: &Leaf{99}, 224 ASTImplementationType: &Leaf{2}, 225 }, ast) 226 227 _ = Rewrite(ast, rewriteLeaf(2, 55), nil) 228 229 assert.Equal(t, &RefContainer{ 230 ASTType: &Leaf{99}, 231 ASTImplementationType: &Leaf{55}, 232 }, ast) 233 } 234 235 func TestRewriteVisitValueContainerReplace(t *testing.T) { 236 237 ast := ValueContainer{ 238 ASTType: ValueContainer{NotASTType: 12}, 239 ASTImplementationType: &Leaf{2}, 240 } 241 242 defer func() { 243 if r := recover(); r != nil { 244 require.Equal(t, "[BUG] tried to replace 'ASTType' on 'ValueContainer'", r) 245 } 246 }() 247 _ = Rewrite(ast, func(cursor *Cursor) bool { 248 leaf, ok := cursor.node.(ValueContainer) 249 if ok && leaf.NotASTType == 12 { 250 cursor.Replace(&Leaf{99}) 251 } 252 return true 253 }, nil) 254 255 } 256 257 func TestRewriteVisitValueContainerReplace2(t *testing.T) { 258 ast := ValueContainer{ 259 ASTType: ValueContainer{NotASTType: 12}, 260 ASTImplementationType: &Leaf{2}, 261 } 262 263 defer func() { 264 if r := recover(); r != nil { 265 require.Equal(t, "[BUG] tried to replace 'ASTImplementationType' on 'ValueContainer'", r) 266 } 267 }() 268 _ = Rewrite(ast, rewriteLeaf(2, 10), nil) 269 } 270 271 func TestRewriteVisitRefContainerPreOrPostOnly(t *testing.T) { 272 leaf1 := &Leaf{1} 273 leaf2 := &Leaf{2} 274 container := &RefContainer{ASTType: leaf1, ASTImplementationType: leaf2} 275 containerContainer := &RefContainer{ASTType: container} 276 277 tv := &rewriteTestVisitor{} 278 279 _ = Rewrite(containerContainer, tv.pre, nil) 280 tv.assertEquals(t, []step{ 281 Pre{containerContainer}, 282 Pre{container}, 283 Pre{leaf1}, 284 Pre{leaf2}, 285 }) 286 287 tv = &rewriteTestVisitor{} 288 _ = Rewrite(containerContainer, nil, tv.post) 289 tv.assertEquals(t, []step{ 290 Post{leaf1}, 291 Post{leaf2}, 292 Post{container}, 293 Post{containerContainer}, 294 }) 295 } 296 297 func rewriteLeaf(from, to int) func(*Cursor) bool { 298 return func(cursor *Cursor) bool { 299 leaf, ok := cursor.node.(*Leaf) 300 if ok && leaf.v == from { 301 cursor.Replace(&Leaf{to}) 302 } 303 return true 304 } 305 } 306 307 func TestRefSliceContainerReplace(t *testing.T) { 308 ast := &RefSliceContainer{ 309 ASTElements: []AST{&Leaf{1}, &Leaf{2}}, 310 ASTImplementationElements: []*Leaf{{3}, {4}}, 311 } 312 313 _ = Rewrite(ast, rewriteLeaf(2, 42), nil) 314 315 assert.Equal(t, &RefSliceContainer{ 316 ASTElements: []AST{&Leaf{1}, &Leaf{42}}, 317 ASTImplementationElements: []*Leaf{{3}, {4}}, 318 }, ast) 319 320 _ = Rewrite(ast, rewriteLeaf(3, 88), nil) 321 322 assert.Equal(t, &RefSliceContainer{ 323 ASTElements: []AST{&Leaf{1}, &Leaf{42}}, 324 ASTImplementationElements: []*Leaf{{88}, {4}}, 325 }, ast) 326 } 327 328 type step interface { 329 String() string 330 } 331 type Pre struct { 332 el AST 333 } 334 335 func (r Pre) String() string { 336 return fmt.Sprintf("Pre(%s)", r.el.String()) 337 } 338 func (r Post) String() string { 339 return fmt.Sprintf("Post(%s)", r.el.String()) 340 } 341 342 type Post struct { 343 el AST 344 } 345 346 type rewriteTestVisitor struct { 347 walk []step 348 } 349 350 func (tv *rewriteTestVisitor) pre(cursor *Cursor) bool { 351 tv.walk = append(tv.walk, Pre{el: cursor.Node()}) 352 return true 353 } 354 func (tv *rewriteTestVisitor) post(cursor *Cursor) bool { 355 tv.walk = append(tv.walk, Post{el: cursor.Node()}) 356 return true 357 } 358 func (tv *rewriteTestVisitor) assertEquals(t *testing.T, expected []step) { 359 t.Helper() 360 var lines []string 361 error := false 362 expectedSize := len(expected) 363 for i, step := range tv.walk { 364 if expectedSize <= i { 365 t.Errorf("❌️ - Expected less elements %v", tv.walk[i:]) 366 break 367 } else { 368 e := expected[i] 369 if reflect.DeepEqual(e, step) { 370 a := "✔️ - " + e.String() 371 if error { 372 fmt.Println(a) 373 } else { 374 lines = append(lines, a) 375 } 376 } else { 377 if !error { 378 // first error we see. 379 error = true 380 for _, line := range lines { 381 fmt.Println(line) 382 } 383 } 384 t.Errorf("❌️ - Expected: %s Got: %s\n", e.String(), step.String()) 385 } 386 } 387 } 388 walkSize := len(tv.walk) 389 if expectedSize > walkSize { 390 t.Errorf("❌️ - Expected more elements %v", expected[walkSize:]) 391 } 392 393 }