11 "github.com/robertkrimen/otto/ast"
12 "github.com/robertkrimen/otto/parser"
19 func (w *walker) Enter(node ast.Node) ast.Visitor {
20 w.nodes = append(w.nodes, node)
24 func (w *walker) Exit(node ast.Node) {
27 func getAllNodes(node ast.Node) []ast.Node {
33 func getCalls(node ast.Node, name string) []*ast.CallExpression {
34 nodes := []*ast.CallExpression{}
35 for _, n := range getAllNodes(node) {
36 if ce, ok := n.(*ast.CallExpression); ok {
38 switch callee := ce.Callee.(type) {
40 calleeName = callee.Name
41 case *ast.DotExpression:
42 calleeName = callee.Identifier.Name
46 if calleeName == name {
47 nodes = append(nodes, ce)
54 func getPropertyValue(node ast.Node, key string) ast.Expression {
55 for _, p := range node.(*ast.ObjectLiteral).Value {
63 type operation struct {
73 operations []operation
82 func stringSliceToGoSource(slice []string) string {
84 b.WriteString("[]string{\n")
85 for _, s := range slice {
86 b.WriteString(fmt.Sprintf("%#v,\n", s))
92 func testToGoTest(test test, name string) string {
95 b.WriteString("func Test")
97 b.WriteString("(t *testing.T) {\n")
99 for _, c := range test.checks {
100 b.WriteString("check(\n")
101 b.WriteString("t,\n")
102 b.WriteString(fmt.Sprintf("%v,\n", stringSliceToGoSource(c.before)))
103 b.WriteString("[]operation{\n")
104 for _, op := range c.operations {
105 b.WriteString("operation{\n")
106 b.WriteString(fmt.Sprintf("start: Loc{%v, %v},\n", op.startColumn, op.startLine))
107 b.WriteString(fmt.Sprintf("end: Loc{%v, %v},\n", op.endColumn, op.endLine))
108 b.WriteString(fmt.Sprintf("text: %v,\n", stringSliceToGoSource(op.text)))
109 b.WriteString("},\n")
111 b.WriteString("},\n")
112 b.WriteString(fmt.Sprintf("%v,\n", stringSliceToGoSource(c.after)))
121 func nodeToStringSlice(node ast.Node) []string {
123 for _, s := range node.(*ast.ArrayLiteral).Value {
124 result = append(result, s.(*ast.StringLiteral).Value)
129 func nodeToStringSlice2(node ast.Node) []string {
131 for _, o := range node.(*ast.ArrayLiteral).Value {
132 result = append(result, getPropertyValue(o, "text").(*ast.StringLiteral).Value)
137 func nodeToInt(node ast.Node) int {
138 return int(node.(*ast.NumberLiteral).Value.(int64))
141 func getChecks(node ast.Node) []check {
144 for _, ce := range getCalls(node, "testApplyEdits") {
145 if len(ce.ArgumentList) != 3 {
150 before := nodeToStringSlice2(ce.ArgumentList[0])
151 after := nodeToStringSlice2(ce.ArgumentList[2])
153 var operations []operation
154 for _, op := range ce.ArgumentList[1].(*ast.ArrayLiteral).Value {
155 args := getPropertyValue(op, "range").(*ast.NewExpression).ArgumentList
156 operations = append(operations, operation{
157 startLine: nodeToInt(args[0]) - 1,
158 startColumn: nodeToInt(args[1]) - 1,
159 endLine: nodeToInt(args[2]) - 1,
160 endColumn: nodeToInt(args[3]) - 1,
161 text: []string{getPropertyValue(op, "text").(*ast.StringLiteral).Value},
165 checks = append(checks, check{before, operations, after})
168 for _, ce := range getCalls(node, "testApplyEditsWithSyncedModels") {
169 if len(ce.ArgumentList) > 3 && ce.ArgumentList[3].(*ast.BooleanLiteral).Value {
170 // inputEditsAreInvalid == true
174 before := nodeToStringSlice(ce.ArgumentList[0])
175 after := nodeToStringSlice(ce.ArgumentList[2])
177 var operations []operation
178 for _, op := range getCalls(ce.ArgumentList[1], "editOp") {
179 operations = append(operations, operation{
180 startLine: nodeToInt(op.ArgumentList[0]) - 1,
181 startColumn: nodeToInt(op.ArgumentList[1]) - 1,
182 endLine: nodeToInt(op.ArgumentList[2]) - 1,
183 endColumn: nodeToInt(op.ArgumentList[3]) - 1,
184 text: nodeToStringSlice(op.ArgumentList[4]),
188 checks = append(checks, check{before, operations, after})
194 func getTests(node ast.Node) []test {
196 for _, ce := range getCalls(node, "test") {
197 description := ce.ArgumentList[0].(*ast.StringLiteral).Value
198 body := ce.ArgumentList[1].(*ast.FunctionLiteral).Body
199 checks := getChecks(body)
201 tests = append(tests, test{description, checks})
210 for _, filename := range os.Args[1:] {
211 source, err := ioutil.ReadFile(filename)
216 program, err := parser.ParseFile(nil, "", source, parser.IgnoreRegExpErrors)
221 tests = append(tests, getTests(program)...)
225 log.Fatalln("no tests found!")
228 fmt.Println("// This file is generated from VSCode model tests by the testgen tool.")
229 fmt.Println("// DO NOT EDIT THIS FILE BY HAND; your changes will be overwritten!\n")
230 fmt.Println("package buffer")
231 fmt.Println(`import "testing"`)
233 re := regexp.MustCompile(`[^\w]`)
234 usedNames := map[string]bool{}
236 for _, test := range tests {
237 name := strings.Title(strings.ToLower(test.description))
238 name = re.ReplaceAllLiteralString(name, "")
244 newName := fmt.Sprintf("%v_%v", name, i)
245 if !usedNames[newName] {
251 usedNames[name] = true
253 fmt.Println(testToGoTest(test, name))