diff --git a/examples/gno.land/r/gnoland/users/v1/users.gno b/examples/gno.land/r/gnoland/users/v1/users.gno index e1b58cac200..551af2e4120 100644 --- a/examples/gno.land/r/gnoland/users/v1/users.gno +++ b/examples/gno.land/r/gnoland/users/v1/users.gno @@ -9,9 +9,6 @@ import ( const ( reValidUsername = "^[a-z]{3}[_a-z0-9]{0,14}[0-9]{3}$" - RegisterEvent = "Registered" - UpdateNameEvent = "NameUpdated" - DeleteUserEvent = "UserDeleted" ) var reUsername = regexp.MustCompile(reValidUsername) @@ -37,7 +34,6 @@ func Register(username string) error { return err } - std.Emit(RegisterEvent, "registrant", registrant.String(), "username", username) return nil } @@ -51,16 +47,19 @@ func UpdateName(newName string) error { return ErrPaused } + if matched := reUsername.MatchString(newName); !matched { + return ErrInvalidUsername + } + registrant := std.PrevRealm().Addr() if err := users.UpdateName(newName, registrant); err != nil { return err } - std.Emit(UpdateNameEvent, "registrant", registrant.String(), "newName", newName) return nil } -// DeleteUser makes all names associated with the PrevRealm() address unresolvable. +// DeleteUser makes all names associated with the `PrevRealm()` address unresolvable. // WARN: After deletion, the same address WILL NOT be able to register a new name. func DeleteUser() error { std.AssertOriginCall() @@ -74,6 +73,5 @@ func DeleteUser() error { return err } - std.Emit(DeleteUserEvent, "address", addr.String()) return nil } diff --git a/examples/gno.land/r/gnoland/users/v1/users_test.gno b/examples/gno.land/r/gnoland/users/v1/users_test.gno new file mode 100644 index 00000000000..cf556ced9fa --- /dev/null +++ b/examples/gno.land/r/gnoland/users/v1/users_test.gno @@ -0,0 +1,104 @@ +package v1 + +import ( + "std" + "testing" + + "gno.land/p/demo/testutils" + "gno.land/p/demo/uassert" + "gno.land/p/demo/urequire" + + "gno.land/r/sys/users" +) + +var ( + alice = "alice123" + bob = "bob123" + aliceAddr = testutils.TestAddress(alice) + bobAddr = testutils.TestAddress(bob) +) + +func TestRegister_Valid(t *testing.T) { + std.TestSetRealm(std.NewUserRealm(aliceAddr)) + std.TestSetOrigCaller(aliceAddr) + + uassert.NoError(t, Register(alice)) + res, latest := users.ResolveName(alice) + + uassert.NotEqual(t, nil, res) + uassert.Equal(t, alice, res.Name()) + uassert.Equal(t, aliceAddr, res.Addr()) + uassert.False(t, res.IsDeleted()) + uassert.True(t, latest) +} + +func TestRegister_Invalid(t *testing.T) { + std.TestSetRealm(std.NewUserRealm(bobAddr)) + std.TestSetOrigCaller(bobAddr) + + // Invalid usernames + uassert.Error(t, Register("alice"), ErrInvalidUsername.Error()) // vanity + uassert.Error(t, Register(""), ErrInvalidUsername.Error()) // empty + uassert.Error(t, Register(" "), ErrInvalidUsername.Error()) // empty + uassert.Error(t, Register("123"), ErrInvalidUsername.Error()) // only numbers + uassert.Error(t, Register("alice&#($)"), ErrInvalidUsername.Error()) // non-allowed chars + uassert.Error(t, Register("Alice123"), ErrInvalidUsername.Error()) // upper-case + uassert.Error(t, Register("toolongusernametoolongusernametoolongusername123"), + ErrInvalidUsername.Error()) // too long + + // Name taken + urequire.NoError(t, Register(bob)) + uassert.Error(t, Register(bob), users.ErrNameTaken.Error()) +} + +func TestUpdateName_Valid(t *testing.T) { + std.TestSetRealm(std.NewUserRealm(aliceAddr)) + std.TestSetOrigCaller(aliceAddr) + + newalice := "newalice123" + // resolve old name + urequire.NoError(t, UpdateName(newalice)) + + res, latest := users.ResolveName(alice) + uassert.NotEqual(t, nil, res) + uassert.Equal(t, newalice, res.Name()) + uassert.Equal(t, aliceAddr, res.Addr()) + uassert.False(t, res.IsDeleted()) + uassert.False(t, latest) +} + +func TestUpdateName_Invalid(t *testing.T) { + std.TestSetRealm(std.NewUserRealm(aliceAddr)) + std.TestSetOrigCaller(aliceAddr) + + // Invalid names + uassert.Error(t, UpdateName("alice"), ErrInvalidUsername.Error()) // vanity + uassert.Error(t, UpdateName(""), ErrInvalidUsername.Error()) // empty + uassert.Error(t, UpdateName(" "), ErrInvalidUsername.Error()) // empty + uassert.Error(t, UpdateName("123"), ErrInvalidUsername.Error()) // only numbers + uassert.Error(t, UpdateName("alice&#($)"), ErrInvalidUsername.Error()) // non-allowed chars + uassert.Error(t, UpdateName("Alice123"), ErrInvalidUsername.Error()) // upper-case + uassert.Error(t, UpdateName("toolongusernametoolongusernametoolongusername123"), + ErrInvalidUsername.Error()) // too long + + urequire.Error(t, UpdateName(bob), users.ErrNameTaken.Error()) +} + +func TestDeleteUser(t *testing.T) { + std.TestSetRealm(std.NewUserRealm(aliceAddr)) + std.TestSetOrigCaller(aliceAddr) + + urequire.NoError(t, DeleteUser()) + res, _ := users.ResolveName(alice) + uassert.Equal(t, nil, res) + res = users.ResolveAddress(aliceAddr) + uassert.Equal(t, nil, res) +} + +func TestDeleteUser_Invalid(t *testing.T) { + std.TestSetRealm(std.NewUserRealm(aliceAddr)) + std.TestSetOrigCaller(aliceAddr) + + // Already deleted user + urequire.Error(t, DeleteUser(), users.ErrUserNotExist.Error()) +} diff --git a/examples/gno.land/r/sys/users/errors.gno b/examples/gno.land/r/sys/users/errors.gno index 86da596faff..41d9bd7e464 100644 --- a/examples/gno.land/r/sys/users/errors.gno +++ b/examples/gno.land/r/sys/users/errors.gno @@ -17,7 +17,6 @@ var ( ErrAlreadyHasName = errors.New(prefix + "username for this address already registered - try creating an Alias") ErrDeletedUser = errors.New(prefix + "cannot register a new username after deleting") - ErrAlreadyDeleted = errors.New(prefix + "cannot delete same user twice") ErrAliasBeforeName = errors.New(prefix + "cannot register Alias before a username") ErrUserNotExist = errors.New(prefix + "this user has not been registered before") diff --git a/examples/gno.land/r/sys/users/store.gno b/examples/gno.land/r/sys/users/store.gno index 8e6eaf0c5a7..dfc5ce9fa9f 100644 --- a/examples/gno.land/r/sys/users/store.gno +++ b/examples/gno.land/r/sys/users/store.gno @@ -16,9 +16,9 @@ var ( ) const ( - RegisterUserEvent = "UserRegistered" - RegisterAliasEvent = "AliasRegistered" - DeleteUserEvent = "UserDeleted" + RegisterUserEvent = "Registered" + UpdateNameEvent = "NameUpdated" + DeleteUserEvent = "Deleted" maxUsernameLen = 64 ) @@ -117,7 +117,7 @@ func UpdateName(newName string, address std.Address) error { userData.username = newName nameStore.Set(newName, userData) - std.Emit(RegisterAliasEvent, "Alias", newName, "address", address.String()) + std.Emit(UpdateNameEvent, "Alias", newName, "address", address.String()) return nil }