Skip to content
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
422 changes: 422 additions & 0 deletions tools/operations-gen/internal/families/evm/abi.go

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,29 +1,10 @@
package evm
package evm_test

import (
"testing"
)

// TestToSnakeCase covers the algorithmic EVM name-normalisation helper
// across representative contract names and mixed casing patterns.
func TestToSnakeCase(t *testing.T) {
t.Parallel()
cases := []struct{ input, want string }{
{"OnRamp", "on_ramp"},
{"OffRamp", "off_ramp"},
{"LinkToken", "link_token"},
{"FeeQuoter", "fee_quoter"},
{"EVM2EVMOnRamp", "evm2evm_on_ramp"},
}
for _, tc := range cases {
t.Run(tc.input, func(t *testing.T) {
t.Parallel()
if got := toSnakeCase(tc.input); got != tc.want {
t.Errorf("toSnakeCase(%q) = %q, want %q", tc.input, got, tc.want)
}
})
}
}
"github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/internal/families/evm"
)

func TestSolidityToGoType(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -60,7 +41,7 @@ func TestSolidityToGoType(t *testing.T) {
for _, tc := range cases {
t.Run(tc.solidity, func(t *testing.T) {
t.Parallel()
if got := solidityToGoType(tc.solidity, evmTypeMap); got != tc.want {
if got := evm.SolidityToGoType(tc.solidity, evm.EvmTypeMap); got != tc.want {
t.Errorf("solidityToGoType(%q) = %q, want %q", tc.solidity, got, tc.want)
}
})
Expand Down Expand Up @@ -90,8 +71,8 @@ func TestExtractStructName(t *testing.T) {
for _, tc := range cases {
t.Run(tc.internalType, func(t *testing.T) {
t.Parallel()
if got := extractStructName(tc.internalType); got != tc.want {
t.Errorf("extractStructName(%q) = %q, want %q", tc.internalType, got, tc.want)
if got := evm.ExtractStructName(tc.internalType); got != tc.want {
t.Errorf("ExtractStructName(%q) = %q, want %q", tc.internalType, got, tc.want)
}
})
}
Expand Down Expand Up @@ -120,8 +101,8 @@ func TestSanitizeFieldName(t *testing.T) {
for _, tc := range cases {
t.Run(tc.input, func(t *testing.T) {
t.Parallel()
if got := sanitizeFieldName(tc.input); got != tc.want {
t.Errorf("sanitizeFieldName(%q) = %q, want %q", tc.input, got, tc.want)
if got := evm.SanitizeFieldName(tc.input); got != tc.want {
t.Errorf("SanitizeFieldName(%q) = %q, want %q", tc.input, got, tc.want)
}
})
}
Expand All @@ -145,22 +126,22 @@ func TestSanitizeParamName(t *testing.T) {
for _, tc := range cases {
t.Run(tc.input, func(t *testing.T) {
t.Parallel()
if got := sanitizeParamName(tc.input); got != tc.want {
t.Errorf("sanitizeParamName(%q) = %q, want %q", tc.input, got, tc.want)
if got := evm.SanitizeParamName(tc.input); got != tc.want {
t.Errorf("SanitizeParamName(%q) = %q, want %q", tc.input, got, tc.want)
}
})
}
}

func TestFindFunctionInABIOverloads(t *testing.T) {
t.Parallel()
entries := []ABIEntry{
{Type: "function", Name: "transfer", Inputs: []ABIParam{{Name: "to", Type: "address"}, {Name: "amount", Type: "uint256"}}, StateMutability: "nonpayable"},
{Type: "function", Name: "transfer", Inputs: []ABIParam{{Name: "to", Type: "address"}, {Name: "amount", Type: "uint256"}, {Name: "data", Type: "bytes"}}, StateMutability: "nonpayable"},
{Type: "function", Name: "transfer", Inputs: []ABIParam{{Name: "to", Type: "address"}, {Name: "amount", Type: "uint256"}, {Name: "data", Type: "bytes"}, {Name: "extra", Type: "bytes32"}}, StateMutability: "nonpayable"},
entries := []evm.ABIEntry{
{Type: "function", Name: "transfer", Inputs: []evm.ABIParam{{Name: "to", Type: "address"}, {Name: "amount", Type: "uint256"}}, StateMutability: "nonpayable"},
{Type: "function", Name: "transfer", Inputs: []evm.ABIParam{{Name: "to", Type: "address"}, {Name: "amount", Type: "uint256"}, {Name: "data", Type: "bytes"}}, StateMutability: "nonpayable"},
{Type: "function", Name: "transfer", Inputs: []evm.ABIParam{{Name: "to", Type: "address"}, {Name: "amount", Type: "uint256"}, {Name: "data", Type: "bytes"}, {Name: "extra", Type: "bytes32"}}, StateMutability: "nonpayable"},
}

results := findFunctionInABI(entries, "transfer", "mypkg", evmTypeMap)
results := evm.FindFunctionInABI(entries, "transfer", "mypkg", evm.EvmTypeMap)

if len(results) != 3 {
t.Fatalf("expected 3 overloads, got %d", len(results))
Expand All @@ -181,8 +162,8 @@ func TestFindFunctionInABIOverloads(t *testing.T) {

func TestReadABIAndBytecodeInvalidABIFileSuffix(t *testing.T) {
t.Parallel()
cfg := evmContractConfig{ABIFile: "contract.abi"}
_, _, err := readABIAndBytecode(cfg, "contract", "v1_0_0", evmInputConfig{
cfg := evm.EvmContractConfig{ABIFile: "contract.abi"}
_, _, err := evm.ReadABIAndBytecode(cfg, "contract", "v1_0_0", evm.EvmInputConfig{
ABIBasePath: t.TempDir(),
BytecodeBasePath: t.TempDir(),
})
Expand All @@ -193,98 +174,10 @@ func TestReadABIAndBytecodeInvalidABIFileSuffix(t *testing.T) {

func TestFindFunctionInABINotFound(t *testing.T) {
t.Parallel()
entries := []ABIEntry{
entries := []evm.ABIEntry{
{Type: "function", Name: "transfer"},
}
if got := findFunctionInABI(entries, "mint", "pkg", evmTypeMap); got != nil {
if got := evm.FindFunctionInABI(entries, "mint", "pkg", evm.EvmTypeMap); got != nil {
t.Errorf("expected nil for missing function, got %v", got)
}
}

func TestCheckNeedsBigInt(t *testing.T) {
t.Parallel()
makeFuncInfo := func(goType string) *functionInfo {
return &functionInfo{
Name: "Foo",
Parameters: []parameterInfo{{GoType: goType}},
}
}

t.Run("parameter needs big.Int", func(t *testing.T) {
t.Parallel()
info := &contractInfo{
Functions: map[string]*functionInfo{"Foo": makeFuncInfo("*big.Int")},
FunctionOrder: []string{"Foo"},
}
if !checkNeedsBigInt(info) {
t.Error("expected true")
}
})

t.Run("return param needs big.Int", func(t *testing.T) {
t.Parallel()
info := &contractInfo{
Functions: map[string]*functionInfo{
"Foo": {Name: "Foo", ReturnParams: []parameterInfo{{GoType: "*big.Int"}}},
},
FunctionOrder: []string{"Foo"},
}
if !checkNeedsBigInt(info) {
t.Error("expected true")
}
})

t.Run("constructor param needs big.Int", func(t *testing.T) {
t.Parallel()
entry := ABIEntry{
Type: "constructor",
Inputs: []ABIParam{{Name: "supply", Type: "uint256"}},
}
fi := parseABIFunction(entry, "pkg", evmTypeMap)
info := &contractInfo{
Constructor: fi,
Functions: map[string]*functionInfo{},
FunctionOrder: []string{},
}
if !checkNeedsBigInt(info) {
t.Error("expected true for constructor uint256 param")
}
})

t.Run("no big.Int", func(t *testing.T) {
t.Parallel()
info := &contractInfo{
Functions: map[string]*functionInfo{"Foo": makeFuncInfo("common.Address")},
FunctionOrder: []string{"Foo"},
}
if checkNeedsBigInt(info) {
t.Error("expected false")
}
})

t.Run("nested tuple component needs big.Int", func(t *testing.T) {
t.Parallel()
info := &contractInfo{
Functions: map[string]*functionInfo{
"Foo": {
Name: "Foo",
Parameters: []parameterInfo{
{
Name: "metadata",
GoType: "RootMetadata",
IsStruct: true,
StructName: "RootMetadata",
Components: []parameterInfo{
{Name: "chainId", GoType: "*big.Int"},
},
},
},
},
},
FunctionOrder: []string{"Foo"},
}
if !checkNeedsBigInt(info) {
t.Error("expected true for nested tuple component using *big.Int")
}
})
}
Loading
Loading