diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-08 21:59:10 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-08 21:59:10 +0300 |
| commit | 103f369cee209f6f0a15ef953cff138ffa025a26 (patch) | |
| tree | ba9ee209acab34726fc1d43753aee18bc98a46d0 /internal/ui/helpers_test.go | |
| parent | bcfeb2deb2fc089c81971744774095409ad12a43 (diff) | |
task b: protect regex cache with RWMutex
Diffstat (limited to 'internal/ui/helpers_test.go')
| -rw-r--r-- | internal/ui/helpers_test.go | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/internal/ui/helpers_test.go b/internal/ui/helpers_test.go index 9760277..1fe853b 100644 --- a/internal/ui/helpers_test.go +++ b/internal/ui/helpers_test.go @@ -3,7 +3,9 @@ package ui import ( "fmt" "reflect" + "regexp" "strings" + "sync" "testing" "time" @@ -98,6 +100,52 @@ func TestFormatDueText(t *testing.T) { } } +func TestSearchRegexCacheConcurrentAccess(t *testing.T) { + searchRegexMu.Lock() + searchRegexCache = make(map[string]*regexp.Regexp) + searchRegexMu.Unlock() + t.Cleanup(func() { + searchRegexMu.Lock() + searchRegexCache = make(map[string]*regexp.Regexp) + searchRegexMu.Unlock() + }) + + patterns := []string{`alpha`, `beta`} + var wg sync.WaitGroup + errCh := make(chan error, 128) + + for i := 0; i < 16; i++ { + for _, pattern := range patterns { + wg.Add(1) + go func(pattern string) { + defer wg.Done() + + re, err := compileAndCacheRegex(pattern) + if err != nil { + errCh <- err + return + } + if re == nil || !re.MatchString(pattern) { + errCh <- fmt.Errorf("compiled regex for %q did not match", pattern) + return + } + if cached, ok := cachedSearchRegex(pattern); !ok || cached == nil { + errCh <- fmt.Errorf("missing cached regex for %q", pattern) + } + }(pattern) + } + } + + wg.Wait() + close(errCh) + + for err := range errCh { + if err != nil { + t.Fatal(err) + } + } +} + func TestValidateTagName(t *testing.T) { tests := []struct { name string @@ -414,6 +462,7 @@ func TestValidateRecurrence(t *testing.T) { }) } } + // TestParseFilterInput verifies that parseFilterInput correctly handles // taskwarrior filter expressions, including attribute filters (proj:xxx), // tag filters (+tag), quoted values (description:"some text"), and empty input. |
