third_party: Add github.com/bmatcuk/doublestar

The native Go file glob doesn't support '**' patterns for matching
any number of path components.

MultiPart: 3/3
Change-Id: Ic836555c4df1b4c85ac54874f4e9aa54740b423d
diff --git a/go/src/github.com/bmatcuk/doublestar/.gitignore b/go/src/github.com/bmatcuk/doublestar/.gitignore
new file mode 100644
index 0000000..76d92ba
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/.gitignore
@@ -0,0 +1,29 @@
+# vi
+*~
+*.swp
+*.swo
+
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/go/src/github.com/bmatcuk/doublestar/.travis.yml b/go/src/github.com/bmatcuk/doublestar/.travis.yml
new file mode 100644
index 0000000..92cf2ce
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/.travis.yml
@@ -0,0 +1,15 @@
+language: go
+
+go:
+  - 1.3
+  - 1.4
+
+before_install:
+  - sudo pip install codecov
+
+script:
+  - go test -coverprofile=coverage.txt -covermode=atomic
+
+after_success:
+  - codecov
+
diff --git a/go/src/github.com/bmatcuk/doublestar/LICENSE b/go/src/github.com/bmatcuk/doublestar/LICENSE
new file mode 100644
index 0000000..309c9d1
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Bob Matcuk
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/go/src/github.com/bmatcuk/doublestar/README.google b/go/src/github.com/bmatcuk/doublestar/README.google
new file mode 100644
index 0000000..62f6d10
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/README.google
@@ -0,0 +1,10 @@
+URL: https://github.com/bmatcuk/doublestar/archive/3d7b9fdaa0003377934692e98a5d3233f11a5baa.zip
+Version: 3d7b9fdaa0003377934692e98a5d3233f11a5baa
+License: MIT
+License File: LICENSE
+
+Description:
+doublestar expands Go file globbing to match `**` (any number of path components).
+
+Local Modifications:
+Applied gofmt.
diff --git a/go/src/github.com/bmatcuk/doublestar/README.md b/go/src/github.com/bmatcuk/doublestar/README.md
new file mode 100644
index 0000000..335a793
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/README.md
@@ -0,0 +1,80 @@
+![Release](https://img.shields.io/github/release/bmatcuk/doublestar.svg?branch=master)
+[![Build Status](https://travis-ci.org/bmatcuk/doublestar.svg?branch=master)](https://travis-ci.org/bmatcuk/doublestar)
+[![codecov.io](https://img.shields.io/codecov/c/github/bmatcuk/doublestar.svg?branch=master)](https://codecov.io/github/bmatcuk/doublestar?branch=master)
+
+# doublestar
+
+**doublestar** is a [golang](http://golang.org/) implementation of path pattern matching and globbing with support for "doublestar" (aka globstar: `**`) patterns.
+
+doublestar patterns match files and directories recursively. For example, if you had the following directory structure:
+
+```
+grandparent
+`-- parent
+    |-- child1
+    `-- child2
+```
+
+You could find the children with patterns such as: `**/child*`, `grandparent/**/child?`, `**/parent/*`, or even just `**` by itself (which will return all files and directories recursively).
+
+## Installation
+
+**doublestar** can be installed via `go get`:
+
+```bash
+go get github.com/bmatcuk/doublestar
+```
+
+To use it in your code, you must import it:
+
+```go
+import "github.com/bmatcuk/doublestar"
+```
+
+## Functions
+
+### Match
+```go
+func Match(pattern, name string) (bool, error)
+```
+
+Match returns true if `name` matches the file name `pattern` ([see below](#patterns)). `name` and `pattern` are split on forward slash (`/`) characters.
+
+### PathMatch
+```go
+func PathMatch(pattern, name string) (bool, error)
+```
+
+PathMatch returns true  if `name` matches the file name `pattern` ([see below](#patterns)). The difference between Match and PathMatch is that PathMatch will automatically use your system's path separator to split `name` and `pattern`.
+
+### Glob
+```go
+func Glob(pattern string) ([]string, error)
+```
+
+Glob finds all files and directories in the filesystem that match `pattern` ([see below](#patterns)).
+
+## Patterns
+
+**doublestar** supports the following special terms in the patterns:
+
+Special Terms | Meaning
+------------- | -------
+`*`           | matches any sequence of non-path-separators
+`**`          | matches any sequence of characters, including path separators
+`?`           | matches any single non-path-separator character
+`[class]`     | matches any single non-path-separator character against a class of characters ([see below](#character-classes))
+`{alt1,...}`  | matches a sequence of characters if one of the comma-separated alternatives matches
+
+Any character with a special meaning can be escaped with a backslash (`\`).
+
+### Character Classes
+
+Character classes support the following:
+
+Class      | Meaning
+---------- | -------
+`[abc]`    | matches any single character within the set
+`[a-z]`    | matches any single character in the range
+`[^class]` | matches any single character which does *not* match the class
+
diff --git a/go/src/github.com/bmatcuk/doublestar/doublestar.go b/go/src/github.com/bmatcuk/doublestar/doublestar.go
new file mode 100644
index 0000000..7256309
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/doublestar.go
@@ -0,0 +1,392 @@
+package doublestar
+
+import (
+	"os"
+	"path"
+	"path/filepath"
+	"strings"
+	"unicode/utf8"
+)
+
+var ErrBadPattern = path.ErrBadPattern
+
+func splitPathOnSeparator(path string, separator rune) []string {
+	// if the separator is '\\', then we can just split...
+	if separator == '\\' {
+		return strings.Split(path, string(separator))
+	}
+
+	// otherwise, we need to be careful of situations where the separator was escaped
+	cnt := strings.Count(path, string(separator))
+	if cnt == 0 {
+		return []string{path}
+	}
+	ret := make([]string, cnt+1)
+	pathlen := len(path)
+	separatorLen := utf8.RuneLen(separator)
+	idx := 0
+	for start := 0; start < pathlen; {
+		end := indexRuneWithEscaping(path[start:], separator)
+		if end == -1 {
+			end = pathlen
+		} else {
+			end += start
+		}
+		ret[idx] = path[start:end]
+		start = end + separatorLen
+		idx++
+	}
+	return ret[:idx]
+}
+
+func indexRuneWithEscaping(s string, r rune) int {
+	end := strings.IndexRune(s, r)
+	if end == -1 {
+		return -1
+	}
+	if end > 0 && s[end-1] == '\\' {
+		start := end + utf8.RuneLen(r)
+		end = indexRuneWithEscaping(s[start:], r)
+		if end != -1 {
+			end += start
+		}
+	}
+	return end
+}
+
+// Match returns true if name matches the shell file name pattern.
+// The pattern syntax is:
+//
+//	pattern:
+//		{ term }
+//	term:
+//		'*'         matches any sequence of non-path-separators
+//              '**'        matches any sequence of characters, including
+//                          path separators.
+//		'?'         matches any single non-path-separator character
+//		'[' [ '^' ] { character-range } ']'
+//			    character class (must be non-empty)
+//		'{' { term } [ ',' { term } ... ] '}'
+//		c           matches character c (c != '*', '?', '\\', '[')
+//		'\\' c      matches character c
+//
+//	character-range:
+//		c           matches character c (c != '\\', '-', ']')
+//		'\\' c      matches character c
+//		lo '-' hi   matches character c for lo <= c <= hi
+//
+// Match requires pattern to match all of name, not just a substring.
+// The path-separator defaults to the '/' character. The only possible
+// returned error is ErrBadPattern, when pattern is malformed.
+//
+func Match(pattern, name string) (bool, error) {
+	return matchWithSeparator(pattern, name, '/')
+}
+
+// PathMatch is like Match except that it uses your system's path separator.
+// For most systems, this will be '/'. However, for Windows, it would be '\\'.
+// Note that for systems where the path separator is '\\', escaping is
+// disabled.
+//
+func PathMatch(pattern, name string) (bool, error) {
+	return matchWithSeparator(pattern, name, os.PathSeparator)
+}
+
+// Match returns true if name matches the shell file name pattern.
+// The pattern syntax is:
+//
+//	pattern:
+//		{ term }
+//	term:
+//		'*'         matches any sequence of non-path-separators
+//              '**'        matches any sequence of characters, including
+//                          path separators.
+//		'?'         matches any single non-path-separator character
+//		'[' [ '^' ] { character-range } ']'
+//			    character class (must be non-empty)
+//		'{' { term } [ ',' { term } ... ] '}'
+//		c           matches character c (c != '*', '?', '\\', '[')
+//		'\\' c      matches character c
+//
+//	character-range:
+//		c           matches character c (c != '\\', '-', ']')
+//		'\\' c      matches character c, unless separator is '\\'
+//		lo '-' hi   matches character c for lo <= c <= hi
+//
+// Match requires pattern to match all of name, not just a substring.
+// The only possible returned error is ErrBadPattern, when pattern
+// is malformed.
+//
+func matchWithSeparator(pattern, name string, separator rune) (bool, error) {
+	patternComponents := splitPathOnSeparator(pattern, separator)
+	nameComponents := splitPathOnSeparator(name, separator)
+	return doMatching(patternComponents, nameComponents)
+}
+
+func doMatching(patternComponents, nameComponents []string) (matched bool, err error) {
+	patternLen, nameLen := len(patternComponents), len(nameComponents)
+	if patternLen == 0 && nameLen == 0 {
+		return true, nil
+	}
+	if patternLen == 0 || nameLen == 0 {
+		return false, nil
+	}
+	patIdx, nameIdx := 0, 0
+	for patIdx < patternLen && nameIdx < nameLen {
+		if patternComponents[patIdx] == "**" {
+			if patIdx++; patIdx >= patternLen {
+				return true, nil
+			}
+			for ; nameIdx < nameLen; nameIdx++ {
+				if m, _ := doMatching(patternComponents[patIdx:], nameComponents[nameIdx:]); m {
+					return true, nil
+				}
+			}
+			return false, nil
+		} else {
+			matched, err = matchComponent(patternComponents[patIdx], nameComponents[nameIdx])
+			if !matched || err != nil {
+				return
+			}
+		}
+		patIdx++
+		nameIdx++
+	}
+	return patIdx >= patternLen && nameIdx >= nameLen, nil
+}
+
+// Glob returns the names of all files matching pattern or nil
+// if there is no matching file. The syntax of pattern is the same
+// as in Match. The pattern may describe hierarchical names such as
+// /usr/*/bin/ed (assuming the Separator is '/').
+//
+// Glob ignores file system errors such as I/O errors reading directories.
+// The only possible returned error is ErrBadPattern, when pattern
+// is malformed.
+//
+// Your system path separator is automatically used. This means on
+// systems where the separator is '\\' (Windows), escaping will be
+// disabled.
+//
+func Glob(pattern string) (matches []string, err error) {
+	patternComponents := splitPathOnSeparator(pattern, os.PathSeparator)
+	if len(patternComponents) == 0 {
+		return nil, nil
+	}
+
+	// if the first pattern component is blank, the pattern is an absolute path.
+	if patternComponents[0] == "" {
+		return doGlob("", patternComponents, matches)
+	}
+	return doGlob(".", patternComponents, matches)
+}
+
+func doGlob(basedir string, components, matches []string) (m []string, e error) {
+	m = matches
+	e = nil
+
+	// figure out how many components we don't need to glob because they're
+	// just straight directory names
+	patLen := len(components)
+	patIdx := 0
+	for ; patIdx < patLen; patIdx++ {
+		if strings.IndexAny(components[patIdx], "*?[{\\") >= 0 {
+			break
+		}
+	}
+	if patIdx > 0 {
+		basedir = filepath.Join(basedir, filepath.Join(components[0:patIdx]...))
+	}
+
+	// Stat will return an error if the file/directory doesn't exist
+	fi, err := os.Stat(basedir)
+	if err != nil {
+		return
+	}
+
+	// if there are no more components, we've found a match
+	if patIdx >= patLen {
+		m = append(m, basedir)
+		return
+	}
+
+	// otherwise, we need to check each item in the directory...
+	// so confirm it's a directory first...
+	if !fi.IsDir() {
+		return
+	}
+
+	// read directory
+	dir, err := os.Open(basedir)
+	if err != nil {
+		return
+	}
+	defer dir.Close()
+
+	files, _ := dir.Readdir(-1)
+	lastComponent := patIdx+1 >= patLen
+	if components[patIdx] == "**" {
+		// if the current component is a doublestar, we'll try depth-first
+		for _, file := range files {
+			if file.IsDir() {
+				m = append(m, filepath.Join(basedir, file.Name()))
+				m, e = doGlob(filepath.Join(basedir, file.Name()), components[patIdx:], m)
+			} else if lastComponent {
+				// if the pattern's last component is a doublestar, we match filenames, too
+				m = append(m, filepath.Join(basedir, file.Name()))
+			}
+		}
+		if lastComponent {
+			return
+		}
+		patIdx++
+		lastComponent = patIdx+1 >= patLen
+	}
+
+	var match bool
+	for _, file := range files {
+		match, e = matchComponent(components[patIdx], file.Name())
+		if e != nil {
+			return
+		}
+		if match {
+			if lastComponent {
+				m = append(m, filepath.Join(basedir, file.Name()))
+			} else {
+				m, e = doGlob(filepath.Join(basedir, file.Name()), components[patIdx+1:], m)
+			}
+		}
+	}
+	return
+}
+
+func matchComponent(pattern, name string) (bool, error) {
+	patternLen, nameLen := len(pattern), len(name)
+	if patternLen == 0 && nameLen == 0 {
+		return true, nil
+	}
+	if patternLen == 0 {
+		return false, nil
+	}
+	if nameLen == 0 && pattern != "*" {
+		return false, nil
+	}
+	patIdx, nameIdx := 0, 0
+	for patIdx < patternLen && nameIdx < nameLen {
+		patRune, patAdj := utf8.DecodeRuneInString(pattern[patIdx:])
+		nameRune, nameAdj := utf8.DecodeRuneInString(name[nameIdx:])
+		if patRune == '\\' {
+			patIdx += patAdj
+			patRune, patAdj = utf8.DecodeRuneInString(pattern[patIdx:])
+			if patRune == utf8.RuneError {
+				return false, ErrBadPattern
+			} else if patRune == nameRune {
+				patIdx += patAdj
+				nameIdx += nameAdj
+			} else {
+				return false, nil
+			}
+		} else if patRune == '*' {
+			if patIdx += patAdj; patIdx >= patternLen {
+				return true, nil
+			}
+			for ; nameIdx < nameLen; nameIdx += nameAdj {
+				if m, _ := matchComponent(pattern[patIdx:], name[nameIdx:]); m {
+					return true, nil
+				}
+			}
+			return false, nil
+		} else if patRune == '[' {
+			patIdx += patAdj
+			endClass := indexRuneWithEscaping(pattern[patIdx:], ']')
+			if endClass == -1 {
+				return false, ErrBadPattern
+			}
+			endClass += patIdx
+			classRunes := []rune(pattern[patIdx:endClass])
+			classRunesLen := len(classRunes)
+			if classRunesLen > 0 {
+				classIdx := 0
+				matchClass := false
+				if classRunes[0] == '^' {
+					classIdx++
+				}
+				for classIdx < classRunesLen {
+					low := classRunes[classIdx]
+					if low == '-' {
+						return false, ErrBadPattern
+					}
+					classIdx++
+					if low == '\\' {
+						if classIdx < classRunesLen {
+							low = classRunes[classIdx]
+							classIdx++
+						} else {
+							return false, ErrBadPattern
+						}
+					}
+					high := low
+					if classIdx < classRunesLen && classRunes[classIdx] == '-' {
+						if classIdx++; classIdx >= classRunesLen {
+							return false, ErrBadPattern
+						}
+						high = classRunes[classIdx]
+						if high == '-' {
+							return false, ErrBadPattern
+						}
+						classIdx++
+						if high == '\\' {
+							if classIdx < classRunesLen {
+								high = classRunes[classIdx]
+								classIdx++
+							} else {
+								return false, ErrBadPattern
+							}
+						}
+					}
+					if low <= nameRune && nameRune <= high {
+						matchClass = true
+					}
+				}
+				if matchClass == (classRunes[0] == '^') {
+					return false, nil
+				}
+			} else {
+				return false, ErrBadPattern
+			}
+			patIdx = endClass + 1
+			nameIdx += nameAdj
+		} else if patRune == '{' {
+			patIdx += patAdj
+			endOptions := indexRuneWithEscaping(pattern[patIdx:], '}')
+			if endOptions == -1 {
+				return false, ErrBadPattern
+			}
+			endOptions += patIdx
+			options := splitPathOnSeparator(pattern[patIdx:endOptions], ',')
+			patIdx = endOptions + 1
+			for _, o := range options {
+				m, e := matchComponent(o+pattern[patIdx:], name[nameIdx:])
+				if e != nil {
+					return false, e
+				}
+				if m {
+					return true, nil
+				}
+			}
+			return false, nil
+		} else if patRune == '?' || patRune == nameRune {
+			patIdx += patAdj
+			nameIdx += nameAdj
+		} else {
+			return false, nil
+		}
+	}
+	if patIdx >= patternLen && nameIdx >= nameLen {
+		return true, nil
+	}
+	if nameIdx >= nameLen && pattern[patIdx:] == "*" {
+		return true, nil
+	}
+	return false, nil
+}
diff --git a/go/src/github.com/bmatcuk/doublestar/doublestar_test.go b/go/src/github.com/bmatcuk/doublestar/doublestar_test.go
new file mode 100644
index 0000000..d931da3
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/doublestar_test.go
@@ -0,0 +1,139 @@
+// This file is mostly copied from Go's path/match_test.go
+
+package doublestar
+
+import "testing"
+
+type MatchTest struct {
+	pattern, s string
+	match      bool
+	err        error
+	testGlob   bool
+}
+
+var matchTests = []MatchTest{
+	{"abc", "abc", true, nil, true},
+	{"*", "abc", true, nil, true},
+	{"*c", "abc", true, nil, true},
+	{"a*", "a", true, nil, true},
+	{"a*", "abc", true, nil, true},
+	{"a*", "ab/c", false, nil, true},
+	{"a*/b", "abc/b", true, nil, true},
+	{"a*/b", "a/c/b", false, nil, true},
+	{"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil, true},
+	{"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil, true},
+	{"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil, true},
+	{"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil, true},
+	{"a*b?c*x", "abxbbxdbxebxczzx", true, nil, true},
+	{"a*b?c*x", "abxbbxdbxebxczzy", false, nil, true},
+	{"ab[c]", "abc", true, nil, true},
+	{"ab[b-d]", "abc", true, nil, true},
+	{"ab[e-g]", "abc", false, nil, true},
+	{"ab[^c]", "abc", false, nil, true},
+	{"ab[^b-d]", "abc", false, nil, true},
+	{"ab[^e-g]", "abc", true, nil, true},
+	{"a\\*b", "a*b", true, nil, true},
+	{"a\\*b", "ab", false, nil, true},
+	{"a?b", "a☺b", true, nil, true},
+	{"a[^a]b", "a☺b", true, nil, true},
+	{"a???b", "a☺b", false, nil, true},
+	{"a[^a][^a][^a]b", "a☺b", false, nil, true},
+	{"[a-ζ]*", "α", true, nil, true},
+	{"*[a-ζ]", "A", false, nil, true},
+	{"a?b", "a/b", false, nil, true},
+	{"a*b", "a/b", false, nil, true},
+	{"[\\]a]", "]", true, nil, true},
+	{"[\\-]", "-", true, nil, true},
+	{"[x\\-]", "x", true, nil, true},
+	{"[x\\-]", "-", true, nil, true},
+	{"[x\\-]", "z", false, nil, true},
+	{"[\\-x]", "x", true, nil, true},
+	{"[\\-x]", "-", true, nil, true},
+	{"[\\-x]", "a", false, nil, true},
+	{"[]a]", "]", false, ErrBadPattern, true},
+	{"[-]", "-", false, ErrBadPattern, true},
+	{"[x-]", "x", false, ErrBadPattern, true},
+	{"[x-]", "-", false, ErrBadPattern, true},
+	{"[x-]", "z", false, ErrBadPattern, true},
+	{"[-x]", "x", false, ErrBadPattern, true},
+	{"[-x]", "-", false, ErrBadPattern, true},
+	{"[-x]", "a", false, ErrBadPattern, true},
+	{"\\", "a", false, ErrBadPattern, true},
+	{"[a-b-c]", "a", false, ErrBadPattern, true},
+	{"[", "a", false, ErrBadPattern, true},
+	{"[^", "a", false, ErrBadPattern, true},
+	{"[^bc", "a", false, ErrBadPattern, true},
+	{"a[", "a", false, nil, false},
+	{"a[", "ab", false, ErrBadPattern, true},
+	{"*x", "xxx", true, nil, true},
+	{"a/**", "a", false, nil, true},
+	{"a/**", "a/b", true, nil, true},
+	{"a/**", "a/b/c", true, nil, true},
+	{"**/c", "c", true, nil, true},
+	{"**/c", "b/c", true, nil, true},
+	{"**/c", "a/b/c", true, nil, true},
+	{"a/**/b", "a/b", true, nil, true},
+	{"a/**/c", "a/b/c", true, nil, true},
+	{"a/**/d", "a/b/c/d", true, nil, true},
+	{"a/\\**", "a/b/c", false, nil, true},
+	{"a/\\**", "a/*", true, nil, true},
+	{"ab{c,d}", "abc", true, nil, true},
+	{"ab{c,d,*}", "abcde", true, nil, true},
+	{"ab{c,d}[", "abcd", false, ErrBadPattern, true},
+}
+
+func TestMatch(t *testing.T) {
+	for idx, tt := range matchTests {
+		testMatchWith(t, idx, tt)
+	}
+}
+
+func testMatchWith(t *testing.T, idx int, tt MatchTest) {
+	defer func() {
+		if r := recover(); r != nil {
+			t.Errorf("#%v. Match(%#q, %#q) panicked: %#v", idx, tt.pattern, tt.s, r)
+		}
+	}()
+
+	ok, err := Match(tt.pattern, tt.s)
+	if ok != tt.match || err != tt.err {
+		t.Errorf("#%v. Match(%#q, %#q) = %v, %v want %v, %v", idx, tt.pattern, tt.s, ok, err, tt.match, tt.err)
+	}
+}
+
+func TestGlob(t *testing.T) {
+	for idx, tt := range matchTests {
+		if tt.testGlob {
+			testGlobWith(t, idx, tt)
+		}
+	}
+}
+
+func testGlobWith(t *testing.T, idx int, tt MatchTest) {
+	defer func() {
+		if r := recover(); r != nil {
+			t.Errorf("#%v. Glob(%#q) panicked: %#v", idx, tt.pattern, r)
+		}
+	}()
+
+	matches, err := Glob("test/" + tt.pattern)
+	if inSlice("test/"+tt.s, matches) != tt.match {
+		if tt.match {
+			t.Errorf("#%v. Glob(%#q) = %#v - doesn't contain %v, but should", idx, tt.pattern, matches, tt.s)
+		} else {
+			t.Errorf("#%v. Glob(%#q) = %#v - contains %v, but shouldn't", idx, tt.pattern, matches, tt.s)
+		}
+	}
+	if err != tt.err {
+		t.Errorf("#%v. Glob(%#q) has error %v, but should be %v", idx, tt.pattern, err, tt.err)
+	}
+}
+
+func inSlice(s string, a []string) bool {
+	for _, i := range a {
+		if i == s {
+			return true
+		}
+	}
+	return false
+}
diff --git a/go/src/github.com/bmatcuk/doublestar/test/- b/go/src/github.com/bmatcuk/doublestar/test/-
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/-
diff --git a/go/src/github.com/bmatcuk/doublestar/test/README.md b/go/src/github.com/bmatcuk/doublestar/test/README.md
new file mode 100644
index 0000000..7312628
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/README.md
@@ -0,0 +1 @@
+This directory and associated subdirectories and files are for testing the Glob() function.
diff --git "a/go/src/github.com/bmatcuk/doublestar/test/\135" "b/go/src/github.com/bmatcuk/doublestar/test/\135"
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ "b/go/src/github.com/bmatcuk/doublestar/test/\135"
diff --git a/go/src/github.com/bmatcuk/doublestar/test/a*b b/go/src/github.com/bmatcuk/doublestar/test/a*b
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/a*b
diff --git a/go/src/github.com/bmatcuk/doublestar/test/a/* b/go/src/github.com/bmatcuk/doublestar/test/a/*
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/a/*
diff --git a/go/src/github.com/bmatcuk/doublestar/test/a/b/c/d b/go/src/github.com/bmatcuk/doublestar/test/a/b/c/d
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/a/b/c/d
diff --git a/go/src/github.com/bmatcuk/doublestar/test/a/c/b b/go/src/github.com/bmatcuk/doublestar/test/a/c/b
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/a/c/b
diff --git a/go/src/github.com/bmatcuk/doublestar/test/abc/b b/go/src/github.com/bmatcuk/doublestar/test/abc/b
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/abc/b
diff --git a/go/src/github.com/bmatcuk/doublestar/test/abcd b/go/src/github.com/bmatcuk/doublestar/test/abcd
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/abcd
diff --git a/go/src/github.com/bmatcuk/doublestar/test/abcde b/go/src/github.com/bmatcuk/doublestar/test/abcde
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/abcde
diff --git a/go/src/github.com/bmatcuk/doublestar/test/abxbbxdbxebxczzx b/go/src/github.com/bmatcuk/doublestar/test/abxbbxdbxebxczzx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/abxbbxdbxebxczzx
diff --git a/go/src/github.com/bmatcuk/doublestar/test/abxbbxdbxebxczzy b/go/src/github.com/bmatcuk/doublestar/test/abxbbxdbxebxczzy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/abxbbxdbxebxczzy
diff --git a/go/src/github.com/bmatcuk/doublestar/test/axbxcxdxe/f b/go/src/github.com/bmatcuk/doublestar/test/axbxcxdxe/f
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/axbxcxdxe/f
diff --git a/go/src/github.com/bmatcuk/doublestar/test/axbxcxdxe/xxx/f b/go/src/github.com/bmatcuk/doublestar/test/axbxcxdxe/xxx/f
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/axbxcxdxe/xxx/f
diff --git a/go/src/github.com/bmatcuk/doublestar/test/axbxcxdxexxx/f b/go/src/github.com/bmatcuk/doublestar/test/axbxcxdxexxx/f
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/axbxcxdxexxx/f
diff --git a/go/src/github.com/bmatcuk/doublestar/test/axbxcxdxexxx/fff b/go/src/github.com/bmatcuk/doublestar/test/axbxcxdxexxx/fff
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/axbxcxdxexxx/fff
diff --git "a/go/src/github.com/bmatcuk/doublestar/test/a\342\230\272b" "b/go/src/github.com/bmatcuk/doublestar/test/a\342\230\272b"
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ "b/go/src/github.com/bmatcuk/doublestar/test/a\342\230\272b"
diff --git a/go/src/github.com/bmatcuk/doublestar/test/b/c b/go/src/github.com/bmatcuk/doublestar/test/b/c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/b/c
diff --git a/go/src/github.com/bmatcuk/doublestar/test/c b/go/src/github.com/bmatcuk/doublestar/test/c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/c
diff --git a/go/src/github.com/bmatcuk/doublestar/test/x b/go/src/github.com/bmatcuk/doublestar/test/x
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/x
diff --git a/go/src/github.com/bmatcuk/doublestar/test/xxx b/go/src/github.com/bmatcuk/doublestar/test/xxx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/xxx
diff --git a/go/src/github.com/bmatcuk/doublestar/test/z b/go/src/github.com/bmatcuk/doublestar/test/z
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/go/src/github.com/bmatcuk/doublestar/test/z
diff --git "a/go/src/github.com/bmatcuk/doublestar/test/\316\261" "b/go/src/github.com/bmatcuk/doublestar/test/\316\261"
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ "b/go/src/github.com/bmatcuk/doublestar/test/\316\261"