From c0d6e21dac675eb131eb15f5e581cdf5c2464592 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sun, 1 May 2011 15:37:42 +0200 Subject: [PATCH 01/13] Reorder repository tests --- LibGit2Sharp.Tests/RepositoryFixture.cs | 154 ++++++++++++------------ 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/LibGit2Sharp.Tests/RepositoryFixture.cs b/LibGit2Sharp.Tests/RepositoryFixture.cs index 59efd7c92..5a56c46e4 100644 --- a/LibGit2Sharp.Tests/RepositoryFixture.cs +++ b/LibGit2Sharp.Tests/RepositoryFixture.cs @@ -13,24 +13,6 @@ public class RepositoryFixture private const string commitSha = "8496071c1b46c854b31185ea97743be6a8774479"; private const string notFoundSha = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; - [Test] - public void CallingExistsWithEmptyThrows() - { - using (var repo = new Repository(Constants.TestRepoPath)) - { - Assert.Throws(() => repo.HasObject(string.Empty)); - } - } - - [Test] - public void CallingExistsWithNullThrows() - { - using (var repo = new Repository(Constants.TestRepoPath)) - { - Assert.Throws(() => repo.HasObject(null)); - } - } - [Test] public void CanCreateBareRepo() { @@ -69,6 +51,18 @@ public void CanCreateStandardRepo() } } + [Test] + public void CreateRepoWithEmptyStringThrows() + { + Assert.Throws(() => Repository.Init(string.Empty)); + } + + [Test] + public void CreateRepoWithNullThrows() + { + Assert.Throws(() => Repository.Init(null)); + } + [Test] public void CanLookupACommitByTheNameOfABranch() { @@ -135,128 +129,134 @@ public void CanOpenRepoWithFullPath() } [Test] - [Platform(Exclude = "Linux,Unix", Reason = "No need to test windows path separators on non-windows platforms")] - // See http://www.nunit.org/index.php?p=platform&r=2.6 for other platforms that can be excluded/included. - public void CanOpenRepoWithWindowsPathSeparators() + public void LookupObjectByWrongShaReturnsNull() { - using (new Repository(@".\Resources\testrepo.git")) + using (var repo = new Repository(Constants.TestRepoPath)) { + repo.Lookup(notFoundSha).ShouldBeNull(); + repo.Lookup(notFoundSha).ShouldBeNull(); } } [Test] - public void CanOpenRepository() + public void LookupObjectByWrongTypeReturnsNull() { using (var repo = new Repository(Constants.TestRepoPath)) { - repo.Info.Path.ShouldNotBeNull(); - repo.Info.WorkingDirectory.ShouldBeNull(); - repo.Info.IsBare.ShouldBeTrue(); - repo.Info.IsEmpty.ShouldBeFalse(); - repo.Info.IsHeadDetached.ShouldBeFalse(); + repo.Lookup(commitSha).ShouldNotBeNull(); + repo.Lookup(commitSha).ShouldNotBeNull(); + repo.Lookup(commitSha).ShouldBeNull(); } } [Test] - public void CanTellIfObjectsExistInRepository() + public void LookupWithEmptyStringThrows() { using (var repo = new Repository(Constants.TestRepoPath)) { - repo.HasObject("8496071c1b46c854b31185ea97743be6a8774479").ShouldBeTrue(); - repo.HasObject("1385f264afb75a56a5bec74243be9b367ba4ca08").ShouldBeTrue(); - repo.HasObject("ce08fe4884650f067bd5703b6a59a8b3b3c99a09").ShouldBeFalse(); - repo.HasObject("8496071c1c46c854b31185ea97743be6a8774479").ShouldBeFalse(); + Assert.Throws(() => repo.Lookup(string.Empty)); + Assert.Throws(() => repo.Lookup(string.Empty)); } } [Test] - public void CheckForDetachedHeadOnNewRepo() + public void LookupWithNullThrows() { - using (new SelfCleaningDirectory(newRepoPath)) + using (var repo = new Repository(Constants.TestRepoPath)) { - var dir = Repository.Init(newRepoPath, true); - Path.IsPathRooted(dir).ShouldBeTrue(); - Directory.Exists(dir).ShouldBeTrue(); + Assert.Throws(() => repo.Lookup((string)null)); + Assert.Throws(() => repo.Lookup((ObjectId)null)); + Assert.Throws(() => repo.Lookup((string)null)); + Assert.Throws(() => repo.Lookup((ObjectId)null)); + } + } - using (var repo = new Repository(dir)) - { - repo.Info.IsEmpty.ShouldBeTrue(); - repo.Info.IsHeadDetached.ShouldBeFalse(); - } + [Test] + [Platform(Exclude = "Linux,Unix", Reason = "No need to test windows path separators on non-windows platforms")] + // See http://www.nunit.org/index.php?p=platform&r=2.6 for other platforms that can be excluded/included. + public void CanOpenRepoWithWindowsPathSeparators() + { + using (new Repository(@".\Resources\testrepo.git")) + { } } [Test] - public void CreateRepoWithEmptyStringThrows() + public void CanOpenRepository() { - Assert.Throws(() => Repository.Init(string.Empty)); + using (var repo = new Repository(Constants.TestRepoPath)) + { + repo.Info.Path.ShouldNotBeNull(); + repo.Info.WorkingDirectory.ShouldBeNull(); + repo.Info.IsBare.ShouldBeTrue(); + repo.Info.IsEmpty.ShouldBeFalse(); + repo.Info.IsHeadDetached.ShouldBeFalse(); + } } [Test] - public void CreateRepoWithNullThrows() + public void OpenNonExistentRepoThrows() { - Assert.Throws(() => Repository.Init(null)); + Assert.Throws(() => { new Repository("a_bad_path"); }); } [Test] - public void LookupObjectByWrongShaReturnsNull() + public void OpeningRepositoryWithEmptyPathThrows() { - using (var repo = new Repository(Constants.TestRepoPath)) - { - repo.Lookup(notFoundSha).ShouldBeNull(); - repo.Lookup(notFoundSha).ShouldBeNull(); - } + Assert.Throws(() => new Repository(string.Empty)); } [Test] - public void LookupObjectByWrongTypeReturnsNull() + public void OpeningRepositoryWithNullPathThrows() { - using (var repo = new Repository(Constants.TestRepoPath)) - { - repo.Lookup(commitSha).ShouldNotBeNull(); - repo.Lookup(commitSha).ShouldNotBeNull(); - repo.Lookup(commitSha).ShouldBeNull(); - } + Assert.Throws(() => new Repository(null)); } [Test] - public void LookupWithEmptyStringThrows() + public void CanTellIfObjectsExistInRepository() { using (var repo = new Repository(Constants.TestRepoPath)) { - Assert.Throws(() => repo.Lookup(string.Empty)); - Assert.Throws(() => repo.Lookup(string.Empty)); + repo.HasObject("8496071c1b46c854b31185ea97743be6a8774479").ShouldBeTrue(); + repo.HasObject("1385f264afb75a56a5bec74243be9b367ba4ca08").ShouldBeTrue(); + repo.HasObject("ce08fe4884650f067bd5703b6a59a8b3b3c99a09").ShouldBeFalse(); + repo.HasObject("8496071c1c46c854b31185ea97743be6a8774479").ShouldBeFalse(); } } [Test] - public void LookupWithNullThrows() + public void CallingExistsWithEmptyThrows() { using (var repo = new Repository(Constants.TestRepoPath)) { - Assert.Throws(() => repo.Lookup((string) null)); - Assert.Throws(() => repo.Lookup(null)); - Assert.Throws(() => repo.Lookup((string) null)); - Assert.Throws(() => repo.Lookup((ObjectId) null)); + Assert.Throws(() => repo.HasObject(string.Empty)); } } [Test] - public void OpenNonExistentRepoThrows() + public void CallingExistsWithNullThrows() { - Assert.Throws(() => { new Repository("a_bad_path"); }); + using (var repo = new Repository(Constants.TestRepoPath)) + { + Assert.Throws(() => repo.HasObject(null)); + } } [Test] - public void OpeningRepositoryWithEmptyPathThrows() + public void CheckForDetachedHeadOnNewRepo() { - Assert.Throws(() => new Repository(string.Empty)); - } + using (new SelfCleaningDirectory(newRepoPath)) + { + var dir = Repository.Init(newRepoPath, true); + Path.IsPathRooted(dir).ShouldBeTrue(); + Directory.Exists(dir).ShouldBeTrue(); - [Test] - public void OpeningRepositoryWithNullPathThrows() - { - Assert.Throws(() => new Repository(null)); + using (var repo = new Repository(dir)) + { + repo.Info.IsEmpty.ShouldBeTrue(); + repo.Info.IsHeadDetached.ShouldBeFalse(); + } + } } } } \ No newline at end of file From 03512839a9e58fd92494507e900064d0fbf7ef19 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sun, 1 May 2011 15:38:47 +0200 Subject: [PATCH 02/13] Push down an overload from Repository extension methods to main API --- LibGit2Sharp/Repository.cs | 22 ++++++++++++++++++-- LibGit2Sharp/RepositoryExtensions.cs | 30 ++++------------------------ 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index a265b41bb..7d3c918f3 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -178,8 +178,8 @@ public static string Init(string path, bool bare = false) /// Try to lookup an object by its and . If no matching object is found, null will be returned. /// /// The id to lookup. - /// - /// the or null if it was not found. + /// The kind of GitObject being looked up + /// The or null if it was not found. public GitObject Lookup(ObjectId id, GitObjectType type = GitObjectType.Any) { Ensure.ArgumentNotNull(id, "id"); @@ -196,5 +196,23 @@ public GitObject Lookup(ObjectId id, GitObjectType type = GitObjectType.Any) return GitObject.CreateFromPtr(obj, id, this); } + + /// + /// Try to lookup an object by its sha or a reference name and . If no matching object is found, null will be returned. + /// + /// The shaOrRef to lookup. + /// The kind of GitObject being looked up + /// The or null if it was not found. + public GitObject Lookup(string shaOrRef, GitObjectType type = GitObjectType.Any) + { + ObjectId id = ObjectId.CreateFromMaybeSha(shaOrRef); + if (id != null) + { + return Lookup(id, type); + } + + var reference = Refs[shaOrRef]; + return Lookup(reference.ResolveToDirectReference().Target.Id, type); + } } } \ No newline at end of file diff --git a/LibGit2Sharp/RepositoryExtensions.cs b/LibGit2Sharp/RepositoryExtensions.cs index b4a416552..1e8df9e8d 100644 --- a/LibGit2Sharp/RepositoryExtensions.cs +++ b/LibGit2Sharp/RepositoryExtensions.cs @@ -1,7 +1,8 @@ -using LibGit2Sharp.Core; - -namespace LibGit2Sharp +namespace LibGit2Sharp { + /// + /// Provides helper overloads to a . + /// public static class RepositoryExtensions { /// @@ -27,28 +28,5 @@ public static T Lookup(this Repository repository, ObjectId id) where T : Git { return (T)repository.Lookup(id, GitObject.TypeToTypeMap[typeof(T)]); } - - /// - /// Try to lookup an object by its sha or a reference name and . If no matching object is found, null will be returned. - /// - /// Exceptions: - /// ArgumentNullException - /// - /// The being looked up. - /// The shaOrRef to lookup. - /// - /// the or null if it was not found. - public static GitObject Lookup(this Repository repository, string shaOrRef, GitObjectType type = GitObjectType.Any) - { - ObjectId id = ObjectId.CreateFromMaybeSha(shaOrRef); - if (id != null) - { - return repository.Lookup(id, type); - } - - var reference = repository.Refs[shaOrRef]; - return repository.Lookup(reference.ResolveToDirectReference().Target.Id, type); - } - } } \ No newline at end of file From a2f93dd403d0b4f6e0ea17530ea43bb9ba060639 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sun, 1 May 2011 15:46:36 +0200 Subject: [PATCH 03/13] Fix the implementation of Repository.Lookup() when being passed a non existing reference --- LibGit2Sharp.Tests/RepositoryFixture.cs | 10 ++++++++++ LibGit2Sharp/Repository.cs | 18 ++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/LibGit2Sharp.Tests/RepositoryFixture.cs b/LibGit2Sharp.Tests/RepositoryFixture.cs index 5a56c46e4..9183778f3 100644 --- a/LibGit2Sharp.Tests/RepositoryFixture.cs +++ b/LibGit2Sharp.Tests/RepositoryFixture.cs @@ -149,6 +149,16 @@ public void LookupObjectByWrongTypeReturnsNull() } } + [Test] + public void LookupObjectByUnknownReferenceNameReturnsNull() + { + using (var repo = new Repository(Constants.TestRepoPath)) + { + repo.Lookup("refs/heads/chopped/off").ShouldBeNull(); + repo.Lookup(notFoundSha).ShouldBeNull(); + } + } + [Test] public void LookupWithEmptyStringThrows() { diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 7d3c918f3..b326f23f7 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -198,20 +198,26 @@ public GitObject Lookup(ObjectId id, GitObjectType type = GitObjectType.Any) } /// - /// Try to lookup an object by its sha or a reference name and . If no matching object is found, null will be returned. + /// Try to lookup an object by its sha or a reference canonical name and . If no matching object is found, null will be returned. /// - /// The shaOrRef to lookup. - /// The kind of GitObject being looked up + /// The sha or reference canonical name to lookup. + /// The kind of being looked up /// The or null if it was not found. - public GitObject Lookup(string shaOrRef, GitObjectType type = GitObjectType.Any) + public GitObject Lookup(string shaOrReferenceName, GitObjectType type = GitObjectType.Any) { - ObjectId id = ObjectId.CreateFromMaybeSha(shaOrRef); + ObjectId id = ObjectId.CreateFromMaybeSha(shaOrReferenceName); if (id != null) { return Lookup(id, type); } - var reference = Refs[shaOrRef]; + var reference = Refs[shaOrReferenceName]; + + if (reference == null) + { + return null; + } + return Lookup(reference.ResolveToDirectReference().Target.Id, type); } } From d2116674f334ab5a6b707daa941c708e16194b6a Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sun, 1 May 2011 21:55:36 +0200 Subject: [PATCH 04/13] Port some tests from cgit and fix implementation to make them pass --- LibGit2Sharp.Tests/TagFixture.cs | 33 ++++++++++++++++++++++++++++ LibGit2Sharp/Reference.cs | 5 +++++ LibGit2Sharp/ReferenceCollection.cs | 5 ----- LibGit2Sharp/Repository.cs | 7 +++++- LibGit2Sharp/RepositoryExtensions.cs | 10 +++++++++ 5 files changed, 54 insertions(+), 6 deletions(-) diff --git a/LibGit2Sharp.Tests/TagFixture.cs b/LibGit2Sharp.Tests/TagFixture.cs index 9a23d6b2e..efacbb337 100644 --- a/LibGit2Sharp.Tests/TagFixture.cs +++ b/LibGit2Sharp.Tests/TagFixture.cs @@ -10,6 +10,8 @@ namespace LibGit2Sharp.Tests [TestFixture] public class TagFixture { + private const string newRepoPath = "new_repo"; + private readonly List expectedTags = new List {"test", "e90810b", "lw"}; private static readonly Signature signatureTim = new Signature("Tim Clem", "timothy.clem@gmail.com", DateTimeOffset.UtcNow); @@ -126,6 +128,21 @@ public void CreatingAnAnnotatedTagIsDeterministic() } } + [Test] + [Description("Ported from cgit (https://github.com/git/git/blob/master/t/t7004-tag.sh)")] + public void CreatingATagInAEmptyRepositoryThrows() + { + using (new SelfCleaningDirectory(newRepoPath)) + { + var dir = Repository.Init(newRepoPath); + + using (var repo = new Repository(dir)) + { + Assert.Throws(() => repo.ApplyTag("mynotag")); + } + } + } + [Test] public void BlindlyCreatingALightweightTagOverAnExistingOneThrows() { @@ -296,6 +313,22 @@ public void CanListTags() } } + [Test] + [Description("Ported from cgit (https://github.com/git/git/blob/master/t/t7004-tag.sh)")] + public void CanListAllTagsInAEmptyRepository() + { + using (new SelfCleaningDirectory(newRepoPath)) + { + var dir = Repository.Init(newRepoPath); + + using (var repo = new Repository(dir)) + { + repo.Info.IsEmpty.ShouldBeTrue(); + repo.Tags.Count().ShouldEqual(0); + } + } + } + [Test] public void CanLookupALightweightTag() { diff --git a/LibGit2Sharp/Reference.cs b/LibGit2Sharp/Reference.cs index 7ba3f0443..cabeca1de 100644 --- a/LibGit2Sharp/Reference.cs +++ b/LibGit2Sharp/Reference.cs @@ -19,6 +19,11 @@ public abstract class Reference : IEquatable internal static T BuildFromPtr(IntPtr ptr, Repository repo) where T : class { + if (ptr == IntPtr.Zero) + { + return default(T); + } + var name = NativeMethods.git_reference_name(ptr); var type = NativeMethods.git_reference_type(ptr); diff --git a/LibGit2Sharp/ReferenceCollection.cs b/LibGit2Sharp/ReferenceCollection.cs index 82f51b73c..a7a43e213 100644 --- a/LibGit2Sharp/ReferenceCollection.cs +++ b/LibGit2Sharp/ReferenceCollection.cs @@ -158,11 +158,6 @@ internal T Resolve(string name) where T : class IntPtr reference = RetrieveReferencePtr(name, false); - if (reference == IntPtr.Zero) - { - return default(T); - } - return Reference.BuildFromPtr(reference, repo); } diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index b326f23f7..9e9f49a52 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -213,12 +213,17 @@ public GitObject Lookup(string shaOrReferenceName, GitObjectType type = GitObjec var reference = Refs[shaOrReferenceName]; - if (reference == null) + if (!IsReferencePeelable(reference)) { return null; } return Lookup(reference.ResolveToDirectReference().Target.Id, type); } + + private static bool IsReferencePeelable(Reference reference) + { + return reference != null && ((reference is DirectReference) ||(reference is SymbolicReference && ((SymbolicReference)reference).Target != null)); + } } } \ No newline at end of file diff --git a/LibGit2Sharp/RepositoryExtensions.cs b/LibGit2Sharp/RepositoryExtensions.cs index 1e8df9e8d..6669bf5ff 100644 --- a/LibGit2Sharp/RepositoryExtensions.cs +++ b/LibGit2Sharp/RepositoryExtensions.cs @@ -28,5 +28,15 @@ public static T Lookup(this Repository repository, ObjectId id) where T : Git { return (T)repository.Lookup(id, GitObject.TypeToTypeMap[typeof(T)]); } + + /// + /// Creates a lightweight tag with the specified name. This tag will point at the commit pointed at by the . + /// + /// The being looked up. + /// The name of the tag to create. + public static Tag ApplyTag(this Repository repository, string tagName) + { + return repository.Tags.Create(tagName, repository.Head.CanonicalName); + } } } \ No newline at end of file From 8035f4aac35832eb2af6b595abe81600b8c3e9b2 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Mon, 2 May 2011 20:19:20 +0200 Subject: [PATCH 05/13] Allow a reference to hold a null target --- LibGit2Sharp.Tests/ReferenceFixture.cs | 2 ++ LibGit2Sharp.Tests/RepositoryFixture.cs | 17 +++++++++++++---- LibGit2Sharp/Reference.cs | 24 ++++++++++++++++++------ LibGit2Sharp/SymbolicReference.cs | 2 +- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/LibGit2Sharp.Tests/ReferenceFixture.cs b/LibGit2Sharp.Tests/ReferenceFixture.cs index f93696de7..710d1ec26 100644 --- a/LibGit2Sharp.Tests/ReferenceFixture.cs +++ b/LibGit2Sharp.Tests/ReferenceFixture.cs @@ -24,6 +24,7 @@ public void CanCreateADirectReference() newRef.CanonicalName.ShouldEqual(name); newRef.Target.ShouldNotBeNull(); newRef.Target.Sha.ShouldEqual("be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + newRef.TargetIdentifier.ShouldEqual(newRef.Target.Sha); repo.Refs[name].ShouldNotBeNull(); } } @@ -41,6 +42,7 @@ public void CanCreateASymbolicReference() newRef.ShouldNotBeNull(); newRef.CanonicalName.ShouldEqual(name); newRef.Target.CanonicalName.ShouldEqual(target); + newRef.TargetIdentifier.ShouldEqual(newRef.Target.CanonicalName); newRef.ResolveToDirectReference().Target.Sha.ShouldEqual("4c062a6361ae6959e06292c1fa5e2822d9c96345"); repo.Refs[name].ShouldNotBeNull(); } diff --git a/LibGit2Sharp.Tests/RepositoryFixture.cs b/LibGit2Sharp.Tests/RepositoryFixture.cs index 9183778f3..ade31bb4b 100644 --- a/LibGit2Sharp.Tests/RepositoryFixture.cs +++ b/LibGit2Sharp.Tests/RepositoryFixture.cs @@ -24,10 +24,10 @@ public void CanCreateBareRepo() using (var repo = new Repository(dir)) { - repo.Info.Path.ShouldNotBeNull(); repo.Info.WorkingDirectory.ShouldBeNull(); repo.Info.IsBare.ShouldBeTrue(); - repo.Info.IsEmpty.ShouldBeTrue(); + + AssertInitializedRepository(repo); } } } @@ -43,14 +43,23 @@ public void CanCreateStandardRepo() using (var repo = new Repository(dir)) { - repo.Info.Path.ShouldNotBeNull(); repo.Info.WorkingDirectory.ShouldNotBeNull(); repo.Info.IsBare.ShouldBeFalse(); - repo.Info.IsEmpty.ShouldBeTrue(); + + AssertInitializedRepository(repo); } } } + private static void AssertInitializedRepository(Repository repo) + { + repo.Info.Path.ShouldNotBeNull(); + repo.Info.IsEmpty.ShouldBeTrue(); + repo.Info.IsHeadDetached.ShouldBeFalse(); + repo.Head.TargetIdentifier.ShouldEqual("refs/heads/master"); + repo.Head.ResolveToDirectReference().ShouldBeNull(); + } + [Test] public void CreateRepoWithEmptyStringThrows() { diff --git a/LibGit2Sharp/Reference.cs b/LibGit2Sharp/Reference.cs index cabeca1de..f31d1a59d 100644 --- a/LibGit2Sharp/Reference.cs +++ b/LibGit2Sharp/Reference.cs @@ -33,16 +33,19 @@ internal static T BuildFromPtr(IntPtr ptr, Repository repo) where T : class { case GitReferenceType.Symbolic: IntPtr resolveRef; + var targetName = NativeMethods.git_reference_target(ptr); NativeMethods.git_reference_resolve(out resolveRef, ptr); var targetRef = BuildFromPtr(resolveRef, repo); - reference = new SymbolicReference { CanonicalName = name, Target = targetRef }; + reference = new SymbolicReference { CanonicalName = name, Target = targetRef, TargetIdentifier = targetName}; break; case GitReferenceType.Oid: var oidPtr = NativeMethods.git_reference_oid(ptr); var oid = (GitOid)Marshal.PtrToStructure(oidPtr, typeof(GitOid)); - var target = repo.Lookup(new ObjectId(oid)); - reference = new DirectReference { CanonicalName = name, Target = target }; + var targetId = new ObjectId(oid); + + var target = repo.Lookup(targetId); + reference = new DirectReference { CanonicalName = name, Target = target, TargetIdentifier = targetId.Sha}; break; default: @@ -72,13 +75,22 @@ internal static T BuildFromPtr(IntPtr ptr, Repository repo) where T : class Enum.GetName(typeof (GitReferenceType), type))); } + protected abstract object ProvideAdditionalEqualityComponent(); + /// /// Recursively peels the target of the reference until a direct reference is encountered. /// /// The this points to. - public abstract DirectReference ResolveToDirectReference(); - - protected abstract object ProvideAdditionalEqualityComponent(); + public abstract DirectReference ResolveToDirectReference(); + + /// + /// Gets the target declared by the reference. + /// + /// If this reference is a , returns the canonical name of the target. + /// Otherwise, if this reference is a , returns the sha of the target. + /// + /// + public string TargetIdentifier { get; private set; } //TODO: Maybe find a better name for this property. /// /// Determines whether the specified is equal to the current . diff --git a/LibGit2Sharp/SymbolicReference.cs b/LibGit2Sharp/SymbolicReference.cs index 29307ec35..0ddc5be67 100644 --- a/LibGit2Sharp/SymbolicReference.cs +++ b/LibGit2Sharp/SymbolicReference.cs @@ -21,7 +21,7 @@ protected override object ProvideAdditionalEqualityComponent() /// The this points to. public override DirectReference ResolveToDirectReference() { - return Target.ResolveToDirectReference(); + return (Target == null) ? null : Target.ResolveToDirectReference(); } } } \ No newline at end of file From 7f69dc1c2664a8dca370f8c0f7bf58885aabd1a1 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Mon, 2 May 2011 21:48:19 +0200 Subject: [PATCH 06/13] Port some tests from cgit and fix implementation to make them pass --- LibGit2Sharp.Tests/TagFixture.cs | 89 ++++++++++++++++++++++++++-- LibGit2Sharp/RepositoryExtensions.cs | 11 ++++ 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/LibGit2Sharp.Tests/TagFixture.cs b/LibGit2Sharp.Tests/TagFixture.cs index efacbb337..e49fd81f4 100644 --- a/LibGit2Sharp.Tests/TagFixture.cs +++ b/LibGit2Sharp.Tests/TagFixture.cs @@ -19,6 +19,7 @@ public class TagFixture private const string tagTestSha = "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"; private const string commitE90810BSha = "e90810b8df3e80c413d903f631643c716887138d"; private const string tagE90810BSha = "7b4384978d2493e851f9cca7858815fac9b10980"; + const string invalidTargetId = "deadbeef1b46c854b31185ea97743be6a8774479"; [Test] public void CanCreateALightWeightTagFromSha() @@ -129,7 +130,7 @@ public void CreatingAnAnnotatedTagIsDeterministic() } [Test] - [Description("Ported from cgit (https://github.com/git/git/blob/master/t/t7004-tag.sh)")] + [Description("Ported from cgit (https://github.com/git/git/blob/1c08bf50cfcf924094eca56c2486a90e2bf1e6e2/t/t7004-tag.sh#L32)")] public void CreatingATagInAEmptyRepositoryThrows() { using (new SelfCleaningDirectory(newRepoPath)) @@ -143,6 +144,88 @@ public void CreatingATagInAEmptyRepositoryThrows() } } + [Test] + [Description("Ported from cgit (https://github.com/git/git/blob/1c08bf50cfcf924094eca56c2486a90e2bf1e6e2/t/t7004-tag.sh#L37)")] + public void CreatingATagForHeadInAEmptyRepositoryThrows() + { + using (new SelfCleaningDirectory(newRepoPath)) + { + var dir = Repository.Init(newRepoPath); + + using (var repo = new Repository(dir)) + { + Assert.Throws(() => repo.ApplyTag("mytaghead", "HEAD")); + } + } + } + + [Test] + [Description("Ported from cgit (https://github.com/git/git/blob/1c08bf50cfcf924094eca56c2486a90e2bf1e6e2/t/t7004-tag.sh#L42)")] + public void CreatingATagForAnUnknowReferenceShouldFail() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + Assert.Throws(() => repo.ApplyTag("mytagnorev", "aaaaaaaaaaa")); + } + } + + [Test] + [Description("Ported from cgit (https://github.com/git/git/blob/1c08bf50cfcf924094eca56c2486a90e2bf1e6e2/t/t7004-tag.sh#L42)")] + public void CreatingATagForAnUnknowObjectIdShouldFail() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + Assert.Throws(() => repo.ApplyTag("mytagnorev", invalidTargetId)); + } + } + + [Test] + [Description("Ported from cgit (https://github.com/git/git/blob/1c08bf50cfcf924094eca56c2486a90e2bf1e6e2/t/t7004-tag.sh#L48)")] + public void CanCreateATagForImplicitHead() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + var tag = repo.ApplyTag("mytag"); + tag.ShouldNotBeNull(); + + tag.Target.Id.ShouldEqual(repo.Head.ResolveToDirectReference().Target.Id); + + var retrievedTag = repo.Tags[tag.CanonicalName]; + tag.ShouldEqual(retrievedTag); + } + } + + [Test] + [Description("Ported from cgit (https://github.com/git/git/blob/1c08bf50cfcf924094eca56c2486a90e2bf1e6e2/t/t7004-tag.sh#L87)")] + public void CreatingADuplicateTagShouldFail() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + repo.ApplyTag("mytag"); + + Assert.Throws(() => repo.ApplyTag("mytag")); + } + } + + [Test] + [Description("Ported from cgit (https://github.com/git/git/blob/1c08bf50cfcf924094eca56c2486a90e2bf1e6e2/t/t7004-tag.sh#L90)")] + public void CreatingATagWithANonValidNameShouldFail() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + Assert.Throws(() => repo.ApplyTag("")); + Assert.Throws(() => repo.ApplyTag(".othertag")); + Assert.Throws(() => repo.ApplyTag("other tag")); + Assert.Throws(() => repo.ApplyTag("othertag^")); + Assert.Throws(() => repo.ApplyTag("other~tag")); + } + } + [Test] public void BlindlyCreatingALightweightTagOverAnExistingOneThrows() { @@ -202,8 +285,6 @@ public void CreateTagWithEmptyTargetThrows() [Test] public void CreateTagWithNotExistingTargetThrows() { - const string invalidTargetId = "deadbeef1b46c854b31185ea97743be6a8774479"; - using (var repo = new Repository(Constants.TestRepoPath)) { Assert.Throws(() => repo.Tags.Create("test_tag", invalidTargetId, signatureTim, "message")); @@ -314,7 +395,7 @@ public void CanListTags() } [Test] - [Description("Ported from cgit (https://github.com/git/git/blob/master/t/t7004-tag.sh)")] + [Description("Ported from cgit (https://github.com/git/git/blob/1c08bf50cfcf924094eca56c2486a90e2bf1e6e2/t/t7004-tag.sh#L24)")] public void CanListAllTagsInAEmptyRepository() { using (new SelfCleaningDirectory(newRepoPath)) diff --git a/LibGit2Sharp/RepositoryExtensions.cs b/LibGit2Sharp/RepositoryExtensions.cs index 6669bf5ff..9cb79f708 100644 --- a/LibGit2Sharp/RepositoryExtensions.cs +++ b/LibGit2Sharp/RepositoryExtensions.cs @@ -38,5 +38,16 @@ public static Tag ApplyTag(this Repository repository, string tagName) { return repository.Tags.Create(tagName, repository.Head.CanonicalName); } + + /// + /// Creates a lightweight tag with the specified name. This tag will point at the . + /// + /// The being looked up. + /// The name of the tag to create. + /// The canonical reference name or sha which should be pointed at by the Tag. + public static Tag ApplyTag(this Repository repository, string tagName, string target) + { + return repository.Tags.Create(tagName, target); + } } } \ No newline at end of file From 51bc57b085e37e4311c386b75c424182c502a4a4 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Tue, 3 May 2011 15:22:58 +0200 Subject: [PATCH 07/13] Port some tests from cgit and fix implementation to make them pass --- LibGit2Sharp.Tests/TagFixture.cs | 27 +++++++++++++++++++++++++++ LibGit2Sharp/RepositoryExtensions.cs | 2 +- LibGit2Sharp/TagCollection.cs | 9 ++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/LibGit2Sharp.Tests/TagFixture.cs b/LibGit2Sharp.Tests/TagFixture.cs index e49fd81f4..69d7697b5 100644 --- a/LibGit2Sharp.Tests/TagFixture.cs +++ b/LibGit2Sharp.Tests/TagFixture.cs @@ -226,6 +226,23 @@ public void CreatingATagWithANonValidNameShouldFail() } } + [Test] + [Description("Ported from cgit (https://github.com/git/git/blob/1c08bf50cfcf924094eca56c2486a90e2bf1e6e2/t/t7004-tag.sh#L101)")] + public void CanCreateATagUsingHead() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + var tag = repo.ApplyTag("mytag", "HEAD"); + tag.ShouldNotBeNull(); + + tag.Target.Id.ShouldEqual(repo.Head.ResolveToDirectReference().Target.Id); + + var retrievedTag = repo.Tags[tag.CanonicalName]; + tag.ShouldEqual(retrievedTag); + } + } + [Test] public void BlindlyCreatingALightweightTagOverAnExistingOneThrows() { @@ -381,6 +398,16 @@ public void DeletingATagDecreasesTheTagsCount() } } + [Test] + [Description("Ported from cgit (https://github.com/git/git/blob/1c08bf50cfcf924094eca56c2486a90e2bf1e6e2/t/t7004-tag.sh#L108)")] + public void DeletingAnUnknownTagShouldFail() + { + using (var repo = new Repository(Constants.TestRepoPath)) + { + Assert.Throws(() => repo.Tags.Delete("unknown-tag")); + } + } + [Test] public void CanListTags() { diff --git a/LibGit2Sharp/RepositoryExtensions.cs b/LibGit2Sharp/RepositoryExtensions.cs index 9cb79f708..98ad094dc 100644 --- a/LibGit2Sharp/RepositoryExtensions.cs +++ b/LibGit2Sharp/RepositoryExtensions.cs @@ -36,7 +36,7 @@ public static T Lookup(this Repository repository, ObjectId id) where T : Git /// The name of the tag to create. public static Tag ApplyTag(this Repository repository, string tagName) { - return repository.Tags.Create(tagName, repository.Head.CanonicalName); + return ApplyTag(repository, tagName, repository.Head.CanonicalName); } /// diff --git a/LibGit2Sharp/TagCollection.cs b/LibGit2Sharp/TagCollection.cs index 17031e56e..941bf5d77 100644 --- a/LibGit2Sharp/TagCollection.cs +++ b/LibGit2Sharp/TagCollection.cs @@ -120,7 +120,14 @@ public void Delete(string name) { Ensure.ArgumentNotNullOrEmptyString(name, "name"); - repo.Refs.Delete(this[name].CanonicalName); //TODO: To be replaced by native libgit2 git_tag_delete() when available. + Tag tag = this[name]; + + if (tag == null) + { + throw new ApplicationException(String.Format("No tag identified by '{0}' can be found in the repository.", name)); + } + + repo.Refs.Delete(tag.CanonicalName); //TODO: To be replaced by native libgit2 git_tag_delete() when available. } private GitObject RetrieveObjectToTag(string target) From 73a3fc1b493ff2266391b92aba1a9cdab9c96398 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Tue, 3 May 2011 18:30:05 +0200 Subject: [PATCH 08/13] Fix some issues pinpointed by Code Analysis --- LibGit2Sharp/Branch.cs | 9 +++++---- LibGit2Sharp/BranchCollection.cs | 3 ++- LibGit2Sharp/CommitCollection.cs | 2 +- LibGit2Sharp/Core/Ensure.cs | 3 ++- LibGit2Sharp/LibGit2Sharp.csproj | 1 + LibGit2Sharp/ObjectId.cs | 3 ++- LibGit2Sharp/Reference.cs | 3 ++- LibGit2Sharp/ReferenceCollection.cs | 7 ++++--- LibGit2Sharp/Repository.cs | 4 ++-- LibGit2Sharp/TagCollection.cs | 7 ++++--- backlog.md | 2 +- 11 files changed, 26 insertions(+), 18 deletions(-) diff --git a/LibGit2Sharp/Branch.cs b/LibGit2Sharp/Branch.cs index b0961e442..3918ee6b7 100644 --- a/LibGit2Sharp/Branch.cs +++ b/LibGit2Sharp/Branch.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using LibGit2Sharp.Core; namespace LibGit2Sharp @@ -109,22 +110,22 @@ public override int GetHashCode() private static bool IsRemoteBranch(string canonicalName) { - return canonicalName.StartsWith("refs/remotes/"); + return canonicalName.StartsWith("refs/remotes/", StringComparison.Ordinal); } private static string ShortenName(string branchName) { - if (branchName.StartsWith("refs/heads/")) + if (branchName.StartsWith("refs/heads/", StringComparison.Ordinal)) { return branchName.Substring("refs/heads/".Length); } - if (branchName.StartsWith("refs/remotes/")) + if (branchName.StartsWith("refs/remotes/", StringComparison.Ordinal)) { return branchName.Substring("refs/remotes/".Length); } - throw new ArgumentException(string.Format("'{0}' does not look like a valid branch name.", branchName)); + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,"'{0}' does not look like a valid branch name.", branchName)); } /// diff --git a/LibGit2Sharp/BranchCollection.cs b/LibGit2Sharp/BranchCollection.cs index 6d2677d68..351b24e96 100644 --- a/LibGit2Sharp/BranchCollection.cs +++ b/LibGit2Sharp/BranchCollection.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Globalization; using System.Linq; using LibGit2Sharp.Core; @@ -114,7 +115,7 @@ private static string NormalizeToCanonicalName(string name) return name; } - return string.Format("refs/heads/{0}", name); + return string.Format(CultureInfo.InvariantCulture, "refs/heads/{0}", name); } } } \ No newline at end of file diff --git a/LibGit2Sharp/CommitCollection.cs b/LibGit2Sharp/CommitCollection.cs index 46f9fa694..15c0fa0f7 100644 --- a/LibGit2Sharp/CommitCollection.cs +++ b/LibGit2Sharp/CommitCollection.cs @@ -131,7 +131,7 @@ private class CommitEnumerator : IEnumerator { private readonly bool forCountOnly; private readonly Repository repo; - private readonly IntPtr walker = IntPtr.Zero; + private readonly IntPtr walker = IntPtr.Zero; //TODO: Convert to SafeHandle? private bool disposed; public CommitEnumerator(Repository repo, bool forCountOnly = false) diff --git a/LibGit2Sharp/Core/Ensure.cs b/LibGit2Sharp/Core/Ensure.cs index a0ceafb21..88eb96908 100644 --- a/LibGit2Sharp/Core/Ensure.cs +++ b/LibGit2Sharp/Core/Ensure.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; namespace LibGit2Sharp.Core { @@ -47,7 +48,7 @@ public static void Success(int result) } throw new ApplicationException( - String.Format("There was an error in libgit2, but error handling sucks right now, so I can't tell you what it was. Error code = {0} ({1})", Enum.GetName(typeof(GitErrorCode), result) + String.Format(CultureInfo.InvariantCulture, "There was an error in libgit2, but error handling sucks right now, so I can't tell you what it was. Error code = {0} ({1})", Enum.GetName(typeof(GitErrorCode), result) , result)); } diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index 812417cb9..7ff8e63c8 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -25,6 +25,7 @@ false true x86 + AllRules.ruleset pdbonly diff --git a/LibGit2Sharp/ObjectId.cs b/LibGit2Sharp/ObjectId.cs index 80f2a9246..d576a769a 100644 --- a/LibGit2Sharp/ObjectId.cs +++ b/LibGit2Sharp/ObjectId.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Text; using LibGit2Sharp.Core; @@ -90,7 +91,7 @@ internal static ObjectId CreateFromMaybeSha(string sha) return null; } - throw new ArgumentException(string.Format("'{0}' is not a valid sha. Expected length should equal {1}.", sha, hexSize)); + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "'{0}' is not a valid sha. Expected length should equal {1}.", sha, hexSize)); } GitOid oid; diff --git a/LibGit2Sharp/Reference.cs b/LibGit2Sharp/Reference.cs index f31d1a59d..d37cb9444 100644 --- a/LibGit2Sharp/Reference.cs +++ b/LibGit2Sharp/Reference.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Runtime.InteropServices; using LibGit2Sharp.Core; @@ -70,7 +71,7 @@ internal static T BuildFromPtr(IntPtr ptr, Repository repo) where T : class } throw new InvalidOperationException( - string.Format("Unable to build a new instance of '{0}' from a reference of type '{1}'.", + string.Format(CultureInfo.InvariantCulture, "Unable to build a new instance of '{0}' from a reference of type '{1}'.", typeof (T), Enum.GetName(typeof (GitReferenceType), type))); } diff --git a/LibGit2Sharp/ReferenceCollection.cs b/LibGit2Sharp/ReferenceCollection.cs index a7a43e213..8c77ff56e 100644 --- a/LibGit2Sharp/ReferenceCollection.cs +++ b/LibGit2Sharp/ReferenceCollection.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Globalization; using System.Linq; using LibGit2Sharp.Core; @@ -179,16 +180,16 @@ public void UpdateTarget(string name, string target) switch (type) { case GitReferenceType.Oid: - if (id == null) throw new ArgumentException(String.Format("The reference specified by {0} is an Oid reference, you must provide a sha as the target.", name), "target"); + if (id == null) throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The reference specified by {0} is an Oid reference, you must provide a sha as the target.", name), "target"); var oid = id.Oid; res = NativeMethods.git_reference_set_oid(reference, ref oid); break; case GitReferenceType.Symbolic: - if (id != null) throw new ArgumentException(String.Format("The reference specified by {0} is an Symbolic reference, you must provide a symbol as the target.", name), "target"); + if (id != null) throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The reference specified by {0} is an Symbolic reference, you must provide a symbol as the target.", name), "target"); res = NativeMethods.git_reference_set_target(reference, target); break; default: - throw new InvalidOperationException(string.Format("Reference '{0}' has an un unexpected type ('{1}').", name, Enum.GetName(typeof(GitReferenceType), type))); + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Reference '{0}' has an un unexpected type ('{1}').", name, Enum.GetName(typeof(GitReferenceType), type))); } Ensure.Success(res); diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 9e9f49a52..c5bcf3c96 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -126,9 +126,9 @@ protected virtual void Dispose(bool disposing) handle.Dispose(); } - if (Index != null) + if (index != null) { - Index.Dispose(); + index.Dispose(); } } diff --git a/LibGit2Sharp/TagCollection.cs b/LibGit2Sharp/TagCollection.cs index 941bf5d77..b7fd9677d 100644 --- a/LibGit2Sharp/TagCollection.cs +++ b/LibGit2Sharp/TagCollection.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Globalization; using System.Linq; using LibGit2Sharp.Core; @@ -124,7 +125,7 @@ public void Delete(string name) if (tag == null) { - throw new ApplicationException(String.Format("No tag identified by '{0}' can be found in the repository.", name)); + throw new ApplicationException(String.Format(CultureInfo.InvariantCulture, "No tag identified by '{0}' can be found in the repository.", name)); } repo.Refs.Delete(tag.CanonicalName); //TODO: To be replaced by native libgit2 git_tag_delete() when available. @@ -136,7 +137,7 @@ private GitObject RetrieveObjectToTag(string target) if (objectToTag == null) { - throw new ApplicationException(String.Format("No object identified by '{0}' can be found in the repository.", target)); + throw new ApplicationException(String.Format(CultureInfo.InvariantCulture, "No object identified by '{0}' can be found in the repository.", target)); } return objectToTag; @@ -151,7 +152,7 @@ private static string NormalizeToCanonicalName(string name) return name; } - return string.Format("refs/tags/{0}", name); + return string.Format(CultureInfo.InvariantCulture, "refs/tags/{0}", name); } } } \ No newline at end of file diff --git a/backlog.md b/backlog.md index 6b17db2e7..cfd5ef30c 100644 --- a/backlog.md +++ b/backlog.md @@ -11,7 +11,7 @@ - https://bugzilla.novell.com/show_bug.cgi?id=324680 generates false-positive warnings regarding xml documentation when LibGit2Sharp is built with xbuild - The freeing of a newly created signature pointer doesn't "feel" to be done at the right place. - Should we throw when trying to delete a reference which can not be found? - - Favor overloads over optional parameters + - Favor overloads over optional parameters (http://msdn.microsoft.com/en-us/library/ms182135.aspx) - Ensure that types that are not supposed to be built by the Consumer do not expose a constructor. - Escape as early as possible from a method. Fight against the arrowhead effect (cf. http://elegantcode.com/2009/08/14/observations-on-the-if-statement/) From a4b67fa59e2b0392d0724139f56c1601c4a2cdb8 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Tue, 3 May 2011 22:16:34 +0200 Subject: [PATCH 09/13] Port some tests from cgit and fix implementation to make them pass --- LibGit2Sharp.Tests/TagFixture.cs | 38 +++++++++++++++++++++------- LibGit2Sharp/RepositoryExtensions.cs | 12 +++++++++ LibGit2Sharp/TagCollection.cs | 2 +- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/LibGit2Sharp.Tests/TagFixture.cs b/LibGit2Sharp.Tests/TagFixture.cs index 69d7697b5..6e898c7c7 100644 --- a/LibGit2Sharp.Tests/TagFixture.cs +++ b/LibGit2Sharp.Tests/TagFixture.cs @@ -101,6 +101,20 @@ public void CanCreateAnAnnotatedTagFromSha() } } + [Test] + [Description("Ported from cgit (https://github.com/git/git/blob/1c08bf50cfcf924094eca56c2486a90e2bf1e6e2/t/t7004-tag.sh#L359)")] + public void CanCreateAnAnnotatedTagWithAnEmptyMessage() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + var newTag = repo.ApplyTag("empty-annotated-tag", signatureNtk, string.Empty); + newTag.ShouldNotBeNull(); + newTag.IsAnnotated.ShouldBeTrue(); + newTag.Annotation.Message.ShouldEqual(string.Empty); + } + } + [Test] public void CanCreateAndOverwriteAnAnnotatedTag() { @@ -272,15 +286,6 @@ public void CreateTagWithADuplicateNameThrows() } } - [Test] - public void CreateTagWithEmptyMessageThrows() - { - using (var repo = new Repository(Constants.TestRepoPath)) - { - Assert.Throws(() => repo.Tags.Create("test_tag", "refs/heads/master", signatureTim, string.Empty)); - } - } - [Test] public void CreateTagWithEmptyNameThrows() { @@ -437,6 +442,21 @@ public void CanListAllTagsInAEmptyRepository() } } + [Test] + [Description("Ported from cgit (https://github.com/git/git/blob/1c08bf50cfcf924094eca56c2486a90e2bf1e6e2/t/t7004-tag.sh#L165)")] + public void ListAllTagsShouldOutputThemInAnOrderedWay() + { + using (var repo = new Repository(Constants.TestRepoPath)) + { + List tagNames = repo.Tags.Select(t => t.Name).ToList(); + + var sortedTags = expectedTags; + sortedTags.Sort(); + + CollectionAssert.AreEqual(sortedTags, tagNames); + } + } + [Test] public void CanLookupALightweightTag() { diff --git a/LibGit2Sharp/RepositoryExtensions.cs b/LibGit2Sharp/RepositoryExtensions.cs index 98ad094dc..cde016060 100644 --- a/LibGit2Sharp/RepositoryExtensions.cs +++ b/LibGit2Sharp/RepositoryExtensions.cs @@ -49,5 +49,17 @@ public static Tag ApplyTag(this Repository repository, string tagName, string ta { return repository.Tags.Create(tagName, target); } + + /// + /// Creates an annotated tag with the specified name. This tag will point at the commit pointed at by the . + /// + /// The being looked up. + /// The name of the tag to create. + /// The identity of the creator of this tag. + /// The annotation message. + public static Tag ApplyTag(this Repository repository, string tagName, Signature tagger, string message) + { + return repository.Tags.Create(tagName, repository.Head.CanonicalName, tagger, message); + } } } \ No newline at end of file diff --git a/LibGit2Sharp/TagCollection.cs b/LibGit2Sharp/TagCollection.cs index b7fd9677d..929cc5fba 100644 --- a/LibGit2Sharp/TagCollection.cs +++ b/LibGit2Sharp/TagCollection.cs @@ -73,7 +73,7 @@ public Tag Create(string name, string target, Signature tagger, string message, Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNullOrEmptyString(target, "target"); Ensure.ArgumentNotNull(tagger, "tagger"); - Ensure.ArgumentNotNullOrEmptyString(message, "message"); + Ensure.ArgumentNotNull(message, "message"); GitObject objectToTag = RetrieveObjectToTag(target); From 6ba4b0011e95b234db962cc164e4c89eca039810 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 4 May 2011 18:13:53 +0200 Subject: [PATCH 10/13] Add more tests covering the creation of tags --- LibGit2Sharp.Tests/TagFixture.cs | 90 ++++++++++++++++++++++++++++ LibGit2Sharp/RepositoryExtensions.cs | 15 ++++- 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/LibGit2Sharp.Tests/TagFixture.cs b/LibGit2Sharp.Tests/TagFixture.cs index 6e898c7c7..4d121b901 100644 --- a/LibGit2Sharp.Tests/TagFixture.cs +++ b/LibGit2Sharp.Tests/TagFixture.cs @@ -77,6 +77,18 @@ public void CanCreateATagWithNameContainingASlash() } } + [Test] + public void CreatingATagWithNameMatchingAnAlreadyExistingReferenceHierarchyThows() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + repo.ApplyTag("i/am/deep"); + Assert.Throws(() => repo.ApplyTag("i/am/deep/rooted")); + Assert.Throws(() => repo.ApplyTag("i/am")); + } + } + [Test] public void CanCreateAnAnnotatedTagFromABranchName() { @@ -257,6 +269,84 @@ public void CanCreateATagUsingHead() } } + [Test] + public void CanCreateATagPointingToATree() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + var headCommit = (Commit)repo.Head.ResolveToDirectReference().Target; + var tree = headCommit.Tree; + + var tag = repo.ApplyTag("tree-tag", tree.Sha); + tag.ShouldNotBeNull(); + tag.IsAnnotated.ShouldBeFalse(); + tag.Target.Id.ShouldEqual(tree.Id); + + repo.Lookup(tag.Target.Id).ShouldEqual(tree); + repo.Tags[tag.Name].ShouldEqual(tag); + } + } + + [Test] + public void CanCreateATagPointingToABlob() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + var headCommit = (Commit)repo.Head.ResolveToDirectReference().Target; + var blob = headCommit.Tree.Files.First(); + + var tag = repo.ApplyTag("blob-tag", blob.Sha); + tag.ShouldNotBeNull(); + tag.IsAnnotated.ShouldBeFalse(); + tag.Target.Id.ShouldEqual(blob.Id); + + repo.Lookup(tag.Target.Id).ShouldEqual(blob); + repo.Tags[tag.Name].ShouldEqual(tag); + } + } + + [Test] + public void CreatingALightweightTagPointingToATagAnnotationGeneratesAnAnnotatedTagReusingThePointedAtTagAnnotation() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + var annotatedTag = repo.Tags["e90810b"]; + var annotation = annotatedTag.Annotation; + + var tag = repo.ApplyTag("lightweight-tag", annotation.Sha); + tag.ShouldNotBeNull(); + tag.IsAnnotated.ShouldBeTrue(); + tag.Target.Id.ShouldEqual(annotation.Id); + tag.Annotation.ShouldEqual(annotation); + + repo.Lookup(tag.Target.Id).ShouldEqual(annotation); + repo.Tags[tag.Name].ShouldEqual(tag); + } + } + + [Test] + public void CanCreateAnAnnotatedTagPointingToATagAnnotation() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + var annotatedTag = repo.Tags["e90810b"]; + var annotation = annotatedTag.Annotation; + + var tag = repo.ApplyTag("annotatedtag-tag", annotation.Sha, signatureNtk, "A new annotation"); + tag.ShouldNotBeNull(); + tag.IsAnnotated.ShouldBeTrue(); + tag.Annotation.TargetId.ShouldEqual(annotation.Id); + tag.Annotation.ShouldNotEqual(annotation); + + repo.Lookup(tag.Target.Id).ShouldEqual(tag.Annotation); + repo.Tags[tag.Name].ShouldEqual(tag); + } + } + [Test] public void BlindlyCreatingALightweightTagOverAnExistingOneThrows() { diff --git a/LibGit2Sharp/RepositoryExtensions.cs b/LibGit2Sharp/RepositoryExtensions.cs index cde016060..f5f91938d 100644 --- a/LibGit2Sharp/RepositoryExtensions.cs +++ b/LibGit2Sharp/RepositoryExtensions.cs @@ -59,7 +59,20 @@ public static Tag ApplyTag(this Repository repository, string tagName, string ta /// The annotation message. public static Tag ApplyTag(this Repository repository, string tagName, Signature tagger, string message) { - return repository.Tags.Create(tagName, repository.Head.CanonicalName, tagger, message); + return ApplyTag(repository, tagName, repository.Head.CanonicalName, tagger, message); + } + + /// + /// Creates an annotated tag with the specified name. This tag will point at the . + /// + /// The being looked up. + /// The name of the tag to create. + /// The canonical reference name or sha which should be pointed at by the Tag. + /// The identity of the creator of this tag. + /// The annotation message. + public static Tag ApplyTag(this Repository repository, string tagName, string target, Signature tagger, string message) + { + return repository.Tags.Create(tagName, target, tagger, message); } } } \ No newline at end of file From 35c3ec00facdd0a5a58a605cd6d7d45af895edab Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 5 May 2011 21:31:44 +0200 Subject: [PATCH 11/13] Add some (currently failing and ignored) tests related to reference moving/renaming --- LibGit2Sharp.Tests/ReferenceFixture.cs | 34 +++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/LibGit2Sharp.Tests/ReferenceFixture.cs b/LibGit2Sharp.Tests/ReferenceFixture.cs index 710d1ec26..ab13754d0 100644 --- a/LibGit2Sharp.Tests/ReferenceFixture.cs +++ b/LibGit2Sharp.Tests/ReferenceFixture.cs @@ -374,7 +374,39 @@ public void UpdatingAReferenceTargetWithBadParametersFails() } [Test] - public void CanMoveAReference() + [Ignore("Currently fails because of feature which is not yet implemented in libgit2")] + public void CanMoveAReferenceToADeeperReferenceHierarchy() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + const string newName = "refs/tags/test/deep"; + + Reference moved = repo.Refs.Move("refs/tags/test", newName); + moved.ShouldNotBeNull(); + moved.CanonicalName.ShouldEqual(newName); + } + } + + [Test] + [Ignore("Currently fails because of feature which is not yet implemented in libgit2")] + public void CanMoveAReferenceToAUpperReferenceHierarchy() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + const string newName = "refs/heads/o/sole"; + const string oldName = newName + "/mio"; + + repo.Refs.Create(oldName, repo.Head.ResolveToDirectReference().TargetIdentifier); + Reference moved = repo.Refs.Move(oldName, newName); + moved.ShouldNotBeNull(); + moved.CanonicalName.ShouldEqual(newName); + } + } + + [Test] + public void CanMoveAReferenceToADifferentReferenceHierarchy() { using (var path = new TemporaryCloneOfTestRepo()) using (var repo = new Repository(path.RepositoryPath)) From 0739544b861de65ba81e081dfe9a927d8d1afa0a Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 5 May 2011 21:32:00 +0200 Subject: [PATCH 12/13] Update backlog --- backlog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backlog.md b/backlog.md index cfd5ef30c..40f12cf3c 100644 --- a/backlog.md +++ b/backlog.md @@ -2,6 +2,7 @@ ### LibGit2Sharp + - Add branch renaming (public Branch Move(string oldName, string newName, bool allowOverwrite = false)) - Turn duplicated strings "refs/xxx" into properties of a generic Constants helper type - Refactor the error handling (OutputResult -> Exceptions) - Launch Code Analysis (Issues related to interop and marshaling will be worked on once we're able to succesffully exchange non ascii encoded data with libgit2) @@ -21,6 +22,8 @@ - Add GitObject equality test suite - Add Reference equality test suite - Ensure former API tests are ported and passing + - Remove Ignore attribute from ReferenceFixture.CanMoveAReferenceToADeeperReferenceHierarchy() once git_reference_rename() is fixed + - Remove Ignore attribute from ReferenceFixture.CanMoveAReferenceToAUpperReferenceHierarchy() once git_reference_rename() is fixed ### Documentation From 5d64757f8b0e2a87558e6dffae60ee4fb9234370 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 6 May 2011 15:32:42 +0200 Subject: [PATCH 13/13] Collapsed some assertions into higher level tests in order to make things easier to read and maintain Credit goes to @tclem for raising this --- LibGit2Sharp.Tests/RepositoryFixture.cs | 34 +++---------------------- 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/LibGit2Sharp.Tests/RepositoryFixture.cs b/LibGit2Sharp.Tests/RepositoryFixture.cs index ade31bb4b..d88334736 100644 --- a/LibGit2Sharp.Tests/RepositoryFixture.cs +++ b/LibGit2Sharp.Tests/RepositoryFixture.cs @@ -61,14 +61,9 @@ private static void AssertInitializedRepository(Repository repo) } [Test] - public void CreateRepoWithEmptyStringThrows() + public void CreatingRepoWithBadParamsThrows() { Assert.Throws(() => Repository.Init(string.Empty)); - } - - [Test] - public void CreateRepoWithNullThrows() - { Assert.Throws(() => Repository.Init(null)); } @@ -169,20 +164,12 @@ public void LookupObjectByUnknownReferenceNameReturnsNull() } [Test] - public void LookupWithEmptyStringThrows() + public void LookingUpWithBadParamsThrows() { using (var repo = new Repository(Constants.TestRepoPath)) { Assert.Throws(() => repo.Lookup(string.Empty)); Assert.Throws(() => repo.Lookup(string.Empty)); - } - } - - [Test] - public void LookupWithNullThrows() - { - using (var repo = new Repository(Constants.TestRepoPath)) - { Assert.Throws(() => repo.Lookup((string)null)); Assert.Throws(() => repo.Lookup((ObjectId)null)); Assert.Throws(() => repo.Lookup((string)null)); @@ -220,14 +207,9 @@ public void OpenNonExistentRepoThrows() } [Test] - public void OpeningRepositoryWithEmptyPathThrows() + public void OpeningRepositoryWithBadParamsThrows() { Assert.Throws(() => new Repository(string.Empty)); - } - - [Test] - public void OpeningRepositoryWithNullPathThrows() - { Assert.Throws(() => new Repository(null)); } @@ -244,19 +226,11 @@ public void CanTellIfObjectsExistInRepository() } [Test] - public void CallingExistsWithEmptyThrows() + public void CheckingForObjectExistenceWithBadParamsThrows() { using (var repo = new Repository(Constants.TestRepoPath)) { Assert.Throws(() => repo.HasObject(string.Empty)); - } - } - - [Test] - public void CallingExistsWithNullThrows() - { - using (var repo = new Repository(Constants.TestRepoPath)) - { Assert.Throws(() => repo.HasObject(null)); } }