mukan-ignite/ignite/pkg/xast/global_test.go
Mukan Erkin Törük 26b204bd04
Some checks are pending
Docs Deploy / build_and_deploy (push) Waiting to run
Generate Docs / cli (push) Waiting to run
Generate Config Doc / cli (push) Waiting to run
Go formatting / go-formatting (push) Waiting to run
Check links / markdown-link-check (push) Waiting to run
Integration / pre-test (push) Waiting to run
Integration / test on (push) Blocked by required conditions
Integration / status (push) Blocked by required conditions
Lint / Lint Go code (push) Waiting to run
Test / test (ubuntu-latest) (push) Waiting to run
feat: fork Ignite CLI v29 as Mukan Ignite — remove cosmos-sdk restrictions
2026-05-11 03:31:37 +03:00

752 lines
14 KiB
Go

package xast
import (
"go/ast"
"go/token"
"testing"
"github.com/stretchr/testify/require"
"github.com/ignite/cli/v29/ignite/pkg/errors"
)
func TestInsertGlobal(t *testing.T) {
type args struct {
fileContent string
globalType GlobalType
globals []GlobalOptions
}
tests := []struct {
name string
args args
want string
err error
}{
{
name: "Insert global int var",
args: args{
fileContent: `package main
import (
"fmt"
)
// This is a comment
`,
globalType: GlobalTypeVar,
globals: []GlobalOptions{
WithGlobal("myIntVar", "int", "42"),
},
},
want: `package main
import (
"fmt"
)
var myIntVar int = 42
// This is a comment
`,
},
{
name: "Insert global int var without type",
args: args{
fileContent: `package main
import (
"fmt"
)
`,
globalType: GlobalTypeVar,
globals: []GlobalOptions{
WithGlobal("myIntVar", "", "42"),
},
},
want: `package main
import (
"fmt"
)
var myIntVar = 42
`,
},
{
name: "Insert global int const",
args: args{
fileContent: `package main
import (
"fmt"
)
// This is a comment
`,
globalType: GlobalTypeConst,
globals: []GlobalOptions{
WithGlobal("myIntConst", "int", "42"),
},
},
want: `package main
import (
"fmt"
)
const myIntConst int = 42
// This is a comment
`,
},
{
name: "Insert string const",
args: args{
fileContent: `package main
import (
"fmt"
)
// This is a comment
`,
globalType: GlobalTypeConst,
globals: []GlobalOptions{
WithGlobal("myStringConst", "string", `"hello"`),
},
},
want: `package main
import (
"fmt"
)
const myStringConst string = "hello"
// This is a comment
`,
},
{
name: "Insert string const when already exist one",
args: args{
fileContent: `package main
import (
"fmt"
)
// myIntConst is my const int
const myIntConst int = 42
// This is a comment
`,
globalType: GlobalTypeConst,
globals: []GlobalOptions{
WithGlobal("myStringConst", "string", `"hello"`),
},
},
want: `package main
import (
"fmt"
)
const myStringConst string = "hello"
// myIntConst is my const int
const myIntConst int = 42
// This is a comment
`,
},
{
name: "Insert multiples consts",
args: args{
fileContent: `package main
import (
"fmt"
)
// This is a comment
`,
globalType: GlobalTypeConst,
globals: []GlobalOptions{
WithGlobal("myStringConst", "string", `"hello"`),
WithGlobal("myBoolConst", "bool", "true"),
WithGlobal("myUintConst", "uint64", "40"),
},
},
want: `package main
import (
"fmt"
)
const myStringConst string = "hello"
const myBoolConst bool = true
const myUintConst uint64 = 40
// This is a comment
`,
},
{
name: "Insert global int var with not imports",
args: args{
fileContent: `package main
// This is a comment
`,
globalType: GlobalTypeVar,
globals: []GlobalOptions{
WithGlobal("myIntVar", "int", "42"),
},
},
want: `package main
var myIntVar int = 42
// This is a comment
`,
},
{
name: "Insert global int var int an empty file",
args: args{
fileContent: ``,
globalType: GlobalTypeVar,
globals: []GlobalOptions{
WithGlobal("myIntVar", "int", "42"),
},
},
err: errors.New("1:1: expected 'package', found 'EOF'"),
},
{
name: "Insert a custom var",
args: args{
fileContent: `package main`,
globalType: GlobalTypeVar,
globals: []GlobalOptions{
WithGlobal("fooVar", "foo", "42"),
},
},
want: `package main
var fooVar foo = 42
`,
},
{
name: "Insert an invalid var",
args: args{
fileContent: `package main`,
globalType: GlobalTypeVar,
globals: []GlobalOptions{
WithGlobal("myInvalidVar", "invalid", "AEF#3fa."),
},
},
err: errors.New("1:4: illegal character U+0023 '#'"),
},
{
name: "Insert an invalid type",
args: args{
fileContent: `package main`,
globalType: "invalid",
globals: []GlobalOptions{
WithGlobal("fooVar", "foo", "42"),
},
},
err: errors.New("unsupported global type: invalid"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := InsertGlobal(tt.args.fileContent, tt.args.globalType, tt.args.globals...)
if tt.err != nil {
require.Error(t, err)
require.Equal(t, tt.err.Error(), err.Error())
return
}
require.NoError(t, err)
require.Equal(t, tt.want, got)
})
}
}
func TestAppendFunction(t *testing.T) {
type args struct {
fileContent string
function string
}
tests := []struct {
name string
args args
want string
err error
}{
{
name: "Append a function after the package declaration",
args: args{
fileContent: `package main`,
function: `func add(a, b int) int {
return a + b
}`,
},
want: `package main
func add(a, b int) int {
return a + b
}
`,
},
{
name: "Append a function after a var",
args: args{
fileContent: `package main
import (
"fmt"
)
var myIntVar int = 42
`,
function: `func add(a, b int) int {
return a + b
}`,
},
want: `package main
import (
"fmt"
)
var myIntVar int = 42
func add(a, b int) int {
return a + b
}
`,
},
{
name: "Append a function after the import",
args: args{
fileContent: `package main
import (
"fmt"
)
`,
function: `func add(a, b int) int {
return a + b
}`,
},
want: `package main
import (
"fmt"
)
func add(a, b int) int {
return a + b
}
`,
},
{
name: "Append a function after another function",
args: args{
fileContent: `package main
import (
"fmt"
)
var myIntVar int = 42
func myFunction() int {
return 42
}
`,
function: `func add(a, b int) int {
return a + b
}`,
},
want: `package main
import (
"fmt"
)
var myIntVar int = 42
func myFunction() int {
return 42
}
func add(a, b int) int {
return a + b
}
`,
},
{
name: "Append a function in an empty file",
args: args{
fileContent: ``,
function: `func add(a, b int) int {
return a + b
}`,
},
err: errors.New("1:1: expected 'package', found 'EOF'"),
},
{
name: "Append a empty function",
args: args{
fileContent: `package main`,
function: ``,
},
err: errors.New("no function declaration found in the provided function body"),
},
{
name: "Append an invalid function",
args: args{
fileContent: `package main`,
function: `@,.l.e,`,
},
err: errors.New("2:1: illegal character U+0040 '@'"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := AppendFunction(tt.args.fileContent, tt.args.function)
if tt.err != nil {
require.Error(t, err)
require.Equal(t, tt.err.Error(), err.Error())
return
}
require.NoError(t, err)
require.Equal(t, tt.want, got)
})
}
}
func TestModifyStruct(t *testing.T) {
type args struct {
fileContent string
structName string
options []StructOpts
}
tests := []struct {
name string
args args
want string
err error
}{
{
name: "Add field to existing struct",
args: args{
fileContent: `package main
type MyStruct struct {
ExistingField int
}
`,
structName: "MyStruct",
options: []StructOpts{AppendStructValue("NewField", "string")},
},
want: `package main
type MyStruct struct {
ExistingField int
NewField string
}
`,
},
{
name: "Add field to empty struct",
args: args{
fileContent: `package main
type EmptyStruct struct {
}
`,
structName: "EmptyStruct",
options: []StructOpts{AppendStructValue("NewField", "string")},
},
want: `package main
type EmptyStruct struct {
NewField string
}
`,
},
{
name: "Struct not found",
args: args{
fileContent: `package main
type AnotherStruct struct {
ExistingField int
}
`,
structName: "NonExistentStruct",
options: []StructOpts{AppendStructValue("NewField", "string")},
},
err: errors.New(`struct "NonExistentStruct" not found in file content`),
},
{
name: "Invalid Go code",
args: args{
fileContent: `package main
type MyStruct`,
structName: "MyStruct",
options: []StructOpts{AppendStructValue("NewField", "string")},
},
err: errors.New("3:14: expected type, found newline"),
},
{
name: "Add field after multiple existing fields",
args: args{
fileContent: `package main
type MyStruct struct {
Field1 int
Field2 string
}
`,
structName: "MyStruct",
options: []StructOpts{AppendStructValue("Field3", "bool")},
},
want: `package main
type MyStruct struct {
Field1 int
Field2 string
Field3 bool
}
`,
},
{
name: "Empty file input",
args: args{
fileContent: ``,
structName: "MyStruct",
options: []StructOpts{AppendStructValue("NewField", "string")},
},
err: errors.New("1:1: expected 'package', found 'EOF'"),
},
{
name: "Add field with pointer type",
args: args{
fileContent: `package main
type MyStruct struct {
ExistingField int
}
`,
structName: "MyStruct",
options: []StructOpts{AppendStructValue("PointerField", "*int")},
},
want: `package main
type MyStruct struct {
ExistingField int
PointerField *int
}
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ModifyStruct(tt.args.fileContent, tt.args.structName, tt.args.options...)
if tt.err != nil {
require.Error(t, err)
require.Equal(t, tt.err.Error(), err.Error())
return
}
require.NoError(t, err)
require.Equal(t, tt.want, got)
})
}
}
func TestModifyGlobalArrayVar(t *testing.T) {
type args struct {
fileContent string
globalName string
options []GlobalArrayOpts
}
tests := []struct {
name string
args args
want string
err error
}{
{
name: "Add field to custom variable array",
args: args{
fileContent: `package app
var (
moduleAccPerms = []*authmodulev1.ModuleAccountPermission{
{Account: nft.ModuleName},
{Account: ibctransfertypes.ModuleName, Permissions: []string{authtypes.Minter, authtypes.Burner}},
}
)
`,
globalName: "moduleAccPerms",
options: []GlobalArrayOpts{AppendGlobalArrayValue("{Account: icatypes.ModuleName}")},
},
want: `package app
var (
moduleAccPerms = []*authmodulev1.ModuleAccountPermission{
{Account: nft.ModuleName},
{Account: ibctransfertypes.ModuleName, Permissions: []string{authtypes.Minter, authtypes.Burner}},
{Account: icatypes.ModuleName},
}
)
`,
},
{
name: "Add field to string variable array",
args: args{
fileContent: `package app
var (
blockAccAddrs = []string{
authtypes.FeeCollectorName,
distrtypes.ModuleName,
minttypes.ModuleName,
stakingtypes.BondedPoolName,
stakingtypes.NotBondedPoolName,
}
)
`,
globalName: "blockAccAddrs",
options: []GlobalArrayOpts{AppendGlobalArrayValue("nft.ModuleName")},
},
want: `package app
var (
blockAccAddrs = []string{
authtypes.FeeCollectorName,
distrtypes.ModuleName,
minttypes.ModuleName,
stakingtypes.BondedPoolName,
stakingtypes.NotBondedPoolName,
nft.ModuleName,
}
)
`,
},
{
name: "name not found",
args: args{
fileContent: `package app
var (
blockAccAddrs = []string{
authtypes.FeeCollectorName,
distrtypes.ModuleName,
minttypes.ModuleName,
stakingtypes.BondedPoolName,
stakingtypes.NotBondedPoolName,
}
)
`,
globalName: "notFound",
options: []GlobalArrayOpts{AppendGlobalArrayValue("nft.ModuleName")},
},
err: errors.New("global array \"notFound\" not found in file content"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ModifyGlobalArrayVar(tt.args.fileContent, tt.args.globalName, tt.args.options...)
if tt.err != nil {
require.Error(t, err)
require.Equal(t, tt.err.Error(), err.Error())
return
}
require.NoError(t, err)
require.Equal(t, tt.want, got)
})
}
}
func TestInsertGlobalNoOptions(t *testing.T) {
content := "not valid go source"
got, err := InsertGlobal(content, GlobalTypeVar)
require.NoError(t, err)
require.Equal(t, content, got)
}
func TestModifyGlobalArrayVarNoOptions(t *testing.T) {
content := "not valid go source"
got, err := ModifyGlobalArrayVar(content, "moduleAccPerms")
require.NoError(t, err)
require.Equal(t, content, got)
}
func TestModifyGlobalArrayVarWithNonArrayValue(t *testing.T) {
content := `package app
var moduleAccPerms = 1
`
_, err := ModifyGlobalArrayVar(content, "moduleAccPerms", AppendGlobalArrayValue("newValue"))
require.EqualError(t, err, `global array "moduleAccPerms" not found in file content`)
}
func TestModifyStructWithTypeAlias(t *testing.T) {
content := `package main
type MyStruct = string
`
_, err := ModifyStruct(content, "MyStruct", AppendStructValue("NewField", "string"))
require.EqualError(t, err, `struct "MyStruct" not found in file content`)
}
func TestGlobalTypeToken(t *testing.T) {
tok, err := globalTypeToken(GlobalTypeVar)
require.NoError(t, err)
require.Equal(t, token.VAR, tok)
tok, err = globalTypeToken(GlobalTypeConst)
require.NoError(t, err)
require.Equal(t, token.CONST, tok)
tok, err = globalTypeToken("invalid")
require.Error(t, err)
require.Equal(t, token.ILLEGAL, tok)
require.Equal(t, "unsupported global type: invalid", err.Error())
}
func TestNewGlobalValueSpec(t *testing.T) {
fileSet := token.NewFileSet()
spec, err := newGlobalValueSpec(fileSet, global{
name: "myVar",
varType: "int",
value: "",
})
require.NoError(t, err)
require.Len(t, spec.Names, 1)
require.Equal(t, "myVar", spec.Names[0].Name)
require.NotNil(t, spec.Type)
require.Equal(t, "int", spec.Type.(*ast.Ident).Name)
require.Len(t, spec.Values, 0)
spec, err = newGlobalValueSpec(fileSet, global{
name: "myExprVar",
value: "1 + 2",
})
require.NoError(t, err)
require.Len(t, spec.Values, 1)
_, err = newGlobalValueSpec(fileSet, global{
name: "badVar",
value: "1 + #",
})
require.Error(t, err)
}