Created unity project
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b5c29f7e37f22e4c8d285687af72aa3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 712896fdadbc6744585b09d9e159c025
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9bb904d2fa36b040bfc7c599e54c407
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ab5c92c8c1059a4e92378da3696821e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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")]
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5f6a9c343f474407aa9c6096dea2d0c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37180d43aa4b85c4b9076e2ef48a3b2a
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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 < 1000; ++i)
|
||||
/// {
|
||||
/// Instantiate(Resources.Load("ComplexPrefab1"));
|
||||
/// }
|
||||
///
|
||||
/// CodeCoverage.PauseRecording();
|
||||
///
|
||||
/// EditorSceneManager.OpenScene("Assets/Scenes/Scene2.unity");
|
||||
///
|
||||
/// CodeCoverage.UnpauseRecording();
|
||||
///
|
||||
/// for (i = 0; i < 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: baf0187acde1d4a4d8183adbd25f4941
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d1e5d1da297ded489d27da1867372cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4d2c6ec2b0608f4d915bdae931a5561
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b33e1d48774f68f479218e97f4ca4a8e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99c7f651b61814e4fbfa07eaa1457453
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace UnityEditor.TestTools.CodeCoverage.CommandLineParser
|
||||
{
|
||||
interface ICommandLineOption
|
||||
{
|
||||
string ArgName { get; }
|
||||
void ApplyValue(string value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e6a21b19469f7743953f66cd419decc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8760551a767291a4f9d72703986de775
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5518f4bf96c8e9849ab65cbaaf1191e1
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae5c3e58418ef514eba4fc6ade0ec75b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8502d38e600753d44a2a65242d06f132
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace UnityEditor.TestTools.CodeCoverage
|
||||
{
|
||||
internal enum CoverageFormat
|
||||
{
|
||||
OpenCover = 0,
|
||||
DotCover = 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8419585fc64d77e4d8e18b7311df59a7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 401e5b541d6e30e489f5751eec729fab
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74449815e747b4b1ba000bf66f12e01a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c2ede2081f2f4c45a6f7f4c92e3a735
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88cac9839726d46718b126833c76c5e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0d40fe321f9746dcbccb27824986511
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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 */} }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 561dcfbc5a4094415b3d8348f1a6b738
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ea0122a5084b4beca6bbb008fea821e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a74e938125304007a53cf9733cd1208
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ebffa2e2071ad4f79a3641b47e74b25e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86783b018856d4f82ab6105c443f2ffa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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 =>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
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f1f74c5e9b1146168b87690081420c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "Unity.TestTools.CodeCoverage.Editor.OpenCover.Model",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19c3df1967929405fba735480b3da9a7
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7c00a2c9a9fd476c947d35ae18e21fd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 448b5b9c7773f48be878eb5f56008baf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2adfa90d9eaaa4702b2457c09db2f5e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e49bf94f7d5348e2a48c3a09f3de201
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f84724c9beb0444b0b1a7166317d7262
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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(); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1b80d503cba7422cb21829a6891cde2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7c779bb30ff546c08fce46737f83ec5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6c4c078b09304bfeaae896e2e4ffa9e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68735f878b89447b4925a73a9074dfe9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2c36198237a34870a85b171e9097887
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c54348b43e9e464fa20499d8315beed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a8056948ac804bf891bd101b3216a55
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eecdf9bdfcb2949619db458f3e24c5e2
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 258e29582df66a741937fe410463ad97
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04c157fc0c43e40708bcbe2aa8738140
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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..");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ada728b01ae678c4eb6eaf209094ecb2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcb98740e9f34674a87ee205613f1de9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7c2d38a2adaf4e098760a3da9d5b6da
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace UnityEditor.TestTools.CodeCoverage
|
||||
{
|
||||
internal enum CoverageReportType
|
||||
{
|
||||
Full,
|
||||
FullEmpty,
|
||||
CoveredMethodsOnly
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 973d27eded053c746a8a3532c65dc75c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8d52aaf8fdd54b95ab33af4cf05772e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6dea3ceed709149e5969d3c20ad1898d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 028ecea1ebd36984e97fff009115e547
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55b039429b8e8984782061e49b8ff4b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 65defabc097778c4a9f9ac529de13d37
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
Reference in New Issue
Block a user