github.com/neohugo/neohugo@v0.123.8/tpl/strings/strings_test.go (about)

     1  // Copyright 2017 The Hugo Authors. All rights reserved.
     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  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package strings
    15  
    16  import (
    17  	"html/template"
    18  	"testing"
    19  
    20  	"github.com/neohugo/neohugo/config/testconfig"
    21  	"github.com/neohugo/neohugo/deps"
    22  
    23  	qt "github.com/frankban/quicktest"
    24  	"github.com/spf13/cast"
    25  )
    26  
    27  var ns = New(&deps.Deps{
    28  	Conf: testconfig.GetTestConfig(nil, nil),
    29  })
    30  
    31  type tstNoStringer struct{}
    32  
    33  func TestChomp(t *testing.T) {
    34  	t.Parallel()
    35  	c := qt.New(t)
    36  
    37  	for _, test := range []struct {
    38  		s      any
    39  		expect any
    40  	}{
    41  		{"\n a\n", "\n a"},
    42  		{"\n a\n\n", "\n a"},
    43  		{"\n a\r\n", "\n a"},
    44  		{"\n a\n\r\n", "\n a"},
    45  		{"\n a\r\r", "\n a"},
    46  		{"\n a\r", "\n a"},
    47  		// errors
    48  		{tstNoStringer{}, false},
    49  	} {
    50  
    51  		result, err := ns.Chomp(test.s)
    52  
    53  		if b, ok := test.expect.(bool); ok && !b {
    54  			c.Assert(err, qt.Not(qt.IsNil))
    55  			continue
    56  		}
    57  
    58  		c.Assert(err, qt.IsNil)
    59  		c.Assert(result, qt.Equals, test.expect)
    60  
    61  		// repeat the check with template.HTML input
    62  		result, err = ns.Chomp(template.HTML(cast.ToString(test.s)))
    63  		c.Assert(err, qt.IsNil)
    64  		c.Assert(result, qt.Equals, template.HTML(cast.ToString(test.expect)))
    65  	}
    66  }
    67  
    68  func TestContains(t *testing.T) {
    69  	t.Parallel()
    70  	c := qt.New(t)
    71  
    72  	for _, test := range []struct {
    73  		s      any
    74  		substr any
    75  		expect bool
    76  		isErr  bool
    77  	}{
    78  		{"", "", true, false},
    79  		{"123", "23", true, false},
    80  		{"123", "234", false, false},
    81  		{"123", "", true, false},
    82  		{"", "a", false, false},
    83  		{123, "23", true, false},
    84  		{123, "234", false, false},
    85  		{123, "", true, false},
    86  		{template.HTML("123"), []byte("23"), true, false},
    87  		{template.HTML("123"), []byte("234"), false, false},
    88  		{template.HTML("123"), []byte(""), true, false},
    89  		// errors
    90  		{"", tstNoStringer{}, false, true},
    91  		{tstNoStringer{}, "", false, true},
    92  	} {
    93  
    94  		result, err := ns.Contains(test.s, test.substr)
    95  
    96  		if test.isErr {
    97  			c.Assert(err, qt.Not(qt.IsNil))
    98  			continue
    99  		}
   100  
   101  		c.Assert(err, qt.IsNil)
   102  		c.Assert(result, qt.Equals, test.expect)
   103  	}
   104  }
   105  
   106  func TestContainsAny(t *testing.T) {
   107  	t.Parallel()
   108  	c := qt.New(t)
   109  
   110  	for _, test := range []struct {
   111  		s      any
   112  		substr any
   113  		expect bool
   114  		isErr  bool
   115  	}{
   116  		{"", "", false, false},
   117  		{"", "1", false, false},
   118  		{"", "123", false, false},
   119  		{"1", "", false, false},
   120  		{"1", "1", true, false},
   121  		{"111", "1", true, false},
   122  		{"123", "789", false, false},
   123  		{"123", "729", true, false},
   124  		{"a☺b☻c☹d", "uvw☻xyz", true, false},
   125  		{1, "", false, false},
   126  		{1, "1", true, false},
   127  		{111, "1", true, false},
   128  		{123, "789", false, false},
   129  		{123, "729", true, false},
   130  		{[]byte("123"), template.HTML("789"), false, false},
   131  		{[]byte("123"), template.HTML("729"), true, false},
   132  		{[]byte("a☺b☻c☹d"), template.HTML("uvw☻xyz"), true, false},
   133  		// errors
   134  		{"", tstNoStringer{}, false, true},
   135  		{tstNoStringer{}, "", false, true},
   136  	} {
   137  
   138  		result, err := ns.ContainsAny(test.s, test.substr)
   139  
   140  		if test.isErr {
   141  			c.Assert(err, qt.Not(qt.IsNil))
   142  			continue
   143  		}
   144  
   145  		c.Assert(err, qt.IsNil)
   146  		c.Assert(result, qt.Equals, test.expect)
   147  	}
   148  }
   149  
   150  func TestContainsNonSpace(t *testing.T) {
   151  	t.Parallel()
   152  	c := qt.New(t)
   153  
   154  	for _, test := range []struct {
   155  		s      any
   156  		expect bool
   157  	}{
   158  		{"", false},
   159  		{" ", false},
   160  		{"        ", false},
   161  		{"\t", false},
   162  		{"\r", false},
   163  		{"a", true},
   164  		{"    a", true},
   165  		{"a\n", true},
   166  	} {
   167  		c.Assert(ns.ContainsNonSpace(test.s), qt.Equals, test.expect)
   168  	}
   169  }
   170  
   171  func TestCountRunes(t *testing.T) {
   172  	t.Parallel()
   173  	c := qt.New(t)
   174  
   175  	for _, test := range []struct {
   176  		s      any
   177  		expect any
   178  	}{
   179  		{"foo bar", 6},
   180  		{"旁边", 2},
   181  		{`<div class="test">旁边</div>`, 2},
   182  		// errors
   183  		{tstNoStringer{}, false},
   184  	} {
   185  
   186  		result, err := ns.CountRunes(test.s)
   187  
   188  		if b, ok := test.expect.(bool); ok && !b {
   189  			c.Assert(err, qt.Not(qt.IsNil))
   190  			continue
   191  		}
   192  
   193  		c.Assert(err, qt.IsNil)
   194  		c.Assert(result, qt.Equals, test.expect)
   195  	}
   196  }
   197  
   198  func TestRuneCount(t *testing.T) {
   199  	t.Parallel()
   200  	c := qt.New(t)
   201  
   202  	for _, test := range []struct {
   203  		s      any
   204  		expect any
   205  	}{
   206  		{"foo bar", 7},
   207  		{"旁边", 2},
   208  		{`<div class="test">旁边</div>`, 26},
   209  		// errors
   210  		{tstNoStringer{}, false},
   211  	} {
   212  
   213  		result, err := ns.RuneCount(test.s)
   214  
   215  		if b, ok := test.expect.(bool); ok && !b {
   216  			c.Assert(err, qt.Not(qt.IsNil))
   217  			continue
   218  		}
   219  
   220  		c.Assert(err, qt.IsNil)
   221  		c.Assert(result, qt.Equals, test.expect)
   222  	}
   223  }
   224  
   225  func TestCountWords(t *testing.T) {
   226  	t.Parallel()
   227  	c := qt.New(t)
   228  
   229  	for _, test := range []struct {
   230  		s      any
   231  		expect any
   232  	}{
   233  		{"Do Be Do Be Do", 5},
   234  		{"旁边", 2},
   235  		{`<div class="test">旁边</div>`, 2},
   236  		{"Here's to you...", 3},
   237  		{"Here’s to you...", 3},
   238  		{"Here’s to you…", 3},
   239  		// errors
   240  		{tstNoStringer{}, false},
   241  	} {
   242  
   243  		result, err := ns.CountWords(test.s)
   244  
   245  		if b, ok := test.expect.(bool); ok && !b {
   246  			c.Assert(err, qt.Not(qt.IsNil))
   247  			continue
   248  		}
   249  
   250  		c.Assert(err, qt.IsNil)
   251  		c.Assert(result, qt.Equals, test.expect)
   252  	}
   253  }
   254  
   255  func TestHasPrefix(t *testing.T) {
   256  	t.Parallel()
   257  	c := qt.New(t)
   258  
   259  	for _, test := range []struct {
   260  		s      any
   261  		prefix any
   262  		expect any
   263  		isErr  bool
   264  	}{
   265  		{"abcd", "ab", true, false},
   266  		{"abcd", "cd", false, false},
   267  		{template.HTML("abcd"), "ab", true, false},
   268  		{template.HTML("abcd"), "cd", false, false},
   269  		{template.HTML("1234"), 12, true, false},
   270  		{template.HTML("1234"), 34, false, false},
   271  		{[]byte("abcd"), "ab", true, false},
   272  		// errors
   273  		{"", tstNoStringer{}, false, true},
   274  		{tstNoStringer{}, "", false, true},
   275  	} {
   276  
   277  		result, err := ns.HasPrefix(test.s, test.prefix)
   278  
   279  		if test.isErr {
   280  			c.Assert(err, qt.Not(qt.IsNil))
   281  			continue
   282  		}
   283  
   284  		c.Assert(err, qt.IsNil)
   285  		c.Assert(result, qt.Equals, test.expect)
   286  	}
   287  }
   288  
   289  func TestHasSuffix(t *testing.T) {
   290  	t.Parallel()
   291  	c := qt.New(t)
   292  
   293  	for _, test := range []struct {
   294  		s      any
   295  		suffix any
   296  		expect any
   297  		isErr  bool
   298  	}{
   299  		{"abcd", "cd", true, false},
   300  		{"abcd", "ab", false, false},
   301  		{template.HTML("abcd"), "cd", true, false},
   302  		{template.HTML("abcd"), "ab", false, false},
   303  		{template.HTML("1234"), 34, true, false},
   304  		{template.HTML("1234"), 12, false, false},
   305  		{[]byte("abcd"), "cd", true, false},
   306  		// errors
   307  		{"", tstNoStringer{}, false, true},
   308  		{tstNoStringer{}, "", false, true},
   309  	} {
   310  
   311  		result, err := ns.HasSuffix(test.s, test.suffix)
   312  
   313  		if test.isErr {
   314  			c.Assert(err, qt.Not(qt.IsNil))
   315  			continue
   316  		}
   317  
   318  		c.Assert(err, qt.IsNil)
   319  		c.Assert(result, qt.Equals, test.expect)
   320  	}
   321  }
   322  
   323  func TestReplace(t *testing.T) {
   324  	t.Parallel()
   325  	c := qt.New(t)
   326  
   327  	for _, test := range []struct {
   328  		s      any
   329  		old    any
   330  		new    any
   331  		limit  any
   332  		expect any
   333  	}{
   334  		{"aab", "a", "b", nil, "bbb"},
   335  		{"11a11", 1, 2, nil, "22a22"},
   336  		{12345, 1, 2, nil, "22345"},
   337  		{"aab", "a", "b", 1, "bab"},
   338  		{"11a11", 1, 2, 2, "22a11"},
   339  		// errors
   340  		{tstNoStringer{}, "a", "b", nil, false},
   341  		{"a", tstNoStringer{}, "b", nil, false},
   342  		{"a", "b", tstNoStringer{}, nil, false},
   343  	} {
   344  
   345  		var (
   346  			result string
   347  			err    error
   348  		)
   349  
   350  		if test.limit != nil {
   351  			result, err = ns.Replace(test.s, test.old, test.new, test.limit)
   352  		} else {
   353  			result, err = ns.Replace(test.s, test.old, test.new)
   354  		}
   355  
   356  		if b, ok := test.expect.(bool); ok && !b {
   357  			c.Assert(err, qt.Not(qt.IsNil))
   358  			continue
   359  		}
   360  
   361  		c.Assert(err, qt.IsNil)
   362  		c.Assert(result, qt.Equals, test.expect)
   363  	}
   364  }
   365  
   366  func TestSliceString(t *testing.T) {
   367  	t.Parallel()
   368  	c := qt.New(t)
   369  
   370  	var err error
   371  	for _, test := range []struct {
   372  		v1     any
   373  		v2     any
   374  		v3     any
   375  		expect any
   376  	}{
   377  		{"abc", 1, 2, "b"},
   378  		{"abc", 1, 3, "bc"},
   379  		{"abcdef", 1, int8(3), "bc"},
   380  		{"abcdef", 1, int16(3), "bc"},
   381  		{"abcdef", 1, int32(3), "bc"},
   382  		{"abcdef", 1, int64(3), "bc"},
   383  		{"abc", 0, 1, "a"},
   384  		{"abcdef", nil, nil, "abcdef"},
   385  		{"abcdef", 0, 6, "abcdef"},
   386  		{"abcdef", 0, 2, "ab"},
   387  		{"abcdef", 2, nil, "cdef"},
   388  		{"abcdef", int8(2), nil, "cdef"},
   389  		{"abcdef", int16(2), nil, "cdef"},
   390  		{"abcdef", int32(2), nil, "cdef"},
   391  		{"abcdef", int64(2), nil, "cdef"},
   392  		{123, 1, 3, "23"},
   393  		{"abcdef", 6, nil, false},
   394  		{"abcdef", 4, 7, false},
   395  		{"abcdef", -1, nil, false},
   396  		{"abcdef", -1, 7, false},
   397  		{"abcdef", 1, -1, false},
   398  		{tstNoStringer{}, 0, 1, false},
   399  		{"ĀĀĀ", 0, 1, "Ā"}, // issue #1333
   400  		{"a", t, nil, false},
   401  		{"a", 1, t, false},
   402  	} {
   403  
   404  		var result string
   405  		if test.v2 == nil {
   406  			result, err = ns.SliceString(test.v1)
   407  		} else if test.v3 == nil {
   408  			result, err = ns.SliceString(test.v1, test.v2)
   409  		} else {
   410  			result, err = ns.SliceString(test.v1, test.v2, test.v3)
   411  		}
   412  
   413  		if b, ok := test.expect.(bool); ok && !b {
   414  			c.Assert(err, qt.Not(qt.IsNil))
   415  			continue
   416  		}
   417  
   418  		c.Assert(err, qt.IsNil)
   419  		c.Assert(result, qt.Equals, test.expect)
   420  	}
   421  
   422  	// Too many arguments
   423  	_, err = ns.SliceString("a", 1, 2, 3)
   424  	if err == nil {
   425  		t.Errorf("Should have errored")
   426  	}
   427  }
   428  
   429  func TestSplit(t *testing.T) {
   430  	t.Parallel()
   431  	c := qt.New(t)
   432  
   433  	for _, test := range []struct {
   434  		v1     any
   435  		v2     string
   436  		expect any
   437  	}{
   438  		{"a, b", ", ", []string{"a", "b"}},
   439  		{"a & b & c", " & ", []string{"a", "b", "c"}},
   440  		{"http://example.com", "http://", []string{"", "example.com"}},
   441  		{123, "2", []string{"1", "3"}},
   442  		{tstNoStringer{}, ",", false},
   443  	} {
   444  
   445  		result, err := ns.Split(test.v1, test.v2)
   446  
   447  		if b, ok := test.expect.(bool); ok && !b {
   448  			c.Assert(err, qt.Not(qt.IsNil))
   449  			continue
   450  		}
   451  
   452  		c.Assert(err, qt.IsNil)
   453  		c.Assert(result, qt.DeepEquals, test.expect)
   454  	}
   455  }
   456  
   457  func TestSubstr(t *testing.T) {
   458  	t.Parallel()
   459  	c := qt.New(t)
   460  
   461  	var err error
   462  	for _, test := range []struct {
   463  		v1     any
   464  		v2     any
   465  		v3     any
   466  		expect any
   467  	}{
   468  		{"abc", 1, 2, "bc"},
   469  		{"abc", 0, 1, "a"},
   470  		{"abcdef", 0, 0, ""},
   471  		{"abcdef", 1, 0, ""},
   472  		{"abcdef", -1, 0, ""},
   473  		{"abcdef", -1, 2, "f"},
   474  		{"abcdef", -3, 3, "def"},
   475  		{"abcdef", -1, nil, "f"},
   476  		{"abcdef", -2, nil, "ef"},
   477  		{"abcdef", -3, 1, "d"},
   478  		{"abcdef", 0, -1, "abcde"},
   479  		{"abcdef", 2, -1, "cde"},
   480  		{"abcdef", 4, -4, ""},
   481  		{"abcdef", 7, 1, ""},
   482  		{"abcdef", 6, nil, ""},
   483  		{"abcdef", 1, 100, "bcdef"},
   484  		{"abcdef", -100, 3, "abc"},
   485  		{"abcdef", -3, -1, "de"},
   486  		{"abcdef", 2, nil, "cdef"},
   487  		{"abcdef", int8(2), nil, "cdef"},
   488  		{"abcdef", int16(2), nil, "cdef"},
   489  		{"abcdef", int32(2), nil, "cdef"},
   490  		{"abcdef", int64(2), nil, "cdef"},
   491  		{"abcdef", 2, int8(3), "cde"},
   492  		{"abcdef", 2, int16(3), "cde"},
   493  		{"abcdef", 2, int32(3), "cde"},
   494  		{"abcdef", 2, int64(3), "cde"},
   495  		{123, 1, 3, "23"},
   496  		{1.2e3, 0, 4, "1200"},
   497  		{tstNoStringer{}, 0, 1, false},
   498  		{"abcdef", 2.0, nil, "cdef"},
   499  		{"abcdef", 2.0, 2, "cd"},
   500  		{"abcdef", 2, 2.0, "cd"},
   501  		{"ĀĀĀ", 1, 2, "ĀĀ"}, // # issue 1333
   502  		{"abcdef", "doo", nil, false},
   503  		{"abcdef", "doo", "doo", false},
   504  		{"abcdef", 1, "doo", false},
   505  		{"", 0, nil, ""},
   506  	} {
   507  
   508  		var result string
   509  
   510  		if test.v3 == nil {
   511  			result, err = ns.Substr(test.v1, test.v2)
   512  		} else {
   513  			result, err = ns.Substr(test.v1, test.v2, test.v3)
   514  		}
   515  
   516  		if b, ok := test.expect.(bool); ok && !b {
   517  			c.Check(err, qt.Not(qt.IsNil), qt.Commentf("%v", test))
   518  			continue
   519  		}
   520  
   521  		c.Assert(err, qt.IsNil, qt.Commentf("%v", test))
   522  		c.Check(result, qt.Equals, test.expect, qt.Commentf("%v", test))
   523  	}
   524  
   525  	_, err = ns.Substr("abcdef")
   526  	c.Assert(err, qt.Not(qt.IsNil))
   527  
   528  	_, err = ns.Substr("abcdef", 1, 2, 3)
   529  	c.Assert(err, qt.Not(qt.IsNil))
   530  }
   531  
   532  func TestTitle(t *testing.T) {
   533  	t.Parallel()
   534  	c := qt.New(t)
   535  
   536  	for _, test := range []struct {
   537  		s      any
   538  		expect any
   539  	}{
   540  		{"test", "Test"},
   541  		{template.HTML("hypertext"), "Hypertext"},
   542  		{[]byte("bytes"), "Bytes"},
   543  		// errors
   544  		{tstNoStringer{}, false},
   545  	} {
   546  
   547  		result, err := ns.Title(test.s)
   548  
   549  		if b, ok := test.expect.(bool); ok && !b {
   550  			c.Assert(err, qt.Not(qt.IsNil))
   551  			continue
   552  		}
   553  
   554  		c.Assert(err, qt.IsNil)
   555  		c.Assert(result, qt.Equals, test.expect)
   556  	}
   557  }
   558  
   559  func TestToLower(t *testing.T) {
   560  	t.Parallel()
   561  	c := qt.New(t)
   562  
   563  	for _, test := range []struct {
   564  		s      any
   565  		expect any
   566  	}{
   567  		{"TEST", "test"},
   568  		{template.HTML("LoWeR"), "lower"},
   569  		{[]byte("BYTES"), "bytes"},
   570  		// errors
   571  		{tstNoStringer{}, false},
   572  	} {
   573  
   574  		result, err := ns.ToLower(test.s)
   575  
   576  		if b, ok := test.expect.(bool); ok && !b {
   577  			c.Assert(err, qt.Not(qt.IsNil))
   578  			continue
   579  		}
   580  
   581  		c.Assert(err, qt.IsNil)
   582  		c.Assert(result, qt.Equals, test.expect)
   583  	}
   584  }
   585  
   586  func TestToUpper(t *testing.T) {
   587  	t.Parallel()
   588  	c := qt.New(t)
   589  
   590  	for _, test := range []struct {
   591  		s      any
   592  		expect any
   593  	}{
   594  		{"test", "TEST"},
   595  		{template.HTML("UpPeR"), "UPPER"},
   596  		{[]byte("bytes"), "BYTES"},
   597  		// errors
   598  		{tstNoStringer{}, false},
   599  	} {
   600  
   601  		result, err := ns.ToUpper(test.s)
   602  
   603  		if b, ok := test.expect.(bool); ok && !b {
   604  			c.Assert(err, qt.Not(qt.IsNil))
   605  			continue
   606  		}
   607  
   608  		c.Assert(err, qt.IsNil)
   609  		c.Assert(result, qt.Equals, test.expect)
   610  	}
   611  }
   612  
   613  func TestTrim(t *testing.T) {
   614  	t.Parallel()
   615  	c := qt.New(t)
   616  
   617  	for _, test := range []struct {
   618  		s      any
   619  		cutset any
   620  		expect any
   621  	}{
   622  		{"abba", "a", "bb"},
   623  		{"abba", "ab", ""},
   624  		{"<tag>", "<>", "tag"},
   625  		{`"quote"`, `"`, "quote"},
   626  		{1221, "1", "22"},
   627  		{1221, "12", ""},
   628  		{template.HTML("<tag>"), "<>", "tag"},
   629  		{[]byte("<tag>"), "<>", "tag"},
   630  		// errors
   631  		{"", tstNoStringer{}, false},
   632  		{tstNoStringer{}, "", false},
   633  	} {
   634  
   635  		result, err := ns.Trim(test.s, test.cutset)
   636  
   637  		if b, ok := test.expect.(bool); ok && !b {
   638  			c.Assert(err, qt.Not(qt.IsNil))
   639  			continue
   640  		}
   641  
   642  		c.Assert(err, qt.IsNil)
   643  		c.Assert(result, qt.Equals, test.expect)
   644  	}
   645  }
   646  
   647  func TestTrimLeft(t *testing.T) {
   648  	t.Parallel()
   649  	c := qt.New(t)
   650  
   651  	for _, test := range []struct {
   652  		s      any
   653  		cutset any
   654  		expect any
   655  	}{
   656  		{"abba", "a", "bba"},
   657  		{"abba", "ab", ""},
   658  		{"<tag>", "<>", "tag>"},
   659  		{`"quote"`, `"`, `quote"`},
   660  		{1221, "1", "221"},
   661  		{1221, "12", ""},
   662  		{"007", "0", "7"},
   663  		{template.HTML("<tag>"), "<>", "tag>"},
   664  		{[]byte("<tag>"), "<>", "tag>"},
   665  		// errors
   666  		{"", tstNoStringer{}, false},
   667  		{tstNoStringer{}, "", false},
   668  	} {
   669  
   670  		result, err := ns.TrimLeft(test.cutset, test.s)
   671  
   672  		if b, ok := test.expect.(bool); ok && !b {
   673  			c.Assert(err, qt.Not(qt.IsNil))
   674  			continue
   675  		}
   676  
   677  		c.Assert(err, qt.IsNil)
   678  		c.Assert(result, qt.Equals, test.expect)
   679  	}
   680  }
   681  
   682  func TestTrimPrefix(t *testing.T) {
   683  	t.Parallel()
   684  	c := qt.New(t)
   685  
   686  	for _, test := range []struct {
   687  		s      any
   688  		prefix any
   689  		expect any
   690  	}{
   691  		{"aabbaa", "a", "abbaa"},
   692  		{"aabb", "b", "aabb"},
   693  		{1234, "12", "34"},
   694  		{1234, "34", "1234"},
   695  		// errors
   696  		{"", tstNoStringer{}, false},
   697  		{tstNoStringer{}, "", false},
   698  	} {
   699  
   700  		result, err := ns.TrimPrefix(test.prefix, test.s)
   701  
   702  		if b, ok := test.expect.(bool); ok && !b {
   703  			c.Assert(err, qt.Not(qt.IsNil))
   704  			continue
   705  		}
   706  
   707  		c.Assert(err, qt.IsNil)
   708  		c.Assert(result, qt.Equals, test.expect)
   709  	}
   710  }
   711  
   712  func TestTrimRight(t *testing.T) {
   713  	t.Parallel()
   714  	c := qt.New(t)
   715  
   716  	for _, test := range []struct {
   717  		s      any
   718  		cutset any
   719  		expect any
   720  	}{
   721  		{"abba", "a", "abb"},
   722  		{"abba", "ab", ""},
   723  		{"<tag>", "<>", "<tag"},
   724  		{`"quote"`, `"`, `"quote`},
   725  		{1221, "1", "122"},
   726  		{1221, "12", ""},
   727  		{"007", "0", "007"},
   728  		{template.HTML("<tag>"), "<>", "<tag"},
   729  		{[]byte("<tag>"), "<>", "<tag"},
   730  		// errors
   731  		{"", tstNoStringer{}, false},
   732  		{tstNoStringer{}, "", false},
   733  	} {
   734  
   735  		result, err := ns.TrimRight(test.cutset, test.s)
   736  
   737  		if b, ok := test.expect.(bool); ok && !b {
   738  			c.Assert(err, qt.Not(qt.IsNil))
   739  			continue
   740  		}
   741  
   742  		c.Assert(err, qt.IsNil)
   743  		c.Assert(result, qt.Equals, test.expect)
   744  	}
   745  }
   746  
   747  func TestTrimSuffix(t *testing.T) {
   748  	t.Parallel()
   749  	c := qt.New(t)
   750  
   751  	for _, test := range []struct {
   752  		s      any
   753  		suffix any
   754  		expect any
   755  	}{
   756  		{"aabbaa", "a", "aabba"},
   757  		{"aabb", "b", "aab"},
   758  		{1234, "12", "1234"},
   759  		{1234, "34", "12"},
   760  		// errors
   761  		{"", tstNoStringer{}, false},
   762  		{tstNoStringer{}, "", false},
   763  	} {
   764  
   765  		result, err := ns.TrimSuffix(test.suffix, test.s)
   766  
   767  		if b, ok := test.expect.(bool); ok && !b {
   768  			c.Assert(err, qt.Not(qt.IsNil))
   769  			continue
   770  		}
   771  
   772  		c.Assert(err, qt.IsNil)
   773  		c.Assert(result, qt.Equals, test.expect)
   774  	}
   775  }
   776  
   777  func TestRepeat(t *testing.T) {
   778  	t.Parallel()
   779  	c := qt.New(t)
   780  
   781  	for _, test := range []struct {
   782  		s      any
   783  		n      any
   784  		expect any
   785  	}{
   786  		{"yo", "2", "yoyo"},
   787  		{"~", "16", "~~~~~~~~~~~~~~~~"},
   788  		{"<tag>", "0", ""},
   789  		{"yay", "1", "yay"},
   790  		{1221, "1", "1221"},
   791  		{1221, 2, "12211221"},
   792  		{template.HTML("<tag>"), "2", "<tag><tag>"},
   793  		{[]byte("<tag>"), 2, "<tag><tag>"},
   794  		// errors
   795  		{"", tstNoStringer{}, false},
   796  		{tstNoStringer{}, "", false},
   797  		{"ab", -1, false},
   798  	} {
   799  
   800  		result, err := ns.Repeat(test.n, test.s)
   801  
   802  		if b, ok := test.expect.(bool); ok && !b {
   803  			c.Assert(err, qt.Not(qt.IsNil))
   804  			continue
   805  		}
   806  
   807  		c.Assert(err, qt.IsNil)
   808  		c.Assert(result, qt.Equals, test.expect)
   809  	}
   810  }