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 }