Skip to content

Commit

Permalink
Rewrite tests (#478)
Browse files Browse the repository at this point in the history
Rewrite tests

This rewrites quite a lot of tests to be much more easily readable.

While working on #472 I wanted to check "how do renames behave now?",
and found this quite hard as most test cases were >90% "plumbing", and
seeing "what file operations does this do?" and "what events do we get?"
was not very easy.

So refactor the lot, based on some work I did in #472:

- Add a bunch of "shell-like" helper functions so you're not forever
  typing error checks, filepath.Join(), and eventSeparator(). Just
  touch(t, tmp, "file") will create a file in tmp.

- Add eventCollector type which will collect all events in in a slice,
  replacing the previous "counter". This also ensures that the Watcher
  is closed within a second (this removes a lot of duplicate code).

  This is also much more precise than merely counting events; before
  random events could get emitted but if you weren't counting those then
  you'd never know.

  Downside is that some tests are a bit more flaky now as some
  behaviours are not always consistent in various edge cases; these are
  pre-existing bugs.

- Add Events (plural) type (only for tests), and helper function to
  create this from a string like:

      REMOVE  /link
      CREATE  /link
      WRITE   /link

  Which makes seeing which events are received, diffing them, etc. much
  easier.

- Add Parallel() for most tests; reduces runtime on my system from ~12
  seconds to ~6 seconds.

All in all it reduces the integrations_test.go from 1279 lines to 405
lines and it's quite easy to see which events are expected for which
operations, which should make things a lot easier going forward.
  • Loading branch information
arp242 committed Jul 31, 2022
1 parent 57e6a49 commit 87dc1fa
Show file tree
Hide file tree
Showing 8 changed files with 1,118 additions and 1,642 deletions.
12 changes: 6 additions & 6 deletions fsnotify.go
Expand Up @@ -43,6 +43,12 @@ const (
Chmod
)

// Common errors that can be reported by a watcher
var (
ErrNonExistentWatch = errors.New("can't remove non-existent watcher")
ErrEventOverflow = errors.New("fsnotify queue overflow")
)

func (op Op) String() string {
var b strings.Builder
if op.Has(Create) {
Expand Down Expand Up @@ -77,9 +83,3 @@ func (e Event) Has(op Op) bool { return e.Op.Has(op) }
func (e Event) String() string {
return fmt.Sprintf("%q: %s", e.Name, e.Op.String())
}

// Common errors that can be reported by a watcher
var (
ErrNonExistentWatch = errors.New("can't remove non-existent watcher")
ErrEventOverflow = errors.New("fsnotify queue overflow")
)
81 changes: 23 additions & 58 deletions fsnotify_test.go
@@ -1,71 +1,36 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build !plan9
// +build !plan9

package fsnotify

import (
"os"
"testing"
"time"
)

func TestEventStringWithValue(t *testing.T) {
for opMask, expectedString := range map[Op]string{
Chmod | Create: `"/usr/someFile": CREATE|CHMOD`,
Rename: `"/usr/someFile": RENAME`,
Remove: `"/usr/someFile": REMOVE`,
Write | Chmod: `"/usr/someFile": WRITE|CHMOD`,
} {
event := Event{Name: "/usr/someFile", Op: opMask}
if event.String() != expectedString {
t.Fatalf("Expected %s, got: %v", expectedString, event.String())
}

}
}

func TestEventOpStringWithValue(t *testing.T) {
expectedOpString := "WRITE|CHMOD"
event := Event{Name: "someFile", Op: Write | Chmod}
if event.Op.String() != expectedOpString {
t.Fatalf("Expected %s, got: %v", expectedOpString, event.Op.String())
}
}

func TestEventOpStringWithNoValue(t *testing.T) {
expectedOpString := ""
event := Event{Name: "testFile", Op: 0}
if event.Op.String() != expectedOpString {
t.Fatalf("Expected %s, got: %v", expectedOpString, event.Op.String())
}
}

// TestWatcherClose tests that the goroutine started by creating the watcher can be
// signalled to return at any time, even if there is no goroutine listening on the events
// or errors channels.
func TestWatcherClose(t *testing.T) {
t.Parallel()

name := tempMkFile(t, "")
w := newWatcher(t)
err := w.Add(name)
if err != nil {
t.Fatal(err)
}

err = os.Remove(name)
if err != nil {
t.Fatal(err)
func TestEventString(t *testing.T) {
tests := []struct {
in Event
want string
}{
{Event{}, `"": `},
{Event{"/file", 0}, `"/file": `},

{Event{"/file", Chmod | Create},
`"/file": CREATE|CHMOD`},
{Event{"/file", Rename},
`"/file": RENAME`},
{Event{"/file", Remove},
`"/file": REMOVE`},
{Event{"/file", Write | Chmod},
`"/file": WRITE|CHMOD`},
}
// Allow the watcher to receive the event.
time.Sleep(time.Millisecond * 100)

err = w.Close()
if err != nil {
t.Fatal(err)
for _, tt := range tests {
t.Run("", func(t *testing.T) {
have := tt.in.String()
if have != tt.want {
t.Errorf("\nhave: %q\nwant: %q", have, tt.want)
}
})
}
}

0 comments on commit 87dc1fa

Please sign in to comment.