From a3451d8c148dc9a66de1fbda0cc41ac3558424a3 Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Mon, 23 Dec 2024 16:08:31 +0900 Subject: [PATCH] test: executeParameterChange2, validateProposalState, checkProposalValidation --- gov/governance/execute2.gno | 84 ++++++++++++ gov/governance/execute2_test.gno | 216 +++++++++++++++++++++++++++++-- 2 files changed, 291 insertions(+), 9 deletions(-) diff --git a/gov/governance/execute2.gno b/gov/governance/execute2.gno index 03293af6a..bf4917e6b 100644 --- a/gov/governance/execute2.gno +++ b/gov/governance/execute2.gno @@ -2,13 +2,18 @@ package governance import ( "errors" + "std" + "strconv" "strings" "time" "gno.land/p/demo/avl" "gno.land/p/demo/ufmt" "gno.land/r/gnoswap/v1/common" + cp "gno.land/r/gnoswap/v1/community_pool" + "gno.land/r/gnoswap/v1/consts" en "gno.land/r/gnoswap/v1/emission" + pl "gno.land/r/gnoswap/v1/pool" ) var ( @@ -107,6 +112,56 @@ func parseMessage(msg string) (pkgPath string, function string, params []string, return parts[0], parts[1], strings.Split(parts[2], ","), nil } +func createParameterHandlers() *ParameterRegistry { + registry := NewParameterRegistry() + + // Community pool + registry.Register(consts.COMMUNITY_POOL_PATH, "TransferToken", func(params []string) error { + if len(params) != 3 { + return ufmt.Errorf("invalid parameters for TransferToken. expected 3 but got %d", len(params)) + } + cp.TransferToken(params[0], std.Address(params[1]), parseUint64(params[2])) + return nil + }) + + // Emission + registry.Register(consts.EMISSION_PATH, "ChangeDistributionPct", func(params []string) error { + if len(params) != 8 { + return ufmt.Errorf("invalid parameters for ChangeDistributionPct. expected 8 but got %d", len(params)) + } + en.ChangeDistributionPct( + parseInt(params[0]), + parseUint64(params[1]), + parseInt(params[2]), + parseUint64(params[3]), + parseInt(params[4]), + parseUint64(params[5]), + parseInt(params[6]), + parseUint64(params[7]), + ) + return nil + }) + + // Pool + registry.Register(consts.POOL_PATH, "SetFeeProtocol", func(params []string) error { + if len(params) != 2 { + return ufmt.Errorf("invalid parameters for SetFeeProtocol. expected 2 but got %d", len(params)) + } + pl.SetFeeProtocol(uint8(parseUint64(params[0])), uint8(parseUint64(params[1]))) + return nil + }) + + registry.Register(consts.POOL_PATH, "SetPoolCreationFee", func(params []string) error { + if len(params) != 1 { + return ufmt.Errorf("invalid parameters for SetPoolCreationFee. expected 1 but got %d", len(params)) + } + pl.SetPoolCreationFee(parseUint64(params[0])) + return nil + }) + + return registry +} + ///////////////////// VALIDATION ///////////////////// type ExecutionValidator struct { @@ -213,3 +268,32 @@ func validateExecutionWindow(now, windowStart, windowEnd uint64) error { return nil } + +///////////////////// UTILS ///////////////////// + +func parseInt(s string) int { + num, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(ufmt.Sprintf("invalid int value: %s", s)) + } + return int(num) +} + +func parseUint64(s string) uint64 { + num, err := strconv.ParseUint(s, 10, 64) + if err != nil { + panic(ufmt.Sprintf("invalid uint64 value: %s", s)) + } + return num +} + +func parseBool(s string) bool { + switch s { + case "true": + return true + case "false": + return false + default: + panic(ufmt.Sprintf("invalid bool value: %s", s)) + } +} diff --git a/gov/governance/execute2_test.gno b/gov/governance/execute2_test.gno index 69cd35690..3cf3beeaa 100644 --- a/gov/governance/execute2_test.gno +++ b/gov/governance/execute2_test.gno @@ -1,7 +1,11 @@ package governance import ( + "errors" + "std" "testing" + + "gno.land/p/demo/uassert" ) func TestParameterRegistry(t *testing.T) { @@ -46,16 +50,10 @@ func TestParameterRegistry(t *testing.T) { handler, err := registry.Handler(tt.pkgPath, tt.function) if tt.wantErr { - if err == nil { - t.Errorf("expected error but got nil") - } - if err.Error() != tt.errMessage { - t.Errorf("expected error message %q but got %q", tt.errMessage, err.Error()) - } + uassert.Error(t, err, tt.errMessage) + uassert.Equal(t, err.Error(), tt.errMessage) } else { - if err != nil { - t.Errorf("unexpected error: %v", err) - } + uassert.NoError(t, err) if handler == nil { t.Error("expected handler to be non-nil") } @@ -63,3 +61,203 @@ func TestParameterRegistry(t *testing.T) { }) } } + +func TestExecuteParameterChange2(t *testing.T) { + registry := NewParameterRegistry() + + registry.Register("test/pkg", "TestFunc", func(params []string) error { + if len(params) != 2 { + return errors.New("invalid params length") + } + return nil + }) + + tests := []struct { + name string + msgs []string + wantErr bool + }{ + { + name: "Pass: Valid message", + msgs: []string{ + "test/pkg*EXE*TestFunc*EXE*param1,param2", + }, + wantErr: false, + }, + { + name: "Fail: Missing separator", + msgs: []string{ + "test/pkg*EXE*TestFunc", + }, + wantErr: true, + }, + { + name: "Fail: Non-existent handler", + msgs: []string{ + "unknown/pkg*EXE*UnknownFunc*EXE*param1", + }, + wantErr: true, + }, + { + name: "Fail: Not enough parameters", + msgs: []string{ + "test/pkg*EXE*TestFunc*EXE*param1", + }, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := executeParameterChange2(tt.msgs, registry) + if (err != nil) != tt.wantErr { + t.Errorf("executeParameterChange2() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestValidateProposalState(t *testing.T) { + tests := []struct { + name string + proposal *ProposalInfo + want ExecutionValidator + }{ + { + name: "Pass: Text proposal", + proposal: &ProposalInfo{ + ProposalType: "TEXT", + ExecutionState: ExecutionState{ + Executed: false, + Canceled: false, + Rejected: false, + Passed: true, + }, + }, + want: ExecutionValidator{ + isTextProposal: true, + isAlreadyExecuted: false, + isAlreadyCanceled: false, + isAlreadyRejected: false, + hasPassed: true, + }, + }, + { + name: "Pass: Already executed", + proposal: &ProposalInfo{ + ProposalType: "PARAMETER_CHANGE", + ExecutionState: ExecutionState{ + Executed: true, + Canceled: false, + Rejected: false, + Passed: true, + }, + }, + want: ExecutionValidator{ + isTextProposal: false, + isAlreadyExecuted: true, + isAlreadyCanceled: false, + isAlreadyRejected: false, + hasPassed: true, + }, + }, + { + name: "Pass: Canceled", + proposal: &ProposalInfo{ + ProposalType: "PARAMETER_CHANGE", + ExecutionState: ExecutionState{ + Executed: false, + Canceled: true, + Rejected: false, + Passed: false, + }, + }, + want: ExecutionValidator{ + isTextProposal: false, + isAlreadyExecuted: false, + isAlreadyCanceled: true, + isAlreadyRejected: false, + hasPassed: false, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := validateProposalState(tt.proposal) + if got != tt.want { + t.Errorf("validateProposalState() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestCheckProposalValidation(t *testing.T) { + // TODO: change error message after error code is defined + tests := []struct { + name string + validator ExecutionValidator + wantErr bool + errMsg string + }{ + { + name: "Pass: Valid proposal", + validator: ExecutionValidator{ + isTextProposal: false, + isAlreadyExecuted: false, + isAlreadyCanceled: false, + isAlreadyRejected: false, + hasPassed: true, + }, + wantErr: false, + }, + { + name: "Fail: Text proposal is not executable", + validator: ExecutionValidator{ + isTextProposal: true, + isAlreadyExecuted: false, + isAlreadyCanceled: false, + isAlreadyRejected: false, + hasPassed: true, + }, + wantErr: true, + errMsg: "[GNOSWAP-GOVERNANCE-014] can not execute text proposal", + }, + { + name: "Fail: Already executed, canceled, or rejected", + validator: ExecutionValidator{ + isTextProposal: false, + isAlreadyExecuted: true, + isAlreadyCanceled: false, + isAlreadyRejected: false, + hasPassed: true, + }, + wantErr: true, + errMsg: "proposal already executed, canceled, or rejected", + }, + { + name: "Fail: Proposal has not passed", + validator: ExecutionValidator{ + isTextProposal: false, + isAlreadyExecuted: false, + isAlreadyCanceled: false, + isAlreadyRejected: false, + hasPassed: false, + }, + wantErr: true, + errMsg: "proposal has not passed", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := checkProposalValidation(tt.validator) + if tt.wantErr { + uassert.Error(t, err, tt.errMsg) + uassert.Equal(t, err.Error(), tt.errMsg) + } else { + uassert.NoError(t, err) + } + }) + } +}