Skip to content

Commit 852dacc

Browse files
committed
Hopefully fix a handful of tests
1 parent 3c0ab94 commit 852dacc

File tree

5 files changed

+254
-8
lines changed

5 files changed

+254
-8
lines changed

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs

+13-3
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ public void CheckMonoComponentsMask (bool enableProfiler, bool useInterpreter, b
273273
[Test]
274274
[TestCaseSource (nameof (CheckAssemblyCountsSource))]
275275
[NonParallelizable]
276+
[Category ("CoreCLR")]
276277
public void CheckAssemblyCounts (bool isRelease, bool aot)
277278
{
278279
if (aot && TargetRuntimeHelper.UseCoreCLR) {
@@ -294,8 +295,17 @@ public void CheckAssemblyCounts (bool isRelease, bool aot)
294295
string objPath = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath);
295296

296297
List<EnvironmentHelper.EnvironmentFile> envFiles = EnvironmentHelper.GatherEnvironmentFiles (objPath, String.Join (";", abis), true);
297-
EnvironmentHelper.ApplicationConfig app_config = EnvironmentHelper.ReadApplicationConfig (envFiles);
298-
Assert.That (app_config, Is.Not.Null, "application_config must be present in the environment files");
298+
uint number_of_assemblies_in_apk;
299+
300+
if (TargetRuntimeHelper.UseMonoRuntime) {
301+
EnvironmentHelper.ApplicationConfig app_config = EnvironmentHelper.ReadApplicationConfig (envFiles);
302+
Assert.That (app_config, Is.Not.Null, "(MonoVM) application_config must be present in the environment files");
303+
number_of_assemblies_in_apk = app_config.number_of_assemblies_in_apk;
304+
} else {
305+
EnvironmentHelper.ApplicationConfigCLR app_config = EnvironmentHelper.ReadApplicationConfigCLR (envFiles);
306+
Assert.That (app_config, Is.Not.Null, "(CoreCLR) application_config must be present in the environment files");
307+
number_of_assemblies_in_apk = app_config.number_of_assemblies_in_apk;
308+
}
299309

300310
if (aot) {
301311
foreach (var env in envFiles) {
@@ -309,7 +319,7 @@ public void CheckAssemblyCounts (bool isRelease, bool aot)
309319
foreach (string abi in abis) {
310320
AndroidTargetArch arch = MonoAndroidHelper.AbiToTargetArch (abi);
311321
Assert.AreEqual (
312-
app_config.number_of_assemblies_in_apk,
322+
number_of_assemblies_in_apk,
313323
helper.GetNumberOfAssemblies (arch: arch),
314324
$"Assembly count must be equal between ApplicationConfig and the archive contents for architecture {arch} (ABI: {abi})"
315325
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
using NUnit.Framework;
5+
namespace Xamarin.Android.Build.Tests;
6+
7+
partial class EnvironmentHelper
8+
{
9+
// This must be identical to the like-named structure in src/native/clr/include/xamarin-app.hh
10+
public sealed class ApplicationConfigCLR
11+
{
12+
public bool uses_assembly_preload;
13+
public bool jni_add_native_method_registration_attribute_present;
14+
public bool marshal_methods_enabled;
15+
public bool ignore_split_configs;
16+
public uint number_of_runtime_properties;
17+
public uint package_naming_policy;
18+
public uint environment_variable_count;
19+
public uint system_property_count;
20+
public uint number_of_assemblies_in_apk;
21+
public uint bundled_assembly_name_width;
22+
public uint number_of_dso_cache_entries;
23+
public uint number_of_aot_cache_entries;
24+
public uint number_of_shared_libraries;
25+
public uint android_runtime_jnienv_class_token;
26+
public uint jnienv_initialize_method_token;
27+
public uint jnienv_registerjninatives_method_token;
28+
public uint jni_remapping_replacement_type_count;
29+
public uint jni_remapping_replacement_method_index_entry_count;
30+
public string android_package_name = String.Empty;
31+
public bool managed_marshal_methods_lookup_enabled;
32+
}
33+
34+
const uint ApplicationConfigFieldCountCLR = 20;
35+
36+
static readonly string[] requiredSharedLibrarySymbolsCLR = {
37+
"app_system_properties",
38+
"init_runtime_property_names",
39+
"init_runtime_property_values",
40+
"java_to_managed_hashes",
41+
"java_to_managed_map",
42+
"java_type_count",
43+
"java_type_names",
44+
"managed_to_java_map",
45+
"managed_to_java_map_module_count",
46+
AppEnvironmentVariablesSymbolName,
47+
ApplicationConfigSymbolName,
48+
};
49+
50+
// Reads all the environment files, makes sure they all have identical contents in the
51+
// `application_config` structure and returns the config if the condition is true
52+
public static ApplicationConfigCLR? ReadApplicationConfigCLR (List<EnvironmentFile> envFilePaths)
53+
{
54+
if (envFilePaths.Count == 0) {
55+
return null;
56+
}
57+
58+
ApplicationConfigCLR app_config = ReadApplicationConfigCLR (envFilePaths [0]);
59+
60+
for (int i = 1; i < envFilePaths.Count; i++) {
61+
AssertApplicationConfigIsIdentical (app_config, envFilePaths [0].Path, ReadApplicationConfigCLR (envFilePaths[i]), envFilePaths[i].Path);
62+
}
63+
64+
return app_config;
65+
}
66+
67+
static ApplicationConfigCLR? ReadApplicationConfigCLR (EnvironmentFile envFile)
68+
{
69+
(NativeAssemblyParser parser, NativeAssemblyParser.AssemblerSymbol appConfigSymbol) = GetAssemblyParserAndValidateConfig (envFile);
70+
71+
var pointers = new List <string> ();
72+
var ret = new ApplicationConfigCLR ();
73+
uint fieldCount = 0;
74+
string[] field;
75+
76+
foreach (NativeAssemblyParser.AssemblerSymbolItem item in appConfigSymbol.Contents) {
77+
field = GetField (envFile.Path, parser.SourceFilePath, item.Contents, item.LineNumber);
78+
79+
if (CanIgnoreAssemblerField (field[0])) {
80+
continue;
81+
}
82+
83+
switch (fieldCount) {
84+
case 0: // uses_assembly_preload: bool / .byte
85+
AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber);
86+
ret.uses_assembly_preload = ConvertFieldToBool ("uses_assembly_preload", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
87+
break;
88+
89+
case 1: // jni_add_native_method_registration_attribute_present: bool / .byte
90+
AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber);
91+
ret.jni_add_native_method_registration_attribute_present = ConvertFieldToBool ("jni_add_native_method_registration_attribute_present", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
92+
break;
93+
94+
case 2: // marshal_methods_enabled: bool / .byte
95+
AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber);
96+
ret.marshal_methods_enabled = ConvertFieldToBool ("marshal_methods_enabled", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
97+
break;
98+
99+
case 3: // ignore_split_configs: bool / .byte
100+
AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber);
101+
ret.ignore_split_configs = ConvertFieldToBool ("ignore_split_configs", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
102+
break;
103+
104+
case 4: // number_of_runtime_properties: uint32_t / .word | .long
105+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
106+
ret.number_of_runtime_properties = ConvertFieldToUInt32 ("number_of_runtime_properties", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
107+
break;
108+
109+
case 5: // package_naming_policy: uint32_t / .word | .long
110+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
111+
ret.package_naming_policy = ConvertFieldToUInt32 ("package_naming_policy", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
112+
break;
113+
114+
case 6: // environment_variable_count: uint32_t / .word | .long
115+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
116+
ret.environment_variable_count = ConvertFieldToUInt32 ("environment_variable_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
117+
break;
118+
119+
case 7: // system_property_count: uint32_t / .word | .long
120+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
121+
ret.system_property_count = ConvertFieldToUInt32 ("system_property_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
122+
break;
123+
124+
case 8: // number_of_assemblies_in_apk: uint32_t / .word | .long
125+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
126+
ret.number_of_assemblies_in_apk = ConvertFieldToUInt32 ("number_of_assemblies_in_apk", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
127+
break;
128+
129+
case 9: // bundled_assembly_name_width: uint32_t / .word | .long
130+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
131+
ret.bundled_assembly_name_width = ConvertFieldToUInt32 ("bundled_assembly_name_width", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
132+
break;
133+
134+
case 10: // number_of_dso_cache_entries: uint32_t / .word | .long
135+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
136+
ret.number_of_dso_cache_entries = ConvertFieldToUInt32 ("number_of_dso_cache_entries", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
137+
break;
138+
139+
case 11: // number_of_aot_cache_entries: uint32_t / .word | .long
140+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
141+
ret.number_of_aot_cache_entries = ConvertFieldToUInt32 ("number_of_aot_cache_entries", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
142+
break;
143+
144+
case 12: // number_of_shared_libraries: uint32_t / .word | .long
145+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
146+
ret.number_of_shared_libraries = ConvertFieldToUInt32 ("number_of_shared_libraries", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
147+
break;
148+
149+
case 13: // android_runtime_jnienv_class_token: uint32_t / .word | .long
150+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
151+
ret.android_runtime_jnienv_class_token = ConvertFieldToUInt32 ("android_runtime_jnienv_class_token", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
152+
break;
153+
154+
case 14: // jnienv_initialize_method_token: uint32_t / .word | .long
155+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
156+
ret.jnienv_initialize_method_token = ConvertFieldToUInt32 ("jnienv_initialize_method_token", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
157+
break;
158+
159+
case 15: // jnienv_registerjninatives_method_token: uint32_t / .word | .long
160+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
161+
ret.jnienv_registerjninatives_method_token = ConvertFieldToUInt32 ("jnienv_registerjninatives_method_token", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
162+
break;
163+
164+
case 16: // jni_remapping_replacement_type_count: uint32_t / .word | .long
165+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
166+
ret.jni_remapping_replacement_type_count = ConvertFieldToUInt32 ("jni_remapping_replacement_type_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
167+
break;
168+
169+
case 17: // jni_remapping_replacement_method_index_entry_count: uint32_t / .word | .long
170+
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
171+
ret.jni_remapping_replacement_method_index_entry_count = ConvertFieldToUInt32 ("jni_remapping_replacement_method_index_entry_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
172+
break;
173+
174+
case 18: // android_package_name: string / [pointer type]
175+
Assert.IsTrue (expectedPointerTypes.Contains (field [0]), $"Unexpected pointer field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
176+
pointers.Add (field [1].Trim ());
177+
break;
178+
179+
case 19: // managed_marshal_methods_lookup_enabled: bool / .byte
180+
AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber);
181+
ret.managed_marshal_methods_lookup_enabled = ConvertFieldToBool ("managed_marshal_methods_lookup_enabled", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
182+
break;
183+
}
184+
fieldCount++;
185+
}
186+
187+
Assert.AreEqual (1, pointers.Count, $"Invalid number of string pointers in 'application_config' structure in environment file '{envFile.Path}'");
188+
189+
NativeAssemblyParser.AssemblerSymbol androidPackageNameSymbol = GetRequiredSymbol (pointers[0], envFile, parser);
190+
ret.android_package_name = GetStringContents (androidPackageNameSymbol, envFile, parser);
191+
192+
Assert.AreEqual (ApplicationConfigFieldCountCLR, fieldCount, $"Invalid 'application_config' field count in environment file '{envFile.Path}'");
193+
Assert.IsFalse (String.IsNullOrEmpty (ret.android_package_name), $"Package name field in 'application_config' in environment file '{envFile.Path}' must not be null or empty");
194+
195+
return ret;
196+
}
197+
198+
static void AssertApplicationConfigIsIdentical (ApplicationConfigCLR firstAppConfig, string firstEnvFile, ApplicationConfigCLR secondAppConfig, string secondEnvFile)
199+
{
200+
Assert.AreEqual (firstAppConfig.uses_assembly_preload, secondAppConfig.uses_assembly_preload, $"Field 'uses_assembly_preload' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'");
201+
Assert.AreEqual (firstAppConfig.marshal_methods_enabled, secondAppConfig.marshal_methods_enabled, $"Field 'marshal_methods_enabled' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'");
202+
Assert.AreEqual (firstAppConfig.environment_variable_count, secondAppConfig.environment_variable_count, $"Field 'environment_variable_count' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'");
203+
Assert.AreEqual (firstAppConfig.system_property_count, secondAppConfig.system_property_count, $"Field 'system_property_count' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'");
204+
Assert.AreEqual (firstAppConfig.android_package_name, secondAppConfig.android_package_name, $"Field 'android_package_name' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'");
205+
Assert.AreEqual (firstAppConfig.managed_marshal_methods_lookup_enabled, secondAppConfig.managed_marshal_methods_lookup_enabled, $"Field 'managed_marshal_methods_lookup_enabled' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'");
206+
}
207+
}

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs

+18-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
namespace Xamarin.Android.Build.Tests
1616
{
17-
class EnvironmentHelper
17+
partial class EnvironmentHelper
1818
{
1919
public sealed class EnvironmentFile
2020
{
@@ -36,7 +36,7 @@ public EnvironmentFile (string path, string abi)
3636
}
3737
}
3838

39-
// This must be identical to the like-named structure in src/native/xamarin-app-stub/xamarin-app.hh
39+
// This must be identical to the like-named structure in src/native/mono/xamarin-app-stub/xamarin-app.hh
4040
public sealed class ApplicationConfig
4141
{
4242
public bool uses_mono_llvm;
@@ -183,7 +183,7 @@ public static ApplicationConfig ReadApplicationConfig (List<EnvironmentFile> env
183183
return app_config;
184184
}
185185

186-
static ApplicationConfig ReadApplicationConfig (EnvironmentFile envFile)
186+
static (NativeAssemblyParser parser, NativeAssemblyParser.AssemblerSymbol appConfigSymbol) GetAssemblyParserAndValidateConfig (EnvironmentFile envFile)
187187
{
188188
NativeAssemblyParser parser = CreateAssemblyParser (envFile);
189189

@@ -193,6 +193,19 @@ static ApplicationConfig ReadApplicationConfig (EnvironmentFile envFile)
193193

194194
Assert.IsTrue (appConfigSymbol.Size != 0, $"{ApplicationConfigSymbolName} size as specified in the '.size' directive must not be 0");
195195

196+
return (parser, appConfigSymbol);
197+
}
198+
199+
static bool CanIgnoreAssemblerField (string field)
200+
{
201+
// padding, we can safely ignore it
202+
return String.Compare (".zero", field, StringComparison.Ordinal) == 0;
203+
}
204+
205+
static ApplicationConfig ReadApplicationConfig (EnvironmentFile envFile)
206+
{
207+
(NativeAssemblyParser parser, NativeAssemblyParser.AssemblerSymbol appConfigSymbol) = GetAssemblyParserAndValidateConfig (envFile);
208+
196209
var pointers = new List <string> ();
197210
var ret = new ApplicationConfig ();
198211
uint fieldCount = 0;
@@ -201,8 +214,8 @@ static ApplicationConfig ReadApplicationConfig (EnvironmentFile envFile)
201214
foreach (NativeAssemblyParser.AssemblerSymbolItem item in appConfigSymbol.Contents) {
202215
field = GetField (envFile.Path, parser.SourceFilePath, item.Contents, item.LineNumber);
203216

204-
if (String.Compare (".zero", field[0], StringComparison.Ordinal) == 0) {
205-
continue; // padding, we can safely ignore it
217+
if (CanIgnoreAssemblerField (field[0])) {
218+
continue;
206219
}
207220

208221
switch (fieldCount) {

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ public void DotNetPublishDefaultValues([Values (false, true)] bool isRelease)
205205
[Test]
206206
public void DotNetPublish ([Values (false, true)] bool isRelease, [ValueSource(nameof(DotNetTargetFrameworks))] object[] data, [Values ("Mono", "CoreCLR")] string runtime)
207207
{
208+
TargetRuntimeHelper.IgnoreOnIncompatibleRuntime (runtime);
209+
208210
var dotnetVersion = (string)data[0];
209211
var platform = (string)data[1];
210212
var apiLevel = (int)data[2];

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/TargetRuntimeHelper.cs

+14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33

4+
using NUnit.Framework;
45
using Xamarin.Android.Tasks;
56

67
namespace Xamarin.ProjectTools;
@@ -13,6 +14,8 @@ public class TargetRuntimeHelper
1314

1415
static TargetRuntimeHelper ()
1516
{
17+
// TODO: this detection should probably depend on something more than an envvar. We can detect Mono
18+
// by looking for one of the Mono-specific types, can we do something similar to detect NativeAOT?
1619
string? envvar = Environment.GetEnvironmentVariable ("USE_MONO_RUNTIME");
1720
if (envvar == null || envvar.Length == 0 || String.Compare ("true", envvar, StringComparison.OrdinalIgnoreCase) == 0) {
1821
useMonoRuntime = true;
@@ -63,4 +66,15 @@ public static bool CoreClrSupportsAllABIs (string abis)
6366

6467
return true;
6568
}
69+
70+
public static void IgnoreOnIncompatibleRuntime (string runtime)
71+
{
72+
if (UseCoreCLR && String.Compare (runtime, "CoreCLR", StringComparison.OrdinalIgnoreCase) != 0) {
73+
Assert.Ignore ($"{runtime} tests not supported under CoreCLR");
74+
}
75+
76+
if (UseMonoRuntime && String.Compare (runtime, "Mono", StringComparison.OrdinalIgnoreCase) != 0) {
77+
Assert.Ignore ($"{runtime} tests not supported under MonoVM");
78+
}
79+
}
6680
}

0 commit comments

Comments
 (0)