github.com/songzhibin97/gkit@v1.2.13/tools/match/match_test.go (about)

     1  package match
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"strings"
     7  	"testing"
     8  	"time"
     9  	"unicode/utf8"
    10  )
    11  
    12  func TestMatch(t *testing.T) {
    13  	if !Match("hello world", "hello world") {
    14  		t.Fatal("fail")
    15  	}
    16  	if Match("hello world", "jello world") {
    17  		t.Fatal("fail")
    18  	}
    19  	if !Match("hello world", "hello*") {
    20  		t.Fatal("fail")
    21  	}
    22  	if Match("hello world", "jello*") {
    23  		t.Fatal("fail")
    24  	}
    25  	if !Match("hello world", "hello?world") {
    26  		t.Fatal("fail")
    27  	}
    28  	if Match("hello world", "jello?world") {
    29  		t.Fatal("fail")
    30  	}
    31  	if !Match("hello world", "he*o?world") {
    32  		t.Fatal("fail")
    33  	}
    34  	if !Match("hello world", "he*o?wor*") {
    35  		t.Fatal("fail")
    36  	}
    37  	if !Match("hello world", "he*o?*r*") {
    38  		t.Fatal("fail")
    39  	}
    40  	if !Match("的情况下解析一个", "*") {
    41  		t.Fatal("fail")
    42  	}
    43  	if !Match("的情况下解析一个", "*况下*") {
    44  		t.Fatal("fail")
    45  	}
    46  	if !Match("的情况下解析一个", "*况?*") {
    47  		t.Fatal("fail")
    48  	}
    49  	if !Match("的情况下解析一个", "的情况?解析一个") {
    50  		t.Fatal("fail")
    51  	}
    52  }
    53  
    54  // TestWildcardMatch - Tests validate the logic of wild card matching.
    55  // `WildcardMatch` supports '*' and '?' wildcards.
    56  // Sample usage: In resource matching for folder policy validation.
    57  func TestWildcardMatch(t *testing.T) {
    58  	testCases := []struct {
    59  		pattern string
    60  		text    string
    61  		matched bool
    62  	}{
    63  		// Test case - 1.
    64  		// Test case with pattern containing key name with a prefix. Should accept the same text without a "*".
    65  		{
    66  			pattern: "my-folder/oo*",
    67  			text:    "my-folder/oo",
    68  			matched: true,
    69  		},
    70  		// Test case - 2.
    71  		// Test case with "*" at the end of the pattern.
    72  		{
    73  			pattern: "my-folder/In*",
    74  			text:    "my-folder/India/Karnataka/",
    75  			matched: true,
    76  		},
    77  		// Test case - 3.
    78  		// Test case with prefixes shuffled.
    79  		// This should fail.
    80  		{
    81  			pattern: "my-folder/In*",
    82  			text:    "my-folder/Karnataka/India/",
    83  			matched: false,
    84  		},
    85  		// Test case - 4.
    86  		// Test case with text expanded to the wildcards in the pattern.
    87  		{
    88  			pattern: "my-folder/In*/Ka*/Ban",
    89  			text:    "my-folder/India/Karnataka/Ban",
    90  			matched: true,
    91  		},
    92  		// Test case - 5.
    93  		// Test case with the  keyname part is repeated as prefix several times.
    94  		// This is valid.
    95  		{
    96  			pattern: "my-folder/In*/Ka*/Ban",
    97  			text:    "my-folder/India/Karnataka/Ban/Ban/Ban/Ban/Ban",
    98  			matched: true,
    99  		},
   100  		// Test case - 6.
   101  		// Test case to validate that `*` can be expanded into multiple prefixes.
   102  		{
   103  			pattern: "my-folder/In*/Ka*/Ban",
   104  			text:    "my-folder/India/Karnataka/Area1/Area2/Area3/Ban",
   105  			matched: true,
   106  		},
   107  		// Test case - 7.
   108  		// Test case to validate that `*` can be expanded into multiple prefixes.
   109  		{
   110  			pattern: "my-folder/In*/Ka*/Ban",
   111  			text:    "my-folder/India/State1/State2/Karnataka/Area1/Area2/Area3/Ban",
   112  			matched: true,
   113  		},
   114  		// Test case - 8.
   115  		// Test case where the keyname part of the pattern is expanded in the text.
   116  		{
   117  			pattern: "my-folder/In*/Ka*/Ban",
   118  			text:    "my-folder/India/Karnataka/Bangalore",
   119  			matched: false,
   120  		},
   121  		// Test case - 9.
   122  		// Test case with prefixes and wildcard expanded for all "*".
   123  		{
   124  			pattern: "my-folder/In*/Ka*/Ban*",
   125  			text:    "my-folder/India/Karnataka/Bangalore",
   126  			matched: true,
   127  		},
   128  		// Test case - 10.
   129  		// Test case with keyname part being a wildcard in the pattern.
   130  		{
   131  			pattern: "my-folder/*",
   132  			text:    "my-folder/India",
   133  			matched: true,
   134  		},
   135  		// Test case - 11.
   136  		{
   137  			pattern: "my-folder/oo*",
   138  			text:    "my-folder/odo",
   139  			matched: false,
   140  		},
   141  
   142  		// Test case with pattern containing wildcard '?'.
   143  		// Test case - 12.
   144  		// "my-folder?/" matches "my-folder1/", "my-folder2/", "my-folder3" etc...
   145  		// doesn't match "myfolder/".
   146  		{
   147  			pattern: "my-folder?/abc*",
   148  			text:    "myfolder/abc",
   149  			matched: false,
   150  		},
   151  		// Test case - 13.
   152  		{
   153  			pattern: "my-folder?/abc*",
   154  			text:    "my-folder1/abc",
   155  			matched: true,
   156  		},
   157  		// Test case - 14.
   158  		{
   159  			pattern: "my-?-folder/abc*",
   160  			text:    "my--folder/abc",
   161  			matched: false,
   162  		},
   163  		// Test case - 15.
   164  		{
   165  			pattern: "my-?-folder/abc*",
   166  			text:    "my-1-folder/abc",
   167  			matched: true,
   168  		},
   169  		// Test case - 16.
   170  		{
   171  			pattern: "my-?-folder/abc*",
   172  			text:    "my-k-folder/abc",
   173  			matched: true,
   174  		},
   175  		// Test case - 17.
   176  		{
   177  			pattern: "my??folder/abc*",
   178  			text:    "myfolder/abc",
   179  			matched: false,
   180  		},
   181  		// Test case - 18.
   182  		{
   183  			pattern: "my??folder/abc*",
   184  			text:    "my4afolder/abc",
   185  			matched: true,
   186  		},
   187  		// Test case - 19.
   188  		{
   189  			pattern: "my-folder?abc*",
   190  			text:    "my-folder/abc",
   191  			matched: true,
   192  		},
   193  		// Test case 20-21.
   194  		// '?' matches '/' too. (works with s3).
   195  		// This is because the namespace is considered flat.
   196  		// "abc?efg" matches both "abcdefg" and "abc/efg".
   197  		{
   198  			pattern: "my-folder/abc?efg",
   199  			text:    "my-folder/abcdefg",
   200  			matched: true,
   201  		},
   202  		{
   203  			pattern: "my-folder/abc?efg",
   204  			text:    "my-folder/abc/efg",
   205  			matched: true,
   206  		},
   207  		// Test case - 22.
   208  		{
   209  			pattern: "my-folder/abc????",
   210  			text:    "my-folder/abc",
   211  			matched: false,
   212  		},
   213  		// Test case - 23.
   214  		{
   215  			pattern: "my-folder/abc????",
   216  			text:    "my-folder/abcde",
   217  			matched: false,
   218  		},
   219  		// Test case - 24.
   220  		{
   221  			pattern: "my-folder/abc????",
   222  			text:    "my-folder/abcdefg",
   223  			matched: true,
   224  		},
   225  		// Test case 25-26.
   226  		// test case with no '*'.
   227  		{
   228  			pattern: "my-folder/abc?",
   229  			text:    "my-folder/abc",
   230  			matched: false,
   231  		},
   232  		{
   233  			pattern: "my-folder/abc?",
   234  			text:    "my-folder/abcd",
   235  			matched: true,
   236  		},
   237  		{
   238  			pattern: "my-folder/abc?",
   239  			text:    "my-folder/abcde",
   240  			matched: false,
   241  		},
   242  		// Test case 27.
   243  		{
   244  			pattern: "my-folder/mnop*?",
   245  			text:    "my-folder/mnop",
   246  			matched: false,
   247  		},
   248  		// Test case 28.
   249  		{
   250  			pattern: "my-folder/mnop*?",
   251  			text:    "my-folder/mnopqrst/mnopqr",
   252  			matched: true,
   253  		},
   254  		// Test case 29.
   255  		{
   256  			pattern: "my-folder/mnop*?",
   257  			text:    "my-folder/mnopqrst/mnopqrs",
   258  			matched: true,
   259  		},
   260  		// Test case 30.
   261  		{
   262  			pattern: "my-folder/mnop*?",
   263  			text:    "my-folder/mnop",
   264  			matched: false,
   265  		},
   266  		// Test case 31.
   267  		{
   268  			pattern: "my-folder/mnop*?",
   269  			text:    "my-folder/mnopq",
   270  			matched: true,
   271  		},
   272  		// Test case 32.
   273  		{
   274  			pattern: "my-folder/mnop*?",
   275  			text:    "my-folder/mnopqr",
   276  			matched: true,
   277  		},
   278  		// Test case 33.
   279  		{
   280  			pattern: "my-folder/mnop*?and",
   281  			text:    "my-folder/mnopqand",
   282  			matched: true,
   283  		},
   284  		// Test case 34.
   285  		{
   286  			pattern: "my-folder/mnop*?and",
   287  			text:    "my-folder/mnopand",
   288  			matched: false,
   289  		},
   290  		// Test case 35.
   291  		{
   292  			pattern: "my-folder/mnop*?and",
   293  			text:    "my-folder/mnopqand",
   294  			matched: true,
   295  		},
   296  		// Test case 36.
   297  		{
   298  			pattern: "my-folder/mnop*?",
   299  			text:    "my-folder/mn",
   300  			matched: false,
   301  		},
   302  		// Test case 37.
   303  		{
   304  			pattern: "my-folder/mnop*?",
   305  			text:    "my-folder/mnopqrst/mnopqrs",
   306  			matched: true,
   307  		},
   308  		// Test case 38.
   309  		{
   310  			pattern: "my-folder/mnop*??",
   311  			text:    "my-folder/mnopqrst",
   312  			matched: true,
   313  		},
   314  		// Test case 39.
   315  		{
   316  			pattern: "my-folder/mnop*qrst",
   317  			text:    "my-folder/mnopabcdegqrst",
   318  			matched: true,
   319  		},
   320  		// Test case 40.
   321  		{
   322  			pattern: "my-folder/mnop*?and",
   323  			text:    "my-folder/mnopqand",
   324  			matched: true,
   325  		},
   326  		// Test case 41.
   327  		{
   328  			pattern: "my-folder/mnop*?and",
   329  			text:    "my-folder/mnopand",
   330  			matched: false,
   331  		},
   332  		// Test case 42.
   333  		{
   334  			pattern: "my-folder/mnop*?and?",
   335  			text:    "my-folder/mnopqanda",
   336  			matched: true,
   337  		},
   338  		// Test case 43.
   339  		{
   340  			pattern: "my-folder/mnop*?and",
   341  			text:    "my-folder/mnopqanda",
   342  			matched: false,
   343  		},
   344  		// Test case 44.
   345  
   346  		{
   347  			pattern: "my-?-folder/abc*",
   348  			text:    "my-folder/mnopqanda",
   349  			matched: false,
   350  		},
   351  	}
   352  	// Iterating over the test cases, call the function under test and asert the output.
   353  	for i, testCase := range testCases {
   354  		actualResult := Match(testCase.text, testCase.pattern)
   355  		if testCase.matched != actualResult {
   356  			t.Errorf("Test %d: Expected the result to be `%v`, but instead found it to be `%v`", i+1, testCase.matched, actualResult)
   357  		}
   358  	}
   359  }
   360  
   361  func TestRandomInput(t *testing.T) {
   362  	rand.Seed(time.Now().UnixNano())
   363  	b1 := make([]byte, 100)
   364  	b2 := make([]byte, 100)
   365  	for i := 0; i < 1000000; i++ {
   366  		if _, err := rand.Read(b1); err != nil {
   367  			t.Fatal(err)
   368  		}
   369  		if _, err := rand.Read(b2); err != nil {
   370  			t.Fatal(err)
   371  		}
   372  		Match(string(b1), string(b2))
   373  	}
   374  }
   375  
   376  func testAllowable(pattern, exmin, exmax string) error {
   377  	min, max := Allowable(pattern)
   378  	if min != exmin || max != exmax {
   379  		return fmt.Errorf("expected '%v'/'%v', got '%v'/'%v'",
   380  			exmin, exmax, min, max)
   381  	}
   382  	return nil
   383  }
   384  
   385  func TestAllowable(t *testing.T) {
   386  	if err := testAllowable("hell*", "hell", "helm"); err != nil {
   387  		t.Fatal(err)
   388  	}
   389  	if err := testAllowable("hell?", "hell"+string(rune(0)), "hell"+string(utf8.MaxRune)); err != nil {
   390  		t.Fatal(err)
   391  	}
   392  	if err := testAllowable("h解析ell*", "h解析ell", "h解析elm"); err != nil {
   393  		t.Fatal(err)
   394  	}
   395  	if err := testAllowable("h解*ell*", "h解", "h觤"); err != nil {
   396  		t.Fatal(err)
   397  	}
   398  }
   399  
   400  func TestIsPattern(t *testing.T) {
   401  	patterns := []string{
   402  		"*", "hello*", "hello*world", "*world",
   403  		"?", "hello?", "hello?world", "?world",
   404  	}
   405  	nonPatterns := []string{
   406  		"", "hello",
   407  	}
   408  	for _, pattern := range patterns {
   409  		if !IsPattern(pattern) {
   410  			t.Fatalf("expected true")
   411  		}
   412  	}
   413  
   414  	for _, s := range nonPatterns {
   415  		if IsPattern(s) {
   416  			t.Fatalf("expected false")
   417  		}
   418  	}
   419  }
   420  
   421  func BenchmarkAscii(t *testing.B) {
   422  	for i := 0; i < t.N; i++ {
   423  		if !Match("hello", "hello") {
   424  			t.Fatal("fail")
   425  		}
   426  	}
   427  }
   428  
   429  func BenchmarkUnicode(t *testing.B) {
   430  	for i := 0; i < t.N; i++ {
   431  		if !Match("h情llo", "h情llo") {
   432  			t.Fatal("fail")
   433  		}
   434  	}
   435  }
   436  
   437  func TestLotsStars(t *testing.T) {
   438  	// This tests that a pattern with lots of stars will complete quickly.
   439  	var str, pat string
   440  
   441  	str = `,**,,**,**,**,**,**,**,`
   442  	pat = `,**********************************************{**",**,,**,**,` +
   443  		`**,**,"",**,**,**,**,**,**,**,**,**,**]`
   444  	Match(pat, str)
   445  
   446  	str = strings.Replace(str, ",", "情", -1)
   447  	pat = strings.Replace(pat, ",", "情", -1)
   448  	Match(pat, str)
   449  }