Skip to content

Commit 2d42bdb

Browse files
Merge pull request #7 from MrUnbelievable92/1.0.9
v1.0.9
2 parents 78bb90e + fced8eb commit 2d42bdb

14 files changed

+751
-320
lines changed

AssemblyInfo.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
using System.Reflection;
22
using System.Runtime.InteropServices;
33

4-
// General Information about an assembly is controlled through the following
4+
// General Information about an assembly is controlled through the following
55
// set of attributes. Change these attribute values to modify the information
66
// associated with an assembly.
77
[assembly: AssemblyTitle("C Sharp Dev Tools")]
88
[assembly: AssemblyDescription("")]
99
[assembly: AssemblyConfiguration("")]
1010
[assembly: AssemblyCompany("")]
1111
[assembly: AssemblyProduct("C Sharp Dev Tools")]
12-
[assembly: AssemblyCopyright("Copyright � 2020 - 2022 Maximilian Kalimon")]
12+
[assembly: AssemblyCopyright("Copyright � 2020 - 2023 Maximilian Kalimon")]
1313
[assembly: AssemblyTrademark("")]
1414
[assembly: AssemblyCulture("")]
1515

16-
// Setting ComVisible to false makes the types in this assembly not visible
17-
// to COM components. If you need to access a type in this assembly from
16+
// Setting ComVisible to false makes the types in this assembly not visible
17+
// to COM components. If you need to access a type in this assembly from
1818
// COM, set the ComVisible attribute to true on that type.
1919
[assembly: ComVisible(false)]
2020

@@ -24,10 +24,10 @@
2424
// Version information for an assembly consists of the following four values:
2525
//
2626
// Major Version
27-
// Minor Version
27+
// Minor Version
2828
// Build Number
2929
// Revision
3030
//
3131
//
32-
[assembly: AssemblyVersion("1.0.8")]
33-
[assembly: AssemblyFileVersion("1.0.8")]
32+
[assembly: AssemblyVersion("1.0.9")]
33+
[assembly: AssemblyFileVersion("1.0.9")]

