@@ -0,0 +1,36 @@
+// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+package lunatask
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+)
+
+// Errors returned by TaskStatus operations.
+var (
+ // ErrInvalidTaskStatus is returned when parsing an unknown task status string.
+ ErrInvalidTaskStatus = errors.New("invalid task status")
+)
+
+// ParseTaskStatus parses a string to a TaskStatus value (case-insensitive).
+// Valid values: "later", "next", "started", "waiting", "completed".
+func ParseTaskStatus(str string) (TaskStatus, error) {
+ switch strings.ToLower(str) {
+ case "later":
+ return StatusLater, nil
+ case "next":
+ return StatusNext, nil
+ case "started":
+ return StatusStarted, nil
+ case "waiting":
+ return StatusWaiting, nil
+ case "completed":
+ return StatusCompleted, nil
+ default:
+ return "", fmt.Errorf("%w: %q", ErrInvalidTaskStatus, str)
+ }
+}
@@ -0,0 +1,56 @@
+// 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 TestParseTaskStatus(t *testing.T) {
+ t.Parallel()
+
+ tests := []struct {
+ name string
+ input string
+ want lunatask.TaskStatus
+ wantErr bool
+ }{
+ {"later_lower", "later", lunatask.StatusLater, false},
+ {"later_upper", "LATER", lunatask.StatusLater, false},
+ {"later_mixed", "LaTeR", lunatask.StatusLater, false},
+ {"next_lower", "next", lunatask.StatusNext, false},
+ {"next_upper", "NEXT", lunatask.StatusNext, false},
+ {"started_lower", "started", lunatask.StatusStarted, false},
+ {"started_upper", "STARTED", lunatask.StatusStarted, false},
+ {"waiting_lower", "waiting", lunatask.StatusWaiting, false},
+ {"waiting_upper", "WAITING", lunatask.StatusWaiting, false},
+ {"completed_lower", "completed", lunatask.StatusCompleted, false},
+ {"completed_upper", "COMPLETED", lunatask.StatusCompleted, false},
+ {"completed_mixed", "CoMpLeTeD", lunatask.StatusCompleted, false},
+ {"invalid", "invalid", "", true},
+ {"empty", "", "", true},
+ {"numeric", "1", "", true},
+ {"typo", "completd", "", true},
+ }
+
+ for _, testCase := range tests {
+ t.Run(testCase.name, func(t *testing.T) {
+ t.Parallel()
+
+ got, err := lunatask.ParseTaskStatus(testCase.input)
+ if (err != nil) != testCase.wantErr {
+ t.Errorf("ParseTaskStatus(%q) error = %v, wantErr %v", testCase.input, err, testCase.wantErr)
+
+ return
+ }
+
+ if !testCase.wantErr && got != testCase.want {
+ t.Errorf("ParseTaskStatus(%q) = %q, want %q", testCase.input, got, testCase.want)
+ }
+ })
+ }
+}