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 }