Skip to content

Commit 9fff0eb

Browse files
committed
Improving test coverage, and added implementations
1 parent fb0b8c7 commit 9fff0eb

File tree

11 files changed

+137
-9
lines changed

11 files changed

+137
-9
lines changed

.gitignore

+6-1
Original file line numberDiff line numberDiff line change
@@ -258,4 +258,9 @@ paket-files/
258258

259259
# Python Tools for Visual Studio (PTVS)
260260
__pycache__/
261-
*.pyc
261+
*.pyc
262+
263+
# Visual Studio Code files
264+
*.code-workspace
265+
launch.json
266+
tasks.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace NetArchTest.Rules.Extensions
2+
{
3+
using System;
4+
using System.Linq;
5+
using System.Collections.Generic;
6+
using Mono.Cecil;
7+
8+
/// <summary>
9+
/// Extensions for the <see cref="FieldDefinition"/> class.
10+
/// </summary>
11+
static internal class FieldDefinitionExtensions
12+
{
13+
/// <summary>
14+
/// Tests whether a field is readonly
15+
/// </summary>
16+
/// <param name="fieldDefinition">The field to test.</param>
17+
/// <returns>An indication of whether the field is readonly.</returns>
18+
public static bool IsReadonly(this FieldDefinition fieldDefinition)
19+
{
20+
return !fieldDefinition.IsPublic || fieldDefinition.IsInitOnly || fieldDefinition.HasConstant;
21+
}
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace NetArchTest.Rules.Extensions
2+
{
3+
using System;
4+
using System.Linq;
5+
using System.Collections.Generic;
6+
using Mono.Cecil;
7+
8+
/// <summary>
9+
/// Extensions for the <see cref="PropertyDefinition"/> class.
10+
/// </summary>
11+
static internal class PropertyDefinitionExtensions
12+
{
13+
/// <summary>
14+
/// Tests whether a property is readonly
15+
/// </summary>
16+
/// <param name="propertyDefinition">The property to test.</param>
17+
/// <returns>An indication of whether the property is readonly.</returns>
18+
public static bool IsReadonly(this PropertyDefinition propertyDefinition)
19+
{
20+
return propertyDefinition.SetMethod == null || !propertyDefinition.SetMethod.IsPublic;
21+
}
22+
}
23+
}

src/NetArchTest.Rules/Extensions/TypeDefinitionExtensions.cs

+13
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq;
55
using System.Collections.Generic;
66
using Mono.Cecil;
7+
using System.Reflection;
78

89
/// <summary>
910
/// Extensions for the <see cref="TypeDefinition"/> class.
@@ -54,5 +55,17 @@ public static Type ToType(this TypeDefinition typeDefinition)
5455
var fullName = typeDefinition.FullName.Replace("/", "+");
5556
return Type.GetType(string.Concat(fullName, ", ", typeDefinition.Module.Assembly.FullName), true);
5657
}
58+
59+
/// <summary>
60+
/// Tests whether a class is immutable, i.e. all public fields are readonly and properties have no set method
61+
/// </summary>
62+
/// <param name="typeDefinition">The class to test.</param>
63+
/// <returns>An indication of whether the type is immutable</returns>
64+
public static bool IsImmutable(this TypeDefinition typeDefinition)
65+
{
66+
var propertiesAreReadonly = typeDefinition.Properties.All(p => p.IsReadonly());
67+
var fieldsAreReadonly = typeDefinition.Fields.All(f => f.IsReadonly());
68+
return propertiesAreReadonly && fieldsAreReadonly;
69+
}
5770
}
5871
}

src/NetArchTest.Rules/FunctionDelegates.cs

+8-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,14 @@ internal static class FunctionDelegates
224224
/// <summary> Function for finding sealed classes. </summary>
225225
internal static FunctionDelegate<bool> BeImmutable = delegate (IEnumerable<TypeDefinition> input, bool dummmy, bool condition)
226226
{
227-
throw new NotImplementedException();
227+
if (condition)
228+
{
229+
return input.Where(c => c.IsImmutable());
230+
}
231+
else
232+
{
233+
return input.Where(c => !c.IsImmutable());
234+
}
228235
};
229236

230237
/// <summary> Function for finding types in a particular namespace. </summary>

src/NetArchTest.Rules/NetArchTest.Rules.xml

+31
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/NetArchTest.Rules.UnitTests/ConditionTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ public void AreImmutable_MatchesFound_ClassSelected()
422422
.That()
423423
.ResideInNamespace("NetArchTest.TestStructure.Mutability")
424424
.And()
425-
.HaveName("ImmutableClass")
425+
.HaveNameStartingWith("ImmutableClass")
426426
.Should()
427427
.BeImmutable().GetResult();
428428

@@ -437,7 +437,7 @@ public void AreMutable_MatchesFound_ClassSelected()
437437
.That()
438438
.ResideInNamespace("NetArchTest.TestStructure.Mutability")
439439
.And()
440-
.DoNotHaveName("ImmutableClass")
440+
.DoNotHaveNameStartingWith("ImmutableClass")
441441
.Should()
442442
.BeMutable().GetResult();
443443

test/NetArchTest.Rules.UnitTests/PredicateTests.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,10 @@ public void AreImmutable_MatchesFound_ClassSelected()
444444
.And()
445445
.AreImmutable().GetTypes();
446446

447-
Assert.Single(result); // One result
448-
Assert.Contains<Type>(typeof(ImmutableClass), result);
447+
Assert.Equal(3, result.Count()); // Three types found
448+
Assert.Contains<Type>(typeof(ImmutableClass1), result);
449+
Assert.Contains<Type>(typeof(ImmutableClass2), result);
450+
Assert.Contains<Type>(typeof(ImmutableClass3), result);
449451
}
450452

451453
[Fact(DisplayName = "Types can be selected for being mutable.")]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace NetArchTest.TestStructure.Mutability
2+
{
3+
/// <summary>
4+
/// An example class that has has no mutable members.
5+
/// </summary>
6+
public class ImmutableClass1
7+
{
8+
public object GetOnlyProperty {get;}
9+
10+
public readonly object readonlyField;
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace NetArchTest.TestStructure.Mutability
2+
{
3+
/// <summary>
4+
/// An example class that has has no mutable members.
5+
/// </summary>
6+
public class ImmutableClass2
7+
{
8+
public object PrivateSetProperty {get; private set;}
9+
10+
public const object constField = null;
11+
}
12+
}

test/NetArchTest.TestStructure/Mutability/ImmutableClass.cs renamed to test/NetArchTest.TestStructure/Mutability/ImmutableClass3.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ namespace NetArchTest.TestStructure.Mutability
33
/// <summary>
44
/// An example class that has has no mutable members.
55
/// </summary>
6-
public class ImmutableClass
6+
public class ImmutableClass3
77
{
8-
public object Property {get;}
8+
protected object Property {get; set;}
99

10-
public readonly object field;
10+
private object privateField;
1111
}
1212
}

0 commit comments

Comments
 (0)