Skip to content

Commit fbb1a7e

Browse files
committed
Code added for emit_coverage
1 parent 8e1ea42 commit fbb1a7e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2829
-1320
lines changed

Ext/P_FileTypeSettings_Intellij.zip

-1.56 KB
Binary file not shown.

Src/PChecker/CheckerCore/CheckerConfiguration.cs

Lines changed: 23 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -194,43 +194,22 @@ public int MaxSchedulingSteps
194194
public bool ReportCodeCoverage;
195195

196196
/// <summary>
197-
/// Enables activity coverage reporting of a program.
197+
/// Enables code coverage tracking from emit_coverage statements.
198198
/// </summary>
199199
[DataMember]
200-
public bool ReportActivityCoverage { get; set; }
200+
public bool EnableEmitCoverage;
201201

202202
/// <summary>
203-
/// Enables activity coverage debugging.
204-
/// </summary>
205-
public bool DebugActivityCoverage;
206-
207-
/// <summary>
208-
/// Is DGML graph showing all test schedules or just one "bug" schedule.
209-
/// False means all, and True means only the schedule containing a bug.
210-
/// </summary>
211-
[DataMember]
212-
public bool IsDgmlBugGraph;
213-
214-
215-
/// <summary>
216-
/// Produce an XML formatted runtime log file.
217-
/// </summary>
218-
[DataMember]
219-
public bool IsXmlLogEnabled { get; set; }
220-
221-
/// <summary>
222-
/// Produce a JSON formatted runtime log file.
223-
/// Defaults to true.
203+
/// Path to store the code coverage report from emit_coverage statements.
224204
/// </summary>
225205
[DataMember]
226-
public bool IsJsonLogEnabled { get; set; } = true;
206+
public string EmitCoverageReportPath;
227207

228208
/// <summary>
229-
/// If specified, requests a custom runtime log to be used instead of the default.
230-
/// This is the AssemblyQualifiedName of the type to load.
209+
/// Enables CSV output for code coverage metrics from emit_coverage statements.
231210
/// </summary>
232211
[DataMember]
233-
public string CustomStateMachineRuntimeLogType;
212+
public bool EmitCoverageCsvOutput;
234213

235214
/// <summary>
236215
/// Enables debugging.
@@ -251,13 +230,6 @@ public int MaxSchedulingSteps
251230
[DataMember]
252231
public uint TestingProcessId;
253232

254-
/// <summary>
255-
/// Additional assembly specifications to instrument for code coverage, besides those in the
256-
/// dependency graph between <see cref="AssemblyToBeAnalyzed"/> and the Microsoft.Coyote DLLs.
257-
/// Key is filename, value is whether it is a list file (true) or a single file (false).
258-
/// </summary>
259-
public Dictionary<string, bool> AdditionalCodeCoverageAssemblies;
260-
261233
/// <summary>
262234
/// Enables colored console output.
263235
/// </summary>
@@ -317,8 +289,9 @@ protected CheckerConfiguration()
317289
ScheduleTrace = string.Empty;
318290

319291
ReportCodeCoverage = false;
320-
ReportActivityCoverage = true;
321-
DebugActivityCoverage = false;
292+
EnableEmitCoverage = false;
293+
EmitCoverageReportPath = "code-coverage.txt";
294+
EmitCoverageCsvOutput = false;
322295

323296
IsVerbose = false;
324297
EnableDebugging = false;
@@ -481,22 +454,21 @@ public CheckerConfiguration WithVerbosityEnabled(bool isVerbose = true)
481454
}
482455

