code.gitea.io/gitea@v1.21.7/models/repo/repo_list_test.go (about)

     1  // Copyright 2017 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package repo_test
     5  
     6  import (
     7  	"strings"
     8  	"testing"
     9  
    10  	"code.gitea.io/gitea/models/db"
    11  	repo_model "code.gitea.io/gitea/models/repo"
    12  	"code.gitea.io/gitea/models/unittest"
    13  	"code.gitea.io/gitea/modules/util"
    14  
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  func getTestCases() []struct {
    19  	name  string
    20  	opts  *repo_model.SearchRepoOptions
    21  	count int
    22  } {
    23  	testCases := []struct {
    24  		name  string
    25  		opts  *repo_model.SearchRepoOptions
    26  		count int
    27  	}{
    28  		{
    29  			name:  "PublicRepositoriesByName",
    30  			opts:  &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, Collaborate: util.OptionalBoolFalse},
    31  			count: 7,
    32  		},
    33  		{
    34  			name:  "PublicAndPrivateRepositoriesByName",
    35  			opts:  &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, Collaborate: util.OptionalBoolFalse},
    36  			count: 14,
    37  		},
    38  		{
    39  			name:  "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFirstPage",
    40  			opts:  &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
    41  			count: 14,
    42  		},
    43  		{
    44  			name:  "PublicAndPrivateRepositoriesByNameWithPagesizeLimitSecondPage",
    45  			opts:  &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 2, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
    46  			count: 14,
    47  		},
    48  		{
    49  			name:  "PublicAndPrivateRepositoriesByNameWithPagesizeLimitThirdPage",
    50  			opts:  &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
    51  			count: 14,
    52  		},
    53  		{
    54  			name:  "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFourthPage",
    55  			opts:  &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
    56  			count: 14,
    57  		},
    58  		{
    59  			name:  "PublicRepositoriesOfUser",
    60  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Collaborate: util.OptionalBoolFalse},
    61  			count: 2,
    62  		},
    63  		{
    64  			name:  "PublicRepositoriesOfUser2",
    65  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Collaborate: util.OptionalBoolFalse},
    66  			count: 0,
    67  		},
    68  		{
    69  			name:  "PublicRepositoriesOfOrg3",
    70  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Collaborate: util.OptionalBoolFalse},
    71  			count: 2,
    72  		},
    73  		{
    74  			name:  "PublicAndPrivateRepositoriesOfUser",
    75  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, Collaborate: util.OptionalBoolFalse},
    76  			count: 4,
    77  		},
    78  		{
    79  			name:  "PublicAndPrivateRepositoriesOfUser2",
    80  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, Collaborate: util.OptionalBoolFalse},
    81  			count: 0,
    82  		},
    83  		{
    84  			name:  "PublicAndPrivateRepositoriesOfOrg3",
    85  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true, Collaborate: util.OptionalBoolFalse},
    86  			count: 4,
    87  		},
    88  		{
    89  			name:  "PublicRepositoriesOfUserIncludingCollaborative",
    90  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15},
    91  			count: 5,
    92  		},
    93  		{
    94  			name:  "PublicRepositoriesOfUser2IncludingCollaborative",
    95  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18},
    96  			count: 1,
    97  		},
    98  		{
    99  			name:  "PublicRepositoriesOfOrg3IncludingCollaborative",
   100  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20},
   101  			count: 3,
   102  		},
   103  		{
   104  			name:  "PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
   105  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true},
   106  			count: 9,
   107  		},
   108  		{
   109  			name:  "PublicAndPrivateRepositoriesOfUser2IncludingCollaborative",
   110  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true},
   111  			count: 4,
   112  		},
   113  		{
   114  			name:  "PublicAndPrivateRepositoriesOfOrg3IncludingCollaborative",
   115  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true},
   116  			count: 7,
   117  		},
   118  		{
   119  			name:  "PublicRepositoriesOfOrganization",
   120  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Collaborate: util.OptionalBoolFalse},
   121  			count: 1,
   122  		},
   123  		{
   124  			name:  "PublicAndPrivateRepositoriesOfOrganization",
   125  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Private: true, Collaborate: util.OptionalBoolFalse},
   126  			count: 2,
   127  		},
   128  		{
   129  			name:  "AllPublic/PublicRepositoriesByName",
   130  			opts:  &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, AllPublic: true, Collaborate: util.OptionalBoolFalse},
   131  			count: 7,
   132  		},
   133  		{
   134  			name:  "AllPublic/PublicAndPrivateRepositoriesByName",
   135  			opts:  &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, AllPublic: true, Collaborate: util.OptionalBoolFalse},
   136  			count: 14,
   137  		},
   138  		{
   139  			name:  "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
   140  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse},
   141  			count: 31,
   142  		},
   143  		{
   144  			name:  "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
   145  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse},
   146  			count: 36,
   147  		},
   148  		{
   149  			name:  "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
   150  			opts:  &repo_model.SearchRepoOptions{Keyword: "test", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true},
   151  			count: 15,
   152  		},
   153  		{
   154  			name:  "AllPublic/PublicAndPrivateRepositoriesOfUser2IncludingCollaborativeByName",
   155  			opts:  &repo_model.SearchRepoOptions{Keyword: "test", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, AllPublic: true},
   156  			count: 13,
   157  		},
   158  		{
   159  			name:  "AllPublic/PublicRepositoriesOfOrganization",
   160  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse},
   161  			count: 31,
   162  		},
   163  		{
   164  			name:  "AllTemplates",
   165  			opts:  &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: util.OptionalBoolTrue},
   166  			count: 2,
   167  		},
   168  		{
   169  			name:  "OwnerSlashRepoSearch",
   170  			opts:  &repo_model.SearchRepoOptions{Keyword: "user/repo2", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0},
   171  			count: 2,
   172  		},
   173  		{
   174  			name:  "OwnerSlashSearch",
   175  			opts:  &repo_model.SearchRepoOptions{Keyword: "user20/", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0},
   176  			count: 4,
   177  		},
   178  	}
   179  
   180  	return testCases
   181  }
   182  
   183  func TestSearchRepository(t *testing.T) {
   184  	assert.NoError(t, unittest.PrepareTestDatabase())
   185  
   186  	// test search public repository on explore page
   187  	repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
   188  		ListOptions: db.ListOptions{
   189  			Page:     1,
   190  			PageSize: 10,
   191  		},
   192  		Keyword:     "repo_12",
   193  		Collaborate: util.OptionalBoolFalse,
   194  	})
   195  
   196  	assert.NoError(t, err)
   197  	if assert.Len(t, repos, 1) {
   198  		assert.Equal(t, "test_repo_12", repos[0].Name)
   199  	}
   200  	assert.Equal(t, int64(1), count)
   201  
   202  	repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
   203  		ListOptions: db.ListOptions{
   204  			Page:     1,
   205  			PageSize: 10,
   206  		},
   207  		Keyword:     "test_repo",
   208  		Collaborate: util.OptionalBoolFalse,
   209  	})
   210  
   211  	assert.NoError(t, err)
   212  	assert.Equal(t, int64(2), count)
   213  	assert.Len(t, repos, 2)
   214  
   215  	// test search private repository on explore page
   216  	repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
   217  		ListOptions: db.ListOptions{
   218  			Page:     1,
   219  			PageSize: 10,
   220  		},
   221  		Keyword:     "repo_13",
   222  		Private:     true,
   223  		Collaborate: util.OptionalBoolFalse,
   224  	})
   225  
   226  	assert.NoError(t, err)
   227  	if assert.Len(t, repos, 1) {
   228  		assert.Equal(t, "test_repo_13", repos[0].Name)
   229  	}
   230  	assert.Equal(t, int64(1), count)
   231  
   232  	repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
   233  		ListOptions: db.ListOptions{
   234  			Page:     1,
   235  			PageSize: 10,
   236  		},
   237  		Keyword:     "test_repo",
   238  		Private:     true,
   239  		Collaborate: util.OptionalBoolFalse,
   240  	})
   241  
   242  	assert.NoError(t, err)
   243  	assert.Equal(t, int64(3), count)
   244  	assert.Len(t, repos, 3)
   245  
   246  	// Test non existing owner
   247  	repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID})
   248  
   249  	assert.NoError(t, err)
   250  	assert.Empty(t, repos)
   251  	assert.Equal(t, int64(0), count)
   252  
   253  	// Test search within description
   254  	repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{
   255  		ListOptions: db.ListOptions{
   256  			Page:     1,
   257  			PageSize: 10,
   258  		},
   259  		Keyword:            "description_14",
   260  		Collaborate:        util.OptionalBoolFalse,
   261  		IncludeDescription: true,
   262  	})
   263  
   264  	assert.NoError(t, err)
   265  	if assert.Len(t, repos, 1) {
   266  		assert.Equal(t, "test_repo_14", repos[0].Name)
   267  	}
   268  	assert.Equal(t, int64(1), count)
   269  
   270  	// Test NOT search within description
   271  	repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{
   272  		ListOptions: db.ListOptions{
   273  			Page:     1,
   274  			PageSize: 10,
   275  		},
   276  		Keyword:            "description_14",
   277  		Collaborate:        util.OptionalBoolFalse,
   278  		IncludeDescription: false,
   279  	})
   280  
   281  	assert.NoError(t, err)
   282  	assert.Empty(t, repos)
   283  	assert.Equal(t, int64(0), count)
   284  
   285  	testCases := getTestCases()
   286  
   287  	for _, testCase := range testCases {
   288  		t.Run(testCase.name, func(t *testing.T) {
   289  			repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, testCase.opts)
   290  
   291  			assert.NoError(t, err)
   292  			assert.Equal(t, int64(testCase.count), count)
   293  
   294  			page := testCase.opts.Page
   295  			if page <= 0 {
   296  				page = 1
   297  			}
   298  			expectedLen := testCase.opts.PageSize
   299  			if testCase.opts.PageSize*page > testCase.count+testCase.opts.PageSize {
   300  				expectedLen = 0
   301  			} else if testCase.opts.PageSize*page > testCase.count {
   302  				expectedLen = testCase.count % testCase.opts.PageSize
   303  			}
   304  			if assert.Len(t, repos, expectedLen) {
   305  				for _, repo := range repos {
   306  					assert.NotEmpty(t, repo.Name)
   307  
   308  					if len(testCase.opts.Keyword) > 0 {
   309  						// Keyword match condition is different for search terms of form "owner/repo"
   310  						if strings.Count(testCase.opts.Keyword, "/") == 1 {
   311  							// May still match as a whole...
   312  							wholeMatch := strings.Contains(repo.Name, testCase.opts.Keyword)
   313  
   314  							pieces := strings.Split(testCase.opts.Keyword, "/")
   315  							ownerName := pieces[0]
   316  							repoName := pieces[1]
   317  							// ... or match in parts
   318  							splitMatch := strings.Contains(repo.OwnerName, ownerName) && strings.Contains(repo.Name, repoName)
   319  
   320  							assert.True(t, wholeMatch || splitMatch, "Keyword '%s' does not match repo '%s/%s'", testCase.opts.Keyword, repo.Owner.Name, repo.Name)
   321  						} else {
   322  							assert.Contains(t, repo.Name, testCase.opts.Keyword)
   323  						}
   324  					}
   325  
   326  					if !testCase.opts.Private {
   327  						assert.False(t, repo.IsPrivate)
   328  					}
   329  
   330  					if testCase.opts.Fork == util.OptionalBoolTrue && testCase.opts.Mirror == util.OptionalBoolTrue {
   331  						assert.True(t, repo.IsFork || repo.IsMirror)
   332  					} else {
   333  						switch testCase.opts.Fork {
   334  						case util.OptionalBoolFalse:
   335  							assert.False(t, repo.IsFork)
   336  						case util.OptionalBoolTrue:
   337  							assert.True(t, repo.IsFork)
   338  						}
   339  
   340  						switch testCase.opts.Mirror {
   341  						case util.OptionalBoolFalse:
   342  							assert.False(t, repo.IsMirror)
   343  						case util.OptionalBoolTrue:
   344  							assert.True(t, repo.IsMirror)
   345  						}
   346  					}
   347  
   348  					if testCase.opts.OwnerID > 0 && !testCase.opts.AllPublic {
   349  						switch testCase.opts.Collaborate {
   350  						case util.OptionalBoolFalse:
   351  							assert.Equal(t, testCase.opts.OwnerID, repo.Owner.ID)
   352  						case util.OptionalBoolTrue:
   353  							assert.NotEqual(t, testCase.opts.OwnerID, repo.Owner.ID)
   354  						}
   355  					}
   356  				}
   357  			}
   358  		})
   359  	}
   360  }
   361  
   362  func TestCountRepository(t *testing.T) {
   363  	assert.NoError(t, unittest.PrepareTestDatabase())
   364  
   365  	testCases := getTestCases()
   366  
   367  	for _, testCase := range testCases {
   368  		t.Run(testCase.name, func(t *testing.T) {
   369  			count, err := repo_model.CountRepository(db.DefaultContext, testCase.opts)
   370  
   371  			assert.NoError(t, err)
   372  			assert.Equal(t, int64(testCase.count), count)
   373  		})
   374  	}
   375  }
   376  
   377  func TestSearchRepositoryByTopicName(t *testing.T) {
   378  	assert.NoError(t, unittest.PrepareTestDatabase())
   379  
   380  	testCases := []struct {
   381  		name  string
   382  		opts  *repo_model.SearchRepoOptions
   383  		count int
   384  	}{
   385  		{
   386  			name:  "AllPublic/SearchPublicRepositoriesFromTopicAndName",
   387  			opts:  &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql"},
   388  			count: 2,
   389  		},
   390  		{
   391  			name:  "AllPublic/OnlySearchPublicRepositoriesFromTopic",
   392  			opts:  &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql", TopicOnly: true},
   393  			count: 1,
   394  		},
   395  		{
   396  			name:  "AllPublic/OnlySearchMultipleKeywordPublicRepositoriesFromTopic",
   397  			opts:  &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql,golang", TopicOnly: true},
   398  			count: 2,
   399  		},
   400  	}
   401  
   402  	for _, testCase := range testCases {
   403  		t.Run(testCase.name, func(t *testing.T) {
   404  			_, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, testCase.opts)
   405  			assert.NoError(t, err)
   406  			assert.Equal(t, int64(testCase.count), count)
   407  		})
   408  	}
   409  }