Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(python): add filter for test value #165

Merged
merged 1 commit into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/gen/filters/filterpy/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ func PopulateFuncMap(fm template.FuncMap) {
fm["pyVars"] = pyVars
fm["pyType"] = pyType
fm["pyExtern"] = pyExtern
fm["pyTestValue"] = pyTestValue
}
93 changes: 93 additions & 0 deletions pkg/gen/filters/filterpy/py_testvalue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package filterpy

import (
"fmt"

"github.com/apigear-io/cli/pkg/gen/filters/common"
"github.com/apigear-io/cli/pkg/model"
)

// ToTestValueString returns the test value string for a given schema.
// We intentionally ignore arrays in order to return the test value of the inner type.
func ToTestValueString(prefix string, schema *model.Schema) (string, error) {
if schema == nil {
return "xxx", fmt.Errorf("pyTestValue schema is nil")
}
if schema.Module == nil {
return "xxx", fmt.Errorf("pyTestValue schema module is nil")
}
var text string
switch schema.KindType {
case model.TypeString:
text = "\"xyz\""
case model.TypeInt, model.TypeInt32, model.TypeInt64:
text = "1"
case model.TypeFloat, model.TypeFloat32, model.TypeFloat64:
text = "1.1"
case model.TypeBool:
text = "True"
case model.TypeVoid:
return ToDefaultString(schema, prefix)
case model.TypeEnum:
e_local := schema.LookupEnum("", schema.Type)
e_imported := schema.LookupEnum(schema.Import, schema.Type)
if e_local == nil && e_imported == nil {
return "xxx", fmt.Errorf("pyTestValue enum not found: %s", schema.Dump())
}
// if enum is local it is found both as e_local and e_imported
name := common.CamelTitleCase(e_imported.Name)
member := common.SnakeUpperCase(e_imported.Members[0].Name)
if len(e_imported.Members) > 1 {
member = common.SnakeUpperCase(e_imported.Members[1].Name)
}
if e_local == nil {
prefix = fmt.Sprintf("%s.api.", e_imported.Module.Name)
}
text = fmt.Sprintf("%s%s.%s", prefix, name, member)
case model.TypeStruct:
s_local := schema.LookupStruct("", schema.Type)
s_imported := schema.LookupStruct(schema.Import, schema.Type)
if s_local == nil && s_imported == nil {
return "xxx", fmt.Errorf("pyTestValue struct not found: %s", schema.Dump())
}
// if struct is local it is found both as s_local and s_imported
ident := common.CamelTitleCase(s_imported.Name)
if s_local == nil {
prefix = fmt.Sprintf("%s.api.", s_imported.Module.Name)
}
text = fmt.Sprintf("%s%s()", prefix, ident)
case model.TypeExtern:
xe := parsePyExtern(schema)
if xe.Default != "" {
text = xe.Default
} else {
py_module := ""
if xe.Import != "" {
py_module = fmt.Sprintf("%s.", xe.Import)
}
text = fmt.Sprintf("%s%s()", py_module, xe.Name)
}
case model.TypeInterface:
i_local := schema.LookupInterface("", schema.Type)
i_imported := schema.LookupInterface(schema.Import, schema.Type)
if i_local == nil && i_imported == nil {
return "xxx", fmt.Errorf("pyTestValue interface not found: %s", schema.Dump())
}
// if interface is local it is found both as s_local and s_imported
ident := common.CamelTitleCase(i_imported.Name)
if i_local == nil {
prefix = fmt.Sprintf("%s.api.", i_imported.Module.Name)
}
text = fmt.Sprintf("%s%s()", prefix, ident)
default:
return "xxx", fmt.Errorf("pyTestValue unknown schema %s", schema.Dump())
}
return text, nil
}

func pyTestValue(prefix string, node *model.TypedNode) (string, error) {
if node == nil {
return "xxx", fmt.Errorf("pyTestValue node is nil")
}
return ToTestValueString(prefix, &node.Schema)
}
140 changes: 140 additions & 0 deletions pkg/gen/filters/filterpy/py_testvalue_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package filterpy

import (
"testing"

"github.com/stretchr/testify/assert"
)

