[v3] MUCH Improved parser for bound structs

This commit is contained in:
Lea Anthony
2023-02-19 20:59:03 +11:00
parent 93aa8345dc
commit 95bb15eef4
7 changed files with 450 additions and 341 deletions
File diff suppressed because it is too large Load Diff
+198 -43
View File
@@ -3,60 +3,215 @@ package parser
import (
"testing"
"github.com/samber/lo"
"github.com/stretchr/testify/require"
"github.com/google/go-cmp/cmp"
)
func TestParseDirectory(t *testing.T) {
tests := []struct {
name string
dir string
want []string
wantErr bool
name string
dir string
wantBoundMethods map[string]map[string][]*BoundMethod
wantErr bool
}{
{
name: "should find single bound service",
dir: "testdata/struct_literal_single",
want: []string{"main.GreetService"},
wantErr: false,
},
{
name: "should find multiple bound services",
dir: "testdata/struct_literal_multiple",
want: []string{"main.GreetService", "main.OtherService"},
wantErr: false,
},
{
name: "should find multiple bound services over multiple files",
dir: "testdata/struct_literal_multiple_files",
want: []string{"main.GreetService", "main.OtherService"},
wantErr: false,
},
{
name: "should find multiple bound services over multiple packages",
dir: "testdata/struct_literal_multiple_other",
want: []string{"main.GreetService", "services.OtherService"},
name: "should find single bound service",
dir: "testdata/struct_literal_single",
//wantModels: []string{"main.GreetService"},
wantBoundMethods: map[string]map[string][]*BoundMethod{
"main": {
"GreetService": {
{
Name: "Greet",
DocComment: "Greet someone\n",
Inputs: []*Parameter{
{
Name: "name",
Type: "string",
IsStruct: false,
IsSlice: false,
},
},
Outputs: []*Parameter{
{
Name: "",
Type: "string",
IsStruct: false,
IsSlice: false,
},
},
},
{
Name: "NoInputsStringOut",
DocComment: "",
Inputs: nil,
Outputs: []*Parameter{
{
Name: "",
Type: "string",
IsStruct: false,
IsSlice: false,
},
},
},
{
Name: "StringArrayInputStringOut",
Inputs: []*Parameter{
{
Name: "in",
Type: "string",
IsSlice: true,
},
},
Outputs: []*Parameter{
{
Type: "string",
},
},
},
{
Name: "StringArrayInputStringArrayOut",
Inputs: []*Parameter{
{
Name: "in",
Type: "string",
IsSlice: true,
},
},
Outputs: []*Parameter{
{
Type: "string",
IsSlice: true,
},
},
},
{
Name: "StringArrayInputNamedOutput",
Inputs: []*Parameter{
{
Name: "in",
Type: "string",
IsSlice: true,
},
},
Outputs: []*Parameter{
{
Name: "output",
Type: "string",
IsSlice: true,
},
},
},
{
Name: "StringArrayInputNamedOutputs",
Inputs: []*Parameter{
{
Name: "in",
Type: "string",
IsSlice: true,
},
},
Outputs: []*Parameter{
{
Name: "output",
Type: "string",
IsSlice: true,
},
{
Name: "err",
Type: "error",
},
},
},
{
Name: "IntPointerInputNamedOutputs",
Inputs: []*Parameter{
{
Name: "in",
Type: "int",
IsPointer: true,
},
},
Outputs: []*Parameter{
{
Name: "output",
Type: "int",
IsPointer: true,
},
{
Name: "err",
Type: "error",
},
},
},
{
Name: "StructPointerInputErrorOutput",
Inputs: []*Parameter{
{
Name: "in",
Type: "Person",
IsStruct: true,
IsPointer: true,
},
},
Outputs: []*Parameter{
{
Type: "error",
},
},
},
{
Name: "StructPointerInputStructPointerOutput",
Inputs: []*Parameter{
{
Name: "in",
Type: "Person",
IsStruct: true,
IsPointer: true,
},
},
Outputs: []*Parameter{
{
Type: "Person",
IsPointer: true,
IsStruct: true,
},
},
},
},
},
},
wantErr: false,
},
//{
// name: "should find multiple bound services",
// dir: "testdata/struct_literal_multiple",
// //wantModels: []string{"main.GreetService", "main.OtherService"},
// wantErr: false,
//},
//{
// name: "should find multiple bound services over multiple files",
// dir: "testdata/struct_literal_multiple_files",
// //wantModels: []string{"main.GreetService", "main.OtherService"},
// wantErr: false,
//},
//{
// name: "should find multiple bound services over multiple packages",
// dir: "testdata/struct_literal_multiple_other",
// //wantModels: []string{"main.GreetService", "services.OtherService", "main.Person"},
// wantErr: false,
//},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Debug = true
got, err := ParseDirectory(tt.dir)
got, err := ParseProject(tt.dir)
if (err != nil) != tt.wantErr {
t.Errorf("ParseDirectory() error = %v, wantErr %v", err, tt.wantErr)
return
}
for name, pkg := range got.packages {
for structName, structType := range pkg.boundStructs {
require.NotNil(t, structType)
require.True(t, lo.Contains(tt.want, name+"."+structName))
tt.want = lo.Without(tt.want, name+"."+structName)
}
if diff := cmp.Diff(tt.wantBoundMethods, got.BoundMethods); diff != "" {
t.Errorf("ParseDirectory() failed:\n" + diff)
}
require.Empty(t, tt.want)
})
}
@@ -66,13 +221,13 @@ func TestParseDirectory(t *testing.T) {
// tests := []struct {
// name string
// dir string
// want string
// wantModels string
// wantErr bool
// }{
// {
// name: "should find single bound service",
// dir: "testdata/struct_literal_single",
// want: `namespace main {
// wantModels: `namespace main {
// class GreetService {
// SomeVariable: number;
// }
@@ -83,7 +238,7 @@ func TestParseDirectory(t *testing.T) {
// {
// name: "should find multiple bound services",
// dir: "testdata/struct_literal_multiple",
// want: `namespace main {
// wantModels: `namespace main {
// class GreetService {
// SomeVariable: number;
// }
@@ -96,7 +251,7 @@ func TestParseDirectory(t *testing.T) {
// {
// name: "should find multiple bound services over multiple files",
// dir: "testdata/struct_literal_multiple_files",
// want: `namespace main {
// wantModels: `namespace main {
// class GreetService {
// SomeVariable: number;
// }
@@ -109,7 +264,7 @@ func TestParseDirectory(t *testing.T) {
// {
// name: "should find bound services from other packages",
// dir: "../../examples/binding",
// want: `namespace main {
// wantModels: `namespace main {
// class localStruct {
// }
//}
@@ -139,7 +294,7 @@ func TestParseDirectory(t *testing.T) {
//
// ts, err := GenerateModels(context)
// require.NoError(t, err)
// require.Equal(t, tt.want, string(ts))
// require.Equal(t, tt.wantModels, string(ts))
//
// })
// }
@@ -12,6 +12,11 @@ import (
type GreetService struct {
SomeVariable int
lowerCase string
target *Person
}
type Person struct {
Name string
}
// Greet does XYZ
@@ -19,6 +24,11 @@ func (*GreetService) Greet(name string) string {
return "Hello " + name
}
// NewPerson creates a new person
func (*GreetService) NewPerson(name string) *Person {
return &Person{Name: name}
}
func main() {
app := application.New(application.Options{
Bind: []interface{}{
@@ -7,6 +7,6 @@ type OtherService struct {
}
// Yay does this and that
func (o *OtherService) Yay() {
func (o *OtherService) Yay() []int {
return []int{0, 1, 2}
}
@@ -3,19 +3,58 @@ package main
import (
_ "embed"
"log"
"strings"
"github.com/wailsapp/wails/v3/pkg/application"
)
type Person struct {
Name string
}
// GreetService is great
type GreetService struct {
SomeVariable int
lowerCase string
}
// Greet someone
func (*GreetService) Greet(name string) string {
return "Hello " + name
}
func (*GreetService) NoInputsStringOut() string {
return "Hello"
}
func (*GreetService) StringArrayInputStringOut(in []string) string {
return strings.Join(in, ",")
}
func (*GreetService) StringArrayInputStringArrayOut(in []string) []string {
return in
}
func (*GreetService) StringArrayInputNamedOutput(in []string) (output []string) {
return in
}
func (*GreetService) StringArrayInputNamedOutputs(in []string) (output []string, err error) {
return in, nil
}
func (*GreetService) IntPointerInputNamedOutputs(in *int) (output *int, err error) {
return in, nil
}
func (*GreetService) StructPointerInputErrorOutput(in *Person) error {
return nil
}
func (*GreetService) StructPointerInputStructPointerOutput(in *Person) *Person {
return in
}
func main() {
app := application.New(application.Options{
Bind: []interface{}{