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  }