1package txlink23import (4 "chain/runtime"5 "testing"67 "gno.land/p/nt/urequire/v0"8)910func TestCall(t *testing.T) {11 cd := runtime.ChainDomain()1213 tests := []struct {14 fn string15 args []string16 want string17 realm_XXX Realm18 }{19 {"foo", []string{"bar", "1", "baz", "2"}, "/p/moul/txlink/v0$help&func=foo&bar=1&baz=2", ""},20 {"testFunc", []string{"key", "value"}, "/p/moul/txlink/v0$help&func=testFunc&key=value", ""},21 {"noArgsFunc", []string{}, "/p/moul/txlink/v0$help&func=noArgsFunc", ""},22 {"oddArgsFunc", []string{"key"}, "/p/moul/txlink/v0$help&func=oddArgsFunc&error=odd+number+of+arguments", ""},23 {"foo", []string{"bar", "1", "baz", "2"}, "/r/lorem/ipsum$help&func=foo&bar=1&baz=2", Realm(cd + "/r/lorem/ipsum")},24 {"testFunc", []string{"key", "value"}, "/r/lorem/ipsum$help&func=testFunc&key=value", Realm(cd + "/r/lorem/ipsum")},25 {"noArgsFunc", []string{}, "/r/lorem/ipsum$help&func=noArgsFunc", Realm(cd + "/r/lorem/ipsum")},26 {"oddArgsFunc", []string{"key"}, "/r/lorem/ipsum$help&func=oddArgsFunc&error=odd+number+of+arguments", Realm(cd + "/r/lorem/ipsum")},27 {"foo", []string{"bar", "1", "baz", "2"}, "https://gno.world/r/lorem/ipsum$help&func=foo&bar=1&baz=2", "gno.world/r/lorem/ipsum"},28 {"testFunc", []string{"key", "value"}, "https://gno.world/r/lorem/ipsum$help&func=testFunc&key=value", "gno.world/r/lorem/ipsum"},29 {"noArgsFunc", []string{}, "https://gno.world/r/lorem/ipsum$help&func=noArgsFunc", "gno.world/r/lorem/ipsum"},30 {"oddArgsFunc", []string{"key"}, "https://gno.world/r/lorem/ipsum$help&func=oddArgsFunc&error=odd+number+of+arguments", "gno.world/r/lorem/ipsum"},31 {"test", []string{"key", "hello world"}, "/p/moul/txlink/v0$help&func=test&key=hello+world", ""},32 {"test", []string{"key", "a&b=c"}, "/p/moul/txlink/v0$help&func=test&key=a%26b%3Dc", ""},33 {"test", []string{"key", ""}, "/p/moul/txlink/v0$help&func=test&key=", ""},34 {"testSend", []string{"key", "hello world", ".send", "1000000ugnot"}, "/p/moul/txlink/v0$help&func=testSend&.send=1000000ugnot&key=hello+world", ""},35 }3637 for _, tt := range tests {38 title := string(tt.realm_XXX) + "_" + tt.fn39 t.Run(title, func(t *testing.T) {40 if tt.fn == "oddArgsFunc" {41 defer func() {42 if r := recover(); r != nil {43 if r != "odd number of arguments" {44 t.Errorf("expected panic with message 'odd number of arguments', got: %v", r)45 }46 } else {47 t.Error("expected panic for odd number of arguments, but did not panic")48 }49 }()50 }51 got := tt.realm_XXX.Call(tt.fn, tt.args...)52 urequire.Equal(t, tt.want, got)53 })54 }55}5657func TestBuilder(t *testing.T) {58 cases := []struct {59 name string60 build func() string61 expected string62 }{63 // Basic functionality tests64 {65 name: "empty_function",66 build: func() string {67 return NewLink("").URL()68 },69 expected: "",70 },71 {72 name: "function_without_args",73 build: func() string {74 return NewLink("MyFunc").URL()75 },76 expected: "/p/moul/txlink/v0$help&func=MyFunc",77 },7879 // Realm tests80 {81 name: "gnoland_realm",82 build: func() string {83 return Realm("gno.land/r/demo").84 NewLink("MyFunc").85 AddArgs("key", "value").86 URL()87 },88 expected: "/r/demo$help&func=MyFunc&key=value",89 },90 {91 name: "external_realm",92 build: func() string {93 return Realm("gno.world/r/demo").94 NewLink("MyFunc").95 AddArgs("key", "value").96 URL()97 },98 expected: "https://gno.world/r/demo$help&func=MyFunc&key=value",99 },100 {101 name: "empty_realm",102 build: func() string {103 return Realm("").104 NewLink("func").105 AddArgs("key", "value").106 URL()107 },108 expected: "/p/moul/txlink/v0$help&func=func&key=value",109 },110111 // URL encoding tests112 {113 name: "url_encoding_with_spaces",114 build: func() string {115 return NewLink("test").116 AddArgs("key", "hello world").117 URL()118 },119 expected: "/p/moul/txlink/v0$help&func=test&key=hello+world",120 },121 {122 name: "url_encoding_with_special_chars",123 build: func() string {124 return NewLink("test").125 AddArgs("key", "a&b=c").126 URL()127 },128 expected: "/p/moul/txlink/v0$help&func=test&key=a%26b%3Dc",129 },130 {131 name: "url_encoding_with_unicode",132 build: func() string {133 return NewLink("func").134 AddArgs("key", "🌟").135 URL()136 },137 expected: "/p/moul/txlink/v0$help&func=func&key=%F0%9F%8C%9F",138 },139 {140 name: "url_encoding_with_special_chars_in_key",141 build: func() string {142 return NewLink("func").143 AddArgs("my/key", "value").144 URL()145 },146 expected: "/p/moul/txlink/v0$help&func=func&my%2Fkey=value",147 },148149 // AddArgs tests150 {151 name: "addargs_with_multiple_pairs",152 build: func() string {153 return NewLink("MyFunc").154 AddArgs("key1", "value1", "key2", "value2").155 URL()156 },157 expected: "/p/moul/txlink/v0$help&func=MyFunc&key1=value1&key2=value2",158 },159 {160 name: "addargs_with_odd_number_of_args",161 build: func() string {162 defer func() {163 if r := recover(); r != nil {164 if r != "odd number of arguments" {165 t.Errorf("expected panic with message 'odd number of arguments', got: %v", r)166 }167 } else {168 t.Error("expected panic for odd number of arguments, but did not panic")169 }170 }()171 return NewLink("MyFunc").172 AddArgs("key1", "value1", "orphan").173 URL()174 },175 expected: "",176 },177178 // Empty values tests179 {180 name: "empty_key_should_be_ignored",181 build: func() string {182 return NewLink("func").183 AddArgs("", "value").184 URL()185 },186 expected: "/p/moul/txlink/v0$help&func=func",187 },188 {189 name: "empty_value_should_be_kept",190 build: func() string {191 return NewLink("func").192 AddArgs("key", "").193 URL()194 },195 expected: "/p/moul/txlink/v0$help&func=func&key=",196 },197198 // Send tests199 {200 name: "send_via_addsend_method",201 build: func() string {202 return NewLink("MyFunc").203 AddArgs("key", "value").204 SetSend("1000000ugnot").205 URL()206 },207 expected: "/p/moul/txlink/v0$help&func=MyFunc&.send=1000000ugnot&key=value",208 },209 {210 name: "send_via_addarg_method_panic",211 build: func() string {212 defer func() {213 if r := recover(); r != nil {214 if r != "invalid key" {215 t.Errorf("expected panic with message 'invalid key', got: %v", r)216 }217 } else {218 t.Errorf("expected panic for .send key, but did not panic")219 }220 }()221 NewLink("MyFunc").AddArgs(".send", "1000000ugnot")222 return "no panic occurred"223 },224 expected: "",225 },226 {227 name: "addsend_should_override_previous_addsend",228 build: func() string {229 return NewLink("MyFunc").230 SetSend("1000000ugnot").231 SetSend("2000000ugnot").232 URL()233 },234 expected: "/p/moul/txlink/v0$help&func=MyFunc&.send=2000000ugnot",235 },236 }237238 for _, tc := range cases {239 t.Run(tc.name, func(t *testing.T) {240 got := tc.build()241 urequire.Equal(t, tc.expected, got)242 })243 }244}245Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.