Assert.Group.cs

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.IO;
5+
using System.Reflection;
6+
using System.Threading.Tasks;
7+
8+
namespace DevTools
9+
{
10+
public static partial class Assert
11+
{
12+
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
13+
internal class GroupAttribute : Attribute
14+
{
15+
internal const string __FILE__BOOLEAN_CONDITION_CHECKS = "BOOLEAN_CONDITION_CHECKS";
16+
internal const string __FILE__NULL_CHECKS = "NULL_CHECKS";
17+
internal const string __FILE__FILE_PATH_CHECKS = "FILE_PATH_CHECKS";
18+
internal const string __FILE__ARRAY_BOUNDS_CHECKS = "ARRAY_BOUNDS_CHECKS";
19+
internal const string __FILE__COMPARISON_CHECKS = "COMPARISON_CHECKS";
20+
internal const string __FILE__ARITHMETIC_LOGIC_CHECKS = "ARITHMETIC_LOGIC_CHECKS";
21+
internal const string __FILE__MEMORY_CHECKS = "MEMORY_CHECKS";
22+
23+
/// <summary> Boolean Condition Checks </summary>
24+
internal const string __NAME__BOOLEAN_CONDITION_CHECKS = "Boolean Condition Checks";
25+
/// <summary> Null Checks </summary>
26+
internal const string __NAME__NULL_CHECKS = "Null Checks";
27+
/// <summary> File Path Checks </summary>
28+
internal const string __NAME__FILE_PATH_CHECKS = "File Path Checks";
29+
/// <summary> Array Bounds Checks </summary>
30+
internal const string __NAME__ARRAY_BOUNDS_CHECKS = "Array Bounds Checks";
31+
/// <summary> Comparison Checks </summary>
32+
internal const string __NAME__COMPARISON_CHECKS = "Comparison Checks";
33+
/// <summary> Arithmetic-Logic Checks </summary>
34+
internal const string __NAME__ARITHMETIC_LOGIC_CHECKS = "Arithmetic-Logic Checks";
35+
/// <summary> Memory Checks </summary>
36+
internal const string __NAME__MEMORY_CHECKS = "Memory Checks";
37+
38+
private GroupAttribute() { }
39+
internal GroupAttribute(string publicName)
40+
{
41+
PublicName = publicName;
42+
FileContent = Defines.Where(grp => grp.PublicName == publicName).First().FileContent;
43+
}
44+
45+
internal string FileContent { get; private set; }
46+
internal string PublicName { get; private set; }
47+
internal static Assert.GroupAttribute[] Defines => new Assert.GroupAttribute[]
48+
{
49+
new Assert.GroupAttribute{ FileContent = __FILE__BOOLEAN_CONDITION_CHECKS, PublicName = __NAME__BOOLEAN_CONDITION_CHECKS },
50+
new Assert.GroupAttribute{ FileContent = __FILE__NULL_CHECKS, PublicName = __NAME__NULL_CHECKS },
51+
new Assert.GroupAttribute{ FileContent = __FILE__FILE_PATH_CHECKS, PublicName = __NAME__FILE_PATH_CHECKS },
52+
new Assert.GroupAttribute{ FileContent = __FILE__ARRAY_BOUNDS_CHECKS, PublicName = __NAME__ARRAY_BOUNDS_CHECKS },
53+
new Assert.GroupAttribute{ FileContent = __FILE__COMPARISON_CHECKS, PublicName = __NAME__COMPARISON_CHECKS },
54+
new Assert.GroupAttribute{ FileContent = __FILE__ARITHMETIC_LOGIC_CHECKS, PublicName = __NAME__ARITHMETIC_LOGIC_CHECKS },
55+
new Assert.GroupAttribute{ FileContent = __FILE__MEMORY_CHECKS, PublicName = __NAME__MEMORY_CHECKS }
56+
};
57+
58+
internal static async Task<Dictionary<Assert.GroupAttribute, ulong>> CountMethodCallsAsync(string projectPath)
59+
{
60+
try
61+
{
62+
Dictionary<MethodInfo, Assert.GroupAttribute> methodToGroupMap = GetAssertionsMappedToGroups();
63+
List<Task<Dictionary<Assert.GroupAttribute, ulong>>> jobs = CreateCountingTasks(methodToGroupMap, projectPath);
64+
65+
return await CombineResults(jobs, methodToGroupMap);
66+
}
67+
catch (Exception ex)
68+
{
69+
ex.Log();
70+
return null;
71+
}
72+
}
73+
74+
private static bool ContainsOverload(Dictionary<MethodInfo, Assert.GroupAttribute> result, MethodInfo method)
75+
{
76+
foreach (KeyValuePair<MethodInfo, Assert.GroupAttribute> item in result)
77+
{
78+
if (item.Key.Name == method.Name)
79+
{
80+
return true;
81+
}
82+
}
83+
84+
return false;
85+
}
86+
private static Dictionary<MethodInfo, Assert.GroupAttribute> GetAssertionsMappedToGroups()
87+
{
88+
Dictionary<MethodInfo, Assert.GroupAttribute> result = new Dictionary<MethodInfo, Assert.GroupAttribute>();
89+
90+
foreach (MethodInfo method in typeof(Assert).GetMethods())
91+
{
92+
Assert.GroupAttribute attribute = method.GetCustomAttribute<Assert.GroupAttribute>(false);
93+
if (attribute != null && !ContainsOverload(result, method))
94+
{
95+
result.Add(method, attribute);
96+
}
97+
}
98+
99+
return result;
100+
}
101+
private static string GetMethodPrefixFromUsingStatements(string script)
102+
{
103+
if (script.Contains("using static DevTools.Assert;"))
104+
{
105+
return string.Empty;
106+
}
107+
else if (script.Contains("using DevTools;") &&
108+
!script.Contains("using NUnit.Framework;") &&
109+
!script.Contains("using static System.Diagnostics.Debug;"))
110+
{
111+
return "Assert.";
112+
}
113+
else
114+
{
115+
return "DevTools.Assert.";
116+
}
117+
}
118+
private static uint CountSubstrings(string instance, string value)
119+
{
120+
Assert.IsFalse(string.IsNullOrEmpty(value));
121+
122+
uint count = 0;
123+
int index = instance.IndexOf(value);
124+
while (index != -1 & index < instance.Length)
125+
{
126+
count++;
127+
index = instance.IndexOf(value, index + value.Length);
128+
}
129+
130+
return count;
131+
}
132+
private static List<Task<Dictionary<Assert.GroupAttribute, ulong>>> CreateCountingTasks(Dictionary<MethodInfo, Assert.GroupAttribute> methodToGroupMap, string path)
133+
{
134+
List<Task<Dictionary<Assert.GroupAttribute, ulong>>> tasks = new List<Task<Dictionary<Assert.GroupAttribute, ulong>>>(256);
135+
136+
DirectoryExtensions.ForEachFile(path,
137+
(file) =>
138+
{
139+
if (Path.GetExtension(file) != ".cs")
140+
{
141+
return;
142+
}
143+
144+
tasks.Add(Task<Dictionary<Assert.GroupAttribute, ulong>>.Factory.StartNew(
145+
() =>
146+
{
147+
Dictionary<Assert.GroupAttribute, ulong> callCounts = new Dictionary<Assert.GroupAttribute, ulong>();
148+
string script = File.ReadAllText(file);
149+
string prefix = GetMethodPrefixFromUsingStatements(script);
150+
151+
foreach (KeyValuePair<MethodInfo, Assert.GroupAttribute> methodMapping in methodToGroupMap)
152+
{
153+
Assert.GroupAttribute group = methodMapping.Value;
154+
ulong numCalls = CountSubstrings(script, prefix + methodMapping.Key.Name);
155+
156+
if (callCounts.ContainsKey(group))
157+
{
158+
callCounts[group] += numCalls;
159+
}
160+
else
161+
{
162+
callCounts.Add(group, numCalls);
163+
}
164+
}
165+
166+
return callCounts;
167+
}));
168+
});
169+
170+
return tasks;
171+
}
172+
private static async Task<Dictionary<Assert.GroupAttribute, ulong>> CombineResults(List<Task<Dictionary<Assert.GroupAttribute, ulong>>> jobs, Dictionary<MethodInfo, Assert.GroupAttribute> methodToGroupMap)
173+
{
174+
Dictionary<Assert.GroupAttribute, ulong> result = await jobs[0]; // at the very least this very script is assigned a job
175+
176+
for (int i = 1; i < jobs.Count; i++)
177+
{
178+
foreach (KeyValuePair<Assert.GroupAttribute, ulong> callCount in await jobs[i])
179+
{
180+
result[callCount.Key] += callCount.Value;
181+
}
182+
}
183+
184+
return result;
185+
}
186+
}
187+
}
188+
}

Assert.Group.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)