-
Notifications
You must be signed in to change notification settings - Fork 36
/
HitContext.cs
133 lines (118 loc) · 4.04 KB
/
HitContext.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
namespace MiniCover.HitServices
{
public class HitContext
{
private static readonly AsyncLocal<HitContext> _currentAsyncLocal = new AsyncLocal<HitContext>();
public static HitContext Current
{
get => _currentAsyncLocal.Value;
set => _currentAsyncLocal.Value = value;
}
private int _methodCount;
public HitContext(
string assemblyName,
string className,
string methodName,
IDictionary<int, int> hits = null)
{
Id = Guid.NewGuid().ToString();
AssemblyName = assemblyName;
ClassName = className;
MethodName = methodName;
Hits = hits != null
? new Dictionary<int, int>(hits)
: new Dictionary<int, int>();
}
public string Id { get; }
public string AssemblyName { get; }
public string ClassName { get; }
public string MethodName { get; }
public IDictionary<int, int> Hits { get; }
public void RecordHit(int id)
{
if (Hits.TryGetValue(id, out var count))
{
Hits[id] = count + 1;
}
else
{
Hits[id] = 1;
}
}
public int GetHitCount(int id)
{
if (!Hits.TryGetValue(id, out var count))
return 0;
return count;
}
public static IEnumerable<HitContext> MergeDuplicates(IEnumerable<HitContext> source)
{
return source
.GroupBy(h => new { h.AssemblyName, h.ClassName, h.MethodName })
.Select(g => new HitContext(
g.Key.AssemblyName,
g.Key.ClassName,
g.Key.MethodName,
g.SelectMany(m => m.Hits)
.GroupBy(kv => kv.Key)
.ToDictionary(g2 => g2.Key, g2 => g2.Sum(kv => kv.Value))
)).ToArray();
}
public int EnterMethod()
{
return Interlocked.Increment(ref _methodCount);
}
public int ExitMethod()
{
return Interlocked.Decrement(ref _methodCount);
}
public void Serialize(Stream stream)
{
using (var binaryWriter = new BinaryWriter(stream, Encoding.UTF8, true))
{
binaryWriter.Write(ClassName);
binaryWriter.Write(MethodName);
binaryWriter.Write(AssemblyName);
binaryWriter.Write(Hits.Count);
foreach (var hitedInstruction in Hits)
{
binaryWriter.Write(hitedInstruction.Key);
binaryWriter.Write(hitedInstruction.Value);
}
}
}
public static IEnumerable<HitContext> Deserialize(Stream stream)
{
var result = new List<HitContext>();
using (var binaryReader = new BinaryReader(stream, Encoding.UTF8))
{
while (stream.Position < stream.Length)
{
result.Add(Read(binaryReader));
}
}
return result;
}
public static HitContext Read(BinaryReader binaryReader)
{
var className = binaryReader.ReadString();
var methodName = binaryReader.ReadString();
var assemblyName = binaryReader.ReadString();
var hitsCount = binaryReader.ReadInt32();
var hits = new Dictionary<int, int>();
for (int i = 0; i < hitsCount; i++)
{
var instructionId = binaryReader.ReadInt32();
var instructionHit = binaryReader.ReadInt32();
hits.Add(instructionId, instructionHit);
}
return new HitContext(assemblyName, className, methodName, hits);
}
}
}