VR4Medical/ICI/Library/PackageCache/com.unity.test-framework.performance@92d1d09a72ed/Editor/TestResultsParser.cs
2025-07-29 13:45:50 +03:00

212 lines
6.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using Unity.PerformanceTesting.Data;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine;
namespace Unity.PerformanceTesting.Editor
{
static class TestResultsParser
{
internal static Run GetPerformanceTestRunData(ITestResultAdaptor testResults)
{
var testOutputs = GetTestOutputsRecursively(testResults);
return ExtractPerformanceRunData(testOutputs);
}
internal static Run GetPerformanceTestRunDataFromXmlFile(string xmlResultsPath)
{
try
{
var xmlDocument = XDocument.Load(xmlResultsPath);
return GetPerformanceTestRunData(xmlDocument);
}
catch (Exception e)
{
Debug.LogWarning("Failed to load performance test results from XML.\n" +
$"{e.GetType()}: {e.Message}\n" +
$"{e.StackTrace}");
}
return null;
}
static Run GetPerformanceTestRunData(XDocument testResults)
{
var testOutputs = testResults.Descendants("output")
.Select(outputElement => outputElement.Value)
.ToArray();
return ExtractPerformanceRunData(testOutputs);
}
static string[] GetTestOutputsRecursively(ITestResultAdaptor testResults)
{
var res = new List<string>();
if (testResults != null)
{
AccumulateTestRunOutputRecursively(testResults, res);
}
return res.ToArray();
}
static void AccumulateTestRunOutputRecursively(ITestResultAdaptor parentResult, List<string> outputs)
{
var children = parentResult.Children;
foreach (var child in children)
{
AccumulateTestRunOutputRecursively(child, outputs);
}
var currentTestOutput = parentResult.Output;
if (!string.IsNullOrEmpty(currentTestOutput))
{
outputs.Add(currentTestOutput);
}
}
internal static Run ExtractPerformanceRunData(string[] testOutputs)
{
if (testOutputs == null || testOutputs.Length == 0)
{
return null;
}
try
{
var run = ExtractPerformanceTestRunInfo(testOutputs);
if (run != null)
{
DeserializeTestResults(testOutputs, run);
}
return run;
}
catch (FormatException fe)
{
Debug.LogError($"Invalid performance test results format: {fe.Message}");
}
catch (Exception e)
{
Debug.LogError($"Unexpected exception while reading performance test results: {e.Message}");
}
return null;
}
static Run ExtractPerformanceTestRunInfo(string[] testOutputs)
{
foreach (var output in testOutputs)
{
const string pattern = @"##performancetestruninfo2:(.+)\n";
var regex = new Regex(pattern);
var matches = regex.Match(output);
if (matches.Groups.Count == 0 || matches.Captures.Count == 0)
{
continue;
}
if (matches.Groups[1].Captures.Count > 1)
{
throw new FormatException("Multiple execution metadata instances found.");
}
var json = matches.Groups[1].Value;
if (string.IsNullOrEmpty(json))
{
throw new FormatException("No execution metadata found.");
}
return ReadPerformanceTestRunJsonObject(json);
}
return null;
}
static Run ReadPerformanceTestRunJsonObject(string json)
{
try
{
return JsonUtility.FromJson<Run>(json);
}
catch (Exception e)
{
throw new FormatException($"Failed to read performance execution metadata from json string: '{json}'.\n" +
$"Exception: {e.Message}\n" +
$"{e.StackTrace}");
}
}
static void DeserializeTestResults(string[] testOutputs, Run run)
{
foreach (var output in testOutputs)
{
foreach (var line in output.Split('\n'))
{
var json = GetJsonFromHashtag("performancetestresult2", line);
if (json == null)
{
continue;
}
var result = ReadPerformanceTestResultJsonObject(json);
if (result != null)
{
run.Results.Add(result);
}
}
}
}
static PerformanceTestResult ReadPerformanceTestResultJsonObject(string json)
{
try
{
return JsonUtility.FromJson<PerformanceTestResult>(json);
}
catch (Exception e)
{
Debug.LogWarning($"Failed to read performance results from json string: '{json}'.\n" +
$"Exception: {e.Message}\n" +
$"{e.StackTrace}");
}
return null;
}
static string GetJsonFromHashtag(string tag, string line)
{
if (!line.Contains($"##{tag}:"))
{
return null;
}
var jsonStart = line.IndexOf('{');
var openBrackets = 0;
var stringIndex = jsonStart;
while (openBrackets > 0 || stringIndex == jsonStart)
{
var character = line[stringIndex];
switch (character)
{
case '{':
openBrackets++;
break;
case '}':
openBrackets--;
break;
}
stringIndex++;
}
var jsonEnd = stringIndex;
return line.Substring(jsonStart, jsonEnd - jsonStart);
}
}
}