test
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:
|
File diff suppressed because it is too large
Load Diff
@@ -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:
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user