Created unity project

This commit is contained in:
2024-12-07 20:55:50 +01:00
parent 539250d964
commit 54fe327198
13758 changed files with 865324 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2b5c29f7e37f22e4c8d285687af72aa3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,228 @@
// #define COVERAGE_ANALYTICS_LOGGING
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.TestTools.CodeCoverage.Utils;
using UnityEngine;
using UnityEngine.Analytics;
namespace UnityEditor.TestTools.CodeCoverage.Analytics
{
[Serializable]
internal class Timer
{
public void Start()
{
startTime = DateTime.Now;
}
public long elapsedTimeMs => (long)(DateTime.Now - startTime).TotalMilliseconds;
[SerializeField]
private DateTime startTime = DateTime.Now;
}
[Serializable]
internal class CoverageAnalytics : ScriptableSingleton<CoverageAnalytics>
{
[SerializeField]
private bool s_Registered;
[SerializeField]
private List<int> s_ResultsIdsList;
public CoverageAnalyticsEvent CurrentCoverageEvent;
public Timer CoverageTimer;
protected CoverageAnalytics() : base()
{
ResetEvents();
}
public void ResetEvents()
{
CurrentCoverageEvent = new CoverageAnalyticsEvent();
CoverageTimer = new Timer();
s_ResultsIdsList = new List<int>();
CurrentCoverageEvent.actionID = ActionID.Other;
CurrentCoverageEvent.coverageModeId = CoverageModeID.None;
CurrentCoverageEvent.numOfIncludedPaths = 0;
CurrentCoverageEvent.numOfExcludedPaths = 0;
}
public void StartTimer()
{
CoverageTimer.Start();
}
// See ResultsLogger.cs for details
public void AddResult(ResultID resultId)
{
s_ResultsIdsList.Add((int)resultId);
}
public void SendCoverageEvent(bool success)
{
CurrentCoverageEvent.success = success;
CurrentCoverageEvent.duration = CoverageTimer.elapsedTimeMs;
CurrentCoverageEvent.resultIds = s_ResultsIdsList.ToArray();
bool runFromCommandLine = CommandLineManager.instance.runFromCommandLine;
bool batchmode = CommandLineManager.instance.batchmode;
bool useProjectSettings = CommandLineManager.instance.useProjectSettings;
CurrentCoverageEvent.runFromCommandLine = runFromCommandLine;
CurrentCoverageEvent.batchmode = batchmode;
CurrentCoverageEvent.useProjectSettings = useProjectSettings;
if (batchmode && !useProjectSettings)
{
CurrentCoverageEvent.autogenerate = CommandLineManager.instance.generateBadgeReport || CommandLineManager.instance.generateHTMLReport || CommandLineManager.instance.generateAdditionalReports;
CurrentCoverageEvent.createBadges = CommandLineManager.instance.generateBadgeReport;
CurrentCoverageEvent.generateHistory = CommandLineManager.instance.generateHTMLReportHistory;
CurrentCoverageEvent.generateHTMLReport = CommandLineManager.instance.generateHTMLReport;
CurrentCoverageEvent.generateMetrics = CommandLineManager.instance.generateAdditionalMetrics;
CurrentCoverageEvent.generateTestReferences = CommandLineManager.instance.generateTestReferences;
CurrentCoverageEvent.generateAdditionalReports = CommandLineManager.instance.generateAdditionalReports;
CurrentCoverageEvent.dontClear = CommandLineManager.instance.dontClear;
CurrentCoverageEvent.useDefaultAssemblyFilters = !CommandLineManager.instance.assemblyFiltersSpecified;
CurrentCoverageEvent.useDefaultPathFilters = !CommandLineManager.instance.pathFiltersSpecified;
CurrentCoverageEvent.useDefaultResultsLoc = CommandLineManager.instance.coverageResultsPath.Length == 0;
CurrentCoverageEvent.useDefaultHistoryLoc = CommandLineManager.instance.coverageHistoryPath.Length == 0;
CurrentCoverageEvent.usePathReplacePatterns = CommandLineManager.instance.pathReplacingSpecified;
CurrentCoverageEvent.useSourcePaths = CommandLineManager.instance.sourcePathsSpecified;
CurrentCoverageEvent.usePathFiltersFromFile = CommandLineManager.instance.pathFiltersFromFileSpecified;
CurrentCoverageEvent.useAssemblyFiltersFromFile = CommandLineManager.instance.assemblyFiltersFromFileSpecified;
}
else
{
CurrentCoverageEvent.autogenerate = CommandLineManager.instance.generateBadgeReport || CommandLineManager.instance.generateHTMLReport || CommandLineManager.instance.generateAdditionalReports || CoveragePreferences.instance.GetBool("AutoGenerateReport", true);
CurrentCoverageEvent.autoOpenReport = CoveragePreferences.instance.GetBool("OpenReportWhenGenerated", true);
CurrentCoverageEvent.createBadges = CommandLineManager.instance.generateBadgeReport || CoveragePreferences.instance.GetBool("GenerateBadge", true);
CurrentCoverageEvent.generateHistory = CommandLineManager.instance.generateHTMLReportHistory || CoveragePreferences.instance.GetBool("IncludeHistoryInReport", true);
CurrentCoverageEvent.generateHTMLReport = CommandLineManager.instance.generateHTMLReport || CoveragePreferences.instance.GetBool("GenerateHTMLReport", true);
CurrentCoverageEvent.generateMetrics = CommandLineManager.instance.generateAdditionalMetrics || CoveragePreferences.instance.GetBool("GenerateAdditionalMetrics", false);
CurrentCoverageEvent.generateTestReferences = CommandLineManager.instance.generateTestReferences || CoveragePreferences.instance.GetBool("GenerateTestReferences", false);
CurrentCoverageEvent.generateAdditionalReports = CommandLineManager.instance.generateAdditionalReports || CoveragePreferences.instance.GetBool("GenerateAdditionalReports", false);
CurrentCoverageEvent.dontClear = CommandLineManager.instance.dontClear;
CurrentCoverageEvent.usePathReplacePatterns = CommandLineManager.instance.pathReplacingSpecified;
CurrentCoverageEvent.useSourcePaths = CommandLineManager.instance.sourcePathsSpecified;
CurrentCoverageEvent.usePathFiltersFromFile = CommandLineManager.instance.pathFiltersFromFileSpecified;
CurrentCoverageEvent.useAssemblyFiltersFromFile = CommandLineManager.instance.assemblyFiltersFromFileSpecified;
CurrentCoverageEvent.useDefaultAssemblyFilters = !CommandLineManager.instance.assemblyFiltersSpecified;
if (!CommandLineManager.instance.assemblyFiltersSpecified)
CurrentCoverageEvent.useDefaultAssemblyFilters = string.Equals(CoveragePreferences.instance.GetString("IncludeAssemblies", AssemblyFiltering.GetUserOnlyAssembliesString()), AssemblyFiltering.GetUserOnlyAssembliesString(), StringComparison.InvariantCultureIgnoreCase);
CurrentCoverageEvent.useDefaultPathFilters = !CommandLineManager.instance.pathFiltersSpecified;
if (!CommandLineManager.instance.pathFiltersSpecified)
CurrentCoverageEvent.useDefaultPathFilters = string.Equals(CoveragePreferences.instance.GetString("PathsToInclude", string.Empty), string.Empty) && string.Equals(CoveragePreferences.instance.GetString("PathsToExclude", string.Empty), string.Empty);
CurrentCoverageEvent.useDefaultResultsLoc = CommandLineManager.instance.coverageResultsPath.Length == 0;
if (CommandLineManager.instance.coverageResultsPath.Length == 0)
CurrentCoverageEvent.useDefaultResultsLoc = string.Equals(CoveragePreferences.instance.GetStringForPaths("Path", string.Empty), CoverageUtils.GetProjectPath(), StringComparison.InvariantCultureIgnoreCase);
CurrentCoverageEvent.useDefaultHistoryLoc = CommandLineManager.instance.coverageHistoryPath.Length == 0;
if (CommandLineManager.instance.coverageHistoryPath.Length == 0)
CurrentCoverageEvent.useDefaultHistoryLoc = string.Equals(CoveragePreferences.instance.GetStringForPaths("HistoryPath", string.Empty), CoverageUtils.GetProjectPath(), StringComparison.InvariantCultureIgnoreCase);
}
#if UNITY_2020_1_OR_NEWER
CurrentCoverageEvent.inDebugMode = Compilation.CompilationPipeline.codeOptimization == Compilation.CodeOptimization.Debug;
#else
CurrentCoverageEvent.inDebugMode = true;
#endif
if (!runFromCommandLine || (runFromCommandLine && !batchmode && !CommandLineManager.instance.assemblyFiltersSpecified))
{
if (CurrentCoverageEvent.actionID == ActionID.ReportOnly)
{
string includeAssemblies = CoveragePreferences.instance.GetString("IncludeAssemblies", AssemblyFiltering.GetUserOnlyAssembliesString());
string[] includeAssembliesArray = includeAssemblies.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
CurrentCoverageEvent.includedAssemblies = includeAssembliesArray;
}
}
Send(EventName.codeCoverage, CurrentCoverageEvent);
ResetEvents();
}
public bool RegisterEvents()
{
if (!EditorAnalytics.enabled)
{
ResultsLogger.LogSessionItem("Editor analytics are disabled", LogVerbosityLevel.Info);
return false;
}
if (s_Registered)
{
return true;
}
var allNames = Enum.GetNames(typeof(EventName));
if (allNames.Any(eventName => !RegisterEvent(eventName)))
{
return false;
}
s_Registered = true;
return true;
}
private bool RegisterEvent(string eventName)
{
const string vendorKey = "unity.testtools.codecoverage";
var result = EditorAnalytics.RegisterEventWithLimit(eventName, 100, 1000, vendorKey);
switch (result)
{
case AnalyticsResult.Ok:
{
#if COVERAGE_ANALYTICS_LOGGING
ResultsLogger.LogSessionItem($"Registered analytics event: {eventName}", LogVerbosityLevel.Info);
#endif
return true;
}
case AnalyticsResult.TooManyRequests:
// this is fine - event registration survives domain reload (native)
return true;
default:
{
ResultsLogger.LogSessionItem($"Failed to register analytics event {eventName}. Result: {result}", LogVerbosityLevel.Error);
return false;
}
}
}
private void Send(EventName eventName, object eventData)
{
if (!RegisterEvents())
{
#if COVERAGE_ANALYTICS_LOGGING
Console.WriteLine($"[{CoverageSettings.PackageName}] Analytics disabled: event='{eventName}', time='{DateTime.Now:HH:mm:ss}', payload={EditorJsonUtility.ToJson(eventData, true)}");
#endif
return;
}
try
{
var result = EditorAnalytics.SendEventWithLimit(eventName.ToString(), eventData);
if (result == AnalyticsResult.Ok)
{
#if COVERAGE_ANALYTICS_LOGGING
ResultsLogger.LogSessionItem($"Event={eventName}, time={DateTime.Now:HH:mm:ss}, payload={EditorJsonUtility.ToJson(eventData, true)}", LogVerbosityLevel.Info);
#endif
}
else
{
ResultsLogger.LogSessionItem($"Failed to send analytics event {eventName}. Result: {result}", LogVerbosityLevel.Error);
}
}
catch (Exception)
{
// ignored
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 712896fdadbc6744585b09d9e159c025
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
namespace UnityEditor.TestTools.CodeCoverage.Analytics
{
internal enum EventName
{
codeCoverage
}
internal enum ActionID
{
Other = 0,
DataOnly = 1,
ReportOnly = 2,
DataReport = 3
}
internal enum CoverageModeID
{
None = 0,
TestRunner = 1,
Recording = 2
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f9bb904d2fa36b040bfc7c599e54c407
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,111 @@
using System;
namespace UnityEditor.TestTools.CodeCoverage.Analytics
{
[Serializable]
internal class CoverageAnalyticsEvent
{
// The action performed on the event (batchmode compatible)
public ActionID actionID;
// Array of resultsIds (batchmode compatible)
public int[] resultIds;
// The coverage mode that was performed on successful action (batchmode compatible)
public CoverageModeID coverageModeId;
// Duration (in ms) for which the Coverage session lasted (batchmode compatible)
public long duration;
// Was the coverage session result a success (batchmode compatible)
public bool success;
// Did the user run the editor from the command line
public bool runFromCommandLine;
// Did the user run the editor in batch mode
public bool batchmode;
// Did the user pass the useProjectSettings option in batch mode (batchmode only)
public bool useProjectSettings;
// Did the user have Generate HTML Report selected (batchmode compatible)
public bool generateHTMLReport;
// Did the user have Generate History selected (batchmode compatible)
public bool generateHistory;
// Did the user have Generate Badges selected (batchmode compatible)
public bool createBadges;
// Did the user have Generate Additional Metrics selected (batchmode compatible)
public bool generateMetrics;
// Did the user have Generate Test Runner References selected (batchmode compatible)
public bool generateTestReferences;
// Did the user have Generate Additional reports selected (batchmode compatible)
public bool generateAdditionalReports;
// Did the user have passed the dontClear coverage option (batchmode compatible)
public bool dontClear;
// Did the user have Auto Generate Report selected (batchmode compatible)
public bool autogenerate;
// Did the user have Auto Open Report selected
public bool autoOpenReport;
// Did the user select the Clear Data button
public bool clearData;
// Did the user select the Clear History button
public bool clearHistory;
// Did the user select the Generate From Last button
public bool generateFromLast;
// Did the user switch to Debug mode (Code Optimization) in the Coverage window
public bool switchToDebugMode;
// Is the editor in Code Optimization: Debug mode (batchmode compatible)
public bool inDebugMode;
// Did the user disable Burst Compilation in the Coverage window
public bool switchBurstOff;
// Did the user select a new Results location or uses the default one (batchmode compatible)
public bool useDefaultResultsLoc;
// Did the user select a new History location or uses the default one (batchmode compatible)
public bool useDefaultHistoryLoc;
// Did the user specify different assemblies from the default ones (batchmode compatible)
public bool useDefaultAssemblyFilters;
// Did the user specify different paths filtering from the default one (batchmode compatible)
public bool useDefaultPathFilters;
// Did the user enter the Selected Assemblies dialog/dropdown
public bool enterAssembliesDialog;
// Did the user update any assemblies via the Selected Assemblies dialog/dropdown
public bool updateAssembliesDialog;
// Did the user update Included Paths
public bool updateIncludedPaths;
// Did the user select Add Folder for Included Paths
public bool selectAddFolder_IncludedPaths;
// Did the user select Add File for Included Paths
public bool selectAddFile_IncludedPaths;
// How many paths are included (batchmode compatible)
public int numOfIncludedPaths;
// Did the user update Excluded Paths
public bool updateExcludedPaths;
// Did the user select Add Folder for Excluded Paths
public bool selectAddFolder_ExcludedPaths;
// Did the user select Add File for Excluded Paths
public bool selectAddFile_ExcludedPaths;
// How many paths are excluded (batchmode compatible)
public int numOfExcludedPaths;
// Did the user use the Coverage API to StartRecording (batchmode compatible)
public bool useAPI_StartRec;
// Did the user use the Coverage API to StopRecording (batchmode compatible)
public bool useAPI_StopRec;
// Did the user use the Coverage API to PauseRecording (batchmode compatible)
public bool useAPI_PauseRec;
// Did the user use the Coverage API to UnpauseRecording (batchmode compatible)
public bool useAPI_UnpauseRec;
// Array of individual included assembly names (batchmode compatible)
public string[] includedAssemblies;
// Array of individual excluded assembly names (batchmode only)
public string[] excludedAssemblies;
// Did the user use the onCoverageSessionStarted event (batchmode compatible)
public bool useEvent_onCoverageSessionStarted;
// Did the user use the onCoverageSessionFinished event (batchmode compatible)
public bool useEvent_onCoverageSessionFinished;
// Did the user use the onCoverageSessionPaused event (batchmode compatible)
public bool useEvent_onCoverageSessionPaused;
// Did the user use the onCoverageSessionUnpaused event (batchmode compatible)
public bool useEvent_onCoverageSessionUnpaused;
// Did the user specify path replace patterns (command line only)
public bool usePathReplacePatterns;
// Did the user specify source paths (command line only)
public bool useSourcePaths;
// Did the user specify path filters from file option (command line only)
public bool usePathFiltersFromFile;
// Did the user specify assembly filters from file option (command line only)
public bool useAssemblyFiltersFromFile;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7ab5c92c8c1059a4e92378da3696821e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Unity.TestTools.CodeCoverage.Editor.Tests")]
[assembly: InternalsVisibleTo("Unity.TestTools.CodeCoverage.Editor.Tests.Performance")]
[assembly: InternalsVisibleTo("Unity.TestTools.CodeCoverage.Editor.CoverageStatsSerializer")]

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b5f6a9c343f474407aa9c6096dea2d0c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,58 @@
{
"name": "Unity.TestTools.CodeCoverage.Editor",
"rootNamespace": "UnityEditor.TestTools.CodeCoverage",
"references": [
"GUID:27619889b8ba8c24980f49ee34dbb44a",
"GUID:0acc523941302664db1f4e527237feb3",
"GUID:19c3df1967929405fba735480b3da9a7",
"GUID:eecdf9bdfcb2949619db458f3e24c5e2",
"GUID:49818357e697641afb75d2f8acaf1861"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll",
"ReportGeneratorMerged.dll"
],
"autoReferenced": true,
"defineConstraints": [
"UNITY_2019_2_OR_NEWER"
],
"versionDefines": [
{
"name": "com.unity.test-framework",
"expression": "1.0.16",
"define": "CONDITIONAL_IGNORE_SUPPORTED"
},
{
"name": "com.unity.burst",
"expression": "1.1.1",
"define": "BURST_INSTALLED"
},
{
"name": "com.unity.test-framework",
"expression": "1.1.18",
"define": "TEST_FRAMEWORK_1_1_18_OR_NEWER"
},
{
"name": "Unity",
"expression": "2021.1.0b10",
"define": "NO_COV_EDITORPREF"
},
{
"name": "com.unity.test-framework",
"expression": "1.3.0",
"define": "TEST_FRAMEWORK_1_3_OR_NEWER"
},
{
"name": "com.unity.test-framework",
"expression": "2.0.0",
"define": "TEST_FRAMEWORK_2_0_OR_NEWER"
}
],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 37180d43aa4b85c4b9076e2ef48a3b2a
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,196 @@
using UnityEditor.TestTools.CodeCoverage.Analytics;
using UnityEditor.TestTools.CodeCoverage.Utils;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.CodeCoverage
{
/// <summary>
/// Utility class for the CodeCoverage API.
/// </summary>
/// <example>
/// The following example loads a scene, starts coverage recording, initializes a number of instances of a prefab, then pauses the recording to load another scene, unpauses the recording, initializes a number of instances of a different prefab and finally stops the recording.
/// It also sets the verbosity level to Verbose, so all logs are printed to the editor log.
/// <code>
/// using UnityEngine;
/// using UnityEditor;
/// using UnityEditor.TestTools.CodeCoverage;
/// using UnityEditor.SceneManagement;
///
/// public class CoverageApiTest : MonoBehaviour
/// {
/// [MenuItem("CodeCoverage/Run Recording")]
/// static void RunRecording()
/// {
/// CodeCoverage.VerbosityLevel = LogVerbosityLevel.Verbose;
///
/// int i;
///
/// EditorSceneManager.OpenScene("Assets/Scenes/Scene1.unity");
///
/// CodeCoverage.StartRecording();
///
/// for (i = 0; i &lt; 1000; ++i)
/// {
/// Instantiate(Resources.Load("ComplexPrefab1"));
/// }
///
/// CodeCoverage.PauseRecording();
///
/// EditorSceneManager.OpenScene("Assets/Scenes/Scene2.unity");
///
/// CodeCoverage.UnpauseRecording();
///
/// for (i = 0; i &lt; 1000; ++i)
/// {
/// Instantiate(Resources.Load("ComplexPrefab2"));
/// }
///
/// CodeCoverage.StopRecording();
/// }
/// }
/// </code>
/// </example>
public static class CodeCoverage
{
private static CoverageReporterManager s_CoverageReporterManager;
/// <summary>
/// Sets the verbosity level used in editor and console logs. The default level is <see cref="LogVerbosityLevel.Info"/>.
/// </summary>
/// <value>
/// The verbosity level used in editor and console logs.
/// </value>
public static LogVerbosityLevel VerbosityLevel
{
set
{
ResultsLogger.VerbosityLevel = value;
}
get
{
return ResultsLogger.VerbosityLevel;
}
}
/// <summary>
/// Call this to start a new coverage recording session.
/// </summary>
public static void StartRecording()
{
CoverageAnalytics.instance.CurrentCoverageEvent.useAPI_StartRec = true;
StartRecordingInternal();
}
internal static void StartRecordingInternal()
{
bool isRunning = CoverageRunData.instance.isRunning;
if (!isRunning)
{
Coverage.ResetAll();
CoverageRunData.instance.StartRecording();
if (s_CoverageReporterManager == null)
s_CoverageReporterManager = CoverageReporterStarter.CoverageReporterManager;
s_CoverageReporterManager.CreateCoverageReporter();
ICoverageReporter coverageReporter = s_CoverageReporterManager.CoverageReporter;
if (coverageReporter != null)
coverageReporter.OnRunStarted(null);
}
}
/// <summary>
/// Call this to pause the recording on the current coverage recording session.
/// </summary>
public static void PauseRecording()
{
CoverageAnalytics.instance.CurrentCoverageEvent.useAPI_PauseRec = true;
PauseRecordingInternal();
}
internal static void PauseRecordingInternal()
{
bool isRunning = CoverageRunData.instance.isRunning;
if (isRunning)
{
if (CoverageRunData.instance.isRecording && !CoverageRunData.instance.isRecordingPaused)
{
if (s_CoverageReporterManager == null)
s_CoverageReporterManager = CoverageReporterStarter.CoverageReporterManager;
ICoverageReporter coverageReporter = s_CoverageReporterManager.CoverageReporter;
if (coverageReporter != null)
coverageReporter.OnCoverageRecordingPaused();
CoverageRunData.instance.PauseRecording();
}
}
}
/// <summary>
/// Call this to continue recording on the current coverage recording session, after having paused the recording.
/// </summary>
public static void UnpauseRecording()
{
CoverageAnalytics.instance.CurrentCoverageEvent.useAPI_UnpauseRec = true;
UnpauseRecordingInternal();
}
internal static void UnpauseRecordingInternal()
{
bool isRunning = CoverageRunData.instance.isRunning;
if (isRunning)
{
if (CoverageRunData.instance.isRecording && CoverageRunData.instance.isRecordingPaused)
{
Coverage.ResetAll();
CoverageRunData.instance.UnpauseRecording();
}
}
}
/// <summary>
/// Call this to end the current coverage recording session.
/// </summary>
public static void StopRecording()
{
CoverageAnalytics.instance.CurrentCoverageEvent.useAPI_StopRec = true;
StopRecordingInternal();
}
internal static void StopRecordingInternal()
{
bool isRunning = CoverageRunData.instance.isRunning;
if (isRunning)
{
if (CoverageRunData.instance.isRecording)
{
if (CoverageRunData.instance.isRecordingPaused)
Coverage.ResetAll();
if (s_CoverageReporterManager == null)
s_CoverageReporterManager = CoverageReporterStarter.CoverageReporterManager;
ICoverageReporter coverageReporter = s_CoverageReporterManager.CoverageReporter;
if (coverageReporter != null)
coverageReporter.OnRunFinished(null);
CoverageRunData.instance.StopRecording();
s_CoverageReporterManager.GenerateReport();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: baf0187acde1d4a4d8183adbd25f4941
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,679 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor.TestTools.CodeCoverage.CommandLineParser;
using UnityEditor.TestTools.CodeCoverage.Utils;
using UnityEngine;
namespace UnityEditor.TestTools.CodeCoverage
{
internal class CommandLineManager : CommandLineManagerImplementation
{
private static CommandLineManager s_Instance = null;
public static CommandLineManager instance
{
get
{
if (s_Instance == null)
s_Instance = new CommandLineManager();
return s_Instance;
}
}
protected CommandLineManager() : base(Environment.GetCommandLineArgs())
{
}
}
internal class CommandLineManagerImplementation
{
public bool runFromCommandLine
{
get;
private set;
}
public string coverageResultsPath
{
get;
private set;
}
public string coverageHistoryPath
{
get;
private set;
}
public bool generateAdditionalMetrics
{
get;
private set;
}
public bool generateTestReferences
{
get;
private set;
}
public bool generateHTMLReportHistory
{
get;
private set;
}
public bool generateHTMLReport
{
get;
private set;
}
public bool generateBadgeReport
{
get;
private set;
}
public bool generateAdditionalReports
{
get;
private set;
}
public bool useProjectSettings
{
get;
private set;
}
public bool generateRootEmptyReport
{
get;
private set;
}
public bool dontClear
{
get;
private set;
}
public bool verbosityLevelSpecified
{
get;
private set;
}
public bool assemblyFiltersSpecified
{
get;
private set;
}
public bool assemblyFiltersFromFileSpecified
{
get;
private set;
}
public bool pathFiltersSpecified
{
get;
private set;
}
public bool pathFiltersFromFileSpecified
{
get;
private set;
}
public bool pathReplacingSpecified
{
get;
private set;
}
public string sourcePaths
{
get;
private set;
}
public bool sourcePathsSpecified
{
get;
private set;
}
public AssemblyFiltering assemblyFiltering
{
get;
private set;
}
public PathFiltering pathFiltering
{
get;
private set;
}
public PathReplacing pathReplacing
{
get;
private set;
}
public bool runTests
{
get;
private set;
}
public bool batchmode
{
get;
private set;
}
public bool burstDisabled
{
get;
private set;
}
private string m_CoverageOptionsArg;
private string m_IncludeAssemblies;
private string m_ExcludeAssemblies;
private string m_IncludePaths;
private string m_ExcludePaths;
private string m_PathReplacePatterns;
public CommandLineManagerImplementation(string[] commandLineArgs)
{
runFromCommandLine = false;
coverageResultsPath = string.Empty;
coverageHistoryPath = string.Empty;
sourcePaths = string.Empty;
generateAdditionalMetrics = false;
generateTestReferences = false;
generateHTMLReportHistory = false;
generateHTMLReport = false;
generateBadgeReport = false;
generateAdditionalReports = false;
useProjectSettings = false;
generateRootEmptyReport = false;
dontClear = false;
verbosityLevelSpecified = false;
assemblyFiltersSpecified = false;
pathFiltersSpecified = false;
pathReplacingSpecified = false;
sourcePathsSpecified = false;
pathFiltersFromFileSpecified = false;
assemblyFiltering = new AssemblyFiltering();
pathFiltering = new PathFiltering();
pathReplacing = new PathReplacing();
runTests = false;
batchmode = false;
burstDisabled = false;
m_CoverageOptionsArg = string.Empty;
m_IncludeAssemblies = string.Empty;
m_ExcludeAssemblies = string.Empty;
m_IncludePaths = string.Empty;
m_ExcludePaths = string.Empty;
m_PathReplacePatterns = string.Empty;
CommandLineOptionSet optionSet = new CommandLineOptionSet(
new CommandLineOption("enableCodeCoverage", () => { runFromCommandLine = true; }),
new CommandLineOption("coverageResultsPath", filePathArg => { SetCoverageResultsPath(filePathArg); }),
new CommandLineOption("coverageHistoryPath", filePathArg => { SetCoverageHistoryPath(filePathArg); }),
new CommandLineOption("coverageOptions", optionsArg => { AddCoverageOptions(optionsArg); }),
new CommandLineOption("runTests", () => { runTests = true; }),
new CommandLineOption("batchmode", () => { batchmode = true; }),
new CommandLineOption("-burst-disable-compilation", () => { burstDisabled = true; })
);
optionSet.Parse(commandLineArgs);
ValidateCoverageResultsPath();
ValidateCoverageHistoryPath();
if (runFromCommandLine)
ParseCoverageOptions();
}
private void SetCoverageResultsPath(string filePathArg)
{
if (coverageResultsPath != string.Empty)
{
ResultsLogger.Log(ResultID.Warning_MultipleResultsPaths, coverageResultsPath);
}
else
{
if (filePathArg != null)
{
coverageResultsPath = CoverageUtils.NormaliseFolderSeparators(filePathArg);
}
}
}
private void ValidateCoverageResultsPath()
{
if (!CoverageUtils.EnsureFolderExists(coverageResultsPath))
coverageResultsPath = string.Empty;
}
private void SetCoverageHistoryPath(string filePathArg)
{
if (coverageHistoryPath != string.Empty)
{
ResultsLogger.Log(ResultID.Warning_MultipleHistoryPaths, coverageHistoryPath);
}
else
{
if (filePathArg != null)
{
coverageHistoryPath = CoverageUtils.NormaliseFolderSeparators(filePathArg);
}
}
}
private void ValidateCoverageHistoryPath()
{
if (!CoverageUtils.EnsureFolderExists(coverageHistoryPath))
coverageHistoryPath = string.Empty;
}
private void AddCoverageOptions(string coverageOptionsArg)
{
if (coverageOptionsArg != null)
{
coverageOptionsArg = coverageOptionsArg.Trim('\'');
if (coverageOptionsArg != string.Empty)
{
if (m_CoverageOptionsArg == string.Empty)
{
m_CoverageOptionsArg = coverageOptionsArg;
}
else
{
m_CoverageOptionsArg += ";";
m_CoverageOptionsArg += coverageOptionsArg;
}
}
}
}
private void ParseCoverageOptions()
{
// Make sure there is no trailing quotes at the end of the options
m_CoverageOptionsArg = m_CoverageOptionsArg.TrimEnd('"');
// 'sourcePaths' option is moved at the beginning to ensure it is handled first,
// since it may be needed for other options
var options = m_CoverageOptionsArg.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
if (options.Count > 1)
{
var sourcePath = options.FirstOrDefault(option => option.StartsWith("SOURCEPATHS:", StringComparison.InvariantCultureIgnoreCase));
if (sourcePath != null)
{
var sourcePathIndex = options.IndexOf(sourcePath);
var firstElement = options[0];
options[sourcePathIndex] = firstElement;
options[0] = sourcePath;
}
}
string[] coverageOptions = options.ToArray();
foreach (string optionArgsStr in coverageOptions)
{
if (optionArgsStr.Length == 0)
continue;
string optionName = optionArgsStr;
string optionArgs = string.Empty;
int indexOfColon = optionArgsStr.IndexOf(':');
if (indexOfColon > 0)
{
optionName = optionArgsStr.Substring(0, indexOfColon);
optionArgs = optionArgsStr.Substring(indexOfColon+1);
}
switch (optionName.ToUpperInvariant())
{
case "GENERATEADDITIONALMETRICS":
generateAdditionalMetrics = true;
break;
case "GENERATEHTMLREPORTHISTORY":
generateHTMLReportHistory = true;
break;
case "GENERATEHTMLREPORT":
generateHTMLReport = true;
break;
case "GENERATEBADGEREPORT":
generateBadgeReport = true;
break;
case "GENERATEADDITIONALREPORTS":
generateAdditionalReports = true;
break;
case "GENERATEROOTEMPTYREPORT":
generateRootEmptyReport = true;
break;
case "DONTCLEAR":
dontClear = true;
break;
case "GENERATETESTREFERENCES":
generateTestReferences = true;
break;
case "USEPROJECTSETTINGS":
if (batchmode)
useProjectSettings = true;
else
ResultsLogger.Log(ResultID.Warning_UseProjectSettingsNonBatchmode);
break;
case "VERBOSITY":
if (optionArgs.Length > 0)
{
verbosityLevelSpecified = true;
switch (optionArgs.ToUpperInvariant())
{
case "VERBOSE":
ResultsLogger.VerbosityLevel = LogVerbosityLevel.Verbose;
break;
case "INFO":
ResultsLogger.VerbosityLevel = LogVerbosityLevel.Info;
break;
case "WARNING":
ResultsLogger.VerbosityLevel = LogVerbosityLevel.Warning;
break;
case "ERROR":
ResultsLogger.VerbosityLevel = LogVerbosityLevel.Error;
break;
case "OFF":
ResultsLogger.VerbosityLevel = LogVerbosityLevel.Off;
break;
}
}
break;
case "ASSEMBLYFILTERS":
if (optionArgs.Length > 0)
{
assemblyFiltersSpecified = true;
string[] assemblyFilters = optionArgs.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
ParseAssemblyFilters(assemblyFilters);
}
break;
case "PATHFILTERSFROMFILE":
if (optionArgs.Length > 0)
{
pathFiltersFromFileSpecified = true;
ResultsLogger.Log(ResultID.Warning_PathFiltersFromFileDeprecation);
if (File.Exists(optionArgs))
{
try
{
ParsePathFilters( GetPathFiltersFromFile(optionArgs) );
}
catch (Exception e)
{
ResultsLogger.Log(ResultID.Warning_FailedToExtractPathFiltersFromFile, e.Message, optionArgs);
}
}
}
break;
case "PATHFILTERS":
if (optionArgs.Length > 0)
{
string[] pathFilters = optionArgs.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
ParsePathFilters(pathFilters);
}
break;
case "FILTERSFROMFILE":
if (optionArgs.Length > 0)
{
try
{
JsonFile jsonFile = GetFiltersFromFile(optionArgs);
if (jsonFile != null)
{
string[] pathFilters = ConvertToFilterArray(jsonFile.pathsInclude, jsonFile.pathsExclude);
if (pathFilters != null && pathFilters.Length > 0)
{
pathFiltersFromFileSpecified = true;
ParsePathFilters(pathFilters);
}
string[] assemblyFilters = ConvertToFilterArray(jsonFile.assembliesInclude, jsonFile.assembliesExclude);
if (assemblyFilters != null && assemblyFilters.Length > 0)
{
assemblyFiltersFromFileSpecified = true;
ParseAssemblyFilters(assemblyFilters);
}
}
}
catch (Exception e)
{
ResultsLogger.Log(ResultID.Warning_FailedToExtractFiltersFromFile, e.Message, optionArgs);
}
}
break;
case "PATHREPLACEPATTERNS":
if (optionArgs.Length > 0)
{
pathReplacingSpecified = true;
m_PathReplacePatterns = optionArgs;
}
break;
case "SOURCEPATHS":
if (optionArgs.Length > 0)
{
string[] rawSourcePaths = optionArgs.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < rawSourcePaths.Length; ++i)
{
if (sourcePaths.Length > 0)
sourcePaths += ",";
sourcePaths += CoverageUtils.NormaliseFolderSeparators(rawSourcePaths[i]);
}
if (sourcePaths.Length > 0)
sourcePathsSpecified = true;
}
break;
default:
ResultsLogger.Log(ResultID.Warning_UnknownCoverageOptionProvided, optionArgsStr);
break;
}
}
if (m_IncludeAssemblies.Length == 0)
{
// If there are no inlcudedAssemblies specified but there are includedPaths specified
// then include all project assemblies so path filtering can take precedence over assembly filtering,
// othewise if there are no includedPaths specified neither then inlcude just the user assemblies (found under the Assets folder)
if (m_IncludePaths.Length > 0)
m_IncludeAssemblies = AssemblyFiltering.GetAllProjectAssembliesString();
else
m_IncludeAssemblies = AssemblyFiltering.GetUserOnlyAssembliesString();
}
assemblyFiltering.Parse(m_IncludeAssemblies, m_ExcludeAssemblies);
pathFiltering.Parse(m_IncludePaths, m_ExcludePaths);
pathReplacing.Parse(m_PathReplacePatterns);
}
private void ParseAssemblyFilters(string[] assemblyFilters)
{
for (int i = 0; i < assemblyFilters.Length; ++i)
{
string filter = assemblyFilters[i];
string filterBody = filter.Length > 1 ? filter.Substring(1) : string.Empty;
if (filter.StartsWith("+", StringComparison.OrdinalIgnoreCase))
{
if (m_IncludeAssemblies.Length > 0)
m_IncludeAssemblies += ",";
if (filterBody.StartsWith("<", StringComparison.OrdinalIgnoreCase))
{
if (string.Equals(filterBody, AssemblyFiltering.kAssetsAlias, StringComparison.OrdinalIgnoreCase))
m_IncludeAssemblies += AssemblyFiltering.GetUserOnlyAssembliesString();
else if (string.Equals(filterBody, AssemblyFiltering.kAllAlias, StringComparison.OrdinalIgnoreCase))
m_IncludeAssemblies += AssemblyFiltering.GetAllProjectAssembliesString();
else if (string.Equals(filterBody, AssemblyFiltering.kPackagesAlias, StringComparison.OrdinalIgnoreCase))
m_IncludeAssemblies += AssemblyFiltering.GetPackagesOnlyAssembliesString();
else if (string.Equals(filterBody, AssemblyFiltering.kCoreAlias, StringComparison.OrdinalIgnoreCase))
m_IncludeAssemblies += AssemblyFiltering.kCoreAssemblies;
}
else
{
m_IncludeAssemblies += filterBody;
}
}
else if (filter.StartsWith("-", StringComparison.OrdinalIgnoreCase))
{
if (m_ExcludeAssemblies.Length > 0)
m_ExcludeAssemblies += ",";
if (filterBody.StartsWith("<", StringComparison.OrdinalIgnoreCase))
{
if (string.Equals(filterBody, AssemblyFiltering.kAssetsAlias, StringComparison.OrdinalIgnoreCase))
m_ExcludeAssemblies += AssemblyFiltering.GetUserOnlyAssembliesString();
else if (string.Equals(filterBody, AssemblyFiltering.kAllAlias, StringComparison.OrdinalIgnoreCase))
m_ExcludeAssemblies += AssemblyFiltering.GetAllProjectAssembliesString();
else if (string.Equals(filterBody, AssemblyFiltering.kPackagesAlias, StringComparison.OrdinalIgnoreCase))
m_ExcludeAssemblies += AssemblyFiltering.GetPackagesOnlyAssembliesString();
else if (string.Equals(filterBody, AssemblyFiltering.kCoreAlias, StringComparison.OrdinalIgnoreCase))
m_ExcludeAssemblies += AssemblyFiltering.kCoreAssemblies;
}
else
{
m_ExcludeAssemblies += filterBody;
}
}
else
{
ResultsLogger.Log(ResultID.Warning_AssemblyFiltersNotPrefixed, filter);
}
}
}
private void ParsePathFilters(string[] pathFilters)
{
var sources = new string[0];
if (sourcePathsSpecified)
sources = sourcePaths.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < pathFilters.Length; ++i)
{
string filter = pathFilters[i];
string filterBody = filter.Length > 1 ? filter.Substring(1) : string.Empty;
var isRelative = !filterBody.StartsWith("*") && !filterBody.StartsWith("?") && string.IsNullOrEmpty(Path.GetPathRoot(filterBody));
//If current path is relative - expand it to an absolute path using specified source paths
if (isRelative && sourcePathsSpecified)
{
string expandedPaths = string.Empty;
foreach (var source in sources)
{
if (expandedPaths.Length > 0)
expandedPaths += ",";
expandedPaths += CoverageUtils.NormaliseFolderSeparators(Path.Combine(source, filterBody));
}
filterBody = expandedPaths;
}
if (filter.StartsWith("+", StringComparison.OrdinalIgnoreCase))
{
if (m_IncludePaths.Length > 0)
m_IncludePaths += ",";
m_IncludePaths += filterBody;
}
else if (filter.StartsWith("-", StringComparison.OrdinalIgnoreCase))
{
if (m_ExcludePaths.Length > 0)
m_ExcludePaths += ",";
m_ExcludePaths += filterBody;
}
else
{
ResultsLogger.Log(ResultID.Warning_PathFiltersNotPrefixed, filter);
}
}
if (m_IncludePaths.Length > 0 || m_ExcludePaths.Length > 0)
pathFiltersSpecified = true;
}
internal string[] GetPathFiltersFromFile(string path)
{
var paths = new List<string>();
foreach (var line in File.ReadAllLines(path))
{
var entry = line.Trim();
paths.Add(CoverageUtils.NormaliseFolderSeparators(entry));
}
return paths.ToArray();
}
internal JsonFile GetFiltersFromFile(string path)
{
string jsonString = JsonUtils.CleanJsonString(File.ReadAllText(path));
JsonUtils.ValidateJsonKeys(jsonString);
JsonFile jsonFile = JsonUtility.FromJson<JsonFile>(jsonString);
return jsonFile;
}
internal string[] ConvertToFilterArray(string[] include, string[] exclude)
{
var filtersList = new List<string>();
if (include != null && include.Length > 0)
{
foreach (var filter in include)
{
filtersList.Add($"+{filter}");
}
}
if (exclude != null && exclude.Length > 0)
{
foreach (var filter in exclude)
{
filtersList.Add($"-{filter}");
}
}
return filtersList.ToArray();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3d1e5d1da297ded489d27da1867372cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a4d2c6ec2b0608f4d915bdae931a5561
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,45 @@
using System;
using System.Linq;
namespace UnityEditor.TestTools.CodeCoverage.CommandLineParser
{
internal class CommandLineOption : ICommandLineOption
{
readonly Action<string> m_ArgAction;
public CommandLineOption(string argName, Action action)
{
ArgName = argName;
m_ArgAction = s => action();
}
public CommandLineOption(string argName, Action<string> action)
{
ArgName = argName;
m_ArgAction = action;
}
public CommandLineOption(string argName, Action<string[]> action)
{
ArgName = argName;
m_ArgAction = s => action(SplitStringToArray(s));
}
public string ArgName { get; private set; }
public void ApplyValue(string value)
{
m_ArgAction(value);
}
static string[] SplitStringToArray(string value)
{
if (string.IsNullOrEmpty(value))
{
return new string[] { };
}
return value.Split(';').ToArray();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b33e1d48774f68f479218e97f4ca4a8e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
using System;
namespace UnityEditor.TestTools.CodeCoverage.CommandLineParser
{
internal class CommandLineOptionSet
{
readonly ICommandLineOption[] m_Options;
public CommandLineOptionSet(params ICommandLineOption[] options)
{
m_Options = options;
}
public void Parse(string[] args)
{
var i = 0;
while (i < args.Length)
{
var arg = args[i];
if (!arg.StartsWith("-"))
{
i++;
continue;
}
string value = null;
if (i + 1 < args.Length && !args[i + 1].StartsWith("-"))
{
value = args[i + 1];
i++;
}
ApplyValueToMatchingOptions(arg, value);
i++;
}
}
private void ApplyValueToMatchingOptions(string argName, string value)
{
foreach (var option in m_Options)
{
if ("-" + option.ArgName == argName)
{
option.ApplyValue(value);
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 99c7f651b61814e4fbfa07eaa1457453
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
namespace UnityEditor.TestTools.CodeCoverage.CommandLineParser
{
interface ICommandLineOption
{
string ArgName { get; }
void ApplyValue(string value);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8e6a21b19469f7743953f66cd419decc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8760551a767291a4f9d72703986de775
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
{
"name": "Unity.TestTools.CodeCoverage.Editor.Compatibility",
"references": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [
"!UNITY_2019_2_OR_NEWER"
],
"versionDefines": []
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5518f4bf96c8e9849ab65cbaaf1191e1
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
using UnityEngine;
namespace UnityEditor.TestTools.CodeCoverage
{
[InitializeOnLoad]
internal class CompatibilityInitializer
{
static CompatibilityInitializer()
{
Debug.LogError("[Code Coverage] The Code Coverage package is not compatible with versions of Unity earlier than 2019.2.");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ae5c3e58418ef514eba4fc6ade0ec75b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8502d38e600753d44a2a65242d06f132
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
namespace UnityEditor.TestTools.CodeCoverage
{
internal enum CoverageFormat
{
OpenCover = 0,
DotCover = 1
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8419585fc64d77e4d8e18b7311df59a7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 401e5b541d6e30e489f5751eec729fab
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,158 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using Mono.Reflection;
namespace UnityEditor.TestTools.CodeCoverage.OpenCover
{
internal static class CyclomaticComplexity
{
private static List<Instruction> targets = new List<Instruction>();
public static int CalculateCyclomaticComplexity(this MethodBase method)
{
if (method == null || method.GetMethodBody() == null)
{
return 1;
}
bool hasSwitch = false;
foreach (Instruction ins in method.GetInstructions())
{
if (ins.OpCode.OperandType == OperandType.InlineSwitch)
{
hasSwitch = true;
break;
}
}
if (hasSwitch)
{
return GetSwitchCyclomaticComplexity(method);
}
return GetFastCyclomaticComplexity(method);
}
private static int GetFastCyclomaticComplexity(MethodBase method)
{
int cc = 1;
foreach (Instruction ins in method.GetInstructions())
{
switch (ins.OpCode.FlowControl)
{
case FlowControl.Branch:
// detect ternary pattern
Instruction previous = ins.Previous;
if (previous != null && previous.OpCode.Name.StartsWith("ld"))
{
++cc;
}
break;
case FlowControl.Cond_Branch:
++cc;
break;
}
}
return cc;
}
private static int GetSwitchCyclomaticComplexity(MethodBase method)
{
Instruction previous = null;
Instruction branch = null;
int cc = 1;
foreach (Instruction ins in method.GetInstructions())
{
switch (ins.OpCode.FlowControl)
{
case FlowControl.Branch:
if (previous == null)
{
continue;
}
// detect ternary pattern
previous = ins.Previous;
if (previous.OpCode.Name.StartsWith("ld"))
{
cc++;
}
// or 'default' (xmcs)
if (previous.OpCode.FlowControl == FlowControl.Cond_Branch)
{
branch = (previous.Operand as Instruction);
// branch can be null (e.g. switch -> Instruction[])
if ((branch != null) && targets.Contains(branch) && !targets.Contains(ins))
{
targets.Add(ins);
}
}
break;
case FlowControl.Cond_Branch:
// note: a single switch (C#) with sparse values can be broken into several swicth (IL)
// that will use the same 'targets' and must be counted only once
if (ins.OpCode.OperandType == OperandType.InlineSwitch)
{
AccumulateSwitchTargets(ins);
}
else
{
// some conditional branch can be related to the sparse switch
branch = (ins.Operand as Instruction);
previous = branch.Previous;
if ((previous != null) && previous.Previous.OpCode.OperandType != OperandType.InlineSwitch)
{
if (!targets.Contains(branch))
{
cc++;
}
}
}
break;
}
}
// count all unique targets (and default if more than one C# switch is used)
cc += targets.Count;
targets.Clear();
return cc;
}
private static void AccumulateSwitchTargets(Instruction ins)
{
Instruction[] cases = (Instruction[])ins.Operand;
foreach (Instruction target in cases)
{
// ignore targets that are the next instructions (xmcs)
if (target != ins.Next && !targets.Contains(target))
targets.Add(target);
}
// add 'default' branch (if one exists)
Instruction next = ins.Next;
if (next.OpCode.FlowControl == FlowControl.Branch)
{
Instruction unc = FindFirstUnconditionalBranchTarget(cases[0]);
if (unc != next.Operand && !targets.Contains(next.Operand as Instruction))
targets.Add(next.Operand as Instruction);
}
}
private static Instruction FindFirstUnconditionalBranchTarget(Instruction ins)
{
while (ins != null)
{
if (FlowControl.Branch == ins.OpCode.FlowControl)
return ((Instruction)ins.Operand);
ins = ins.Next;
}
return null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 74449815e747b4b1ba000bf66f12e01a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9c2ede2081f2f4c45a6f7f4c92e3a735
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,63 @@
//
// OpenCover - S Wilde
//
// This source code is released under the MIT License; see the accompanying license file.
//
using System.Linq;
using System.Xml.Serialization;
namespace OpenCover.Framework.Model
{
/// <summary>
/// a branch point
/// </summary>
public class BranchPoint : InstrumentationPoint, IDocumentReference
{
/// <summary>
/// Line of the branching instruction
/// </summary>
[XmlAttribute("sl")]
public int StartLine { get; set; }
/// <summary>
/// A path that can be taken
/// </summary>
[XmlAttribute("path")]
public int Path { get; set; }
/// <summary>
/// List of OffsetPoints between Offset and EndOffset (exclusive)
/// </summary>
[XmlAttribute("offsetchain")]
public System.Collections.Generic.List<int> OffsetPoints { get; set; }
/// <summary>
/// Should offset points be serialized
/// </summary>
/// <returns></returns>
public bool ShouldSerializeOffsetPoints()
{
return OffsetPoints.Maybe(_ => _.Any());
}
/// <summary>
/// Last Offset == EndOffset.
/// Can be same as Offset
/// </summary>
[XmlAttribute("offsetend")]
public int EndOffset { get; set; }
/// <summary>
/// The file associated with the supplied startline
/// </summary>
[XmlAttribute("fileid")]
public uint FileId { get; set; }
/// <summary>
/// The url to the document if an entry was not mapped to an id
/// </summary>
[XmlAttribute("url")]
public string Document { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 88cac9839726d46718b126833c76c5e9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
//
// OpenCover - S Wilde
//
// This source code is released under the MIT License; see the accompanying license file.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace OpenCover.Framework.Model
{
/// <summary>
/// An entity that contains methods
/// </summary>
public class Class : SummarySkippedEntity
{
/// <summary>
/// instantiate
/// </summary>
public Class()
{
Methods = new Method[0];
}
/// <summary>
/// The full name of the class
/// </summary>
public string FullName { get; set; }
[XmlIgnore]
internal File[] Files { get; set; }
/// <summary>
/// A list of methods that make up the class
/// </summary>
public Method[] Methods { get; set; }
/// <summary>
/// If a class was skipped by instrumentation, supply the reason why
/// </summary>
/// <param name="reason"></param>
public override void MarkAsSkipped(SkippedMethod reason)
{
SkippedDueTo = reason;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c0d40fe321f9746dcbccb27824986511
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,54 @@
//
// OpenCover - S Wilde
//
// This source code is released under the MIT License; see the accompanying license file.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace OpenCover.Framework.Model
{
/// <summary>
/// A coverage session
/// </summary>
public class CoverageSession
{
private string _version;
/// <summary>
/// initialise a coverage session
/// </summary>
public CoverageSession()
{
Modules = new Module[0];
Summary = new Summary();
_version = GetType().Assembly.GetName().Version.ToString();
}
/// <summary>
/// A unique session identifier
/// </summary>
public string SessionId { get; set; }
/// <summary>
/// A Summary of results for the session
/// </summary>
public Summary Summary { get; set; }
/// <summary>
/// A list of modules that have been profiled under the session
/// </summary>
public Module[] Modules { get; set; }
/// <summary>
/// The current version
/// </summary>
[XmlAttribute("Version")]
public string Version {
get { return _version; }
// ReSharper disable once ValueParameterNotUsed
set { /* intentionally left blank */} }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 561dcfbc5a4094415b3d8348f1a6b738
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,68 @@
//
// OpenCover - S Wilde
//
// This source code is released under the MIT License; see the accompanying license file.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Xml.Serialization;
namespace OpenCover.Framework.Model
{
/// <summary>
/// A file reference within the coverage session and is used to point to an existing File entity
/// </summary>
public class FileRef
{
/// <summary>
/// The uniqueid of a file in a coverage session
/// </summary>
[XmlAttribute("uid")]
public UInt32 UniqueId { get; set; }
}
/// <summary>
/// File details of a source file
/// </summary>
public class File : FileRef
{
private static int _uId;
static readonly List<File> Files = new List<File>();
internal static void ResetAfterLoading()
{
_uId = (int)Files.Max(x => x.UniqueId);
}
/// <summary>
/// A standard constructor
/// </summary>
public File()
{
UniqueId = (UInt32)Interlocked.Increment(ref _uId);
Files.Add(this);
}
/// <summary>
/// The path to file
/// </summary>
[XmlAttribute("fullPath")]
public string FullPath { get; set; }
}
internal class FileEqualityComparer : IEqualityComparer<File>
{
public bool Equals(File x, File y)
{
return x.FullPath == y.FullPath;
}
public int GetHashCode(File obj)
{
return 0;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4ea0122a5084b4beca6bbb008fea821e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,36 @@
using System;
namespace OpenCover.Framework
{
internal static class HelperExtensions
{
public static TRet Maybe<T, TRet>(this T value, Func<T, TRet> action, TRet defValue = default(TRet))
where T : class
{
return (value != null) ? action(value) : defValue;
}
public static T Do<T>(this T value, Action<T> action)
where T : class
{
if (value != null)
action(value);
return value;
}
public static T Try<T>(this T value, Action<T> action)
where T : class
{
try
{
if (value != null)
action(value);
}
catch (Exception)
{
// ignore error
}
return value;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a74e938125304007a53cf9733cd1208
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
//
// OpenCover - S Wilde
//
// This source code is released under the MIT License; see the accompanying license file.
//
namespace OpenCover.Framework.Model
{
/// <summary>
/// A point may have a document reference
/// </summary>
public interface IDocumentReference
{
/// <summary>
/// The document url
/// </summary>
string Document { get; set; }
/// <summary>
/// The document id after lookup
/// </summary>
uint FileId { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ebffa2e2071ad4f79a3641b47e74b25e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
namespace OpenCover.Framework.Model
{
/// <summary>
/// An instrumentable point
/// </summary>
public class InstrumentationPoint
{
private static int _instrumentPoint;
private static readonly object LockObject = new object();
private static readonly List<InstrumentationPoint> InstrumentPoints;
static InstrumentationPoint()
{
_instrumentPoint = 0;
InstrumentPoints = new List<InstrumentationPoint>(8192) {null};
}
internal static void Clear()
{
InstrumentPoints.Clear();
InstrumentPoints.Add(null);
_instrumentPoint = 0;
}
internal static void ResetAfterLoading()
{
var points = InstrumentPoints
.Where(x => x != null)
.GroupBy(x => x.UniqueSequencePoint)
.Select(g => g.OrderBy(x => x.OrigSequencePoint).First())
.ToList();
var max = (int)points.Max(x => x.UniqueSequencePoint);
InstrumentPoints.Clear();
InstrumentPoints.Add(null);
for (var i = 1; i <= max; i++)
{
var point = new SequencePoint();
InstrumentPoints[i] = point;
point.UniqueSequencePoint = (uint)i;
}
foreach (var instrumentationPoint in points)
{
InstrumentPoints[(int)instrumentationPoint.UniqueSequencePoint] = instrumentationPoint;
}
_instrumentPoint = max;
}
/// <summary>
/// Return the number of visit points
/// </summary>
public static int Count {
get { return InstrumentPoints.Count; }
}
/// <summary>
/// Get the number of recorded visit points for this identifier
/// </summary>
/// <param name="spid">the sequence point identifier - NOTE 0 is not used</param>
public static int GetVisitCount(uint spid)
{
return InstrumentPoints[(int) spid].VisitCount;
}
/// <summary>
/// Add a number of recorded visit ppints against this identifier
/// </summary>
/// <param name="spid">the sequence point identifier - NOTE 0 is not used</param>
/// <param name="trackedMethodId">the id of a tracked method - Note 0 means no method currently tracking</param>
/// <param name="amount">the number of visit points to add</param>
public static bool AddVisitCount(uint spid, uint trackedMethodId, int amount)
{
if (spid != 0 && spid < InstrumentPoints.Count)
{
var point = InstrumentPoints[(int) spid];
point.VisitCount += amount;
if (point.VisitCount < 0)
{
point.VisitCount = int.MaxValue;
}
if (trackedMethodId != 0)
{
AddOrUpdateTrackingPoint(trackedMethodId, amount, point);
}
return true;
}
return false;
}
private static void AddOrUpdateTrackingPoint(uint trackedMethodId, int amount, InstrumentationPoint point)
{
point._tracked = point._tracked ?? new List<TrackedMethodRef>();
var tracked = point._tracked.Find(x => x.UniqueId == trackedMethodId);
if (tracked == null)
{
tracked = new TrackedMethodRef {UniqueId = trackedMethodId, VisitCount = amount};
point._tracked.Add(tracked);
}
else
{
tracked.VisitCount += amount;
if (tracked.VisitCount < 0)
tracked.VisitCount = int.MaxValue;
}
}
private List<TrackedMethodRef> _tracked;
/// <summary>
/// Initialise
/// </summary>
public InstrumentationPoint()
{
lock (LockObject)
{
UniqueSequencePoint = (uint)++_instrumentPoint;
InstrumentPoints.Add(this);
OrigSequencePoint = UniqueSequencePoint;
}
}
/// <summary>
/// Store the number of visits
/// </summary>
[XmlAttribute("vc")]
public int VisitCount { get; set; }
/// <summary>
/// A unique number
/// </summary>
[XmlAttribute("uspid")]
public UInt32 UniqueSequencePoint { get; set; }
/// <summary>
/// An order of the point within the method
/// </summary>
[XmlAttribute("ordinal")]
public UInt32 Ordinal { get; set; }
/// <summary>
/// The IL offset of the point
/// </summary>
[XmlAttribute("offset")]
public int Offset { get; set; }
/// <summary>
/// Used to hide an instrumentation point
/// </summary>
[XmlIgnore]
public bool IsSkipped { get; set; }
/// <summary>
/// The list of tracked methods
/// </summary>
public TrackedMethodRef[] TrackedMethodRefs
{
get
{
if (_tracked != null)
{
return _tracked.ToArray();
}
return null;
}
set
{
_tracked = null;
if (value == null)
return;
_tracked = new List<TrackedMethodRef>(value);
}
}
/// <summary>
///
/// </summary>
[XmlIgnore]
public UInt32 OrigSequencePoint { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 86783b018856d4f82ab6105c443f2ffa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,195 @@
//
// OpenCover - S Wilde
//
// This source code is released under the MIT License; see the accompanying license file.
//
using System;
using System.Text.RegularExpressions;
using System.Xml.Serialization;
namespace OpenCover.Framework.Model
{
/// <summary>
/// An method entity that can be instrumented
/// </summary>
public class Method : SummarySkippedEntity
{
/// <summary>
/// The MetadataToken used to identify this entity within the assembly
/// </summary>
public int MetadataToken { get; set; }
/// <summary>
/// The full name of the method (method-definition), includes return-type namespace-class::call-name(argument-types)
/// </summary>
[XmlElement("Name")]
public string FullName { get; set; }
/// <summary>
/// A reference to a file in the file collection (used to help visualisation)
/// </summary>
public FileRef FileRef { get; set; }
internal UInt32 FileRefUniqueId {
get { return FileRef == null? 0 : FileRef.UniqueId; }
}
/// <summary>
/// A list of sequence points that have been produced for this method
/// </summary>
public SequencePoint[] SequencePoints {
get {
return _sequencePoints;
}
set {
_sequencePoints = value ?? new SequencePoint[0];
}
}
private SequencePoint[] _sequencePoints = new SequencePoint[0];
/// <summary>
/// A list of branch points that have been identified for this method
/// </summary>
public BranchPoint[] BranchPoints {
get {
return _branchPoints;
}
set {
_branchPoints = value ?? new BranchPoint[0];
}
}
private BranchPoint[] _branchPoints = new BranchPoint[0];
/// <summary>
/// A method point to identify the entry of a method
/// </summary>
public InstrumentationPoint MethodPoint { get; set; }
/// <summary>
/// Has the method been visited
/// </summary>
[XmlAttribute("visited")]
public bool Visited { get; set; }
/// <summary>
/// What is the cyclomatic complexity of this method.
/// </summary>
/// <remarks>Calculated using the Gendarme rules library</remarks>
[XmlAttribute("cyclomaticComplexity")]
public int CyclomaticComplexity { get; set; }
/// <summary>
/// What is the NPath complexity of this method.
/// </summary>
/// <remarks>Product of path branches (ie:path0=2;path1=3;path2=2 =&gt;2*3*2==12</remarks>
[XmlAttribute("nPathComplexity")]
public int NPathComplexity { get; set; }
/// <summary>
/// What is the sequence coverage of this method
/// </summary>
/// <remarks>Rounded for ease</remarks>
[XmlAttribute("sequenceCoverage")]
public decimal SequenceCoverage { get; set; }
/// <summary>
/// What is the branch coverage of this method
/// </summary>
/// <remarks>Rounded for ease</remarks>
[XmlAttribute("branchCoverage")]
public decimal BranchCoverage { get; set; }
/// <summary>
/// What is the crap score of this method
/// based on the following calculation
/// CRAP1(m) = comp(m)^2 * (1 cov(m)/100)^3 + comp(m)
/// </summary>
/// <remarks>Rounded for ease</remarks>
[XmlAttribute("crapScore")]
public decimal CrapScore { get; set; }
/// <summary>
/// Is this method a constructor
/// </summary>
[XmlAttribute("isConstructor")]
public bool IsConstructor { get; set; }
/// <summary>
/// Is this method static
/// </summary>
[XmlAttribute("isStatic")]
public bool IsStatic { get; set; }
/// <summary>
/// Is this method a property getter
/// </summary>
[XmlAttribute("isGetter")]
public bool IsGetter { get; set; }
/// <summary>
/// Is this method a property setter
/// </summary>
[XmlAttribute("isSetter")]
public bool IsSetter { get; set; }
/// <summary>
/// Mark an entity as skipped
/// </summary>
/// <param name="reason">Provide a reason</param>
public override void MarkAsSkipped(SkippedMethod reason)
{
SkippedDueTo = reason;
if (MethodPoint != null)
MethodPoint.IsSkipped = true;
MethodPoint = null;
SequencePoints = null;
BranchPoints = null;
}
#region IsGenerated & CallName
/// <summary>
/// True if this.FullName matches generated-method-regex-pattern
/// </summary>
internal bool IsGenerated {
get {
if (_resolvedIsGenerated == null) {
_resolvedIsGenerated = !(string.IsNullOrEmpty(FullName) || FullName.Trim().Length == 0)
&& FullName.Contains("__") // quick test before using regex heavy weapon
&& IsGeneratedMethodRegex.IsMatch(FullName);
}
return _resolvedIsGenerated == true;
}
}
/// <summary>
/// Method "::CallName(". (Name excluding return type, namespace and arguments)
/// </summary>
internal string CallName {
get {
if (_resolvedCallName != null)
return _resolvedCallName;
_resolvedCallName = string.Empty; // init resolve value
if (!(string.IsNullOrEmpty(FullName) || FullName.Trim().Length == 0)) {
var startIndex = FullName.IndexOf("::", StringComparison.Ordinal);
startIndex += 2;
var finalIndex = FullName.IndexOf('(', startIndex);
if (startIndex > 1 && finalIndex > startIndex) {
_resolvedCallName = FullName // resolve cache
.Substring(startIndex, finalIndex - startIndex);
}
}
return _resolvedCallName;
}
}
private bool? _resolvedIsGenerated;
private string _resolvedCallName;
private const RegexOptions RegexOptions = System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.ExplicitCapture;
private static readonly Regex IsGeneratedMethodRegex = new Regex(@"(<[^\s:>]+>\w__\w)", RegexOptions);
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7f1f74c5e9b1146168b87690081420c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
{
"name": "Unity.TestTools.CodeCoverage.Editor.OpenCover.Model",
"references": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": []
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 19c3df1967929405fba735480b3da9a7
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,77 @@
//
// OpenCover - S Wilde
//
// This source code is released under the MIT License; see the accompanying license file.
//
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
namespace OpenCover.Framework.Model
{
/// <summary>
/// The details of a module
/// </summary>
public class Module : SummarySkippedEntity
{
/// <summary>
/// simple constructor
/// </summary>
public Module()
{
Aliases = new List<string>();
}
/// <summary>
/// The full path name to the module
/// </summary>
public string ModulePath { get; set; }
/// <summary>
/// GetlastWriteTimeUtc
/// </summary>
public DateTime ModuleTime { get; set; }
/// <summary>
/// A list of aliases
/// </summary>
[XmlIgnore]
public IList<string> Aliases { get; private set; }
/// <summary>
/// The name of the module
/// </summary>
public string ModuleName { get; set; }
/// <summary>
/// The files that make up the module
/// </summary>
public File[] Files { get; set; }
/// <summary>
/// The classes that make up the module
/// </summary>
public Class[] Classes { get; set; }
/// <summary>
/// Methods that are being tracked i.e. test methods
/// </summary>
public TrackedMethod[] TrackedMethods { get; set; }
/// <summary>
/// A hash of the file used to group them together (especially when running against mstest)
/// </summary>
[XmlAttribute("hash")]
public string ModuleHash { get; set; }
/// <summary>
/// Mark an entity as skipped
/// </summary>
/// <param name="reason">Provide a reason</param>
public override void MarkAsSkipped(SkippedMethod reason)
{
SkippedDueTo = reason;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f7c00a2c9a9fd476c947d35ae18e21fd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,124 @@
//
// OpenCover - S Wilde
//
// This source code is released under the MIT License; see the accompanying license file.
//
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
namespace OpenCover.Framework.Model
{
/// <summary>
/// a sequence point
/// </summary>
public class SequencePoint : InstrumentationPoint, IDocumentReference
{
/// <summary>
/// The start line of the sequence point
/// </summary>
[XmlAttribute("sl")]
public int StartLine { get; set; }
/// <summary>
/// The start column of the sequence point
/// </summary>
[XmlAttribute("sc")]
public int StartColumn { get; set; }
/// <summary>
/// The end line of the sequence point
/// </summary>
[XmlAttribute("el")]
public int EndLine { get; set; }
/// <summary>
/// The end column of the sequence point
/// </summary>
[XmlAttribute("ec")]
public int EndColumn { get; set; }
/// <summary>
/// Count of merged branches
/// </summary>
/// <summary>
/// The number of branch exits
/// </summary>
[XmlAttribute("bec")]
public int BranchExitsCount { get; set; }
/// <summary>
/// Visit count of merged branches
/// </summary>
[XmlAttribute("bev")]
public int BranchExitsVisit { get; set; }
/// <summary>
/// The file associated with the supplied startline
/// </summary>
[XmlAttribute("fileid")]
public uint FileId { get; set; }
/// <summary>
/// The url to the document if an entry was not mapped to an id
/// </summary>
[XmlAttribute("url")]
public string Document { get; set; }
internal List<BranchPoint> BranchPoints {
get{
return _branchPoints;
}
set{
_branchPoints = value ?? new List<BranchPoint>();
}
}
private List<BranchPoint> _branchPoints = new List<BranchPoint>();
/// <summary>
/// Property
/// </summary>
public bool IsSingleCharSequencePoint {
get {
return (StartLine == EndLine) && (EndColumn - StartColumn) == 1;
}
}
/// <summary>
/// SonnarQube wants no more than 3 boolean conditions
/// </summary>
/// <param name="sp"></param>
/// <returns></returns>
private bool IsLineEqual (SequencePoint sp) {
return StartLine == sp.StartLine && EndLine == sp.EndLine;
}
/// <summary>
/// SonnarQube wants no more than 3 boolean conditions
/// </summary>
/// <param name="sp"></param>
/// <returns></returns>
private bool IsColumnEqual (SequencePoint sp) {
return StartColumn == sp.StartColumn && EndColumn == sp.EndColumn;
}
/// <summary>
/// Is Start/End Line/Column equal
/// </summary>
/// <param name="sp"></param>
/// <returns></returns>
public bool IsPositionEqual (SequencePoint sp) {
return sp != null && IsLineEqual (sp) && IsColumnEqual (sp);
}
/// <summary>
/// Is FileId equal? (If FileId is 0 then file is unknown)
/// </summary>
/// <param name="sp"></param>
/// <returns></returns>
public bool IsFileIdEqual (SequencePoint sp) {
return sp != null && FileId != 0 && FileId == sp.FileId;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 448b5b9c7773f48be878eb5f56008baf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
using System.Xml.Serialization;
namespace OpenCover.Framework.Model
{
/// <summary>
/// The entity can be skipped from coverage but needs to supply a reason
/// </summary>
public abstract class SkippedEntity
{
private SkippedMethod? _skippedDueTo;
/// <summary>
/// If this class has been skipped then this value will describe why
/// </summary>
[XmlAttribute("skippedDueTo")]
public SkippedMethod SkippedDueTo
{
get { return _skippedDueTo.GetValueOrDefault(); }
set { _skippedDueTo = value; }
}
/// <summary>
/// If this class has been skipped then this value will allow the data to be serialized
/// </summary>
public bool ShouldSerializeSkippedDueTo() { return _skippedDueTo.HasValue; }
/// <summary>
/// Mark an entity as skipped
/// </summary>
/// <param name="reason">Provide a reason</param>
public abstract void MarkAsSkipped(SkippedMethod reason);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2adfa90d9eaaa4702b2457c09db2f5e2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,64 @@
namespace OpenCover.Framework.Model
{
/// <summary>
/// Describes how a method or class was skipped
/// </summary>
public enum SkippedMethod
{
/// <summary>
/// Entity was skipped due to a matching exclusion attribute filter
/// </summary>
Attribute = 3,
/// <summary>
/// Entity was skipped due to a matching exclusion file filter
/// </summary>
File = 4,
/// <summary>
/// Entity was skipped due to a matching exclusion module/class filter
/// </summary>
Filter = 2,
/// <summary>
/// Entity was skipped due to a missing PDB
/// </summary>
MissingPdb = 1,
/// <summary>
/// Entity was skipped by inference (usually related to File filters)
/// </summary>
Inferred = 5,
/// <summary>
/// Entity (method) was skipped as it is an auto-implemented property.
/// </summary>
AutoImplementedProperty = 6,
/// <summary>
/// Entity (method) was skipped as it is native code.
/// </summary>
NativeCode = 7,
/// <summary>
/// Entity (method) was skipped for other reasons.
/// </summary>
Unknown = 8,
/// <summary>
/// Entity (dll) was skipped due to folder exclusion.
/// </summary>
FolderExclusion = 9,
/// <summary>
/// Entity (method) was skipped due to being a delegate.
/// </summary>
Delegate = 10,
/// <summary>
/// Entity (method) was skipped due to being an F# internal implementation
/// detail (in either a record or discriminated union type).
/// </summary>
FSharpInternal = 11,
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3e49bf94f7d5348e2a48c3a09f3de201
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace OpenCover.Framework.Model
{
/// <summary>
/// A summary of results
/// </summary>
public class Summary
{
/// <summary>
/// The number of sequence points
/// </summary>
[XmlAttribute("numSequencePoints")]
public int NumSequencePoints { get; set; }
/// <summary>
/// The number of sequence points visited
/// </summary>
[XmlAttribute("visitedSequencePoints")]
public int VisitedSequencePoints { get; set; }
/// <summary>
/// The number of branch points
/// </summary>
[XmlAttribute("numBranchPoints")]
public int NumBranchPoints { get; set; }
/// <summary>
/// The number of branch points visited
/// </summary>
[XmlAttribute("visitedBranchPoints")]
public int VisitedBranchPoints { get; set; }
/// <summary>
/// What is the sequence coverage?
/// </summary>
/// <remarks>Rounded for ease</remarks>
[XmlAttribute("sequenceCoverage")]
public decimal SequenceCoverage { get; set; }
/// <summary>
/// What is the branch coverage?
/// </summary>
/// <remarks>Rounded for ease</remarks>
[XmlAttribute("branchCoverage")]
public decimal BranchCoverage { get; set; }
/// <summary>
/// What is the maximum cyclomatic complexity.
/// </summary>
/// <remarks>Calculated using the Gendarme rules library</remarks>
[XmlAttribute("maxCyclomaticComplexity")]
public int MaxCyclomaticComplexity { get; set; }
/// <summary>
/// What is the minimum cyclomatic complexity.
/// </summary>
/// <remarks>Calculated using the Gendarme rules library</remarks>
[XmlAttribute("minCyclomaticComplexity")]
public int MinCyclomaticComplexity { get; set; }
/// <summary>
/// What is the maximum crap score
/// </summary>
[XmlAttribute("maxCrapScore")]
public decimal MaxCrapScore { get; set; }
/// <summary>
/// What is the minimum crap score.
/// </summary>
[XmlAttribute("minCrapScore")]
public decimal MinCrapScore { get; set; }
/// <summary>
/// What is the number of visited classes
/// </summary>
[XmlAttribute("visitedClasses")]
public int VisitedClasses { get; set; }
/// <summary>
/// What is the total number of classes
/// </summary>
[XmlAttribute("numClasses")]
public int NumClasses { get; set; }
/// <summary>
/// What is the number of visited methods
/// </summary>
[XmlAttribute("visitedMethods")]
public int VisitedMethods { get; set; }
/// <summary>
/// What is the total number of methods
/// </summary>
[XmlAttribute("numMethods")]
public int NumMethods { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f84724c9beb0444b0b1a7166317d7262
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
namespace OpenCover.Framework.Model
{
/// <summary>
/// A skipped entity that also carries a Summary object which is not
/// always serialized
/// </summary>
public abstract class SummarySkippedEntity : SkippedEntity
{
/// <summary>
/// Initialise
/// </summary>
protected SummarySkippedEntity()
{
Summary = new Summary();
}
/// <summary>
/// A Summary of results for a entity
/// </summary>
public Summary Summary { get; set; }
/// <summary>
/// Control serialization of the Summary object
/// </summary>
/// <returns></returns>
public bool ShouldSerializeSummary() { return !ShouldSerializeSkippedDueTo(); }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b1b80d503cba7422cb21829a6891cde2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Xml.Serialization;
namespace OpenCover.Framework.Model
{
/// <summary>
/// A reference to a tracked method
/// </summary>
public class TrackedMethodRef
{
/// <summary>
/// unique id assigned
/// </summary>
[XmlAttribute("uid")]
public UInt32 UniqueId { get; set; }
/// <summary>
/// The visit count
/// </summary>
[XmlAttribute("vc")]
public int VisitCount { get; set; }
}
/// <summary>
/// A method being tracked
/// </summary>
[Serializable]
public sealed class TrackedMethod
{
/// <summary>
/// unique id assigned
/// </summary>
[XmlAttribute("uid")]
public UInt32 UniqueId { get; set; }
/// <summary>
/// The MetadataToken used to identify this entity within the assembly
/// </summary>
[XmlAttribute("token")]
public int MetadataToken { get; set; }
/// <summary>
/// The name of the method being tracked
/// </summary>
[XmlAttribute("name")]
public string FullName { get; set; }
/// <summary>
/// The reason/plugin why the method is being tracked
/// </summary>
[XmlAttribute("strategy")]
public string Strategy { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d7c779bb30ff546c08fce46737f83ec5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b6c4c078b09304bfeaae896e2e4ffa9e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,130 @@
//
// ByteBuffer.cs
//
// Author:
// Jb Evain (jbevain@novell.com)
//
// (C) 2009 - 2010 Novell, Inc. (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
namespace Mono.Reflection {
class ByteBuffer {
internal byte [] buffer;
internal int position;
public ByteBuffer (byte [] buffer)
{
this.buffer = buffer;
}
public byte ReadByte ()
{
CheckCanRead (1);
return buffer [position++];
}
public byte [] ReadBytes (int length)
{
CheckCanRead (length);
var value = new byte [length];
Buffer.BlockCopy (buffer, position, value, 0, length);
position += length;
return value;
}
public short ReadInt16 ()
{
CheckCanRead (2);
short value = (short) (buffer [position]
| (buffer [position + 1] << 8));
position += 2;
return value;
}
public int ReadInt32 ()
{
CheckCanRead (4);
int value = buffer [position]
| (buffer [position + 1] << 8)
| (buffer [position + 2] << 16)
| (buffer [position + 3] << 24);
position += 4;
return value;
}
public long ReadInt64 ()
{
CheckCanRead (8);
uint low = (uint) (buffer [position]
| (buffer [position + 1] << 8)
| (buffer [position + 2] << 16)
| (buffer [position + 3] << 24));
uint high = (uint) (buffer [position + 4]
| (buffer [position + 5] << 8)
| (buffer [position + 6] << 16)
| (buffer [position + 7] << 24));
long value = (((long) high) << 32) | low;
position += 8;
return value;
}
public float ReadSingle ()
{
if (!BitConverter.IsLittleEndian) {
var bytes = ReadBytes (4);
Array.Reverse (bytes);
return BitConverter.ToSingle (bytes, 0);
}
CheckCanRead (4);
float value = BitConverter.ToSingle (buffer, position);
position += 4;
return value;
}
public double ReadDouble ()
{
if (!BitConverter.IsLittleEndian) {
var bytes = ReadBytes (8);
Array.Reverse (bytes);
return BitConverter.ToDouble (bytes, 0);
}
CheckCanRead (8);
double value = BitConverter.ToDouble (buffer, position);
position += 8;
return value;
}
void CheckCanRead (int count)
{
if (position + count > buffer.Length)
throw new ArgumentOutOfRangeException ();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 68735f878b89447b4925a73a9074dfe9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,45 @@
//
// Disassembler.cs
//
// Author:
// Jb Evain (jbevain@novell.com)
//
// (C) 2009 - 2010 Novell, Inc. (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Mono.Reflection {
public static class Disassembler {
public static IList<Instruction> GetInstructions (this MethodBase self)
{
if (self == null)
throw new ArgumentNullException ("self");
return MethodBodyReader.GetInstructions (self).AsReadOnly ();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f2c36198237a34870a85b171e9097887
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,156 @@
//
// Instruction.cs
//
// Author:
// Jb Evain (jbevain@novell.com)
//
// (C) 2009 - 2010 Novell, Inc. (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Reflection.Emit;
using System.Text;
namespace Mono.Reflection {
public sealed class Instruction {
int offset;
OpCode opcode;
object operand;
Instruction previous;
Instruction next;
public int Offset {
get { return offset; }
}
public OpCode OpCode {
get { return opcode; }
}
public object Operand {
get { return operand; }
internal set { operand = value; }
}
public Instruction Previous {
get { return previous; }
internal set { previous = value; }
}
public Instruction Next {
get { return next; }
internal set { next = value; }
}
public int Size {
get {
int size = opcode.Size;
switch (opcode.OperandType) {
case OperandType.InlineSwitch:
size += (1 + ((Instruction []) operand).Length) * 4;
break;
case OperandType.InlineI8:
case OperandType.InlineR:
size += 8;
break;
case OperandType.InlineBrTarget:
case OperandType.InlineField:
case OperandType.InlineI:
case OperandType.InlineMethod:
case OperandType.InlineString:
case OperandType.InlineTok:
case OperandType.InlineType:
case OperandType.ShortInlineR:
size += 4;
break;
case OperandType.InlineVar:
size += 2;
break;
case OperandType.ShortInlineBrTarget:
case OperandType.ShortInlineI:
case OperandType.ShortInlineVar:
size += 1;
break;
}
return size;
}
}
internal Instruction (int offset, OpCode opcode)
{
this.offset = offset;
this.opcode = opcode;
}
public override string ToString ()
{
var instruction = new StringBuilder ();
AppendLabel (instruction, this);
instruction.Append (':');
instruction.Append (' ');
instruction.Append (opcode.Name);
if (operand == null)
return instruction.ToString ();
instruction.Append (' ');
switch (opcode.OperandType) {
case OperandType.ShortInlineBrTarget:
case OperandType.InlineBrTarget:
AppendLabel (instruction, (Instruction) operand);
break;
case OperandType.InlineSwitch:
var labels = (Instruction []) operand;
for (int i = 0; i < labels.Length; i++) {
if (i > 0)
instruction.Append (',');
AppendLabel (instruction, labels [i]);
}
break;
case OperandType.InlineString:
instruction.Append ('\"');
instruction.Append (operand);
instruction.Append ('\"');
break;
default:
instruction.Append (operand);
break;
}
return instruction.ToString ();
}
static void AppendLabel (StringBuilder builder, Instruction instruction)
{
builder.Append ("IL_");
builder.Append (instruction.offset.ToString ("x4"));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c54348b43e9e464fa20499d8315beed
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,306 @@
//
// MethodBodyReader.cs
//
// Author:
// Jb Evain (jbevain@novell.com)
//
// (C) 2009 - 2010 Novell, Inc. (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using UnityEngine;
namespace Mono.Reflection {
class MethodBodyReader {
static readonly OpCode [] one_byte_opcodes;
static readonly OpCode [] two_bytes_opcodes;
static MethodBodyReader ()
{
one_byte_opcodes = new OpCode [0xe1];
two_bytes_opcodes = new OpCode [0x1f];
var fields = typeof (OpCodes).GetFields (
BindingFlags.Public | BindingFlags.Static);
foreach (var field in fields) {
var opcode = (OpCode) field.GetValue (null);
if (opcode.OpCodeType == OpCodeType.Nternal)
continue;
if (opcode.Size == 1)
one_byte_opcodes [opcode.Value] = opcode;
else
two_bytes_opcodes [opcode.Value & 0xff] = opcode;
}
}
readonly MethodBase method;
readonly MethodBody body;
readonly Module module;
readonly Type [] type_arguments;
readonly Type [] method_arguments;
readonly ByteBuffer il;
readonly ParameterInfo this_parameter;
readonly ParameterInfo [] parameters;
readonly IList<LocalVariableInfo> locals;
readonly List<Instruction> instructions;
MethodBodyReader (MethodBase method)
{
this.method = method;
this.body = method.GetMethodBody ();
if (this.body == null)
throw new ArgumentException ("Method has no body");
var bytes = body.GetILAsByteArray ();
if (bytes == null)
throw new ArgumentException ("Can not get the body of the method");
if (!(method is ConstructorInfo))
method_arguments = method.GetGenericArguments ();
if (method.DeclaringType != null)
type_arguments = method.DeclaringType.GetGenericArguments ();
if (!method.IsStatic)
this.this_parameter = new ThisParameter (method);
this.parameters = method.GetParameters ();
this.locals = body.LocalVariables;
this.module = method.Module;
this.il = new ByteBuffer (bytes);
this.instructions = new List<Instruction> ((bytes.Length + 1) / 2);
}
void ReadInstructions ()
{
Instruction previous = null;
while (il.position < il.buffer.Length) {
var instruction = new Instruction (il.position, ReadOpCode ());
ReadOperand (instruction);
if (previous != null) {
instruction.Previous = previous;
previous.Next = instruction;
}
instructions.Add (instruction);
previous = instruction;
}
ResolveBranches ();
}
void ReadOperand (Instruction instruction)
{
switch (instruction.OpCode.OperandType) {
case OperandType.InlineNone:
break;
case OperandType.InlineSwitch:
int length = il.ReadInt32 ();
int base_offset = il.position + (4 * length);
int [] branches = new int [length];
for (int i = 0; i < length; i++)
branches [i] = il.ReadInt32 () + base_offset;
instruction.Operand = branches;
break;
case OperandType.ShortInlineBrTarget:
instruction.Operand = (((sbyte) il.ReadByte ()) + il.position);
break;
case OperandType.InlineBrTarget:
instruction.Operand = il.ReadInt32 () + il.position;
break;
case OperandType.ShortInlineI:
if (instruction.OpCode == OpCodes.Ldc_I4_S)
instruction.Operand = (sbyte) il.ReadByte ();
else
instruction.Operand = il.ReadByte ();
break;
case OperandType.InlineI:
instruction.Operand = il.ReadInt32 ();
break;
case OperandType.ShortInlineR:
instruction.Operand = il.ReadSingle ();
break;
case OperandType.InlineR:
instruction.Operand = il.ReadDouble ();
break;
case OperandType.InlineI8:
instruction.Operand = il.ReadInt64 ();
break;
case OperandType.InlineSig:
instruction.Operand = module.ResolveSignature (il.ReadInt32 ());
break;
case OperandType.InlineString:
instruction.Operand = module.ResolveString (il.ReadInt32 ());
break;
case OperandType.InlineTok:
{
int metaDataToken = il.ReadInt32 ();
try
{
instruction.Operand = module.ResolveMember (metaDataToken, type_arguments, method_arguments);
}
catch(BadImageFormatException)
{
instruction.Operand = module.ResolveMember (metaDataToken);
}
break;
}
case OperandType.InlineType:
instruction.Operand = module.ResolveType (il.ReadInt32 (), type_arguments, method_arguments);
break;
case OperandType.InlineMethod:
{
int metaDataToken = il.ReadInt32 ();
try
{
instruction.Operand = module.ResolveMethod (metaDataToken, type_arguments, method_arguments);
}
catch(TypeLoadException)
{
}
break;
}
case OperandType.InlineField:
instruction.Operand = module.ResolveField (il.ReadInt32 (), type_arguments, method_arguments);
break;
case OperandType.ShortInlineVar:
instruction.Operand = GetVariable (instruction, il.ReadByte ());
break;
case OperandType.InlineVar:
instruction.Operand = GetVariable (instruction, il.ReadInt16 ());
break;
default:
throw new NotSupportedException ();
}
}
void ResolveBranches ()
{
foreach (var instruction in instructions) {
switch (instruction.OpCode.OperandType) {
case OperandType.ShortInlineBrTarget:
case OperandType.InlineBrTarget:
instruction.Operand = GetInstruction (instructions, (int) instruction.Operand);
break;
case OperandType.InlineSwitch:
var offsets = (int []) instruction.Operand;
var branches = new Instruction [offsets.Length];
for (int j = 0; j < offsets.Length; j++)
branches [j] = GetInstruction (instructions, offsets [j]);
instruction.Operand = branches;
break;
}
}
}
static Instruction GetInstruction (List<Instruction> instructions, int offset)
{
var size = instructions.Count;
if (offset < 0 || offset > instructions [size - 1].Offset)
return null;
int min = 0;
int max = size - 1;
while (min <= max) {
int mid = min + ((max - min) / 2);
var instruction = instructions [mid];
var instruction_offset = instruction.Offset;
if (offset == instruction_offset)
return instruction;
if (offset < instruction_offset)
max = mid - 1;
else
min = mid + 1;
}
return null;
}
object GetVariable (Instruction instruction, int index)
{
return TargetsLocalVariable (instruction.OpCode)
? (object) GetLocalVariable (index)
: (object) GetParameter (index);
}
static bool TargetsLocalVariable (OpCode opcode)
{
return opcode.Name.Contains ("loc");
}
LocalVariableInfo GetLocalVariable (int index)
{
return locals [index];
}
ParameterInfo GetParameter (int index)
{
if (method.IsStatic)
return parameters [index];
if (index == 0)
return this_parameter;
return parameters [index - 1];
}
OpCode ReadOpCode ()
{
byte op = il.ReadByte ();
return op != 0xfe
? one_byte_opcodes [op]
: two_bytes_opcodes [il.ReadByte ()];
}
public static List<Instruction> GetInstructions (MethodBase method)
{
var reader = new MethodBodyReader (method);
reader.ReadInstructions ();
return reader.instructions;
}
class ThisParameter : ParameterInfo
{
public ThisParameter (MethodBase method)
{
this.MemberImpl = method;
this.ClassImpl = method.DeclaringType;
this.NameImpl = "this";
this.PositionImpl = -1;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1a8056948ac804bf891bd101b3216a55
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
{
"name": "Unity.TestTools.CodeCoverage.Editor.OpenCover.Mono.Reflection",
"references": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": []
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: eecdf9bdfcb2949619db458f3e24c5e2
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 258e29582df66a741937fe410463ad97
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,75 @@
namespace UnityEditor.TestTools.CodeCoverage.OpenCover
{
internal class OpenCoverReporterFilter : ICoverageReporterFilter
{
private AssemblyFiltering m_AssemblyFiltering;
private PathFiltering m_PathFiltering;
public void SetupFiltering()
{
if (!CommandLineManager.instance.runFromCommandLine || !CommandLineManager.instance.assemblyFiltersSpecified)
{
m_AssemblyFiltering = new AssemblyFiltering();
string includeAssemblies = CoveragePreferences.instance.GetString("IncludeAssemblies", AssemblyFiltering.GetUserOnlyAssembliesString());
m_AssemblyFiltering.Parse(includeAssemblies, string.Empty);
}
if (!CommandLineManager.instance.runFromCommandLine || !CommandLineManager.instance.pathFiltersSpecified)
{
m_PathFiltering = new PathFiltering();
string pathsToInclude = CoveragePreferences.instance.GetStringForPaths("PathsToInclude", string.Empty);
string pathsToExclude = CoveragePreferences.instance.GetStringForPaths("PathsToExclude", string.Empty);
m_PathFiltering.Parse(pathsToInclude, pathsToExclude);
}
}
public AssemblyFiltering GetAssemblyFiltering()
{
if (CommandLineManager.instance.batchmode && !CommandLineManager.instance.useProjectSettings)
return CommandLineManager.instance.assemblyFiltering;
else
return CommandLineManager.instance.assemblyFiltersSpecified ?
CommandLineManager.instance.assemblyFiltering :
m_AssemblyFiltering;
}
public bool ShouldProcessAssembly(string assemblyName)
{
return GetAssemblyFiltering().IsAssemblyIncluded(assemblyName);
}
public PathFiltering GetPathFiltering()
{
if (CommandLineManager.instance.batchmode && !CommandLineManager.instance.useProjectSettings)
return CommandLineManager.instance.pathFiltering;
else
return CommandLineManager.instance.pathFiltersSpecified ?
CommandLineManager.instance.pathFiltering :
m_PathFiltering;
}
public bool ShouldProcessFile(string filename)
{
return GetPathFiltering().IsPathIncluded(filename);
}
public bool ShouldGenerateAdditionalMetrics()
{
if (CommandLineManager.instance.batchmode && !CommandLineManager.instance.useProjectSettings)
return CommandLineManager.instance.generateAdditionalMetrics;
else
return CommandLineManager.instance.generateAdditionalMetrics || CoveragePreferences.instance.GetBool("GenerateAdditionalMetrics", false);
}
public bool ShouldGenerateTestReferences()
{
if (CommandLineManager.instance.batchmode && !CommandLineManager.instance.useProjectSettings)
return CommandLineManager.instance.generateTestReferences;
else
return CommandLineManager.instance.generateTestReferences || CoveragePreferences.instance.GetBool("GenerateTestReferences", false);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 04c157fc0c43e40708bcbe2aa8738140
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
using UnityEngine;
namespace UnityEditor.TestTools.CodeCoverage
{
internal static class OpenCoverReporterStyles
{
public static readonly GUIContent ProgressTitle = EditorGUIUtility.TrTextContent("Code Coverage");
public static readonly GUIContent ProgressGatheringResults = EditorGUIUtility.TrTextContent("Gathering Coverage results..");
public static readonly GUIContent ProgressWritingFile = EditorGUIUtility.TrTextContent("Writing Coverage results to file..");
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ada728b01ae678c4eb6eaf209094ecb2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,36 @@
using System.Xml.Serialization;
using System.IO;
using OpenCover.Framework.Model;
using UnityEditor.TestTools.CodeCoverage.Utils;
namespace UnityEditor.TestTools.CodeCoverage.OpenCover
{
internal class OpenCoverResultWriter : CoverageResultWriterBase<CoverageSession>
{
public OpenCoverResultWriter(CoverageSettings coverageSettings) : base(coverageSettings)
{
}
public override void WriteCoverageSession(CoverageReportType reportType)
{
bool atRoot = CommandLineManager.instance.generateRootEmptyReport && reportType == CoverageReportType.FullEmpty;
XmlSerializer serializer = new XmlSerializer(typeof(CoverageSession));
string fileFullPath = atRoot ? GetRootFullEmptyPath() : GetNextFullFilePath();
if (!System.IO.File.Exists(fileFullPath))
{
using (TextWriter writer = new StreamWriter(fileFullPath))
{
serializer.Serialize(writer, CoverageSession);
if (!CommandLineManager.instance.batchmode)
EditorUtility.DisplayProgressBar(OpenCoverReporterStyles.ProgressTitle.text, OpenCoverReporterStyles.ProgressWritingFile.text, 1f);
}
ResultsLogger.Log(reportType == CoverageReportType.CoveredMethodsOnly ? ResultID.Log_VisitedResultsSaved : ResultID.Log_ResultsSaved, fileFullPath);
CoverageEventData.instance.AddSessionResultPath(fileFullPath);
base.WriteCoverageSession(reportType);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fcb98740e9f34674a87ee205613f1de9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,118 @@
using UnityEditor.SettingsManagement;
using UnityEditor.TestTools.CodeCoverage.Utils;
namespace UnityEditor.TestTools.CodeCoverage
{
internal class CoveragePreferences : CoveragePreferencesImplementation
{
private static CoveragePreferences s_Instance = null;
private const string k_PackageName = "com.unity.testtools.codecoverage";
public static CoveragePreferences instance
{
get
{
if (s_Instance == null)
s_Instance = new CoveragePreferences();
return s_Instance;
}
}
protected CoveragePreferences() : base(k_PackageName)
{
}
}
internal class CoveragePreferencesImplementation
{
private const string k_ProjectPathAlias = "{ProjectPath}";
protected Settings m_Settings;
public CoveragePreferencesImplementation(string packageName)
{
m_Settings = new Settings(packageName);
}
public bool GetBool(string key, bool defaultValue, SettingsScope scope = SettingsScope.Project)
{
if (m_Settings.ContainsKey<bool>(key, scope))
{
return m_Settings.Get<bool>(key, scope, defaultValue);
}
return defaultValue;
}
public int GetInt(string key, int defaultValue, SettingsScope scope = SettingsScope.Project)
{
if (m_Settings.ContainsKey<int>(key, scope))
{
return m_Settings.Get<int>(key, scope, defaultValue);
}
return defaultValue;
}
public string GetStringForPaths(string key, string defaultValue, SettingsScope scope = SettingsScope.Project)
{
string value = GetString(key, defaultValue, scope);
value = value.Replace(k_ProjectPathAlias, CoverageUtils.GetProjectPath());
return value;
}
public string GetString(string key, string defaultValue, SettingsScope scope = SettingsScope.Project)
{
if (m_Settings.ContainsKey<string>(key, scope))
{
return m_Settings.Get<string>(key, scope, defaultValue);
}
return defaultValue;
}
public void SetBool(string key, bool value, SettingsScope scope = SettingsScope.Project)
{
m_Settings.Set<bool>(key, value, scope);
m_Settings.Save();
}
public void SetInt(string key, int value, SettingsScope scope = SettingsScope.Project)
{
m_Settings.Set<int>(key, value, scope);
m_Settings.Save();
}
public void SetStringForPaths(string key, string value, SettingsScope scope = SettingsScope.Project)
{
value = CoverageUtils.NormaliseFolderSeparators(value, false);
value = value.Replace(CoverageUtils.GetProjectPath(), k_ProjectPathAlias);
SetString(key, value, scope);
}
public void SetString(string key, string value, SettingsScope scope = SettingsScope.Project)
{
m_Settings.Set<string>(key, value, scope);
m_Settings.Save();
}
public void DeleteBool(string key, SettingsScope scope = SettingsScope.Project)
{
m_Settings.DeleteKey<bool>(key, scope);
m_Settings.Save();
}
public void DeleteInt(string key, SettingsScope scope = SettingsScope.Project)
{
m_Settings.DeleteKey<int>(key, scope);
m_Settings.Save();
}
public void DeleteString(string key, SettingsScope scope = SettingsScope.Project)
{
m_Settings.DeleteKey<string>(key, scope);
m_Settings.Save();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c7c2d38a2adaf4e098760a3da9d5b6da
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
namespace UnityEditor.TestTools.CodeCoverage
{
internal enum CoverageReportType
{
Full,
FullEmpty,
CoveredMethodsOnly
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 973d27eded053c746a8a3532c65dc75c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,236 @@
using UnityEditor.TestTools.CodeCoverage.Analytics;
using UnityEditor.TestTools.CodeCoverage.Utils;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine;
using UnityEngine.TestTools;
#if NO_COV_EDITORPREF
using System.Linq;
using UnityEditor.PackageManager;
#endif
namespace UnityEditor.TestTools.CodeCoverage
{
internal class CoverageReporterListener : ScriptableObject, ICallbacks
{
private CoverageReporterManager m_CoverageReporterManager;
private bool m_IsConnectedToPlayer;
#if TEST_FRAMEWORK_1_3_OR_NEWER
private bool m_Temp_RunFinishedCalled;
#endif
public void SetCoverageReporterManager(CoverageReporterManager manager)
{
m_CoverageReporterManager = manager;
}
public void RunStarted(ITestAdaptor testsToRun)
{
if (!Coverage.enabled)
return;
#if TEST_FRAMEWORK_1_3_OR_NEWER
m_Temp_RunFinishedCalled = false;
#endif
m_IsConnectedToPlayer = CoverageUtils.IsConnectedToPlayer;
if (m_IsConnectedToPlayer)
{
ResultsLogger.Log(ResultID.Warning_StandaloneUnsupported);
return;
}
if (CoverageRunData.instance.isRunning || EditorApplication.isCompiling)
return;
CoverageRunData.instance.Start();
m_CoverageReporterManager.CreateCoverageReporter();
ICoverageReporter coverageReporter = m_CoverageReporterManager.CoverageReporter;
if (coverageReporter != null)
coverageReporter.OnRunStarted(testsToRun);
}
public void RunFinished(ITestResultAdaptor result)
{
#if TEST_FRAMEWORK_1_3_OR_NEWER
if (m_Temp_RunFinishedCalled)
return;
#endif
if (!Coverage.enabled)
return;
if (CoverageRunData.instance.isRecording || m_IsConnectedToPlayer)
return;
CoverageRunData.instance.Stop();
if (!CoverageRunData.instance.DidTestsRun())
return;
ICoverageReporter coverageReporter = m_CoverageReporterManager.CoverageReporter;
if (coverageReporter != null)
coverageReporter.OnRunFinished(result);
m_CoverageReporterManager.GenerateReport();
#if TEST_FRAMEWORK_1_3_OR_NEWER
m_Temp_RunFinishedCalled = true;
#endif
}
public void TestStarted(ITestAdaptor test)
{
if (!Coverage.enabled)
return;
if (CoverageRunData.instance.HasLastIgnoredSuiteID() || m_IsConnectedToPlayer)
return;
if (test.RunState == RunState.Ignored)
{
if (test.IsSuite)
CoverageRunData.instance.SetLastIgnoredSuiteID(test.Id);
return;
}
if (test.IsSuite)
return;
CoverageRunData.instance.IncrementTestRunCount();
ICoverageReporter coverageReporter = m_CoverageReporterManager.CoverageReporter;
if (coverageReporter != null)
coverageReporter.OnTestStarted(test);
}
public void TestFinished(ITestResultAdaptor result)
{
if (!Coverage.enabled)
return;
if (m_IsConnectedToPlayer)
return;
if (result.Test.RunState == RunState.Ignored)
{
if (result.Test.IsSuite && string.Equals(CoverageRunData.instance.GetLastIgnoredSuiteID(), result.Test.Id))
CoverageRunData.instance.SetLastIgnoredSuiteID(string.Empty);
}
else if (!CoverageRunData.instance.HasLastIgnoredSuiteID() && !result.Test.IsSuite)
{
ICoverageReporter coverageReporter = m_CoverageReporterManager.CoverageReporter;
if (coverageReporter != null)
coverageReporter.OnTestFinished(result);
}
#if TEST_FRAMEWORK_1_3_OR_NEWER
// Temporary fix for UTF issue https://issuetracker.unity3d.com/issues/registered-callbacks-dont-work-after-domain-reload
// so that RunFinished is called on the last TestFinished
if (result.Test.IsSuite && result.Test.Parent == null)
{
RunFinished(result);
}
#endif
}
}
[InitializeOnLoad]
internal static class CoverageReporterStarter
{
public readonly static CoverageReporterManager CoverageReporterManager;
static CoverageReporterStarter()
{
#if NO_COV_EDITORPREF
if (!CommandLineManager.instance.runFromCommandLine)
{
bool localCoverageEnabled = CoveragePreferences.instance.GetBool("EnableCodeCoverage", false);
if (localCoverageEnabled != Coverage.enabled)
Coverage.enabled = localCoverageEnabled;
PackageManager.Events.registeringPackages += OnRegisteringPackages;
}
#endif
if (!Coverage.enabled)
return;
#if CONDITIONAL_IGNORE_SUPPORTED
ConditionalIgnoreAttribute.AddConditionalIgnoreMapping("IgnoreForCoverage", true);
#endif
CoverageReporterListener listener = ScriptableObject.CreateInstance<CoverageReporterListener>();
#if TEST_FRAMEWORK_1_3_OR_NEWER
TestRunnerApi.RegisterTestCallback(listener);
#else
TestRunnerApi api = ScriptableObject.CreateInstance<TestRunnerApi>();
api.RegisterCallbacks(listener);
#endif
CoverageSettings coverageSettings = new CoverageSettings()
{
resultsPathFromCommandLine = CommandLineManager.instance.coverageResultsPath,
historyPathFromCommandLine = CommandLineManager.instance.coverageHistoryPath
};
CoverageReporterManager = new CoverageReporterManager(coverageSettings);
listener.SetCoverageReporterManager(CoverageReporterManager);
AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload;
AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
// Generate a report if running from the command line,
// generateHTMLReport or generateBadgeReport or generateAdditionalReports is passed to -coverageOptions
// and -runTests has not been passed to the command line,
if (CommandLineManager.instance.runFromCommandLine &&
CoverageReporterManager.ShouldAutoGenerateReport() &&
!CommandLineManager.instance.runTests &&
!CoverageRunData.instance.reportWasGenerated)
{
// Start the timer for analytics for Report only
CoverageAnalytics.instance.StartTimer();
CoverageAnalytics.instance.CurrentCoverageEvent.actionID = ActionID.ReportOnly;
coverageSettings.rootFolderPath = CoverageUtils.GetRootFolderPath(coverageSettings);
coverageSettings.historyFolderPath = CoverageUtils.GetHistoryFolderPath(coverageSettings);
CoverageReporterManager.ReportGenerator.Generate(coverageSettings);
}
}
#if NO_COV_EDITORPREF
static void OnRegisteringPackages(PackageRegistrationEventArgs args)
{
if (args.removed.Any(info => info.name == "com.unity.testtools.codecoverage"))
{
Coverage.enabled = false;
}
}
#endif
static void OnBeforeAssemblyReload()
{
if (!CoverageRunData.instance.isRunning)
return;
if (!CoverageRunData.instance.DidTestsRun())
return;
if (CoverageRunData.instance.isRecording && CoverageRunData.instance.isRecordingPaused)
return;
ICoverageReporter coverageReporter = CoverageReporterManager.CoverageReporter;
if (coverageReporter != null)
coverageReporter.OnBeforeAssemblyReload();
}
static void OnAfterAssemblyReload()
{
if (!CoverageRunData.instance.isRunning)
return;
CoverageReporterManager.CreateCoverageReporter();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d8d52aaf8fdd54b95ab33af4cf05772e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,129 @@
using UnityEngine;
using UnityEditor.TestTools.CodeCoverage.OpenCover;
using UnityEditor.TestTools.CodeCoverage.Analytics;
namespace UnityEditor.TestTools.CodeCoverage
{
internal class CoverageReporterManager
{
private readonly CoverageSettings m_CoverageSettings = null;
private ICoverageReporter m_CoverageReporter = null;
CoverageReportGenerator m_ReportGenerator = null;
public CoverageReporterManager(CoverageSettings coverageSettings)
{
m_CoverageSettings = coverageSettings;
}
public ICoverageReporter CoverageReporter
{
get
{
if (m_CoverageReporter == null)
{
CreateCoverageReporter();
}
return m_CoverageReporter;
}
}
public void CreateCoverageReporter()
{
m_CoverageReporter = null;
// Use OpenCover format as currently this is the only one supported
CoverageFormat coverageFormat = CoverageFormat.OpenCover;
switch (coverageFormat)
{
case CoverageFormat.OpenCover:
m_CoverageSettings.resultsFileExtension = "xml";
m_CoverageSettings.resultsFolderSuffix = "-opencov";
m_CoverageSettings.resultsFileName = CoverageRunData.instance.isRecording ? "RecordingCoverageResults" : "TestCoverageResults";
m_CoverageReporter = new OpenCoverReporter();
break;
}
if (m_CoverageReporter != null)
{
m_CoverageReporter.OnInitialise(m_CoverageSettings);
}
}
public bool ShouldAutoGenerateReport()
{
bool shouldAutoGenerateReport = false;
bool cmdLineGenerateHTMLReport = CommandLineManager.instance.generateHTMLReport;
bool cmdLineGenerateBadge = CommandLineManager.instance.generateBadgeReport;
bool cmdLineGenerateAdditionalReports = CommandLineManager.instance.generateAdditionalReports;
bool generateHTMLReport = CoveragePreferences.instance.GetBool("GenerateHTMLReport", true);
bool generateAdditionalReports = CoveragePreferences.instance.GetBool("GenerateAdditionalReports", false);
bool generateBadge = CoveragePreferences.instance.GetBool("GenerateBadge", true);
bool autoGenerateReport = CoveragePreferences.instance.GetBool("AutoGenerateReport", true);
if (CommandLineManager.instance.runFromCommandLine)
{
if (CommandLineManager.instance.batchmode)
{
if (CommandLineManager.instance.useProjectSettings)
{
shouldAutoGenerateReport = cmdLineGenerateHTMLReport ||
cmdLineGenerateBadge ||
cmdLineGenerateAdditionalReports ||
(autoGenerateReport && (generateHTMLReport || generateBadge || generateAdditionalReports));
}
else
{
shouldAutoGenerateReport = cmdLineGenerateHTMLReport || cmdLineGenerateBadge || cmdLineGenerateAdditionalReports;
}
}
else
{
shouldAutoGenerateReport = cmdLineGenerateHTMLReport ||
cmdLineGenerateBadge ||
cmdLineGenerateAdditionalReports ||
(autoGenerateReport && (generateHTMLReport || generateBadge || generateAdditionalReports));
}
}
else
{
shouldAutoGenerateReport = autoGenerateReport && (generateHTMLReport || generateBadge || generateAdditionalReports);
}
return shouldAutoGenerateReport;
}
public void GenerateReport()
{
if (ShouldAutoGenerateReport())
{
if (m_CoverageSettings != null)
{
CoverageAnalytics.instance.CurrentCoverageEvent.actionID = ActionID.DataReport;
ReportGenerator.Generate(m_CoverageSettings);
}
}
else
{
// Clear ProgressBar left from saving results to file,
// otherwise continue on the same ProgressBar
EditorUtility.ClearProgressBar();
// Send Analytics event (Data Only)
CoverageAnalytics.instance.SendCoverageEvent(true);
}
}
public CoverageReportGenerator ReportGenerator
{
get
{
if (m_ReportGenerator == null)
m_ReportGenerator = new CoverageReportGenerator();
return m_ReportGenerator;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6dea3ceed709149e5969d3c20ad1898d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,91 @@
using System.IO;
using UnityEditor.TestTools.CodeCoverage.Utils;
namespace UnityEditor.TestTools.CodeCoverage
{
internal abstract class CoverageResultWriterBase<T> where T : class
{
protected CoverageSettings m_CoverageSettings;
public T CoverageSession { get; set; }
protected CoverageResultWriterBase(CoverageSettings coverageSettings)
{
m_CoverageSettings = coverageSettings;
}
public virtual void WriteCoverageSession(CoverageReportType reportType)
{
#if UNITY_2020_1_OR_NEWER
if (Compilation.CompilationPipeline.codeOptimization == Compilation.CodeOptimization.Release)
{
ResultsLogger.Log(ResultID.Warning_DebugCodeOptimization);
if (!CommandLineManager.instance.batchmode)
{
if (EditorUtility.DisplayDialog(
L10n.Tr("Code Coverage"),
L10n.Tr($"Code Coverage requires Code Optimization to be set to debug mode in order to obtain accurate coverage information. Do you want to switch to debug mode?\n\nNote that you would need to rerun {(CoverageRunData.instance.isRecording ? "the Coverage Recording session." : "the tests.")}"),
L10n.Tr("Switch to debug mode"),
L10n.Tr("Cancel")))
{
Compilation.CompilationPipeline.codeOptimization = Compilation.CodeOptimization.Debug;
EditorPrefs.SetBool("ScriptDebugInfoEnabled", true);
}
}
}
#endif
#if BURST_INSTALLED
if (EditorPrefs.GetBool("BurstCompilation", false) && !CommandLineManager.instance.burstDisabled)
{
ResultsLogger.Log(ResultID.Warning_BurstCompilationEnabled);
}
#endif
}
public void SetupCoveragePaths()
{
string folderName = CoverageUtils.GetProjectFolderName();
string resultsRootDirectoryName = string.Concat(folderName, m_CoverageSettings.resultsFolderSuffix);
bool isRecording = CoverageRunData.instance.isRecording;
// We want to save in the 'Recording' subdirectory of the results folder when recording
#if TEST_FRAMEWORK_2_0_OR_NEWER
string testSuite = isRecording ? "Recording" : "Automated";
#else
string testSuite = isRecording ? "Recording" : CoverageRunData.instance.testSuite;
#endif
string directoryName = CoverageUtils.JoinPaths(resultsRootDirectoryName, testSuite != null ? testSuite : "");
m_CoverageSettings.rootFolderPath = CoverageUtils.GetRootFolderPath(m_CoverageSettings);
m_CoverageSettings.historyFolderPath = CoverageUtils.GetHistoryFolderPath(m_CoverageSettings);
string filePath = CoverageUtils.JoinPaths(directoryName, m_CoverageSettings.resultsFileName);
filePath = CoverageUtils.JoinPaths(m_CoverageSettings.rootFolderPath, filePath);
filePath = CoverageUtils.NormaliseFolderSeparators(filePath);
CoverageUtils.EnsureFolderExists(Path.GetDirectoryName(filePath));
m_CoverageSettings.resultsRootFolderPath = CoverageUtils.NormaliseFolderSeparators(CoverageUtils.JoinPaths(m_CoverageSettings.rootFolderPath, resultsRootDirectoryName));
m_CoverageSettings.resultsFolderPath = CoverageUtils.NormaliseFolderSeparators(CoverageUtils.JoinPaths(m_CoverageSettings.rootFolderPath, directoryName));
m_CoverageSettings.resultsFilePath = filePath;
}
public void ClearCoverageFolderIfExists()
{
CoverageUtils.ClearFolderIfExists(m_CoverageSettings.resultsFolderPath, "*.xml");
}
public string GetRootFullEmptyPath()
{
return CoverageUtils.JoinPaths(m_CoverageSettings.rootFolderPath, m_CoverageSettings.resultsFileName + "_fullEmpty" + "." + m_CoverageSettings.resultsFileExtension);
}
protected string GetNextFullFilePath()
{
int nextFileIndex = m_CoverageSettings.hasPersistentRunData ? CoverageUtils.GetNumberOfFilesInFolder(m_CoverageSettings.resultsFolderPath, "*.xml", SearchOption.TopDirectoryOnly) : 0;
string fullFilePath = m_CoverageSettings.resultsFilePath + "_" + nextFileIndex.ToString("D4") + "." + m_CoverageSettings.resultsFileExtension;
return fullFilePath;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 028ecea1ebd36984e97fff009115e547
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,269 @@
using System;
using UnityEditor.TestTools.CodeCoverage.Analytics;
using UnityEngine;
namespace UnityEditor.TestTools.CodeCoverage
{
[Serializable]
internal class CoverageRunDataImplementation
{
[SerializeField]
private bool m_IsRunning = false;
[SerializeField]
private int m_TestRunCount = 0;
[SerializeField]
private string m_LastIgnoredSuite = string.Empty;
[SerializeField]
private bool m_IsRecording = false;
[SerializeField]
private bool m_IsRecordingPaused = false;
[SerializeField]
private bool m_ReportWasGenerated = false;
[SerializeField]
private bool m_IsGeneratingReport = false;
[SerializeField]
private string m_TestSuite = string.Empty;
public void Start(bool setupEvents = true)
{
m_LastIgnoredSuite = string.Empty;
m_IsRunning = true;
m_TestRunCount = 0;
if (setupEvents)
{
CoverageAnalytics.instance.CurrentCoverageEvent.actionID = ActionID.DataOnly;
CoverageAnalytics.instance.CurrentCoverageEvent.coverageModeId = CoverageModeID.TestRunner;
CoverageAnalytics.instance.StartTimer();
CoverageEventData.instance.StartSession(SessionMode.TestRunner);
}
}
public void Stop()
{
m_LastIgnoredSuite = string.Empty;
m_IsRunning = false;
}
public void StartRecording(bool setupEvents = true)
{
Start(setupEvents);
IncrementTestRunCount();
m_IsRecording = true;
m_IsRecordingPaused = false;
if (setupEvents)
{
CoverageAnalytics.instance.CurrentCoverageEvent.coverageModeId = CoverageModeID.Recording;
CoverageEventData.instance.StartSession(SessionMode.Recording);
}
}
public void PauseRecording()
{
m_IsRecordingPaused = true;
}
public void UnpauseRecording()
{
m_IsRecordingPaused = false;
}
public void StopRecording()
{
Stop();
m_IsRecording = false;
m_IsRecordingPaused = false;
}
public bool isRunning
{
get { return m_IsRunning; }
}
public bool isRecording
{
get { return m_IsRecording; }
}
public bool isRecordingPaused
{
get { return m_IsRecordingPaused; }
}
public bool isGeneratingReport
{
get { return m_IsGeneratingReport; }
}
public bool reportWasGenerated
{
get { return m_ReportWasGenerated; }
}
public void ReportGenerationStart()
{
m_IsGeneratingReport = true;
m_ReportWasGenerated = false;
}
public void ReportGenerationEnd(bool success)
{
m_IsGeneratingReport = false;
m_ReportWasGenerated = success;
}
public void IncrementTestRunCount()
{
m_TestRunCount++;
}
public bool DidTestsRun()
{
return m_TestRunCount > 0;
}
public void SetLastIgnoredSuiteID(string id)
{
m_LastIgnoredSuite = id;
}
public bool HasLastIgnoredSuiteID()
{
return m_LastIgnoredSuite.Length > 0;
}
public string GetLastIgnoredSuiteID()
{
return m_LastIgnoredSuite;
}
public string testSuite
{
set
{
if (!string.IsNullOrEmpty(value))
m_TestSuite = value;
}
get { return m_TestSuite; }
}
}
[Serializable]
internal class CoverageRunData : ScriptableSingleton<CoverageRunData>
{
[SerializeField]
private CoverageRunDataImplementation m_CoverageRunDataImplementation = null;
protected CoverageRunData() : base()
{
m_CoverageRunDataImplementation = new CoverageRunDataImplementation();
}
public bool isRunning
{
get { return m_CoverageRunDataImplementation.isRunning; }
}
public bool isRecording
{
get { return m_CoverageRunDataImplementation.isRecording; }
}
public bool isRecordingPaused
{
get { return m_CoverageRunDataImplementation.isRecordingPaused; }
}
public bool reportWasGenerated
{
get { return m_CoverageRunDataImplementation.reportWasGenerated; }
}
public void IncrementTestRunCount()
{
m_CoverageRunDataImplementation.IncrementTestRunCount();
}
public bool DidTestsRun()
{
return m_CoverageRunDataImplementation.DidTestsRun();
}
public void SetLastIgnoredSuiteID(string id)
{
m_CoverageRunDataImplementation.SetLastIgnoredSuiteID(id);
}
public bool HasLastIgnoredSuiteID()
{
return m_CoverageRunDataImplementation.HasLastIgnoredSuiteID();
}
public string GetLastIgnoredSuiteID()
{
return m_CoverageRunDataImplementation.GetLastIgnoredSuiteID();
}
public void Start()
{
m_CoverageRunDataImplementation.Start();
}
public void Stop()
{
m_CoverageRunDataImplementation.Stop();
}
public void StartRecording()
{
m_CoverageRunDataImplementation.StartRecording();
}
public void StopRecording()
{
m_CoverageRunDataImplementation.StopRecording();
}
public void PauseRecording()
{
m_CoverageRunDataImplementation.PauseRecording();
Events.InvokeOnCoverageSessionPaused();
}
public void UnpauseRecording()
{
m_CoverageRunDataImplementation.UnpauseRecording();
Events.InvokeOnCoverageSessionUnpaused();
}
public bool isGeneratingReport
{
get { return m_CoverageRunDataImplementation.isGeneratingReport; }
}
public void ReportGenerationStart()
{
m_CoverageRunDataImplementation.ReportGenerationStart();
}
public void ReportGenerationEnd(bool success)
{
m_CoverageRunDataImplementation.ReportGenerationEnd(success);
}
public string testSuite
{
set { m_CoverageRunDataImplementation.testSuite = value; }
get { return m_CoverageRunDataImplementation.testSuite; }
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 55b039429b8e8984782061e49b8ff4b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
using UnityEngine;
namespace UnityEditor.TestTools.CodeCoverage
{
internal class CoverageSettings
{
public const string ReportFolderName = "Report";
public const string ReportHistoryFolderName = "Report-history";
public const string PackageName = "Code Coverage";
public string rootFolderPath;
public string rootFolderName = "CodeCoverage";
public string resultsPathFromCommandLine;
public string resultsFileName = "TestCoverageResults";
public string resultsFileExtension;
public string resultsFolderSuffix;
public string resultsFolderPath;
public string resultsRootFolderPath;
public string resultsFilePath;
public string historyPathFromCommandLine;
public string historyFolderPath;
public string overrideIncludeAssemblies;
public bool overrideGenerateHTMLReport = false;
public bool hasPersistentRunData = true;
public bool resetCoverageData = true;
public bool revealReportInFinder = true;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 65defabc097778c4a9f9ac529de13d37
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ffd1d4863b8a4651b0579e45633f513a
timeCreated: 1635864462

Some files were not shown because too many files have changed in this diff Show More