diff --git a/NGitLab.Mock.Tests/TagTests.cs b/NGitLab.Mock.Tests/TagTests.cs index 0b9cdc94..90dae75c 100644 --- a/NGitLab.Mock.Tests/TagTests.cs +++ b/NGitLab.Mock.Tests/TagTests.cs @@ -17,7 +17,7 @@ public async Task GetTagAsync() .WithUser("user1", isDefault: true) .WithProject("test-project", id: 1, addDefaultUserAsMaintainer: true, configure: project => project .WithCommit("Initial commit") - .WithCommit("Changes with tag", tags: new[] { "1.0.0" })) + .WithCommit("Changes with tag", tags: ["1.0.0"])) .BuildServer(); var client = server.CreateClient(); @@ -32,7 +32,7 @@ public async Task GetTagAsync() } [Theory] - public void GetTaskAsync_CanSortByName([Values] bool useDefault) + public void GetTagsAsync_CanSortByName([Values] bool useDefault) { // Arrange using var server = new GitLabConfig() @@ -61,7 +61,7 @@ public void GetTaskAsync_CanSortByName([Values] bool useDefault) } [Test] - public void GetTagAsync_CanSortByVersion() + public void GetTagsAsync_CanSortByVersion() { // Arrange using var server = new GitLabConfig() @@ -88,4 +88,49 @@ public void GetTagAsync_CanSortByVersion() // Assert Assert.That(tags.AsEnumerable().Select(t => t.Name), Is.EqualTo(["not-semver", "0.0.1", "0.0.2", "0.0.10"])); } + + [Test] + public async Task SearchTags() + { + // Arrange + using var server = new GitLabConfig() + .WithUser("user1", isDefault: true) + .WithProject("test-project", id: 1, addDefaultUserAsMaintainer: true, configure: project => project + .WithCommit("First Tag", tags: ["v0.5"]) + .WithCommit("Second Tag", tags: ["v0.6"])) + .BuildServer(); + + var client = server.CreateClient(); + var tagClient = client.GetRepository(1).Tags; + + (string, int)[] testCases = + [ + // You can use "^term" and "term$" to find tags that begin and end with "term". No other regular expressions are supported. + // The search expression is case-insensitive. + // https://docs.gitlab.com/api/tags/#list-all-project-repository-tags + ("^v0.5", 1), + ("^v0", 2), + ("^v", 2), + ("^V", 2), + ("^v1", 0), + ("0.5", 1), + ("0", 2), + ("6", 1), + ("V", 2), + ("0.5$", 1), + (".5$", 1), + ("\\.5$", 0), + (".[0-9]$", 0), + ("0\\.", 0), + ]; + + foreach (var (searchExpression, expectedCount) in testCases) + { + // Act + var tags = tagClient.GetAsync(new TagQuery { Search = searchExpression }); + + // Assert + Assert.That(tags.Count(), Is.EqualTo(expectedCount), $"Expected search expression '{searchExpression}' to return {expectedCount} results."); + } + } } diff --git a/NGitLab.Mock/Clients/TagClient.cs b/NGitLab.Mock/Clients/TagClient.cs index 22cbf466..172399c4 100644 --- a/NGitLab.Mock/Clients/TagClient.cs +++ b/NGitLab.Mock/Clients/TagClient.cs @@ -86,16 +86,30 @@ public Tag ToTagClient(LibGit2Sharp.Tag tag) using (Context.BeginOperationScope()) { IEnumerable result = GetProject(_projectId, ProjectPermission.View).Repository.GetTags(); - if (query != null) + if (query is not null) { - result = ApplyQuery(result, query.OrderBy, query.Sort); + result = ApplyQuery(result, query); } return GitLabCollectionResponse.Create(result.Select(ToTagClient).ToArray()); } - static IEnumerable ApplyQuery(IEnumerable tags, string orderBy, string direction) + static IEnumerable ApplyQuery(IEnumerable tags, TagQuery query) { + // First, filter by search term if provided + if (!string.IsNullOrEmpty(query.Search)) + { + tags = query.Search switch + { + string search when search.StartsWith("^", StringComparison.Ordinal) => + tags.Where(t => t.FriendlyName.StartsWith(search[1..], StringComparison.OrdinalIgnoreCase)), + string search when search.EndsWith("$", StringComparison.Ordinal) => + tags.Where(t => t.FriendlyName.EndsWith(search[..^1], StringComparison.OrdinalIgnoreCase)), + _ => tags.Where(t => t.FriendlyName.Contains(query.Search, StringComparison.OrdinalIgnoreCase)), + }; + } + + var orderBy = query.OrderBy?.ToLowerInvariant(); tags = orderBy switch { "name" => tags.OrderBy(t => t.FriendlyName, StringComparer.Ordinal), @@ -103,10 +117,11 @@ public Tag ToTagClient(LibGit2Sharp.Tag tag) null => tags, // LibGitSharp does not really expose tag creation time, so hard to sort using that annotation, - "updated" => throw new NotSupportedException("Sorting by 'updated' is not supported since the info is not available in LibGit2Sharp."), + "updated" => throw new NotSupportedException("Sorting by 'updated' is not supported by mock, since the info is not available in LibGit2Sharp."), _ => throw new NotSupportedException($"Sorting by '{orderBy}' is not supported."), }; + var direction = query.Sort; if (string.IsNullOrEmpty(direction)) direction = "desc"; diff --git a/NGitLab.Tests/TagTests.cs b/NGitLab.Tests/TagTests.cs index cc12c450..a66d49da 100644 --- a/NGitLab.Tests/TagTests.cs +++ b/NGitLab.Tests/TagTests.cs @@ -34,16 +34,8 @@ public async Task Test_can_tag_a_project() } [NGitLabRetry] - [TestCase("^v0.5", 1)] - [TestCase("^v0", 2)] - [TestCase("^v1", 0)] - [TestCase("v1", 0)] - [TestCase("0.5$", 1)] - [TestCase("0\\.", 0)] - [TestCase(".5$", 1)] - [TestCase("\\.5$", 0)] - [TestCase(".[0-9]$", 0)] - public async Task SearchTags(string search, int expectedCount) + [Test] + public async Task SearchTags() { // Arrange using var context = await GitLabTestContext.CreateAsync(); @@ -64,8 +56,35 @@ public async Task SearchTags(string search, int expectedCount) Ref = project.DefaultBranch, }); - var tagFetched = tagClient.GetAsync(new TagQuery { Search = search }); - Assert.That(tagFetched.Count(), Is.EqualTo(expectedCount)); + (string, int)[] testCases = + [ + // You can use "^term" and "term$" to find tags that begin and end with "term". No other regular expressions are supported. + // The search expression is case-insensitive. + // https://docs.gitlab.com/api/tags/#list-all-project-repository-tags + ("^v0.5", 1), + ("^v0", 2), + ("^v", 2), + ("^V", 2), + ("^v1", 0), + ("0.5", 1), + ("0", 2), + ("6", 1), + ("V", 2), + ("0.5$", 1), + (".5$", 1), + ("\\.5$", 0), + (".[0-9]$", 0), + ("0\\.", 0), + ]; + + foreach (var (searchExpression, expectedCount) in testCases) + { + // Act + var tags = tagClient.GetAsync(new TagQuery { Search = searchExpression }); + + // Assert + Assert.That(tags.Count(), Is.EqualTo(expectedCount), $"Expected search expression '{searchExpression}' to return {expectedCount} results."); + } } [NGitLabRetry]