github.com/hattya/go.sh@v0.0.0-20240328132134-f53276d95cc6/pattern/pattern_test.go (about)

     1  //
     2  // go.sh/pattern :: pattern_test.go
     3  //
     4  //   Copyright (c) 2021-2022 Akinori Hattori <hattya@gmail.com>
     5  //
     6  //   SPDX-License-Identifier: MIT
     7  //
     8  
     9  package pattern_test
    10  
    11  import (
    12  	"os"
    13  	"path/filepath"
    14  	"reflect"
    15  	"strings"
    16  	"testing"
    17  
    18  	"github.com/hattya/go.sh/pattern"
    19  )
    20  
    21  var matchTests = []struct {
    22  	patterns []string
    23  	mode     pattern.Mode
    24  	s        string
    25  	e        string
    26  }{
    27  	{[]string{""}, 0, "", ""},
    28  	{[]string{"", ""}, 0, "", ""},
    29  	{[]string{"*.go"}, 0, "go.mod", ""},
    30  	{[]string{"*.go"}, 0, "pattern.go", "pattern.go"},
    31  	{[]string{"*.sw?"}, 0, ".pattern.go.swp", ".pattern.go.swp"},
    32  	{[]string{"\\w"}, 0, "w", "w"},
    33  	{[]string{"\\["}, 0, "[", "["},
    34  	{[]string{"abc[lmn]xyz"}, 0, "abcmxyz", "abcmxyz"},
    35  	{[]string{"abc[!lmn]xyz"}, 0, "abc-xyz", "abc-xyz"},
    36  	{[]string{"[]\\-]"}, 0, "-", "-"},
    37  	{[]string{"[[\\+]"}, 0, "+", "+"},
    38  	{[]string{"[[:digit:]]"}, 0, "1", "1"},
    39  	{[]string{"[[:digit]"}, 0, ":", ":"},
    40  
    41  	{[]string{"/*"}, pattern.Smallest | pattern.Suffix, "foo", ""},
    42  	{[]string{"/*"}, pattern.Smallest | pattern.Suffix, "foo/bar/baz", "/baz"},
    43  	{[]string{"/*"}, pattern.Largest | pattern.Suffix, "foo", ""},
    44  	{[]string{"/*"}, pattern.Largest | pattern.Suffix, "foo/bar/baz", "/bar/baz"},
    45  
    46  	{[]string{"*/"}, pattern.Smallest | pattern.Prefix, "foo", ""},
    47  	{[]string{"*/"}, pattern.Smallest | pattern.Prefix, "foo/bar/baz", "foo/"},
    48  	{[]string{"*/"}, pattern.Largest | pattern.Prefix, "foo", ""},
    49  	{[]string{"*/"}, pattern.Largest | pattern.Prefix, "foo/bar/baz", "foo/bar/"},
    50  
    51  	{[]string{"*"}, pattern.Smallest | pattern.Suffix, "", ""},
    52  	{[]string{"*"}, pattern.Smallest | pattern.Prefix, "", ""},
    53  	{[]string{"*"}, pattern.Suffix | pattern.Prefix, "foo", ""},
    54  	{[]string{"?"}, pattern.Smallest | pattern.Suffix, "\xf0\xff", "\xff"},
    55  	{[]string{"?"}, pattern.Smallest | pattern.Prefix, "\xf0\xff", "\xf0"},
    56  }
    57  
    58  func TestMatch(t *testing.T) {
    59  	for _, tt := range matchTests {
    60  		switch g, err := pattern.Match(tt.patterns, tt.mode, tt.s); {
    61  		case err != nil && err != pattern.NoMatch:
    62  			t.Error("unexpected error:", err)
    63  		case g != tt.e:
    64  			t.Errorf("expected %q, got %q", tt.e, g)
    65  		}
    66  	}
    67  }
    68  
    69  var matchErrorTests = [][]string{
    70  	{"\xff"},
    71  	{"\\"},
    72  	{"\\\xff"},
    73  	{"["},
    74  	{"[\xff"},
    75  	{"[\\"},
    76  	{"[\\\xff"},
    77  	{"[["},
    78  	{"[[\xff"},
    79  	{"[[\\"},
    80  }
    81  
    82  func TestMatchError(t *testing.T) {
    83  	for _, patterns := range matchErrorTests {
    84  		if _, err := pattern.Match(patterns, 0, ""); err == nil {
    85  			t.Error("expected error")
    86  		}
    87  	}
    88  }
    89  
    90  var globTests = []struct {
    91  	pattern string
    92  	paths   []string
    93  }{
    94  	{"*.go", []string{"a.go"}},
    95  	{"[.a]*", []string{"a.go"}},
    96  	{".*", []string{".", "..", ".git", ".gitignore"}},
    97  	{"*", []string{"a.go", "bar", "baz", "foo"}},
    98  	{"*/*", []string{"bar/a.go", "baz/a.go", "foo/a.go"}},
    99  	{"foo/*", []string{"foo/a.go"}},
   100  	{"foo//*", []string{"foo//a.go"}},
   101  	{`foo\/*`, []string{"foo/a.go"}},
   102  	{`foo/\*`, nil},
   103  	{"_.go", nil},
   104  	{"_/*", nil},
   105  	{"_/_", nil},
   106  	{".", []string{"."}},
   107  	{"..", []string{".."}},
   108  	{"", nil},
   109  
   110  	{"${PATDIR}/*.go", []string{"${LITDIR}/a.go"}},
   111  	{"${PATDIR}/.*", []string{"${LITDIR}/.", "${LITDIR}/..", "${LITDIR}/.git", "${LITDIR}/.gitignore"}},
   112  	{"${PATDIR}/foo/*", []string{"${LITDIR}/foo/a.go"}},
   113  	{"${PATDIR}/foo//*", []string{"${LITDIR}/foo//a.go"}},
   114  	{`${PATDIR}/foo\/*`, []string{"${LITDIR}/foo/a.go"}},
   115  	{`${PATDIR}/fo/\*`, nil},
   116  	{"${PATDIR}/_.go", nil},
   117  	{"${PATDIR}/_/*", nil},
   118  	{"${PATDIR}/_/_", nil},
   119  	{"${PATDIR}/", []string{"${LITDIR}/"}},
   120  	{"${PATDIR}/.", []string{"${LITDIR}/."}},
   121  	{"${PATDIR}/..", []string{"${LITDIR}/.."}},
   122  }
   123  
   124  func TestGlob(t *testing.T) {
   125  	dir := t.TempDir()
   126  	popd, err := pushd(dir)
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  	defer popd()
   131  
   132  	for _, p := range []string{
   133  		filepath.Join(".git", "config"),
   134  		".gitignore",
   135  		"a.go",
   136  		filepath.Join("foo", "a.go"),
   137  		filepath.Join("bar", "a.go"),
   138  		filepath.Join("baz", "a.go"),
   139  	} {
   140  		if dir := filepath.Dir(p); dir != "" {
   141  			if err := mkdir(dir); err != nil {
   142  				t.Fatal(err)
   143  			}
   144  		}
   145  		if err := touch(p); err != nil {
   146  			t.Fatal(err)
   147  		}
   148  	}
   149  
   150  	mapper := func(k string) string {
   151  		switch k {
   152  		case "PATDIR":
   153  			return strings.ReplaceAll(dir, `\`, `\\`)
   154  		case "LITDIR":
   155  			return dir
   156  		}
   157  		return ""
   158  	}
   159  	for _, tt := range globTests {
   160  		g, err := pattern.Glob(os.Expand(tt.pattern, mapper))
   161  		if err != nil {
   162  			t.Error("unexpected error:", err)
   163  		}
   164  		var e []string
   165  		for _, p := range tt.paths {
   166  			e = append(e, os.Expand(p, mapper))
   167  		}
   168  		if !reflect.DeepEqual(g, e) {
   169  			t.Errorf("expected %#v, got %#v", e, g)
   170  		}
   171  	}
   172  }
   173  
   174  var globErrorTests = []string{
   175  	"*\xff",
   176  	"_\xff",
   177  }
   178  
   179  func TestGlobError(t *testing.T) {
   180  	for _, pat := range globErrorTests {
   181  		if _, err := pattern.Glob(pat); err == nil {
   182  			t.Error("expected error")
   183  		}
   184  	}
   185  }
   186  
   187  func mkdir(s ...string) error {
   188  	return os.MkdirAll(filepath.Join(s...), 0o777)
   189  }
   190  
   191  func pushd(path string) (func() error, error) {
   192  	wd, err := os.Getwd()
   193  	popd := func() error {
   194  		if err != nil {
   195  			return err
   196  		}
   197  		return os.Chdir(wd)
   198  	}
   199  	return popd, os.Chdir(path)
   200  }
   201  
   202  func touch(s ...string) error {
   203  	return os.WriteFile(filepath.Join(s...), nil, 0o666)
   204  }