Skip to content

Commit 1fa2adc

Browse files
committed
add rules: HaveNumberOfLinesOfCodeLowerThan / HaveNumberOfLinesOfCodeGreaterThan
1 parent c5d8255 commit 1fa2adc

File tree

11 files changed

+400
-2
lines changed

11 files changed

+400
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ What **eNhancedEdition** has to offer, that is not available in the NetArchTest
3434
- at the end, you get more information which should make reasoning about tests easier:
3535

3636

37-
![revit-database-scripting-update-query](documentation/result.printscreen.png)
37+
![revit-database-scripting-update-query](https://raw.githubusercontent.com/NeVeSpl/NetArchTest.eNhancedEdition/main/documentation/result.printscreen.png)
3838

3939

4040

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using NetArchTest.Functions;
5+
6+
namespace NetArchTest.Rules
7+
{
8+
public sealed partial class Condition
9+
{
10+
/// <summary>
11+
/// Selects types that have more logical lines of code than a given number
12+
/// </summary>
13+
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
14+
public ConditionList HaveNumberOfLinesOfCodeGreaterThan(int number)
15+
{
16+
AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveNumberOfLinesOfCodeFewerThan(context, inputTypes, number, false));
17+
return CreateConditionList();
18+
}
19+
20+
/// <summary>
21+
/// Selects types that have fewer logical lines of code than a given number
22+
/// </summary>
23+
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
24+
public ConditionList HaveNumberOfLinesOfCodeLowerThan(int number)
25+
{
26+
AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveNumberOfLinesOfCodeFewerThan(context, inputTypes, number, true));
27+
return CreateConditionList();
28+
}
29+
}
30+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System.CodeDom.Compiler;
2+
using System.Linq;
3+
using System.Runtime.CompilerServices;
4+
using Mono.Cecil;
5+
6+
namespace NetArchTest.Extensions.Mono.Cecil
7+
{
8+
internal static class MethodDefinitionExtensions
9+
{
10+
public static bool IsGeneratedCode(this MethodDefinition method)
11+
{
12+
if (method == null)
13+
return false;
14+
15+
if (method.HasCustomAttributes == false)
16+
return false;
17+
18+
return method.CustomAttributes.Any(x => x?.AttributeType?.FullName == typeof(CompilerGeneratedAttribute).FullName || x?.AttributeType?.FullName == typeof(GeneratedCodeAttribute).FullName);
19+
}
20+
}
21+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using Mono.Cecil;
2+
3+
namespace NetArchTest.Extensions.Mono.Cecil
4+
{
5+
static internal partial class TypeDefinitionExtensions
6+
{
7+
public static int GetNumberOfLogicalLinesOfCode(this TypeDefinition type)
8+
{
9+
int count = 0;
10+
11+
if (type.HasMethods)
12+
{
13+
foreach (var method in type.Methods)
14+
{
15+
if (!method.HasBody) continue;
16+
if (method.IsGeneratedCode()) continue;
17+
if (method.DeclaringType.Module.HasSymbols == false) continue;
18+
19+
var methodLLOC = CountLogicalLinesOfCode(method);
20+
count += methodLLOC;
21+
}
22+
}
23+
24+
return count;
25+
}
26+
27+
28+
private static int CountLogicalLinesOfCode(MethodDefinition method)
29+
{
30+
int count = 0;
31+
int lastLine = int.MinValue;
32+
33+
foreach (var instruction in method.Body.Instructions)
34+
{
35+
var sequencePoint = method.DebugInformation.GetSequencePoint(instruction);
36+
if (sequencePoint == null)
37+
continue;
38+
39+
int line = sequencePoint.StartLine;
40+
// special value for PDB (so that debuggers can ignore a line)
41+
if (line == 0xFEEFEE)
42+
continue;
43+
44+
if (line > lastLine)
45+
count++;
46+
47+
lastLine = line;
48+
}
49+
return count;
50+
}
51+
}
52+
}

sources/NetArchTest/Extensions/Mono.Cecil/TypeDefinitionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
namespace Mono.Cecil
88
{
9-
static internal class TypeDefinitionExtensions
9+
static internal partial class TypeDefinitionExtensions
1010
{
1111
public static bool IsSubclassOf(this TypeReference child, TypeReference parent)
1212
{
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using NetArchTest.Assemblies;
4+
using NetArchTest.Extensions.Mono.Cecil;
5+
using NetArchTest.RuleEngine;
6+
7+
namespace NetArchTest.Functions
8+
{
9+
internal static partial class FunctionDelegates
10+
{
11+
12+
internal static IEnumerable<TypeSpec> HaveNumberOfLinesOfCodeFewerThan(FunctionSequenceExecutionContext context, IEnumerable<TypeSpec> input, int number, bool condition)
13+
{
14+
if (condition)
15+
{
16+
return input.Where(c => c.Definition.GetNumberOfLogicalLinesOfCode() < number);
17+
}
18+
else
19+
{
20+
return input.Where(c => !(c.Definition.GetNumberOfLogicalLinesOfCode() < number));
21+
}
22+
}
23+
}
24+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using NetArchTest.Functions;
5+
6+
namespace NetArchTest.Rules
7+
{
8+
public sealed partial class Predicate
9+
{
10+
/// <summary>
11+
/// Selects types that have more logical lines of code than a given number
12+
/// </summary>
13+
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
14+
public PredicateList HaveNumberOfLinesOfCodeGreaterThan(int number)
15+
{
16+
AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveNumberOfLinesOfCodeFewerThan(context, inputTypes, number, false));
17+
return CreatePredicateList();
18+
}
19+
20+
/// <summary>
21+
/// Selects types that have fewer logical lines of code than a given number
22+
/// </summary>
23+
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
24+
public PredicateList HaveNumberOfLinesOfCodeLowerThan(int number)
25+
{
26+
AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveNumberOfLinesOfCodeFewerThan(context, inputTypes, number, true));
27+
return CreatePredicateList();
28+
}
29+
}
30+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using NetArchTest.TestStructure.Metrics;
7+
using NetArchTest.UnitTests.TestFixtures;
8+
using Xunit;
9+
10+
namespace NetArchTest.UnitTests
11+
{
12+
public class ConditionTests_Metrics(AllTypesFixture fixture) : IClassFixture<AllTypesFixture>
13+
{
14+
15+
[Fact(DisplayName = "HaveNumberOfLinesOfCodeLowerThan")]
16+
public void HaveNumberOfLinesOfCodeLowerThan()
17+
{
18+
var result = fixture.Types
19+
.That()
20+
.ResideInNamespace(typeof(ClassSmall).Namespace)
21+
.And()
22+
.AreOfType(typeof(ClassSmall))
23+
.Should()
24+
.HaveNumberOfLinesOfCodeLowerThan(13).GetResult();
25+
26+
Assert.True(result.IsSuccessful);
27+
}
28+
29+
30+
[Fact(DisplayName = "HaveNumberOfLinesOfCodeGreaterThan")]
31+
public void HaveNumberOfLinesOfCodeGreaterThan()
32+
{
33+
var result = fixture.Types
34+
.That()
35+
.ResideInNamespace(typeof(ClassSmall).Namespace)
36+
.And()
37+
.AreOfType(typeof(ClassLarge))
38+
.Should()
39+
.HaveNumberOfLinesOfCodeGreaterThan(13).GetResult();
40+
41+
Assert.True(result.IsSuccessful);
42+
}
43+
}
44+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using NetArchTest.TestStructure.Metrics;
3+
using NetArchTest.UnitTests.TestFixtures;
4+
using Xunit;
5+
using static NetArchTest.Utils;
6+
7+
namespace NetArchTest.UnitTests
8+
{
9+
public class PredicateTests_Metrics(AllTypesFixture fixture) : IClassFixture<AllTypesFixture>
10+
{
11+
12+
[Fact(DisplayName = "HaveNumberOfLinesOfCodeLowerThan")]
13+
public void HaveNumberOfLinesOfCodeLowerThan()
14+
{
15+
var result = fixture.Types
16+
.That()
17+
.ResideInNamespace(namespaceof<ClassSmall>())
18+
.And()
19+
.HaveNumberOfLinesOfCodeLowerThan(13)
20+
.GetReflectionTypes();
21+
22+
Assert.Single(result);
23+
Assert.Contains<Type>(typeof(ClassSmall), result);
24+
}
25+
26+
[Fact(DisplayName = "HaveNumberOfLinesOfCodeGreaterThan")]
27+
public void HaveNumberOfLinesOfCodeGreaterThan()
28+
{
29+
var result = fixture.Types
30+
.That()
31+
.ResideInNamespace(namespaceof<ClassSmall>())
32+
.And()
33+
.HaveNumberOfLinesOfCodeGreaterThan(13)
34+
.GetReflectionTypes();
35+
36+
Assert.Single(result);
37+
Assert.Contains<Type>(typeof(ClassLarge), result);
38+
}
39+
40+
}
41+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace NetArchTest.TestStructure.Metrics
6+
{
7+
// This class was generated by GPT-4 Turbo :D
8+
public class ClassLarge
9+
{
10+
// Fields
11+
private string owner;
12+
private double balance;
13+
private double interestRate;
14+
15+
// Constructors
16+
public ClassLarge()
17+
{
18+
owner = "Unknown";
19+
balance = 0.0;
20+
interestRate = 0.0;
21+
}
22+
23+
public ClassLarge(string owner, double balance, double interestRate)
24+
{
25+
this.owner = owner;
26+
this.balance = balance;
27+
this.interestRate = interestRate;
28+
}
29+
30+
// Methods
31+
public void Deposit(double amount)
32+
{
33+
// Check if the amount is positive
34+
if (amount > 0)
35+
{
36+
// Add the amount to the balance
37+
balance += amount;
38+
// Print a confirmation message
39+
Console.WriteLine("You have deposited {0:C} to your account.", amount);
40+
}
41+
else
42+
{
43+
// Print an error message
44+
Console.WriteLine("Invalid amount. Please enter a positive number.");
45+
}
46+
}
47+
48+
public void Withdraw(double amount)
49+
{
50+
// Check if the amount is positive
51+
if (amount > 0)
52+
{
53+
// Check if the amount is less than or equal to the balance
54+
if (amount <= balance)
55+
{
56+
// Subtract the amount from the balance
57+
balance -= amount;
58+
// Print a confirmation message
59+
Console.WriteLine("You have withdrawn {0:C} from your account.", amount);
60+
}
61+
else
62+
{
63+
// Print an error message
64+
Console.WriteLine("Insufficient funds. You cannot withdraw more than your balance.");
65+
}
66+
}
67+
else
68+
{
69+
// Print an error message
70+
Console.WriteLine("Invalid amount. Please enter a positive number.");
71+
}
72+
}
73+
74+
public void Transfer(double amount, ClassLarge other)
75+
{
76+
// Check if the other account is not null
77+
if (other != null)
78+
{
79+
// Check if the amount is positive
80+
if (amount > 0)
81+
{
82+
// Check if the amount is less than or equal to the balance
83+
if (amount <= balance)
84+
{
85+
// Subtract the amount from the balance
86+
balance -= amount;
87+
// Add the amount to the other account's balance
88+
other.balance += amount;
89+
// Print a confirmation message
90+
Console.WriteLine("You have transferred {0:C} to {1}'s account.", amount, other.owner);
91+
}
92+
else
93+
{
94+
// Print an error message
95+
Console.WriteLine("Insufficient funds. You cannot transfer more than your balance.");
96+
}
97+
}
98+
else
99+
{
100+
// Print an error message
101+
Console.WriteLine("Invalid amount. Please enter a positive number.");
102+
}
103+
}
104+
else
105+
{
106+
// Print an error message
107+
Console.WriteLine("Invalid account. Please enter a valid account.");
108+
}
109+
}
110+
111+
public void ApplyInterest()
112+
{
113+
// Calculate the interest amount
114+
double interest = balance * interestRate / 100;
115+
// Add the interest amount to the balance
116+
balance += interest;
117+
// Print a confirmation message
118+
Console.WriteLine("You have earned {0:C} in interest.", interest);
119+
}
120+
121+
// Override ToString method
122+
public override string ToString()
123+
{
124+
return $"Owner: {owner}, Balance: {balance:C}, Interest Rate: {interestRate}%";
125+
}
126+
}
127+
}

0 commit comments

Comments
 (0)