483456
/// <summary>
484-
/// Updates the checkerConfiguration with activity coverage enabled or disabled.
457+
/// Updates the checkerConfiguration with emit_coverage tracking enabled or disabled.
485458
/// </summary>
486-
/// <param name="isEnabled">If true, then enables activity coverage.</param>
487-
public CheckerConfiguration WithActivityCoverageEnabled(bool isEnabled = true)
459+
/// <param name="isEnabled">If true, then enables emit_coverage tracking.</param>
460+
/// <param name="reportPath">Path to the code coverage report file.</param>
461+
/// <param name="generateCsv">If true, generates a CSV format report in addition to the text report.</param>
462+
public CheckerConfiguration WithEmitCoverageEnabled(bool isEnabled = true, string reportPath = null, bool generateCsv = false)
488463
{
489-
ReportActivityCoverage = isEnabled;
490-
return this;
491-
}
492-
493-
/// <summary>
494-
/// Updates the checkerConfiguration with XML log generation enabled or disabled.
495-
/// </summary>
496-
/// <param name="isEnabled">If true, then enables XML log generation.</param>
497-
public CheckerConfiguration WithXmlLogEnabled(bool isEnabled = true)
498-
{
499-
IsXmlLogEnabled = isEnabled;
464+
EnableEmitCoverage = isEnabled;
465+
466+
if (reportPath != null)
467+
{
468+
EmitCoverageReportPath = reportPath;
469+
}
470+
471+
EmitCoverageCsvOutput = generateCsv;
500472
return this;
501473
}
502474

