13 "github.com/robertkrimen/otto/ast"
14 "github.com/robertkrimen/otto/parser"
21 func (w *walker) Enter(node ast.Node) ast.Visitor {
22 w.nodes = append(w.nodes, node)
26 func (w *walker) Exit(node ast.Node) {
29 func getAllNodes(node ast.Node) []ast.Node {
35 func getCalls(node ast.Node, name string) []*ast.CallExpression {
36 nodes := []*ast.CallExpression{}
37 for _, n := range getAllNodes(node) {
38 if ce, ok := n.(*ast.CallExpression); ok {
40 switch callee := ce.Callee.(type) {
42 calleeName = callee.Name
43 case *ast.DotExpression:
44 calleeName = callee.Identifier.Name
48 if calleeName == name {
49 nodes = append(nodes, ce)
56 func getPropertyValue(node ast.Node, key string) ast.Expression {
57 for _, p := range node.(*ast.ObjectLiteral).Value {
65 type operation struct {
75 operations []operation
84 func stringSliceToGoSource(slice []string) string {
86 b.WriteString("[]string{\n")
87 for _, s := range slice {
88 b.WriteString(fmt.Sprintf("%#v,\n", s))
94 func testToGoTest(test test, name string) string {
97 b.WriteString("func Test")
99 b.WriteString("(t *testing.T) {\n")
101 for _, c := range test.checks {
102 b.WriteString("check(\n")
103 b.WriteString("t,\n")
104 b.WriteString(fmt.Sprintf("%v,\n", stringSliceToGoSource(c.before)))
105 b.WriteString("[]operation{\n")
106 for _, op := range c.operations {
107 b.WriteString("operation{\n")
108 b.WriteString(fmt.Sprintf("start: Loc{%v, %v},\n", op.startColumn, op.startLine))
109 b.WriteString(fmt.Sprintf("end: Loc{%v, %v},\n", op.endColumn, op.endLine))
110 b.WriteString(fmt.Sprintf("text: %v,\n", stringSliceToGoSource(op.text)))
111 b.WriteString("},\n")
113 b.WriteString("},\n")
114 b.WriteString(fmt.Sprintf("%v,\n", stringSliceToGoSource(c.after)))
123 func nodeToStringSlice(node ast.Node) []string {
125 for _, s := range node.(*ast.ArrayLiteral).Value {
126 result = append(result, s.(*ast.StringLiteral).Value)
131 func nodeToStringSlice2(node ast.Node) []string {
133 for _, o := range node.(*ast.ArrayLiteral).Value {
134 result = append(result, getPropertyValue(o, "text").(*ast.StringLiteral).Value)
139 func nodeToInt(node ast.Node) int {
140 return int(node.(*ast.NumberLiteral).Value.(int64))
143 func getChecks(node ast.Node) []check {
146 for _, ce := range getCalls(node, "testApplyEdits") {
147 if len(ce.ArgumentList) != 3 {
152 before := nodeToStringSlice2(ce.ArgumentList[0])
153 after := nodeToStringSlice2(ce.ArgumentList[2])
155 var operations []operation
156 for _, op := range ce.ArgumentList[1].(*ast.ArrayLiteral).Value {
157 args := getPropertyValue(op, "range").(*ast.NewExpression).ArgumentList
158 operations = append(operations, operation{
159 startLine: nodeToInt(args[0]) - 1,
160 startColumn: nodeToInt(args[1]) - 1,
161 endLine: nodeToInt(args[2]) - 1,
162 endColumn: nodeToInt(args[3]) - 1,
163 text: []string{getPropertyValue(op, "text").(*ast.StringLiteral).Value},
167 checks = append(checks, check{before, operations, after})
170 for _, ce := range getCalls(node, "testApplyEditsWithSyncedModels") {
171 if len(ce.ArgumentList) > 3 && ce.ArgumentList[3].(*ast.BooleanLiteral).Value {
172 // inputEditsAreInvalid == true
176 before := nodeToStringSlice(ce.ArgumentList[0])
177 after := nodeToStringSlice(ce.ArgumentList[2])
179 var operations []operation
180 for _, op := range getCalls(ce.ArgumentList[1], "editOp") {
181 operations = append(operations, operation{
182 startLine: nodeToInt(op.ArgumentList[0]) - 1,
183 startColumn: nodeToInt(op.ArgumentList[1]) - 1,
184 endLine: nodeToInt(op.ArgumentList[2]) - 1,
185 endColumn: nodeToInt(op.ArgumentList[3]) - 1,
186 text: nodeToStringSlice(op.ArgumentList[4]),
190 checks = append(checks, check{before, operations, after})
196 func getTests(node ast.Node) []test {
198 for _, ce := range getCalls(node, "test") {
199 description := ce.ArgumentList[0].(*ast.StringLiteral).Value
200 body := ce.ArgumentList[1].(*ast.FunctionLiteral).Body
201 checks := getChecks(body)
203 tests = append(tests, test{description, checks})
212 for _, filename := range os.Args[1:] {
213 source, err := ioutil.ReadFile(filename)
218 program, err := parser.ParseFile(nil, "", source, parser.IgnoreRegExpErrors)
223 tests = append(tests, getTests(program)...)
227 log.Fatalln("no tests found!")
230 fmt.Println("// This file is generated from VSCode model tests by the testgen tool.")
231 fmt.Println("// DO NOT EDIT THIS FILE BY HAND; your changes will be overwritten!\n")
232 fmt.Println("package buffer")
233 fmt.Println(`import "testing"`)
235 re := regexp.MustCompile(`[^\w]`)
236 usedNames := map[string]bool{}
238 for _, test := range tests {
239 name := strings.Title(strings.ToLower(test.description))
240 name = re.ReplaceAllLiteralString(name, "")
246 newName := fmt.Sprintf("%v_%v", name, i)
247 if !usedNames[newName] {
253 usedNames[name] = true
255 fmt.Println(testToGoTest(test, name))