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 } }
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); } } }
public void WarnFormat(string format, params object[] args) { string message = string.Format(format, args); m_StringBuilder.AppendLine(message); ResultsLogger.LogSessionItem(message, LogVerbosityLevel.Warning); }
public void InfoFormat(string format, params object[] args) { string message = string.Format(format, args); m_StringBuilder.AppendLine(message); ResultsLogger.LogSessionItem(message, LogVerbosityLevel.Info); if (!CommandLineManager.instance.batchmode) { if (string.Equals(format, "Loading report '{0}' {1}/{2}")) { if (args.Length == 3) { if (Int32.TryParse(string.Format("{0}", args[1]), out int currentNum) && Int32.TryParse(string.Format("{0}", args[2]), out int totalNum) && currentNum <= totalNum && currentNum > 0 && totalNum > 0) { float progress = (1f / (totalNum + 1)) * currentNum; EditorUtility.DisplayProgressBar(ReportGeneratorStyles.ProgressTitle.text, ReportGeneratorStyles.ProgressInfoPreparing.text, progress); } } } } }
public void DebugFormat(string format, params object[] args) { string message = string.Format(format, args); m_StringBuilder.AppendLine(message); ResultsLogger.LogSessionItem(message, LogVerbosityLevel.Info); if (!CommandLineManager.instance.batchmode) { if (string.Equals(format, " Creating report {0}/{1} (Assembly: {2}, Class: {3})")) { if (args.Length >= 2) { if (Int32.TryParse(string.Format("{0}", args[0]), out int currentNum) && Int32.TryParse(string.Format("{0}", args[1]), out int totalNum) && currentNum <= totalNum && currentNum > 0 && totalNum > 0) { float progress = (1f / totalNum) * currentNum; EditorUtility.DisplayProgressBar(ReportGeneratorStyles.ProgressTitle.text, ReportGeneratorStyles.ProgressInfoCreating.text, progress); } } } } }
private void ProcessGenericMethods(CoverageSession coverageSession) { CoveredMethodStats[] coveredMethodStats = Coverage.GetStatsForAllCoveredMethods(); foreach (CoveredMethodStats coveredMethodStat in coveredMethodStats) { MethodBase method = coveredMethodStat.method; ResultsLogger.LogSessionItem($"Processing generic method: {method.Name}", LogVerbosityLevel.Verbose); Type declaringType = method.DeclaringType; string assemblyName = declaringType.Assembly.GetName().Name.ToLower(); if (!m_ReporterFilter.ShouldProcessAssembly(assemblyName)) { ResultsLogger.LogSessionItem($"Excluded assembly from generic (Assembly Filtering): {assemblyName}", LogVerbosityLevel.Verbose); continue; } if (!(declaringType.IsGenericType || method.IsGenericMethod)) { continue; } Module module = Array.Find(coverageSession.Modules, element => element.ModuleName.ToLower() == assemblyName); if (module != null) { string className = string.Empty; if (declaringType.IsGenericType) { Type genericTypeDefinition = declaringType.GetGenericTypeDefinition(); className = GenerateTypeName(genericTypeDefinition); } else if (method.IsGenericMethod) { className = GenerateTypeName(declaringType); } Class klass = Array.Find(module.Classes, element => element.FullName == className); if (klass != null) { Method targetMethod = Array.Find(klass.Methods, element => element.MetadataToken == method.MetadataToken); if (targetMethod != null) { ResultsLogger.LogSessionItem($"Processing included generic method: {method.Name}", LogVerbosityLevel.Verbose); CoveredSequencePoint[] coveredSequencePoints = Coverage.GetSequencePointsFor(method); foreach (CoveredSequencePoint coveredSequencePoint in coveredSequencePoints) { SequencePoint targetSequencePoint = Array.Find(targetMethod.SequencePoints, element => (element.StartLine == coveredSequencePoint.line && element.Offset == coveredSequencePoint.ilOffset)); if (targetSequencePoint != null) { targetSequencePoint.VisitCount += (int)coveredSequencePoint.hitCount; } } } } } } }
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); }
internal CoverageSession GenerateOpenCoverSession() { ResultsLogger.LogSessionItem("Started OpenCover Session", LogVerbosityLevel.Info); CoverageSession coverageSession = null; UInt32 fileUID = 0; List <Module> moduleList = new List <Module>(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); float progressInterval = 0.9f / assemblies.Length; float currentProgress = 0.0f; bool shouldGenerateAdditionalMetrics = m_ReporterFilter.ShouldGenerateAdditionalMetrics(); foreach (Assembly assembly in assemblies) { string assemblyName = assembly.GetName().Name.ToLower(); ResultsLogger.LogSessionItem($"Processing assembly: {assemblyName}", LogVerbosityLevel.Verbose); try { if (assembly.GetCustomAttribute <ExcludeFromCoverageAttribute>() != null || assembly.GetCustomAttribute <ExcludeFromCodeCoverageAttribute>() != null) { ResultsLogger.LogSessionItem($"Excluded assembly (ExcludeFromCoverage): {assemblyName}", LogVerbosityLevel.Verbose); continue; } } catch { ResultsLogger.Log(ResultID.Warning_ExcludeAttributeAssembly, assemblyName); } if (!CommandLineManager.instance.batchmode) { EditorUtility.DisplayProgressBar(Styles.ProgressTitle.text, Styles.ProgressGatheringResults.text, currentProgress); } currentProgress += progressInterval; if (!m_ReporterFilter.ShouldProcessAssembly(assemblyName)) { ResultsLogger.LogSessionItem($"Excluded assembly (Assembly Filtering): {assemblyName}", LogVerbosityLevel.Verbose); continue; } List <Class> coveredClasses = new List <Class>(); List <string> filesNotFound = new List <string>(); Dictionary <string, UInt32> fileList = new Dictionary <string, UInt32>(); Type[] assemblyTypes = null; m_ExcludedMethods = null; m_ExcludedTypes = null; try { assemblyTypes = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { // This exception can be thrown if some of the types from this assembly can't be loaded. If this // happens, the Types property array contains a Type for all loaded types and null for each // type that couldn't be loaded. assemblyTypes = ex.Types; m_ReporterFilter.ShouldProcessAssembly(assemblyName); } // Debug.Assert(assemblyTypes != null) ResultsLogger.Log(ResultID.Assert_NullAssemblyTypes, assemblyTypes == null ? "0" : "1"); ResultsLogger.LogSessionItem($"Processing included assembly: {assemblyName}", LogVerbosityLevel.Info); foreach (Type type in assemblyTypes) { // The type can be null if the ReflectionTypeLoadException has been thrown previously. if (type == null) { continue; } string className = type.FullName; ResultsLogger.LogSessionItem($"Processing class: {className}", LogVerbosityLevel.Verbose); try { if (type.GetCustomAttribute <ExcludeFromCoverageAttribute>() != null || type.GetCustomAttribute <ExcludeFromCodeCoverageAttribute>() != null || CheckIfParentMemberIsExcluded(type)) { ResultsLogger.LogSessionItem($"Excluded class (ExcludeFromCoverage): {className}", LogVerbosityLevel.Verbose); if (m_ExcludedTypes == null) { m_ExcludedTypes = new List <string>(); } m_ExcludedTypes.Add(type.FullName); continue; } } catch { ResultsLogger.Log(ResultID.Warning_ExcludeAttributeClass, className, assemblyName); } ResultsLogger.LogSessionItem($"Processing included class: {className}", LogVerbosityLevel.Info); CoveredMethodStats[] classMethodStatsArray = Coverage.GetStatsFor(type); if (classMethodStatsArray.Length > 0) { List <Method> coveredMethods = new List <Method>(); foreach (CoveredMethodStats classMethodStats in classMethodStatsArray) { MethodBase method = classMethodStats.method; if (method == null) { continue; } string methodName = method.Name; ResultsLogger.LogSessionItem($"Processing method: {methodName}", LogVerbosityLevel.Verbose); try { if (method.GetCustomAttribute <ExcludeFromCoverageAttribute>() != null || method.GetCustomAttribute <ExcludeFromCodeCoverageAttribute>() != null || CheckIfParentMemberIsExcluded(method)) { ResultsLogger.LogSessionItem($"Excluded method (ExcludeFromCoverage): {methodName}", LogVerbosityLevel.Verbose); if (m_ExcludedMethods == null) { m_ExcludedMethods = new List <MethodBase>(); } m_ExcludedMethods.Add(method); continue; } } catch { ResultsLogger.Log(ResultID.Warning_ExcludeAttributeMethod, methodName, className, assemblyName); } if (IsGetterSetterPropertyExcluded(method, type)) { ResultsLogger.LogSessionItem($"Excluded method (ExcludeFromCoverage): {methodName}", LogVerbosityLevel.Verbose); continue; } if (classMethodStats.totalSequencePoints > 0) { List <SequencePoint> coveredSequencePoints = new List <SequencePoint>(); uint fileId = 0; CoveredSequencePoint[] classMethodSequencePointsArray = Coverage.GetSequencePointsFor(method); foreach (CoveredSequencePoint classMethodSequencePoint in classMethodSequencePointsArray) { string filename = classMethodSequencePoint.filename; if (filesNotFound.Contains(filename) || !m_ReporterFilter.ShouldProcessFile(filename)) { ResultsLogger.LogSessionItem($"Excluded method (Path Filtering): {methodName}", LogVerbosityLevel.Verbose); continue; } if (!fileList.TryGetValue(filename, out fileId)) { if (!File.Exists(filename)) { filesNotFound.Add(filename); continue; } else { fileId = ++fileUID; fileList.Add(filename, fileId); } } SequencePoint coveredSequencePoint = new SequencePoint(); coveredSequencePoint.FileId = fileId; coveredSequencePoint.StartLine = (int)classMethodSequencePoint.line; coveredSequencePoint.StartColumn = (int)classMethodSequencePoint.column; coveredSequencePoint.EndLine = (int)classMethodSequencePoint.line; coveredSequencePoint.EndColumn = (int)classMethodSequencePoint.column; coveredSequencePoint.VisitCount = (int)classMethodSequencePoint.hitCount; coveredSequencePoint.Offset = (int)classMethodSequencePoint.ilOffset; coveredSequencePoints.Add(coveredSequencePoint); } if (coveredSequencePoints.Count > 0) { Method coveredMethod = new Method(); coveredMethod.MetadataToken = method.MetadataToken; coveredMethod.FullName = GenerateMethodName(method); coveredMethod.FileRef = new FileRef() { UniqueId = fileId }; coveredMethod.IsConstructor = IsConstructor(method) || IsStaticConstructor(method); coveredMethod.IsStatic = method.IsStatic; coveredMethod.IsSetter = IsPropertySetter(method); coveredMethod.IsGetter = IsPropertyGetter(method); coveredMethod.SequencePoints = coveredSequencePoints.ToArray(); if (shouldGenerateAdditionalMetrics) { coveredMethod.CyclomaticComplexity = method.CalculateCyclomaticComplexity(); } ResultsLogger.LogSessionItem($"Processing included method: {coveredMethod.FullName}", LogVerbosityLevel.Verbose); coveredMethods.Add(coveredMethod); } } } if (coveredMethods.Count > 0) { Class coveredClass = new Class(); coveredClass.FullName = GenerateTypeName(type); coveredClass.Methods = coveredMethods.ToArray(); coveredClasses.Add(coveredClass); } } } if (coveredClasses.Count != 0) { Module module = new Module(); module.ModuleName = assembly.GetName().Name; List <ModelFile> coveredFileList = new List <ModelFile>(); foreach (KeyValuePair <string, UInt32> fileEntry in fileList) { ModelFile coveredFile = new ModelFile(); coveredFile.FullPath = CoverageUtils.NormaliseFolderSeparators(fileEntry.Key); if (CommandLineManager.instance.pathStrippingSpecified) { coveredFile.FullPath = CommandLineManager.instance.pathStripping.StripPath(coveredFile.FullPath); } coveredFile.UniqueId = fileEntry.Value; coveredFileList.Add(coveredFile); } module.Files = coveredFileList.ToArray(); module.Classes = coveredClasses.ToArray(); moduleList.Add(module); } } if (moduleList.Count > 0) { coverageSession = new CoverageSession(); coverageSession.Modules = moduleList.ToArray(); ProcessGenericMethods(coverageSession); foreach (Module coveredModule in moduleList) { foreach (Class coveredClass in coveredModule.Classes) { foreach (Method coveredMethod in coveredClass.Methods) { UpdateMethodSummary(coveredMethod); } UpdateClassSummary(coveredClass); } UpdateModuleSummary(coveredModule); } UpdateSessionSummary(coverageSession); } ResultsLogger.LogSessionItem("Finished OpenCover Session", LogVerbosityLevel.Info); return(coverageSession); }