A game about forced loneliness, made by TACStudios
1#if !UNITY_2023_2_OR_NEWER
2using System;
3using System.Collections.Generic;
4using System.Linq;
5using NUnit.Framework;
6using NUnit.Framework.Interfaces;
7using UnityEditor.TestTools.TestRunner.TestRun;
8using UnityEngine;
9using UnityEngine.TestTools;
10
11namespace UnityEditor.TestTools.TestRunner.Api.Analytics
12{
13 internal static class AnalyticsReporter
14 {
15 private const string VendorKey = "unity.test-framework";
16 private const string RunFinishedEventName = "runFinished";
17 private const string AnalyzeTestTreeName = "analyzeTestTree";
18
19 private static bool isSetUp;
20 private static IDictionary<string, bool> methodsAnalyzed;
21 private static IDictionary<string, bool> typesAnalyzed;
22
23 private static void SetUpIfNeeded()
24 {
25 if (isSetUp)
26 {
27 return;
28 }
29
30 isSetUp = true;
31 EditorAnalytics.RegisterEventWithLimit(RunFinishedEventName, 60, 30, VendorKey);
32 EditorAnalytics.RegisterEventWithLimit(AnalyzeTestTreeName, 3, 30, VendorKey);
33 }
34
35 [InitializeOnLoadMethod]
36 private static void RegisterCallbacks()
37 {
38 ScriptableObject.CreateInstance<TestRunnerApi>().RegisterCallbacks(new AnalyticsTestCallback(ReportRunFinished));
39 }
40
41 private static void ReportRunFinished(ITestResultAdaptor testResult)
42 {
43 SetUpIfNeeded();
44
45 var activeRuns = TestJobDataHolder.instance.TestRuns;
46 if (activeRuns.Count == 0)
47 {
48 return;
49 }
50
51 var executionSettings = activeRuns[0].executionSettings;
52 var filter = executionSettings.filters.First();
53 var runFinishedData = new RunFinishedData
54 {
55 totalTests = testResult.Test.TestCaseCount,
56 numPassedTests = testResult.PassCount,
57 numFailedTests = testResult.FailCount,
58 numInconclusiveTests = testResult.InconclusiveCount,
59 numSkippedTests = testResult.SkipCount,
60 testModeFilter = (int)filter.testMode,
61 targetPlatform = executionSettings.targetPlatform != null ? executionSettings.targetPlatform.ToString() : "editor",
62 runSynchronously = executionSettings.runSynchronously,
63 isCustomRunner = false,
64 isFiltering = executionSettings.filters.Any(f => f.HasAny()),
65 isAutomated = IsCommandLineArgSet("-automated"),
66 isFromCommandLine = IsCommandLineArgSet("-runTests"),
67 totalTestDuration = testResult.Duration,
68 totalRunDuration = (DateTime.Now - Convert.ToDateTime(activeRuns[0].startTime)).TotalSeconds
69 };
70
71 EditorAnalytics.SendEventWithLimit(RunFinishedEventName, runFinishedData, 1);
72 }
73
74 private static bool IsCommandLineArgSet(string command)
75 {
76 return Environment.GetCommandLineArgs().Any(c => c == command);
77 }
78
79 internal static void AnalyzeTestTreeAndReport(ITest testTree)
80 {
81 SetUpIfNeeded();
82
83 typesAnalyzed = new Dictionary<string, bool>();
84 methodsAnalyzed = new Dictionary<string, bool>();
85 var data = new TestTreeData();
86 AnalyzeTestTreeNode(testTree, data);
87 EditorAnalytics.SendEventWithLimit(AnalyzeTestTreeName, data, 1);
88 }
89
90 private static void AnalyzeTestTreeNode(ITest node, TestTreeData data)
91 {
92 var attributes = GetAttributes(node).ToArray();
93 if (attributes.OfType<TestAttribute>().Any())
94 {
95 data.numTestAttributes++;
96 }
97 if (attributes.OfType<UnityTestAttribute>().Any())
98 {
99 data.numUnityTestAttributes++;
100 }
101 if (attributes.OfType<CategoryAttribute>().Any())
102 {
103 data.numCategoryAttributes++;
104 }
105 if (attributes.OfType<TestFixtureAttribute>().Any())
106 {
107 data.numTestFixtureAttributes++;
108 }
109 if (attributes.OfType<ConditionalIgnoreAttribute>().Any())
110 {
111 data.numConditionalIgnoreAttributes++;
112 }
113 if (attributes.OfType<UnityPlatformAttribute>().Any())
114 {
115 data.numUnityPlatformAttributes++;
116 }
117
118 if (node.HasChildren)
119 {
120 foreach (var test in node.Tests)
121 {
122 AnalyzeTestTreeNode(test, data);
123 }
124 }
125 else
126 {
127 data.totalNumberOfTests++;
128 }
129 }
130
131 private static IEnumerable<NUnitAttribute> GetAttributes(ITest node)
132 {
133 if (node.Method != null)
134 {
135 var key = $"{node.MethodName},{node.ClassName}";
136 if (methodsAnalyzed.ContainsKey(key))
137 {
138 yield break;
139 }
140
141 methodsAnalyzed[key] = true;
142 foreach (var attribute in (node).Method.GetCustomAttributes<NUnitAttribute>(true))
143 {
144 yield return attribute;
145 }
146
147 var typeKey = node.Method.TypeInfo.FullName;
148 if (typesAnalyzed.ContainsKey(typeKey))
149 {
150 yield break;
151 }
152
153 typesAnalyzed[typeKey] = true;
154 foreach (var attribute in node.Method.TypeInfo.GetCustomAttributes<NUnitAttribute>(true))
155 {
156 yield return attribute;
157 }
158 }
159 }
160 }
161}
162#endif