github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/ast/ast_test.go (about)

     1  package ast
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"go/ast"
     7  	"go/parser"
     8  	"go/token"
     9  	"io/ioutil"
    10  	"reflect"
    11  	"strconv"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/Konstantin8105/c4go/util"
    16  )
    17  
    18  func formatMultiLine(o interface{}) string {
    19  	s := fmt.Sprintf("%#v", o)
    20  	s = strings.Replace(s, "{", "{\n", -1)
    21  	s = strings.Replace(s, ", ", "\n", -1)
    22  
    23  	return s
    24  }
    25  
    26  func runNodeTests(t *testing.T, tests map[string]Node) {
    27  	i := 1
    28  	for line, expected := range tests {
    29  		testName := fmt.Sprintf("Example%d", i)
    30  		i++
    31  
    32  		t.Run(testName, func(t *testing.T) {
    33  			defer func() {
    34  				if r := recover(); r != nil {
    35  					t.Fatalf("Panic for : %v, %v\n%v", testName, line, r)
    36  				}
    37  			}()
    38  			// Append the name of the struct onto the front. This would make the
    39  			// complete line it would normally be parsing.
    40  			name := reflect.TypeOf(expected).Elem().Name()
    41  			actual, err := Parse(name + " " + line)
    42  
    43  			if !reflect.DeepEqual(expected, actual) {
    44  				t.Errorf("%s", util.ShowDiff(formatMultiLine(expected),
    45  					formatMultiLine(actual)))
    46  			}
    47  			if err != nil {
    48  				t.Errorf("Error parsing %v", err)
    49  			}
    50  			if int64(actual.Address()) == 0 {
    51  				t.Errorf("Address for test cannot be nil. %v", actual.Address())
    52  			}
    53  			if len(actual.Children()) != 0 {
    54  				t.Errorf("Amount of children cannot be more 0")
    55  			}
    56  			actual.AddChild(nil)
    57  			if len(actual.Children()) != 1 {
    58  				t.Errorf("Amount of children must be 1")
    59  			}
    60  			if actual.Children()[0] != nil {
    61  				t.Errorf("Children must bee nil")
    62  			}
    63  			pos := actual.Position()
    64  			if pos.Line == 0 && pos.Column == 0 && pos.LineEnd == 0 &&
    65  				pos.ColumnEnd == 0 && pos.File == "" {
    66  				t.Log("Please try to change Position for test. " +
    67  					"Better to test not zero position")
    68  			}
    69  			if pos.Line < 0 || pos.Column < 0 || pos.LineEnd < 0 ||
    70  				pos.ColumnEnd < 0 {
    71  				t.Errorf("Not acceptable negative position")
    72  			}
    73  			var posC Position
    74  			posC.Line = -1
    75  			if pos.Line == -1 {
    76  				t.Fatalf("Not correct default line position")
    77  			}
    78  			setPosition(actual, posC)
    79  			if pos.Line != -1 {
    80  				t.Log("Cannot change position")
    81  			}
    82  		})
    83  	}
    84  }
    85  
    86  func TestPrint(t *testing.T) {
    87  	cond := &ConditionalOperator{}
    88  	cond.AddChild(&ImplicitCastExpr{})
    89  	cond.AddChild(&ImplicitCastExpr{})
    90  	s := Atos(cond)
    91  	if len(s) == 0 {
    92  		t.Fatalf("Cannot convert AST tree : %#v", cond)
    93  	}
    94  	lines := strings.Split(s, "\n")
    95  	var amount int
    96  	for _, l := range lines {
    97  		if strings.Contains(l, "ImplicitCastExpr") {
    98  			amount++
    99  		}
   100  	}
   101  	if amount != 2 {
   102  		t.Error("Not correct design of output")
   103  	}
   104  }
   105  
   106  func TestPanicCheck(t *testing.T) {
   107  	defer func() {
   108  		if r := recover(); r != nil {
   109  			t.Fatalf("panic for parsing string line is not acceptable. %v", r)
   110  		}
   111  	}()
   112  	_, err := Parse("Some strange line")
   113  	if err == nil {
   114  		t.Errorf("Haven`t error for strange string line not acceptable")
   115  	}
   116  	// Correct node of AST:
   117  	// GotoStmt 0x7fb9cc1994d8 <line:18893:9, col:14>  'end_getDigits' 0x7fb9cc199490
   118  	// Modify for panic in ast regexp
   119  	//
   120  	n, err := Parse("GotoStmt 0x7fb9cc1994d8 <lin8893:9, col:14> ts' 99490")
   121  	if err == nil {
   122  		t.Errorf("Haven`t error for guarantee panic line not acceptable\n%v",
   123  			Atos(n))
   124  	}
   125  }
   126  
   127  func TestNullStmt(t *testing.T) {
   128  	n, err := Parse("NullStmt")
   129  	if n != nil || err != nil {
   130  		t.Errorf("Not acceptable for NullStmt")
   131  	}
   132  }
   133  
   134  type Visitor interface {
   135  	Visit(node Node) (w Visitor)
   136  }
   137  
   138  type Founder struct{}
   139  
   140  var nodesFromAst []string
   141  
   142  func (f Founder) Visit(node ast.Node) (w ast.Visitor) {
   143  	if cs, ok := node.(*ast.CaseClause); ok {
   144  		nodesFromAst = append(nodesFromAst, cs.List[0].(*ast.BasicLit).Value)
   145  	}
   146  	return f
   147  }
   148  
   149  func TestAstNodes(t *testing.T) {
   150  	fset := token.NewFileSet() // positions are relative to fset
   151  	f, err := parser.ParseFile(fset, "ast.go", nil, parser.DeclarationErrors)
   152  	if err != nil {
   153  		t.Fatalf("%v", err)
   154  	}
   155  
   156  	var fr Founder
   157  	ast.Walk(fr, f.Decls[4])
   158  
   159  	// 108: *ast.CaseClause {
   160  	// .  Case: -
   161  	// .  List: []ast.Expr (len = 1) {
   162  	// .  .  0: *ast.BasicLit {
   163  	// .  .  .  ValuePos: -
   164  	// .  .  .  Kind: STRING
   165  	// .  .  .  Value: "\"WhileStmt\""
   166  	// .  .  }
   167  	// .  }
   168  
   169  	nodesFromAst = append(nodesFromAst, "")
   170  
   171  	for _, c := range nodesFromAst {
   172  		t.Run(fmt.Sprintf("%v", c), func(t *testing.T) {
   173  			defer func() {
   174  				if r := recover(); r != nil {
   175  					t.Fatalf("Cannot parse")
   176  				}
   177  			}()
   178  			Parse(c)
   179  		})
   180  	}
   181  
   182  	dat, err := ioutil.ReadFile("position.go")
   183  	if err != nil {
   184  		t.Fatalf("Error to read file `position.go`: %v", err)
   185  	}
   186  
   187  	index := bytes.Index(dat, []byte("setPosition"))
   188  	if index < 0 {
   189  		t.Fatalf("cannot found function")
   190  	}
   191  	dat = dat[index:]
   192  
   193  	for _, c := range nodesFromAst {
   194  		if c == "" || c == "\"NullStmt\"" {
   195  			continue
   196  		}
   197  		t.Run(fmt.Sprintf("%v", c), func(t *testing.T) {
   198  			c, err := strconv.Unquote(c)
   199  			if err != nil {
   200  				t.Fatalf("Unquote invalid : %v", err)
   201  			}
   202  			index := bytes.Index(dat, []byte(c))
   203  			if index < 0 {
   204  				t.Fatalf("cannot found type : %v", c)
   205  			}
   206  		})
   207  	}
   208  }