feat(relationship): add parse function

Amolith created

ParseRelationshipStrength with case-insensitive parsing for all 7
values.

Assisted-by: Claude Sonnet 4 via Crush

Change summary

relationship.go      | 41 ++++++++++++++++++++++++++++++
relationship_test.go | 61 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 102 insertions(+)

Detailed changes

relationship.go 🔗

@@ -0,0 +1,41 @@
+// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+package lunatask
+
+import (
+	"errors"
+	"fmt"
+	"strings"
+)
+
+// Errors returned by RelationshipStrength operations.
+var (
+	// ErrInvalidRelationshipStrength is returned when parsing an unknown relationship strength string.
+	ErrInvalidRelationshipStrength = errors.New("invalid relationship strength")
+)
+
+// ParseRelationshipStrength parses a string to a RelationshipStrength value (case-insensitive).
+// Valid values: "family", "intimate-friends", "close-friends", "casual-friends",
+// "acquaintances", "business-contacts", "almost-strangers".
+func ParseRelationshipStrength(str string) (RelationshipStrength, error) {
+	switch strings.ToLower(str) {
+	case "family":
+		return RelationshipFamily, nil
+	case "intimate-friends":
+		return RelationshipIntimateFriend, nil
+	case "close-friends":
+		return RelationshipCloseFriend, nil
+	case "casual-friends":
+		return RelationshipCasualFriend, nil
+	case "acquaintances":
+		return RelationshipAcquaintance, nil
+	case "business-contacts":
+		return RelationshipBusiness, nil
+	case "almost-strangers":
+		return RelationshipAlmostStranger, nil
+	default:
+		return "", fmt.Errorf("%w: %q", ErrInvalidRelationshipStrength, str)
+	}
+}

relationship_test.go 🔗

@@ -0,0 +1,61 @@
+// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+package lunatask_test
+
+import (
+	"testing"
+
+	lunatask "git.secluded.site/go-lunatask"
+)
+
+func TestParseRelationshipStrength(t *testing.T) {
+	t.Parallel()
+
+	tests := []struct {
+		name    string
+		input   string
+		want    lunatask.RelationshipStrength
+		wantErr bool
+	}{
+		{"family_lower", "family", lunatask.RelationshipFamily, false},
+		{"family_upper", "FAMILY", lunatask.RelationshipFamily, false},
+		{"family_mixed", "FaMiLy", lunatask.RelationshipFamily, false},
+		{"intimate_friends_lower", "intimate-friends", lunatask.RelationshipIntimateFriend, false},
+		{"intimate_friends_upper", "INTIMATE-FRIENDS", lunatask.RelationshipIntimateFriend, false},
+		{"close_friends_lower", "close-friends", lunatask.RelationshipCloseFriend, false},
+		{"close_friends_upper", "CLOSE-FRIENDS", lunatask.RelationshipCloseFriend, false},
+		{"casual_friends_lower", "casual-friends", lunatask.RelationshipCasualFriend, false},
+		{"casual_friends_upper", "CASUAL-FRIENDS", lunatask.RelationshipCasualFriend, false},
+		{"acquaintances_lower", "acquaintances", lunatask.RelationshipAcquaintance, false},
+		{"acquaintances_upper", "ACQUAINTANCES", lunatask.RelationshipAcquaintance, false},
+		{"business_contacts_lower", "business-contacts", lunatask.RelationshipBusiness, false},
+		{"business_contacts_upper", "BUSINESS-CONTACTS", lunatask.RelationshipBusiness, false},
+		{"almost_strangers_lower", "almost-strangers", lunatask.RelationshipAlmostStranger, false},
+		{"almost_strangers_upper", "ALMOST-STRANGERS", lunatask.RelationshipAlmostStranger, false},
+		{"almost_strangers_mixed", "Almost-Strangers", lunatask.RelationshipAlmostStranger, false},
+		{"invalid", "invalid", "", true},
+		{"empty", "", "", true},
+		{"numeric", "1", "", true},
+		{"typo", "famly", "", true},
+		{"no_hyphen", "closefriends", "", true},
+	}
+
+	for _, testCase := range tests {
+		t.Run(testCase.name, func(t *testing.T) {
+			t.Parallel()
+
+			got, err := lunatask.ParseRelationshipStrength(testCase.input)
+			if (err != nil) != testCase.wantErr {
+				t.Errorf("ParseRelationshipStrength(%q) error = %v, wantErr %v", testCase.input, err, testCase.wantErr)
+
+				return
+			}
+
+			if !testCase.wantErr && got != testCase.want {
+				t.Errorf("ParseRelationshipStrength(%q) = %q, want %q", testCase.input, got, testCase.want)
+			}
+		})
+	}
+}