go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/data/text/sequence/pattern_test.go (about)

     1  // Copyright 2022 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package sequence_test
    16  
    17  import (
    18  	"testing"
    19  
    20  	. "github.com/smartystreets/goconvey/convey"
    21  	"go.chromium.org/luci/common/data/text/sequence"
    22  	. "go.chromium.org/luci/common/testing/assertions"
    23  )
    24  
    25  func TestAutoPattern(t *testing.T) {
    26  	t.Parallel()
    27  
    28  	Convey(`NewPattern`, t, func() {
    29  		Convey(`works`, func() {
    30  			Convey(`with empty input`, func() {
    31  				pat, err := sequence.NewPattern()
    32  				So(err, ShouldBeNil)
    33  				So(pat, ShouldBeNil)
    34  			})
    35  
    36  			Convey(`with a literal`, func() {
    37  				pat, err := sequence.NewPattern("hello")
    38  				So(err, ShouldBeNil)
    39  				So(pat, ShouldResemble, sequence.Pattern{sequence.LiteralMatcher("hello")})
    40  			})
    41  
    42  			Convey(`with a reserved literal`, func() {
    43  				pat, err := sequence.NewPattern("=^", "==")
    44  				So(err, ShouldBeNil)
    45  				So(pat, ShouldResemble, sequence.Pattern{
    46  					sequence.LiteralMatcher("^"),
    47  					sequence.LiteralMatcher("="),
    48  				})
    49  			})
    50  
    51  			Convey(`with string regexp`, func() {
    52  				pat, err := sequence.NewPattern("/hello/")
    53  				So(err, ShouldBeNil)
    54  				So(pat, ShouldHaveLength, 1)
    55  				So(pat[0], ShouldHaveSameTypeAs, sequence.RegexpMatcher{})
    56  				rem := pat[0].(sequence.RegexpMatcher)
    57  				So(rem.R.String(), ShouldEqual, "hello")
    58  			})
    59  
    60  			Convey(`with string ellipsis`, func() {
    61  				pat, err := sequence.NewPattern("...")
    62  				So(err, ShouldBeNil)
    63  				So(pat, ShouldResemble, sequence.Pattern{sequence.Ellipsis})
    64  			})
    65  
    66  			Convey(`with string edges`, func() {
    67  				pat, err := sequence.NewPattern("^", "$")
    68  				So(err, ShouldBeNil)
    69  				So(pat, ShouldResemble, sequence.Pattern{sequence.Edge, sequence.Edge})
    70  			})
    71  		})
    72  
    73  		Convey(`fails`, func() {
    74  			Convey(`with a bad regexp`, func() {
    75  				_, err := sequence.NewPattern("/unclosed(/")
    76  				So(err, ShouldErrLike, "invalid regexp (i=0)")
    77  			})
    78  
    79  			Convey(`with out of place edges`, func() {
    80  				_, err := sequence.NewPattern("$", "something")
    81  				So(err, ShouldErrLike, "cannot use `$` for Edge except at end")
    82  
    83  				_, err = sequence.NewPattern("something", "^")
    84  				So(err, ShouldErrLike, "cannot use `^` for Edge except at beginning")
    85  			})
    86  
    87  			Convey(`with many ellipsis`, func() {
    88  				_, err := sequence.NewPattern("...", "...")
    89  				So(err, ShouldErrLike, "cannot have multiple Ellipsis in a row (i=1)")
    90  			})
    91  		})
    92  	})
    93  }
    94  
    95  func TestPatternIn(t *testing.T) {
    96  	t.Parallel()
    97  
    98  	m := func(tokens ...string) sequence.Pattern {
    99  		ret, err := sequence.NewPattern(tokens...)
   100  		if err != nil {
   101  			panic(err)
   102  		}
   103  		return ret
   104  	}
   105  
   106  	Convey(`Pattern.In`, t, func() {
   107  		Convey(`works`, func() {
   108  			Convey(`no match`, func() {
   109  				So(m("narp").In("foo", "bar", "baz"), ShouldBeFalse)
   110  			})
   111  
   112  			Convey(`finds single strings`, func() {
   113  				So(m("foo").In("foo", "bar", "baz"), ShouldBeTrue)
   114  				So(m("bar").In("foo", "bar", "baz"), ShouldBeTrue)
   115  				So(m("baz").In("foo", "bar", "baz"), ShouldBeTrue)
   116  
   117  				So(m("narp").In("foo", "bar", "baz"), ShouldBeFalse)
   118  			})
   119  
   120  			Convey(`finds single regex`, func() {
   121  				So(m("/ba./").In("foo", "bar", "baz"), ShouldBeTrue)
   122  				So(m("/a/").In("foo", "bar", "baz"), ShouldBeTrue)
   123  				So(m("/z$/").In("foo", "bar", "baz"), ShouldBeTrue)
   124  				So(m("/^bar$/").In("foo", "bar", "baz"), ShouldBeTrue)
   125  
   126  				So(m("/^a$/").In("foo", "bar", "baz"), ShouldBeFalse)
   127  			})
   128  
   129  			Convey(`finds string sequence`, func() {
   130  				So(m().In("foo", "bar", "baz"), ShouldBeTrue)
   131  				So(m("foo", "bar").In("foo", "bar", "baz"), ShouldBeTrue)
   132  				So(m("bar", "baz").In("foo", "bar", "baz"), ShouldBeTrue)
   133  				So(m("foo", "bar", "baz").In("foo", "bar", "baz"), ShouldBeTrue)
   134  
   135  				So(m("foo", "baz").In("foo", "bar", "baz"), ShouldBeFalse)
   136  			})
   137  
   138  			Convey(`finds mixed sequence`, func() {
   139  				So(m("/.o./", "bar", "/z/").In("foo", "bar", "baz"), ShouldBeTrue)
   140  
   141  				So(m("/f/", "/z/", "/r/").In("foo", "bar", "baz"), ShouldBeFalse)
   142  			})
   143  
   144  			Convey(`finds ellipsis sequence`, func() {
   145  				So(m("a", "foo", "...", "bar").In(
   146  					"a", "foo", "narp", "bar"), ShouldBeTrue)
   147  
   148  				So(m("foo", "...", "bar", "a").In(
   149  					"foo", "bar", "a"), ShouldBeTrue)
   150  
   151  				So(m("foo", "...", "bar", "...", "/^a/").In(
   152  					"foo", "narp", "bar", "tarp", "stuff", "aardvark"), ShouldBeTrue)
   153  
   154  				So(m("foo", "...", "bar").In(
   155  					"foo", "narp"), ShouldBeFalse)
   156  			})
   157  
   158  			Convey(`respects Edges`, func() {
   159  				So(m("^", "foo", "...", "bar").In(
   160  					"foo", "narp", "bar"), ShouldBeTrue)
   161  
   162  				So(m("foo", "...", "bar", "$").In(
   163  					"a", "foo", "narp", "bar"), ShouldBeTrue)
   164  
   165  				So(m("a", "b", "$").In(
   166  					"extra", "a", "b"), ShouldBeTrue)
   167  
   168  				So(m("^", "foo", "...", "bar").In(
   169  					"a", "foo", "narp", "bar"), ShouldBeFalse)
   170  
   171  				So(m("foo", "...", "bar", "$").In(
   172  					"a", "foo", "narp", "bar", "stuff"), ShouldBeFalse)
   173  
   174  			})
   175  		})
   176  
   177  		Convey(`fails`, func() {
   178  			Convey(`bad Ellipsis`, func() {
   179  				So(func() {
   180  					sequence.Pattern{sequence.Ellipsis, sequence.Ellipsis}.In("something")
   181  				}, ShouldPanicLike, "cannot have multiple Ellipsis in a row")
   182  			})
   183  
   184  			Convey(`bad Edge`, func() {
   185  				So(func() {
   186  					sequence.Pattern{
   187  						sequence.Edge,
   188  						sequence.LiteralMatcher("stuff"),
   189  						sequence.Edge,
   190  						sequence.LiteralMatcher("more stuff"),
   191  					}.In("something")
   192  				}, ShouldPanicLike, "cannot have Edge in the middle of a Pattern")
   193  			})
   194  		})
   195  	})
   196  
   197  }