@@ -544,4 +516,4 @@ public void SetOutputDirectory()
544516
}
545517
}
546518
#pragma warning restore CA1724 // Type names should not match namespaces
547-
}
519+
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Linq;
8+
using System.Runtime.Serialization;
9+
using System.Xml;
10+
using System.Threading;
11+
12+
namespace PChecker.Coverage.Code
13+
{
14+
/// <summary>
15+
/// Tracks code coverage information emitted during program execution.
16+
/// </summary>
17+
[DataContract]
18+
public class CodeCoverage
19+
{
20+
/// <summary>
21+
/// Singleton instance of the CodeCoverage class.
22+
/// </summary>
23+
private static readonly Lazy<CodeCoverage> _instance = new Lazy<CodeCoverage>(() => new CodeCoverage());
24+
25+
/// <summary>
26+
/// Gets the singleton instance of the CodeCoverage class.
27+
/// </summary>
28+
public static CodeCoverage Instance => _instance.Value;
29+
30+
/// <summary>
31+
/// Dictionary mapping coverage information to the count of times it was hit.
32+
/// </summary>
33+
[DataMember]
34+
private readonly Dictionary<CodeCoverageInfo, int> CoverageCounter = new Dictionary<CodeCoverageInfo, int>();
35+
36+
/// <summary>
37+
/// Records a coverage metric emitted from code execution.
38+
/// </summary>
39+
/// <param name="label">User-provided label.</param>
40+
/// <param name="codeLocation">Location in code where metric was emitted.</param>
41+
/// <param name="customPayload">Custom payload data.</param>
42+
public void RecordCoverageMetric(string label, string codeLocation, string customPayload)
43+
{
44+
var info = new CodeCoverageInfo(label, codeLocation, customPayload);
45+
46+
if (CoverageCounter.TryGetValue(info, out int count))
47+
{
48+
CoverageCounter[info] = count + 1;
49+
}
50+
else
51+
{
52+
CoverageCounter[info] = 1;
53+
}
54+
}
55+
56+
/// <summary>
57+
/// Gets all recorded coverage metrics and their counts.
58+
/// </summary>
59+
/// <returns>A collection of coverage metrics and their counts.</returns>
60+
public IEnumerable<KeyValuePair<CodeCoverageInfo, int>> GetAllMetrics() => CoverageCounter;
61+
62+
/// <summary>
63+
/// Gets the count for a specific coverage metric.
64+
/// </summary>
65+
/// <param name="label">The label of the metric.</param>
66+
/// <param name="codeLocation">The code location of the metric.</param>
67+
/// <param name="customPayload">The custom payload of the metric.</param>
68+
/// <returns>The number of times the metric was hit, or 0 if it was not hit.</returns>
69+
public int GetMetricCount(string label, string codeLocation, string customPayload)
70+
{
71+
var info = new CodeCoverageInfo(label, codeLocation, customPayload);
72+
return GetMetricCount(info);
73+
}
74+
75+
/// <summary>
76+
/// Gets the count for a specific coverage metric.
77+
/// </summary>
78+
/// <param name="info">The coverage info to query.</param>
79+
/// <returns>The number of times the metric was hit, or 0 if it was not hit.</returns>
80+
public int GetMetricCount(CodeCoverageInfo info)
81+
{
82+
return CoverageCounter.TryGetValue(info, out int count) ? count : 0;
83+
}
84+
85+
/// <summary>
86+
/// Gets the total number of unique coverage points that were hit.
87+
/// </summary>
88+
public int UniquePointsCount => CoverageCounter.Count;
89+
90+
/// <summary>
91+
/// Gets the total number of coverage hits across all metrics.
92+
/// </summary>
93+
public int TotalHitsCount => CoverageCounter.Values.Sum();
94+
95+
/// <summary>
96+
/// Gets all coverage metrics with a specific label.
97+
/// </summary>
98+
/// <param name="label">The label to filter by.</param>
99+
/// <returns>A collection of coverage metrics with the specified label.</returns>
100+
public IEnumerable<KeyValuePair<CodeCoverageInfo, int>> GetMetricsByLabel(string label)
101+
{
102+
return CoverageCounter.Where(pair => pair.Key.Label == label);
103+
}
104+
105+
/// <summary>
106+
/// Gets all coverage metrics for a specific code location.
107+
/// </summary>
108+
/// <param name="codeLocation">The code location to filter by.</param>
109+
/// <returns>A collection of coverage metrics for the specified code location.</returns>
110+
public IEnumerable<KeyValuePair<CodeCoverageInfo, int>> GetMetricsByLocation(string codeLocation)
111+
{
112+
return CoverageCounter.Where(pair => pair.Key.CodeLocation == codeLocation);
113+
}
114+
115+
/// <summary>
116+
/// Merges another CodeCoverage instance into this one.
117+
/// </summary>
118+
/// <param name="other">The other CodeCoverage instance to merge.</param>
119+
public void Merge(CodeCoverage other)
120+
{
121+
if (other == null) return;
122+
123+
foreach (var pair in other.CoverageCounter)
124+
{
125+
if (CoverageCounter.TryGetValue(pair.Key, out int count))
126+
{
127+
CoverageCounter[pair.Key] = count + pair.Value;
128+
}
129+
else
130+
{
131+
CoverageCounter[pair.Key] = pair.Value;
132+
}
133+
}
134+
}
135+
136+
/// <summary>
137+
/// Save the coverage info to the given XML file.
138+
/// </summary>
139+
/// <param name="filePath">The path to the file to create.</param>
140+
public void Save(string filePath)
141+
{
142+
using var fs = new FileStream(filePath, FileMode.Create);
143+
var settings = new DataContractSerializerSettings
144+
{
145+
PreserveObjectReferences = true
146+
};
147+
var ser = new DataContractSerializer(typeof(CodeCoverage), settings);
148+
ser.WriteObject(fs, this);
149+
}
150+
151+
/// <summary>
152+
/// Load the given Coverage info file.
153+
/// </summary>
154+
/// <param name="filePath">Path to the file to load.</param>
155+
/// <returns>The deserialized coverage info.</returns>
156+
public static CodeCoverage Load(string filePath)
157+
{
158+
using var fs = new FileStream(filePath, FileMode.Open);
159+
using var reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
160+
var settings = new DataContractSerializerSettings
161+
{
162+
PreserveObjectReferences = true
163+
};
164+
var ser = new DataContractSerializer(typeof(CodeCoverage), settings);
165+
return (CodeCoverage)ser.ReadObject(reader, true);
166+
}
167+
168+
/// <summary>
169+
/// Clears all coverage data.
170+
/// </summary>
171+
public void Clear()
172+
{
173+
CoverageCounter.Clear();
174+
}
175+
}
176+
}

0 commit comments

Comments
 (0)