github.com/cryptomisa/mattermost-server@v5.11.1+incompatible/model/utils_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package model
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  	"reflect"
    10  	"strings"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestNewId(t *testing.T) {
    19  	for i := 0; i < 1000; i++ {
    20  		id := NewId()
    21  		if len(id) > 26 {
    22  			t.Fatal("ids shouldn't be longer than 26 chars")
    23  		}
    24  	}
    25  }
    26  
    27  func TestRandomString(t *testing.T) {
    28  	for i := 0; i < 1000; i++ {
    29  		r := NewRandomString(32)
    30  		if len(r) != 32 {
    31  			t.Fatal("should be 32 chars")
    32  		}
    33  	}
    34  }
    35  
    36  func TestGetMillisForTime(t *testing.T) {
    37  	thisTimeMillis := int64(1471219200000)
    38  	thisTime := time.Date(2016, time.August, 15, 0, 0, 0, 0, time.UTC)
    39  
    40  	result := GetMillisForTime(thisTime)
    41  
    42  	if thisTimeMillis != result {
    43  		t.Fatalf(fmt.Sprintf("millis are not the same: %d and %d", thisTimeMillis, result))
    44  	}
    45  }
    46  
    47  func TestPadDateStringZeros(t *testing.T) {
    48  	for _, testCase := range []struct {
    49  		Name     string
    50  		Input    string
    51  		Expected string
    52  	}{
    53  		{
    54  			Name:     "Valid date",
    55  			Input:    "2016-08-01",
    56  			Expected: "2016-08-01",
    57  		},
    58  		{
    59  			Name:     "Valid date but requires padding of zero",
    60  			Input:    "2016-8-1",
    61  			Expected: "2016-08-01",
    62  		},
    63  	} {
    64  		t.Run(testCase.Name, func(t *testing.T) {
    65  			assert.Equal(t, testCase.Expected, PadDateStringZeros(testCase.Input))
    66  		})
    67  	}
    68  }
    69  
    70  func TestAppError(t *testing.T) {
    71  	err := NewAppError("TestAppError", "message", nil, "", http.StatusInternalServerError)
    72  	json := err.ToJson()
    73  	rerr := AppErrorFromJson(strings.NewReader(json))
    74  	require.Equal(t, err.Message, rerr.Message)
    75  
    76  	t.Log(err.Error())
    77  }
    78  
    79  func TestAppErrorJunk(t *testing.T) {
    80  	rerr := AppErrorFromJson(strings.NewReader("<html><body>This is a broken test</body></html>"))
    81  	require.Equal(t, "body: <html><body>This is a broken test</body></html>", rerr.DetailedError)
    82  }
    83  
    84  func TestCopyStringMap(t *testing.T) {
    85  	itemKey := "item1"
    86  	originalMap := make(map[string]string)
    87  	originalMap[itemKey] = "val1"
    88  
    89  	copyMap := CopyStringMap(originalMap)
    90  	copyMap[itemKey] = "changed"
    91  
    92  	assert.Equal(t, "val1", originalMap[itemKey])
    93  }
    94  
    95  func TestMapJson(t *testing.T) {
    96  
    97  	m := make(map[string]string)
    98  	m["id"] = "test_id"
    99  	json := MapToJson(m)
   100  
   101  	rm := MapFromJson(strings.NewReader(json))
   102  
   103  	if rm["id"] != "test_id" {
   104  		t.Fatal("map should be valid")
   105  	}
   106  
   107  	rm2 := MapFromJson(strings.NewReader(""))
   108  	if len(rm2) > 0 {
   109  		t.Fatal("make should be ivalid")
   110  	}
   111  }
   112  
   113  func TestIsValidEmail(t *testing.T) {
   114  	for _, testCase := range []struct {
   115  		Input    string
   116  		Expected bool
   117  	}{
   118  		{
   119  			Input:    "corey",
   120  			Expected: false,
   121  		},
   122  		{
   123  			Input:    "corey@example.com",
   124  			Expected: true,
   125  		},
   126  		{
   127  			Input:    "corey+test@example.com",
   128  			Expected: true,
   129  		},
   130  		{
   131  			Input:    "@corey+test@example.com",
   132  			Expected: false,
   133  		},
   134  		{
   135  			Input:    "firstname.lastname@example.com",
   136  			Expected: true,
   137  		},
   138  		{
   139  			Input:    "firstname.lastname@subdomain.example.com",
   140  			Expected: true,
   141  		},
   142  		{
   143  			Input:    "123454567@domain.com",
   144  			Expected: true,
   145  		},
   146  		{
   147  			Input:    "email@domain-one.com",
   148  			Expected: true,
   149  		},
   150  		{
   151  			Input:    "email@domain.co.jp",
   152  			Expected: true,
   153  		},
   154  		{
   155  			Input:    "firstname-lastname@domain.com",
   156  			Expected: true,
   157  		},
   158  		{
   159  			Input:    "@domain.com",
   160  			Expected: false,
   161  		},
   162  		{
   163  			Input:    "Billy Bob <billy@example.com>",
   164  			Expected: false,
   165  		},
   166  		{
   167  			Input:    "email.domain.com",
   168  			Expected: false,
   169  		},
   170  		{
   171  			Input:    "email.@domain.com",
   172  			Expected: false,
   173  		},
   174  		{
   175  			Input:    "email@domain@domain.com",
   176  			Expected: false,
   177  		},
   178  		{
   179  			Input:    "(email@domain.com)",
   180  			Expected: false,
   181  		},
   182  		{
   183  			Input:    "email@汤.中国",
   184  			Expected: true,
   185  		},
   186  		{
   187  			Input:    "email1@domain.com, email2@domain.com",
   188  			Expected: false,
   189  		},
   190  	} {
   191  		t.Run(testCase.Input, func(t *testing.T) {
   192  			assert.Equal(t, testCase.Expected, IsValidEmail(testCase.Input))
   193  		})
   194  	}
   195  }
   196  
   197  func TestValidLower(t *testing.T) {
   198  	if !IsLower("corey+test@hulen.com") {
   199  		t.Error("should be valid")
   200  	}
   201  
   202  	if IsLower("Corey+test@hulen.com") {
   203  		t.Error("should be invalid")
   204  	}
   205  }
   206  
   207  func TestEtag(t *testing.T) {
   208  	etag := Etag("hello", 24)
   209  	require.NotEqual(t, "", etag)
   210  }
   211  
   212  var hashtags = map[string]string{
   213  	"#test":           "#test",
   214  	"test":            "",
   215  	"#test123":        "#test123",
   216  	"#123test123":     "",
   217  	"#test-test":      "#test-test",
   218  	"#test?":          "#test",
   219  	"hi #there":       "#there",
   220  	"#bug #idea":      "#bug #idea",
   221  	"#bug or #gif!":   "#bug #gif",
   222  	"#hüllo":          "#hüllo",
   223  	"#?test":          "",
   224  	"#-test":          "",
   225  	"#yo_yo":          "#yo_yo",
   226  	"(#brakets)":      "#brakets",
   227  	")#stekarb(":      "#stekarb",
   228  	"<#less_than<":    "#less_than",
   229  	">#greater_than>": "#greater_than",
   230  	"-#minus-":        "#minus",
   231  	"_#under_":        "#under",
   232  	"+#plus+":         "#plus",
   233  	"=#equals=":       "#equals",
   234  	"%#pct%":          "#pct",
   235  	"&#and&":          "#and",
   236  	"^#hat^":          "#hat",
   237  	"##brown#":        "#brown",
   238  	"*#star*":         "#star",
   239  	"|#pipe|":         "#pipe",
   240  	":#colon:":        "#colon",
   241  	";#semi;":         "#semi",
   242  	"#Mötley;":        "#Mötley",
   243  	".#period.":       "#period",
   244  	"¿#upside¿":       "#upside",
   245  	"\"#quote\"":      "#quote",
   246  	"/#slash/":        "#slash",
   247  	"\\#backslash\\":  "#backslash",
   248  	"#a":              "",
   249  	"#1":              "",
   250  	"foo#bar":         "",
   251  }
   252  
   253  func TestStringArray_Equal(t *testing.T) {
   254  	for name, tc := range map[string]struct {
   255  		Array1 StringArray
   256  		Array2 StringArray
   257  		Expected bool
   258  	}{
   259  		"Empty": {
   260  			nil,
   261  			nil,
   262  			true,
   263  		},
   264  		"EqualLength_EqualValue": {
   265  			StringArray{"123"},
   266  			StringArray{"123"},
   267  			true,
   268  		},
   269  		"DifferentLength": {
   270  			StringArray{"123"},
   271  			StringArray{"123", "abc"},
   272  			false,
   273  		},
   274  		"DifferentValues_EqualLength": {
   275  			StringArray{"123"},
   276  			StringArray{"abc"},
   277  			false,
   278  		},
   279  		"EqualLength_EqualValues": {
   280  			StringArray{"123", "abc"},
   281  			StringArray{"123", "abc"},
   282  			true,
   283  		},
   284  		"EqualLength_EqualValues_DifferentOrder": {
   285  			StringArray{"abc", "123"},
   286  			StringArray{"123", "abc"},
   287  			false,
   288  		},
   289  	} {
   290  		t.Run(name, func(t *testing.T) {
   291  			assert.Equal(t, tc.Expected, tc.Array1.Equals(tc.Array2))
   292  		})
   293  	}
   294  }
   295  
   296  func TestParseHashtags(t *testing.T) {
   297  	for input, output := range hashtags {
   298  		if o, _ := ParseHashtags(input); o != output {
   299  			t.Fatal("failed to parse hashtags from input=" + input + " expected=" + output + " actual=" + o)
   300  		}
   301  	}
   302  }
   303  
   304  func TestIsValidAlphaNum(t *testing.T) {
   305  	cases := []struct {
   306  		Input  string
   307  		Result bool
   308  	}{
   309  		{
   310  			Input:  "test",
   311  			Result: true,
   312  		},
   313  		{
   314  			Input:  "test-name",
   315  			Result: true,
   316  		},
   317  		{
   318  			Input:  "test--name",
   319  			Result: true,
   320  		},
   321  		{
   322  			Input:  "test__name",
   323  			Result: true,
   324  		},
   325  		{
   326  			Input:  "-",
   327  			Result: false,
   328  		},
   329  		{
   330  			Input:  "__",
   331  			Result: false,
   332  		},
   333  		{
   334  			Input:  "test-",
   335  			Result: false,
   336  		},
   337  		{
   338  			Input:  "test--",
   339  			Result: false,
   340  		},
   341  		{
   342  			Input:  "test__",
   343  			Result: false,
   344  		},
   345  		{
   346  			Input:  "test:name",
   347  			Result: false,
   348  		},
   349  	}
   350  
   351  	for _, tc := range cases {
   352  		actual := IsValidAlphaNum(tc.Input)
   353  		if actual != tc.Result {
   354  			t.Fatalf("case: %v\tshould returned: %#v", tc, tc.Result)
   355  		}
   356  	}
   357  }
   358  
   359  func TestGetServerIpAddress(t *testing.T) {
   360  	if len(GetServerIpAddress()) == 0 {
   361  		t.Fatal("Should find local ip address")
   362  	}
   363  }
   364  
   365  func TestIsValidAlphaNumHyphenUnderscore(t *testing.T) {
   366  	casesWithFormat := []struct {
   367  		Input  string
   368  		Result bool
   369  	}{
   370  		{
   371  			Input:  "test",
   372  			Result: true,
   373  		},
   374  		{
   375  			Input:  "test-name",
   376  			Result: true,
   377  		},
   378  		{
   379  			Input:  "test--name",
   380  			Result: true,
   381  		},
   382  		{
   383  			Input:  "test__name",
   384  			Result: true,
   385  		},
   386  		{
   387  			Input:  "test_name",
   388  			Result: true,
   389  		},
   390  		{
   391  			Input:  "test_-name",
   392  			Result: true,
   393  		},
   394  		{
   395  			Input:  "-",
   396  			Result: false,
   397  		},
   398  		{
   399  			Input:  "__",
   400  			Result: false,
   401  		},
   402  		{
   403  			Input:  "test-",
   404  			Result: false,
   405  		},
   406  		{
   407  			Input:  "test--",
   408  			Result: false,
   409  		},
   410  		{
   411  			Input:  "test__",
   412  			Result: false,
   413  		},
   414  		{
   415  			Input:  "test:name",
   416  			Result: false,
   417  		},
   418  	}
   419  
   420  	for _, tc := range casesWithFormat {
   421  		actual := IsValidAlphaNumHyphenUnderscore(tc.Input, true)
   422  		if actual != tc.Result {
   423  			t.Fatalf("case: %v\tshould returned: %#v", tc, tc.Result)
   424  		}
   425  	}
   426  
   427  	casesWithoutFormat := []struct {
   428  		Input  string
   429  		Result bool
   430  	}{
   431  		{
   432  			Input:  "test",
   433  			Result: true,
   434  		},
   435  		{
   436  			Input:  "test-name",
   437  			Result: true,
   438  		},
   439  		{
   440  			Input:  "test--name",
   441  			Result: true,
   442  		},
   443  		{
   444  			Input:  "test__name",
   445  			Result: true,
   446  		},
   447  		{
   448  			Input:  "test_name",
   449  			Result: true,
   450  		},
   451  		{
   452  			Input:  "test_-name",
   453  			Result: true,
   454  		},
   455  		{
   456  			Input:  "-",
   457  			Result: true,
   458  		},
   459  		{
   460  			Input:  "_",
   461  			Result: true,
   462  		},
   463  		{
   464  			Input:  "test-",
   465  			Result: true,
   466  		},
   467  		{
   468  			Input:  "test--",
   469  			Result: true,
   470  		},
   471  		{
   472  			Input:  "test__",
   473  			Result: true,
   474  		},
   475  		{
   476  			Input:  ".",
   477  			Result: false,
   478  		},
   479  
   480  		{
   481  			Input:  "test,",
   482  			Result: false,
   483  		},
   484  		{
   485  			Input:  "test:name",
   486  			Result: false,
   487  		},
   488  	}
   489  
   490  	for _, tc := range casesWithoutFormat {
   491  		actual := IsValidAlphaNumHyphenUnderscore(tc.Input, false)
   492  		if actual != tc.Result {
   493  			t.Fatalf("case: '%v'\tshould returned: %#v", tc.Input, tc.Result)
   494  		}
   495  	}
   496  }
   497  
   498  func TestIsValidId(t *testing.T) {
   499  	cases := []struct {
   500  		Input  string
   501  		Result bool
   502  	}{
   503  		{
   504  			Input:  NewId(),
   505  			Result: true,
   506  		},
   507  		{
   508  			Input:  "",
   509  			Result: false,
   510  		},
   511  		{
   512  			Input:  "junk",
   513  			Result: false,
   514  		},
   515  		{
   516  			Input:  "qwertyuiop1234567890asdfg{",
   517  			Result: false,
   518  		},
   519  		{
   520  			Input:  NewId() + "}",
   521  			Result: false,
   522  		},
   523  	}
   524  
   525  	for _, tc := range cases {
   526  		actual := IsValidId(tc.Input)
   527  		if actual != tc.Result {
   528  			t.Fatalf("case: %v\tshould returned: %#v", tc, tc.Result)
   529  		}
   530  	}
   531  }
   532  
   533  func TestNowhereNil(t *testing.T) {
   534  	t.Parallel()
   535  
   536  	var nilStringPtr *string
   537  	var nonNilStringPtr *string = new(string)
   538  	var nilSlice []string
   539  	var nilStruct *struct{}
   540  	var nilMap map[bool]bool
   541  
   542  	var nowhereNilStruct = struct {
   543  		X *string
   544  		Y *string
   545  	}{
   546  		nonNilStringPtr,
   547  		nonNilStringPtr,
   548  	}
   549  	var somewhereNilStruct = struct {
   550  		X *string
   551  		Y *string
   552  	}{
   553  		nonNilStringPtr,
   554  		nilStringPtr,
   555  	}
   556  
   557  	var privateSomewhereNilStruct = struct {
   558  		X *string
   559  		y *string
   560  	}{
   561  		nonNilStringPtr,
   562  		nilStringPtr,
   563  	}
   564  
   565  	testCases := []struct {
   566  		Description string
   567  		Value       interface{}
   568  		Expected    bool
   569  	}{
   570  		{
   571  			"nil",
   572  			nil,
   573  			false,
   574  		},
   575  		{
   576  			"empty string",
   577  			"",
   578  			true,
   579  		},
   580  		{
   581  			"non-empty string",
   582  			"not empty!",
   583  			true,
   584  		},
   585  		{
   586  			"nil string pointer",
   587  			nilStringPtr,
   588  			false,
   589  		},
   590  		{
   591  			"non-nil string pointer",
   592  			nonNilStringPtr,
   593  			true,
   594  		},
   595  		{
   596  			"0",
   597  			0,
   598  			true,
   599  		},
   600  		{
   601  			"1",
   602  			1,
   603  			true,
   604  		},
   605  		{
   606  			"0 (int64)",
   607  			int64(0),
   608  			true,
   609  		},
   610  		{
   611  			"1 (int64)",
   612  			int64(1),
   613  			true,
   614  		},
   615  		{
   616  			"true",
   617  			true,
   618  			true,
   619  		},
   620  		{
   621  			"false",
   622  			false,
   623  			true,
   624  		},
   625  		{
   626  			"nil slice",
   627  			nilSlice,
   628  			// A nil slice is observably the same as an empty slice, so allow it.
   629  			true,
   630  		},
   631  		{
   632  			"empty slice",
   633  			[]string{},
   634  			true,
   635  		},
   636  		{
   637  			"slice containing nils",
   638  			[]*string{nil, nil},
   639  			true,
   640  		},
   641  		{
   642  			"nil map",
   643  			nilMap,
   644  			false,
   645  		},
   646  		{
   647  			"non-nil map",
   648  			make(map[bool]bool),
   649  			true,
   650  		},
   651  		{
   652  			"non-nil map containing nil",
   653  			map[bool]*string{true: nilStringPtr, false: nonNilStringPtr},
   654  			// Map values are not checked
   655  			true,
   656  		},
   657  		{
   658  			"nil struct",
   659  			nilStruct,
   660  			false,
   661  		},
   662  		{
   663  			"empty struct",
   664  			struct{}{},
   665  			true,
   666  		},
   667  		{
   668  			"struct containing no nil",
   669  			nowhereNilStruct,
   670  			true,
   671  		},
   672  		{
   673  			"struct containing nil",
   674  			somewhereNilStruct,
   675  			false,
   676  		},
   677  		{
   678  			"struct pointer containing no nil",
   679  			&nowhereNilStruct,
   680  			true,
   681  		},
   682  		{
   683  			"struct pointer containing nil",
   684  			&somewhereNilStruct,
   685  			false,
   686  		},
   687  		{
   688  			"struct containing private nil",
   689  			privateSomewhereNilStruct,
   690  			true,
   691  		},
   692  		{
   693  			"struct pointer containing private nil",
   694  			&privateSomewhereNilStruct,
   695  			true,
   696  		},
   697  	}
   698  
   699  	for _, testCase := range testCases {
   700  		testCase := testCase
   701  		t.Run(testCase.Description, func(t *testing.T) {
   702  			defer func() {
   703  				if r := recover(); r != nil {
   704  					t.Errorf("panic: %v", r)
   705  				}
   706  			}()
   707  
   708  			t.Parallel()
   709  			require.Equal(t, testCase.Expected, checkNowhereNil(t, "value", testCase.Value))
   710  		})
   711  	}
   712  }
   713  
   714  // checkNowhereNil checks that the given interface value is not nil, and if a struct, that all of
   715  // its public fields are also nowhere nil
   716  func checkNowhereNil(t *testing.T, name string, value interface{}) bool {
   717  	if value == nil {
   718  		return false
   719  	}
   720  
   721  	v := reflect.ValueOf(value)
   722  	switch v.Type().Kind() {
   723  	case reflect.Ptr:
   724  		if v.IsNil() {
   725  			t.Logf("%s was nil", name)
   726  			return false
   727  		}
   728  
   729  		return checkNowhereNil(t, fmt.Sprintf("(*%s)", name), v.Elem().Interface())
   730  
   731  	case reflect.Map:
   732  		if v.IsNil() {
   733  			t.Logf("%s was nil", name)
   734  			return false
   735  		}
   736  
   737  		// Don't check map values
   738  		return true
   739  
   740  	case reflect.Struct:
   741  		nowhereNil := true
   742  		for i := 0; i < v.NumField(); i++ {
   743  			f := v.Field(i)
   744  			// Ignore unexported fields
   745  			if v.Type().Field(i).PkgPath != "" {
   746  				continue
   747  			}
   748  
   749  			nowhereNil = nowhereNil && checkNowhereNil(t, fmt.Sprintf("%s.%s", name, v.Type().Field(i).Name), f.Interface())
   750  		}
   751  
   752  		return nowhereNil
   753  
   754  	case reflect.Array:
   755  		fallthrough
   756  	case reflect.Chan:
   757  		fallthrough
   758  	case reflect.Func:
   759  		fallthrough
   760  	case reflect.Interface:
   761  		fallthrough
   762  	case reflect.UnsafePointer:
   763  		t.Logf("unhandled field %s, type: %s", name, v.Type().Kind())
   764  		return false
   765  
   766  	default:
   767  		return true
   768  	}
   769  }