// test with all the types
// properties, operation params, operation return, signal params, struct fields
func TestTestValueFromIdl(t *testing.T) {
t.Parallel()
syss := loadTestSystems(t)
var propTests = []struct {
mn string
in string
pn string
rt string
}{
{"test", "Test1", "propVoid", "None"},
{"test", "Test1", "propBool", "True"},
{"test", "Test1", "propInt", "1"},
{"test", "Test1", "propInt32", "1"},
{"test", "Test1", "propInt64", "1"},
{"test", "Test1", "propFloat", "1.1"},
{"test", "Test1", "propFloat32", "1.1"},
{"test", "Test1", "propFloat64", "1.1"},
{"test", "Test1", "propString", "\"xyz\""},
{"test", "Test1", "propBoolArray", "True"}, // all the array types return value intentionally, it may be put into empty array
{"test", "Test1", "propIntArray", "1"},
{"test", "Test1", "propInt32Array", "1"},
{"test", "Test1", "propInt64Array", "1"},
{"test", "Test1", "propFloatArray", "1.1"},
{"test", "Test1", "propFloat32Array", "1.1"},
{"test", "Test1", "propFloat64Array", "1.1"},
{"test", "Test1", "propStringArray", "\"xyz\""},
}
for _, sys := range syss {
for _, tt := range propTests {
t.Run(tt.pn, func(t *testing.T) {
prop := sys.LookupProperty(tt.mn, tt.in, tt.pn)
assert.NotNil(t, prop)
r, err := pyTestValue("", prop)
assert.NoError(t, err)
assert.Equal(t, tt.rt, r)
})
}
}
}

func TestTestValueSymbolsFromIdl(t *testing.T) {
t.Parallel()
syss := loadTestSystems(t)
var propTests = []struct {
mn string
in string
pn string
rt string
}{
{"test", "Test2", "propEnum", "Enum1.NOT_DEFAULT"},
{"test", "Test2", "propStruct", "Struct1()"},
{"test", "Test2", "propInterface", "Interface1()"},
{"test", "Test2", "propEnumArray", "Enum1.NOT_DEFAULT"},
{"test", "Test2", "propStructArray", "Struct1()"},
{"test", "Test2", "propInterfaceArray", "Interface1()"},
}
for _, sys := range syss {
for _, tt := range propTests {
t.Run(tt.pn, func(t *testing.T) {
prop := sys.LookupProperty(tt.mn, tt.in, tt.pn)
assert.NotNil(t, prop)
r, err := pyTestValue("", prop)
assert.NoError(t, err)
assert.Equal(t, tt.rt, r)
})
}
}
}

func TestTestValueWithErrors(t *testing.T) {
t.Parallel()
s, err := pyTestValue("", nil)
assert.Error(t, err)
assert.Equal(t, "xxx", s)
}

func TestTestValueReturnsExternDefault(t *testing.T) {
syss := loadExternSystems(t)
var propTests = []struct {
mn string
in string
pn string
rt string
}{
{"demo", "Iface1", "prop1", "XType1()"},
{"demo", "Iface1", "prop2", "XType2()"},
{"demo", "Iface1", "prop3", "XType3A()"},
}
for _, sys := range syss {
for _, tt := range propTests {
t.Run(tt.pn, func(t *testing.T) {
prop := sys.LookupProperty(tt.mn, tt.in, tt.pn)
assert.NotNil(t, prop)
r, err := pyTestValue("", prop)
assert.NoError(t, err)
assert.Equal(t, tt.rt, r)
})
}
}
}

func TestTestValueReturnsDefaultExterns(t *testing.T) {
t.Parallel()
table := []struct {
module_name string
interface_name string
operation_name string
result string
}{
{"test_apigear_next", "Iface1", "prop1", "XType1()"},
{"test_apigear_next", "Iface1", "prop2", "demo.x.XType2()"},
{"test_apigear_next", "Iface1", "prop3", "demo.x.createXType3A()"},
{"test_apigear_next", "Iface1", "propList", "demo.x.createXType3A()"},
{"test_apigear_next", "Iface1", "propImportedEnum", "test.api.Enum1.NOT_DEFAULT"},
{"test_apigear_next", "Iface1", "propImportedStruct", "test.api.Struct1()"},
}
syss := loadExternSystemsYAML(t)
prefix := "my_prefix::"
for _, sys := range syss {
for _, tt := range table {
t.Run(tt.operation_name, func(t *testing.T) {
prop := sys.LookupProperty(tt.module_name, tt.interface_name, tt.operation_name)
assert.NotNil(t, prop)
r, err := pyTestValue(prefix, prop)
assert.NoError(t, err)
assert.Equal(t, tt.result, r)
})
}
}
}
2 changes: 2 additions & 0 deletions pkg/gen/filters/testdata/test.module.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -319,9 +319,11 @@ enums:
- name: Enum1
members:
- name: Default
- name: NotDefault
- name: EnumLowerNames
members:
- name: firstValue
- name: secondValue

structs:
- name: Struct1
Loading