package services
import (
+ "errors"
+ "net/url"
+ "strings"
"sync"
"github.com/aloussase/squad-rotation-bot/entities"
}
func (ms *memberServiceImpl) CreateMember(name, avatarUrl string) error {
+ if strings.TrimSpace(name) == "" {
+ return errors.New("Name cannot be empty")
+ }
+
+ if strings.TrimSpace(avatarUrl) == "" {
+ return errors.New("Avatar URL cannot be empty")
+ }
+
+ if !strings.HasPrefix(avatarUrl, "https://") {
+ return errors.New("The avatar URL must be a valid HTTPS URL")
+ }
+
+ if _, err := url.Parse(avatarUrl); err != nil {
+ return err
+ }
+
ms.mu.Lock()
defer ms.mu.Unlock()
--- /dev/null
+package services
+
+import (
+ "strings"
+ "testing"
+)
+
+const (
+ VALID_NAME = "Alexander"
+ VALID_URL = "https://example.com"
+)
+
+func TestMemberServiceRejectsEmptyName(t *testing.T) {
+ impl := Create()
+
+ err := impl.CreateMember("", VALID_URL)
+
+ if err == nil {
+ t.Errorf("Expected service to reject empty member name but did not")
+ }
+
+ if !strings.Contains(strings.ToLower(err.Error()), "name") {
+ t.Errorf("Expected error to contain 'name', but did not")
+ }
+}
+
+func TestMemberServiceRejectsEmptyUrl(t *testing.T) {
+ impl := Create()
+
+ err := impl.CreateMember(VALID_NAME, "")
+
+ if err == nil {
+ t.Errorf("Expected service to reject empty member avatar URL but did not")
+ }
+
+ if !strings.Contains(strings.ToLower(err.Error()), "url") {
+ t.Errorf("Expected error to contain 'url', but did not")
+ }
+}
+
+func TestMemberServiceRejectsMalformedUrl(t *testing.T) {
+ impl := Create()
+
+ tt := []string{
+ "not a URL",
+ "https://invalid URL",
+ }
+
+ for _, x := range tt {
+ err := impl.CreateMember(VALID_NAME, x)
+
+ if err == nil {
+ t.Errorf("Expected service to reject invalid member avatar URL but did not: %s", x)
+ }
+
+ if !strings.Contains(strings.ToLower(err.Error()), "url") {
+ t.Errorf("Expected error to contain 'url', but did not: %v", err)
+ }
+ }
+
+}
+
+// TODO: Test happy path
+
+// TODO: Test concurrent requests