Skip to content

Commit 0f1c7dd

Browse files
author
eddie.stanley
committed
[andrewabestGH-87] Added new (Cecil based) convention to check that code doesn't directly call Guid.NewGuid()
A possible use-case is code written in a functional style (that wants to avoid non-deterministic behaviour)
1 parent 754f500 commit 0f1c7dd

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

src/Core/Conventional.Tests/Conventional/Conventions/Cecil/CecilConventionSpecificationTests.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,5 +515,63 @@ public void LibraryCodeShouldCallConfigureAwaitWhenAwaitingTasks_FailsWhenConfig
515515
result.IsSatisfied.Should().BeFalse();
516516
result.Failures.Single().Should().Be(expectedFailureMessage);
517517
}
518+
519+
# region MustNotUseGuidNewGuid
520+
521+
private interface IGuidProvider
522+
{
523+
Guid CreateIdentifier();
524+
}
525+
526+
private class GoodGuidCreationCitizen
527+
{
528+
public GoodGuidCreationCitizen(IGuidProvider guidProvider)
529+
{
530+
guidProvider.CreateIdentifier();
531+
}
532+
}
533+
534+
[Test]
535+
public void MustNotUseGuidCreationNowConventionSpecification_Success()
536+
{
537+
typeof(GoodGuidCreationCitizen)
538+
.MustConformTo(Convention.MustNotUseGuidNewGuid)
539+
.IsSatisfied
540+
.Should()
541+
.BeTrue();
542+
}
543+
544+
private class OffendingGuidCreationCitizen
545+
{
546+
public OffendingGuidCreationCitizen()
547+
{
548+
Guid.NewGuid();
549+
}
550+
}
551+
552+
private class AsyncOffendingGuidCreationCitizen
553+
{
554+
public async Task<Guid> ResolveIdentifier()
555+
{
556+
await Task.Delay(1);
557+
return Guid.NewGuid();
558+
}
559+
}
560+
561+
[Test]
562+
public void MustNotUseGuidCreationNowConventionSpecification_FailsWhenACallToGuidCreationNowOrGuidCreationUtcNowExists()
563+
{
564+
var result = new []
565+
{
566+
typeof(OffendingGuidCreationCitizen),
567+
typeof(AsyncOffendingGuidCreationCitizen)
568+
}
569+
.MustConformTo(Convention.MustNotUseGuidNewGuid);
570+
571+
result.Results.Should().OnlyContain(x => x.IsSatisfied == false);
572+
result.Failures.Should().HaveCount(2);
573+
}
574+
575+
# endregion
518576
}
519577
}

src/Core/Conventional/Convention.Cecil.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ public static partial class Convention
99

1010
public static MustNotUseDateTimeOffsetNowConventionSpecification MustNotUseDateTimeOffsetNow => new MustNotUseDateTimeOffsetNowConventionSpecification();
1111

12+
public static MustNotUseGuidNewGuidConventionSpecification MustNotUseGuidNewGuid => new MustNotUseGuidNewGuidConventionSpecification();
13+
1214
public static ExceptionsThrownMustBeDerivedFromConventionSpecification ExceptionsThrownMustBeDerivedFrom(Type baseType)
1315
{
1416
return new ExceptionsThrownMustBeDerivedFromConventionSpecification(baseType);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using System.Linq.Expressions;
3+
using System.Reflection;
4+
5+
namespace Conventional.Conventions.Cecil
6+
{
7+
public class MustNotUseGuidNewGuidConventionSpecification :
8+
MustNotCallMethodConventionSpecification
9+
{
10+
private static MethodInfo GetMethod()
11+
{
12+
Expression<Func<Guid>> expr = () => Guid.NewGuid();
13+
return ((MethodCallExpression)expr.Body).Method;
14+
}
15+
16+
public MustNotUseGuidNewGuidConventionSpecification()
17+
: base(new[] { GetMethod() })
18+
{
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)