A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using UnityEditor.TestTools.TestRunner.Api;
6using UnityEngine;
7using UnityEngine.TestRunner.NUnitExtensions.Runner;
8
9namespace UnityEditor.TestTools.TestRunner
10{
11 /// <summary>
12 /// Handles deserialization of TestSettings from a provided json file path.
13 /// </summary>
14 internal class TestSettingsDeserializer : ITestSettingsDeserializer
15 {
16 private static readonly SettingsMap[] s_SettingsMapping =
17 {
18 new SettingsMap<ScriptingImplementation>("scriptingBackend", (settings, value) => settings.scriptingBackend = value),
19 new SettingsMap<string>("architecture", (settings, value) => settings.Architecture = value),
20 new SettingsMap<ApiCompatibilityLevel>("apiProfile", (settings, value) => settings.apiProfile = value),
21 new SettingsMap<bool>("appleEnableAutomaticSigning", (settings, value) => settings.appleEnableAutomaticSigning = value),
22 new SettingsMap<string>("appleDeveloperTeamID", (settings, value) => settings.appleDeveloperTeamID = value),
23 new SettingsMap<ProvisioningProfileType>("iOSManualProvisioningProfileType", (settings, value) => settings.iOSManualProvisioningProfileType = value),
24 new SettingsMap<string>("iOSManualProvisioningProfileID", (settings, value) => settings.iOSManualProvisioningProfileID = value),
25 new SettingsMap<string>("iOSTargetSDK", (settings, value) => settings.iOSTargetSDK = value),
26 new SettingsMap<ProvisioningProfileType>("tvOSManualProvisioningProfileType", (settings, value) => settings.tvOSManualProvisioningProfileType = value),
27 new SettingsMap<string>("tvOSManualProvisioningProfileID", (settings, value) => settings.tvOSManualProvisioningProfileID = value),
28 new SettingsMap<string>("tvOSTargetSDK", (settings, value) => settings.tvOSTargetSDK = value),
29 new SettingsMap<string>("playerGraphicsAPI", (settings, value) =>
30 {
31 settings.autoGraphicsAPIs = false;
32 settings.playerGraphicsAPIs = new[] {value};
33 }),
34 new SettingsMap<bool>("androidBuildAppBundle", (settings, value) =>
35 {
36 settings.androidBuildAppBundle = value;
37 }),
38 new SettingsMap<List<object>>("ignoreTests", (settings, list) =>
39 {
40 settings.ignoreTests = list.Select(item =>
41 {
42 var dictionary = (Dictionary<string, object>)item;
43 if (dictionary.ContainsKey("test") && dictionary.ContainsKey("ignoreComment"))
44 {
45 return new IgnoreTest()
46 {
47 test = dictionary["test"] as string,
48 ignoreComment = dictionary["ignoreComment"] as string
49 };
50 }
51
52 throw new Exception("Wrong format for ignore test. Expected \"test\" and \"ignoreComment\".");
53 }).ToArray();
54 }),
55 new SettingsMap<Dictionary<string, object>>("featureFlags", (settings, dictionary) =>
56 {
57 var converted = dictionary.ToDictionary(pair => pair.Key, pair => (bool)pair.Value);
58 var featureFlags = new FeatureFlags();
59 if (converted.ContainsKey("fileCleanUpCheck"))
60 {
61 featureFlags.fileCleanUpCheck = converted["fileCleanUpCheck"];
62 }
63 if (converted.ContainsKey("strictDomainReload"))
64 {
65 featureFlags.strictDomainReload = converted["strictDomainReload"];
66 }
67 if (converted.ContainsKey("requiresSplashScreen"))
68 {
69 featureFlags.requiresSplashScreen = converted["requiresSplashScreen"];
70 }
71 if (converted.ContainsKey("disableNestedEnumeratorBugfix"))
72 {
73 featureFlags.disableNestedEnumeratorBugfix = converted["disableNestedEnumeratorBugfix"];
74 }
75
76 settings.featureFlags = featureFlags;
77 }),
78#if UNITY_2023_2_OR_NEWER
79 new SettingsMap<WebGLClientBrowserType>("webGLClientBrowserType", (settings, value) => settings.webGLClientBrowserType = value),
80 new SettingsMap<string>("webGLClientBrowserPath", (settings, value) => settings.webGLClientBrowserPath = value),
81#endif
82 };
83
84 private readonly Func<ITestSettings> m_TestSettingsFactory;
85 public TestSettingsDeserializer(Func<ITestSettings> testSettingsFactory)
86 {
87 m_TestSettingsFactory = testSettingsFactory;
88 }
89
90 public ITestSettings GetSettingsFromJsonFile(string jsonFilePath)
91 {
92 var text = File.ReadAllText(jsonFilePath);
93 var settingsDictionary = Json.Deserialize(text) as Dictionary<string, object>;
94
95 var testSettings = m_TestSettingsFactory();
96 if (settingsDictionary == null)
97 {
98 return testSettings;
99 }
100
101 foreach (var settingsMap in s_SettingsMapping)
102 {
103 if (!settingsDictionary.ContainsKey(settingsMap.Key))
104 {
105 continue;
106 }
107
108 if (settingsMap.Type.IsEnum)
109 {
110 SetEnumValue(settingsMap.Key, settingsDictionary[settingsMap.Key], settingsMap.Type, value => settingsMap.ApplyToSettings(testSettings, value));
111 }
112 else
113 {
114 SetValue(settingsMap.Key, settingsDictionary[settingsMap.Key], settingsMap.Type, value => settingsMap.ApplyToSettings(testSettings, value));
115 }
116 }
117
118 return testSettings;
119 }
120
121 private abstract class SettingsMap
122 {
123 public string Key { get; }
124 public Type Type { get; }
125 protected SettingsMap(string key, Type type)
126 {
127 Key = key;
128 Type = type;
129 }
130
131 public abstract void ApplyToSettings(ITestSettings settings, object value);
132 }
133
134 private class SettingsMap<T> : SettingsMap
135 {
136 private Action<ITestSettings, T> m_Setter;
137 public SettingsMap(string key, Action<ITestSettings, T> setter) : base(key, typeof(T))
138 {
139 m_Setter = setter;
140 }
141
142 public override void ApplyToSettings(ITestSettings settings, object value)
143 {
144 m_Setter(settings, (T)value);
145 }
146 }
147
148 private static void SetEnumValue(string key, object value, Type type, Action<object> setter)
149 {
150 object enumValue;
151 if (TryGetEnum(value as string, type, out enumValue))
152 {
153 setter(enumValue);
154 return;
155 }
156
157 var acceptedValues = string.Join(", ", Enum.GetValues(type).OfType<object>().Select(val => val.ToString()).ToArray());
158
159 Debug.LogFormat("Could not convert '{0}' argument '{1}' to a valid {2}. Accepted values: {3}.", key, value, type.Name, acceptedValues);
160 }
161
162 private static bool TryGetEnum(string value, Type type, out object enumValue)
163 {
164 try
165 {
166 enumValue = Enum.Parse(type, value, true);
167 return true;
168 }
169 catch (Exception)
170 {
171 enumValue = null;
172 return false;
173 }
174 }
175
176 private static void SetValue(string key, object value, Type type, Action<object> setter)
177 {
178 if (type.IsInstanceOfType(value))
179 {
180 setter(value);
181 return;
182 }
183
184 Debug.LogFormat("Could not convert '{0}' argument '{1}' to a valid {2}.", key, value, type.Name);
185 }
186 }
187}