webdav: add memFS, an initial implementation of an in-memory
filesystem.

See original mercurial CL: golang.org/cl/171700045

Change-Id: Ib18277df4f7f232afdf6331f4bca5aaa3b00b83b
diff --git a/webdav/file_test.go b/webdav/file_test.go
index 502b236..a25e080 100644
--- a/webdav/file_test.go
+++ b/webdav/file_test.go
@@ -5,7 +5,9 @@
 package webdav
 
 import (
+	"fmt"
 	"path/filepath"
+	"strings"
 	"testing"
 )
 
@@ -115,3 +117,79 @@
 		}
 	}
 }
+
+func TestWalk(t *testing.T) {
+	type walkStep struct {
+		name, frag string
+		final      bool
+	}
+
+	testCases := []struct {
+		dir  string
+		want []walkStep
+	}{
+		{"", []walkStep{
+			{"", "", true},
+		}},
+		{"/", []walkStep{
+			{"", "", true},
+		}},
+		{"/a", []walkStep{
+			{"", "a", true},
+		}},
+		{"/a/", []walkStep{
+			{"", "a", true},
+		}},
+		{"/a/b", []walkStep{
+			{"", "a", false},
+			{"a", "b", true},
+		}},
+		{"/a/b/", []walkStep{
+			{"", "a", false},
+			{"a", "b", true},
+		}},
+		{"/a/b/c", []walkStep{
+			{"", "a", false},
+			{"a", "b", false},
+			{"b", "c", true},
+		}},
+		// The following test case is the one mentioned explicitly
+		// in the method description.
+		{"/foo/bar/x", []walkStep{
+			{"", "foo", false},
+			{"foo", "bar", false},
+			{"bar", "x", true},
+		}},
+	}
+
+	for _, tc := range testCases {
+		fs := NewMemFS().(*memFS)
+
+		parts := strings.Split(tc.dir, "/")
+		for p := 2; p < len(parts); p++ {
+			d := strings.Join(parts[:p], "/")
+			if err := fs.Mkdir(d, 0666); err != nil {
+				t.Errorf("tc.dir=%q: mkdir: %q: %v", tc.dir, d, err)
+			}
+		}
+
+		i := 0
+		err := fs.walk("test", tc.dir, func(dir *memFSNode, frag string, final bool) error {
+			got := walkStep{
+				name:  dir.name,
+				frag:  frag,
+				final: final,
+			}
+			want := tc.want[i]
+
+			if got != want {
+				return fmt.Errorf("got %+v, want %+v", got, want)
+			}
+			i++
+			return nil
+		})
+		if err != nil {
+			t.Errorf("tc.dir=%q: %v", tc.dir, err)
+		}
+	}
+}