@@ -0,0 +1,34 @@
+// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+package lunatask
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+)
+
+// Errors returned by Motivation operations.
+var (
+ // ErrInvalidMotivation is returned when parsing an unknown motivation string.
+ ErrInvalidMotivation = errors.New("invalid motivation")
+)
+
+// ParseMotivation parses a string to a Motivation value (case-insensitive).
+// Valid values: "unknown", "must", "should", "want".
+func ParseMotivation(str string) (Motivation, error) {
+ switch strings.ToLower(str) {
+ case "unknown":
+ return MotivationUnknown, nil
+ case "must":
+ return MotivationMust, nil
+ case "should":
+ return MotivationShould, nil
+ case "want":
+ return MotivationWant, nil
+ default:
+ return "", fmt.Errorf("%w: %q", ErrInvalidMotivation, str)
+ }
+}
@@ -0,0 +1,54 @@
+// 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 TestParseMotivation(t *testing.T) {
+ t.Parallel()
+
+ tests := []struct {
+ name string
+ input string
+ want lunatask.Motivation
+ wantErr bool
+ }{
+ {"unknown_lower", "unknown", lunatask.MotivationUnknown, false},
+ {"unknown_upper", "UNKNOWN", lunatask.MotivationUnknown, false},
+ {"unknown_mixed", "UnKnOwN", lunatask.MotivationUnknown, false},
+ {"must_lower", "must", lunatask.MotivationMust, false},
+ {"must_upper", "MUST", lunatask.MotivationMust, false},
+ {"should_lower", "should", lunatask.MotivationShould, false},
+ {"should_upper", "SHOULD", lunatask.MotivationShould, false},
+ {"want_lower", "want", lunatask.MotivationWant, false},
+ {"want_upper", "WANT", lunatask.MotivationWant, false},
+ {"want_mixed", "WaNt", lunatask.MotivationWant, false},
+ {"invalid", "invalid", "", true},
+ {"empty", "", "", true},
+ {"numeric", "1", "", true},
+ {"typo", "muust", "", true},
+ }
+
+ for _, testCase := range tests {
+ t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
+
+ got, err := lunatask.ParseMotivation(testCase.input)
+ if (err != nil) != testCase.wantErr {
+ t.Errorf("ParseMotivation(%q) error = %v, wantErr %v", testCase.input, err, testCase.wantErr)
+
+ return
+ }
+
+ if !testCase.wantErr && got != testCase.want {
+ t.Errorf("ParseMotivation(%q) = %q, want %q", testCase.input, got, testCase.want)
+ }
+ })
+ }
+}