package host import ( "os" "path/filepath" "sync/atomic" "testing" "time" ) func TestWatcher_DetectsNewFiles(t *testing.T) { dir := t.TempDir() // Create initial file initialFile := filepath.Join(dir, "initial.go") if err := os.WriteFile(initialFile, []byte("package main"), 0644); err != nil { t.Fatal(err) } var changeCount int32 w := NewWatcher(dir, func() { atomic.AddInt32(&changeCount, 1) }, WithInterval(50*time.Millisecond)) if err := w.Start(); err != nil { t.Fatal(err) } defer w.Stop() // Create new file newFile := filepath.Join(dir, "new.go") if err := os.WriteFile(newFile, []byte("package main"), 0644); err != nil { t.Fatal(err) } // Wait for detection time.Sleep(200 * time.Millisecond) if count := atomic.LoadInt32(&changeCount); count == 0 { t.Error("Expected change to be detected for new file") } } func TestWatcher_DetectsModifiedFiles(t *testing.T) { dir := t.TempDir() // Create initial file file := filepath.Join(dir, "test.go") if err := os.WriteFile(file, []byte("package main"), 0644); err != nil { t.Fatal(err) } var changeCount int32 w := NewWatcher(dir, func() { atomic.AddInt32(&changeCount, 1) }, WithInterval(50*time.Millisecond)) if err := w.Start(); err != nil { t.Fatal(err) } defer w.Stop() // Ensure mod time will be different time.Sleep(100 * time.Millisecond) // Modify file if err := os.WriteFile(file, []byte("package main\n// updated"), 0644); err != nil { t.Fatal(err) } // Wait for detection time.Sleep(200 * time.Millisecond) if count := atomic.LoadInt32(&changeCount); count == 0 { t.Error("Expected change to be detected for modified file") } } func TestWatcher_DetectsDeletedFiles(t *testing.T) { dir := t.TempDir() // Create initial file file := filepath.Join(dir, "test.go") if err := os.WriteFile(file, []byte("package main"), 0644); err != nil { t.Fatal(err) } var changeCount int32 w := NewWatcher(dir, func() { atomic.AddInt32(&changeCount, 1) }, WithInterval(50*time.Millisecond)) if err := w.Start(); err != nil { t.Fatal(err) } defer w.Stop() // Delete file if err := os.Remove(file); err != nil { t.Fatal(err) } // Wait for detection time.Sleep(200 * time.Millisecond) if count := atomic.LoadInt32(&changeCount); count == 0 { t.Error("Expected change to be detected for deleted file") } } func TestWatcher_IgnoresNonMatchingExtensions(t *testing.T) { dir := t.TempDir() // Create initial go file goFile := filepath.Join(dir, "main.go") if err := os.WriteFile(goFile, []byte("package main"), 0644); err != nil { t.Fatal(err) } var changeCount int32 w := NewWatcher(dir, func() { atomic.AddInt32(&changeCount, 1) }, WithInterval(50*time.Millisecond), WithExtensions(".go")) if err := w.Start(); err != nil { t.Fatal(err) } defer w.Stop() // Create non-matching file txtFile := filepath.Join(dir, "readme.txt") if err := os.WriteFile(txtFile, []byte("readme"), 0644); err != nil { t.Fatal(err) } // Wait time.Sleep(200 * time.Millisecond) if count := atomic.LoadInt32(&changeCount); count != 0 { t.Error("Expected no change detected for non-matching extension") } } func TestWatcher_CustomExtensions(t *testing.T) { dir := t.TempDir() // Create initial file file := filepath.Join(dir, "style.css") if err := os.WriteFile(file, []byte("body {}"), 0644); err != nil { t.Fatal(err) } var changeCount int32 w := NewWatcher(dir, func() { atomic.AddInt32(&changeCount, 1) }, WithInterval(50*time.Millisecond), WithExtensions(".css", ".html")) if err := w.Start(); err != nil { t.Fatal(err) } defer w.Stop() // Ensure mod time will be different time.Sleep(100 * time.Millisecond) // Modify css file if err := os.WriteFile(file, []byte("body { color: red; }"), 0644); err != nil { t.Fatal(err) } // Wait for detection time.Sleep(200 * time.Millisecond) if count := atomic.LoadInt32(&changeCount); count == 0 { t.Error("Expected change to be detected for custom extension") } } func TestWatcher_SkipsHiddenDirs(t *testing.T) { dir := t.TempDir() // Create hidden directory with go file hiddenDir := filepath.Join(dir, ".hidden") if err := os.MkdirAll(hiddenDir, 0755); err != nil { t.Fatal(err) } // Create a visible go file first visibleFile := filepath.Join(dir, "visible.go") if err := os.WriteFile(visibleFile, []byte("package main"), 0644); err != nil { t.Fatal(err) } var changeCount int32 w := NewWatcher(dir, func() { atomic.AddInt32(&changeCount, 1) }, WithInterval(50*time.Millisecond)) if err := w.Start(); err != nil { t.Fatal(err) } defer w.Stop() // Create file in hidden directory hiddenFile := filepath.Join(hiddenDir, "hidden.go") if err := os.WriteFile(hiddenFile, []byte("package main"), 0644); err != nil { t.Fatal(err) } // Wait time.Sleep(200 * time.Millisecond) if count := atomic.LoadInt32(&changeCount); count != 0 { t.Error("Expected no change detected for hidden directory") } }