Skip to content

Commit 709f537

Browse files
committed
chore: Add tests
1 parent 947ef1c commit 709f537

1 file changed

Lines changed: 336 additions & 0 deletions

File tree

patches/0001-fix-hot-reload-propertymap-eventmap-crash-on-type-addition.patch

Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,339 @@
1+
diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties.cs
2+
new file mode 100644
3+
index 00000000000..f58772c763f
4+
--- /dev/null
5+
+++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties.cs
6+
@@ -0,0 +1,10 @@
7+
+// Licensed to the .NET Foundation under one or more agreements.
8+
+// The .NET Foundation licenses this file to you under the MIT license.
9+
+using System;
10+
+
11+
+namespace System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties;
12+
+
13+
+public class ExistingClass
14+
+{
15+
+ public static void ExistingMethod () {}
16+
+}
17+
diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties_v1.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties_v1.cs
18+
new file mode 100644
19+
index 00000000000..c7608580fa0
20+
--- /dev/null
21+
+++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties_v1.cs
22+
@@ -0,0 +1,31 @@
23+
+// Licensed to the .NET Foundation under one or more agreements.
24+
+// The .NET Foundation licenses this file to you under the MIT license.
25+
+using System;
26+
+
27+
+namespace System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties;
28+
+
29+
+public class ExistingClass
30+
+{
31+
+ public static void ExistingMethod () {}
32+
+}
33+
+
34+
+/// <summary>
35+
+/// New type added in generation 1 with auto-properties.
36+
+/// This produces PROPERTYMAP, PROPERTY, and FIELD ENCLOG entries.
37+
+/// </summary>
38+
+public class NewClassWithProperties
39+
+{
40+
+ public string Title { get; set; } = "Default";
41+
+ public decimal Price { get; set; }
42+
+ public bool IsActive { get; set; }
43+
+
44+
+ public static NewClassWithProperties Create()
45+
+ {
46+
+ return new NewClassWithProperties
47+
+ {
48+
+ Title = "Gen1",
49+
+ Price = 9.99m,
50+
+ IsActive = true,
51+
+ };
52+
+ }
53+
+}
54+
diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties_v2.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties_v2.cs
55+
new file mode 100644
56+
index 00000000000..261faf78c00
57+
--- /dev/null
58+
+++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties_v2.cs
59+
@@ -0,0 +1,35 @@
60+
+// Licensed to the .NET Foundation under one or more agreements.
61+
+// The .NET Foundation licenses this file to you under the MIT license.
62+
+using System;
63+
+
64+
+namespace System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties;
65+
+
66+
+public class ExistingClass
67+
+{
68+
+ public static void ExistingMethod () {}
69+
+}
70+
+
71+
+/// <summary>
72+
+/// Generation 2: Same type as v1, but with a new method added.
73+
+/// This re-emits PROPERTYMAP, PROPERTY, FIELD, and METHODSEMANTICS entries
74+
+/// where is_addition will be false (tokens already exist from gen 1).
75+
+/// This is the exact scenario that triggers the hot_reload crash.
76+
+/// </summary>
77+
+public class NewClassWithProperties
78+
+{
79+
+ public string Title { get; set; } = "Updated";
80+
+ public decimal Price { get; set; }
81+
+ public bool IsActive { get; set; }
82+
+
83+
+ public string GetSummary() => $"{Title}: {Price:C}";
84+
+
85+
+ public static NewClassWithProperties Create()
86+
+ {
87+
+ return new NewClassWithProperties
88+
+ {
89+
+ Title = "Gen2",
90+
+ Price = 19.99m,
91+
+ IsActive = true,
92+
+ };
93+
+ }
94+
+}
95+
diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties.csproj b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties.csproj
96+
new file mode 100644
97+
index 00000000000..4ebca83c87a
98+
--- /dev/null
99+
+++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties.csproj
100+
@@ -0,0 +1,11 @@
101+
+<Project Sdk="Microsoft.NET.Sdk">
102+
+ <PropertyGroup>
103+
+ <RootNamespace>System.Runtime.Loader.Tests</RootNamespace>
104+
+ <TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
105+
+ <TestRuntime>true</TestRuntime>
106+
+ <DeltaScript>deltascript.json</DeltaScript>
107+
+ </PropertyGroup>
108+
+ <ItemGroup>
109+
+ <Compile Include="ReflectionAddNewTypeWithProperties.cs" />
110+
+ </ItemGroup>
111+
+</Project>
112+
diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/deltascript.json b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/deltascript.json
113+
new file mode 100644
114+
index 00000000000..d652e9b86d8
115+
--- /dev/null
116+
+++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/deltascript.json
117+
@@ -0,0 +1,12 @@
118+
+{
119+
+ "changes": [
120+
+ {
121+
+ "document": "ReflectionAddNewTypeWithProperties.cs",
122+
+ "update": "ReflectionAddNewTypeWithProperties_v1.cs"
123+
+ },
124+
+ {
125+
+ "document": "ReflectionAddNewTypeWithProperties.cs",
126+
+ "update": "ReflectionAddNewTypeWithProperties_v2.cs"
127+
+ }
128+
+ ]
129+
+}
130+
diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties.cs
131+
new file mode 100644
132+
index 00000000000..f58772c763f
133+
--- /dev/null
134+
+++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties.cs
135+
@@ -0,0 +1,10 @@
136+
+// Licensed to the .NET Foundation under one or more agreements.
137+
+// The .NET Foundation licenses this file to you under the MIT license.
138+
+using System;
139+
+
140+
+namespace System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties;
141+
+
142+
+public class ExistingClass
143+
+{
144+
+ public static void ExistingMethod () {}
145+
+}
146+
diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties_v1.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties_v1.cs
147+
new file mode 100644
148+
index 00000000000..c7608580fa0
149+
--- /dev/null
150+
+++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties_v1.cs
151+
@@ -0,0 +1,31 @@
152+
+// Licensed to the .NET Foundation under one or more agreements.
153+
+// The .NET Foundation licenses this file to you under the MIT license.
154+
+using System;
155+
+
156+
+namespace System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties;
157+
+
158+
+public class ExistingClass
159+
+{
160+
+ public static void ExistingMethod () {}
161+
+}
162+
+
163+
+/// <summary>
164+
+/// New type added in generation 1 with auto-properties.
165+
+/// This produces PROPERTYMAP, PROPERTY, and FIELD ENCLOG entries.
166+
+/// </summary>
167+
+public class NewClassWithProperties
168+
+{
169+
+ public string Title { get; set; } = "Default";
170+
+ public decimal Price { get; set; }
171+
+ public bool IsActive { get; set; }
172+
+
173+
+ public static NewClassWithProperties Create()
174+
+ {
175+
+ return new NewClassWithProperties
176+
+ {
177+
+ Title = "Gen1",
178+
+ Price = 9.99m,
179+
+ IsActive = true,
180+
+ };
181+
+ }
182+
+}
183+
diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties_v2.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties_v2.cs
184+
new file mode 100644
185+
index 00000000000..261faf78c00
186+
--- /dev/null
187+
+++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/ReflectionAddNewTypeWithProperties_v2.cs
188+
@@ -0,0 +1,35 @@
189+
+// Licensed to the .NET Foundation under one or more agreements.
190+
+// The .NET Foundation licenses this file to you under the MIT license.
191+
+using System;
192+
+
193+
+namespace System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties;
194+
+
195+
+public class ExistingClass
196+
+{
197+
+ public static void ExistingMethod () {}
198+
+}
199+
+
200+
+/// <summary>
201+
+/// Generation 2: Same type as v1, but with a new method added.
202+
+/// This re-emits PROPERTYMAP, PROPERTY, FIELD, and METHODSEMANTICS entries
203+
+/// where is_addition will be false (tokens already exist from gen 1).
204+
+/// This is the exact scenario that triggers the hot_reload crash.
205+
+/// </summary>
206+
+public class NewClassWithProperties
207+
+{
208+
+ public string Title { get; set; } = "Updated";
209+
+ public decimal Price { get; set; }
210+
+ public bool IsActive { get; set; }
211+
+
212+
+ public string GetSummary() => $"{Title}: {Price:C}";
213+
+
214+
+ public static NewClassWithProperties Create()
215+
+ {
216+
+ return new NewClassWithProperties
217+
+ {
218+
+ Title = "Gen2",
219+
+ Price = 19.99m,
220+
+ IsActive = true,
221+
+ };
222+
+ }
223+
+}
224+
diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties.csproj b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties.csproj
225+
new file mode 100644
226+
index 00000000000..4ebca83c87a
227+
--- /dev/null
228+
+++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties.csproj
229+
@@ -0,0 +1,11 @@
230+
+<Project Sdk="Microsoft.NET.Sdk">
231+
+ <PropertyGroup>
232+
+ <RootNamespace>System.Runtime.Loader.Tests</RootNamespace>
233+
+ <TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
234+
+ <TestRuntime>true</TestRuntime>
235+
+ <DeltaScript>deltascript.json</DeltaScript>
236+
+ </PropertyGroup>
237+
+ <ItemGroup>
238+
+ <Compile Include="ReflectionAddNewTypeWithProperties.cs" />
239+
+ </ItemGroup>
240+
+</Project>
241+
diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/deltascript.json b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/deltascript.json
242+
new file mode 100644
243+
index 00000000000..d652e9b86d8
244+
--- /dev/null
245+
+++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties/deltascript.json
246+
@@ -0,0 +1,12 @@
247+
+{
248+
+ "changes": [
249+
+ {
250+
+ "document": "ReflectionAddNewTypeWithProperties.cs",
251+
+ "update": "ReflectionAddNewTypeWithProperties_v1.cs"
252+
+ },
253+
+ {
254+
+ "document": "ReflectionAddNewTypeWithProperties.cs",
255+
+ "update": "ReflectionAddNewTypeWithProperties_v2.cs"
256+
+ }
257+
+ ]
258+
+}
259+
diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs
260+
index c8576441586..8506c146367 100644
261+
--- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs
262+
+++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs
263+
@@ -924,6 +924,61 @@ public static void TestReflectionAddNewType()
264+
});
265+
}
266+
267+
+ [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsSupported))]
268+
+ public static void TestReflectionAddNewTypeWithProperties()
269+
+ {
270+
+ // Regression test: adding a new type with auto-properties across two generations.
271+
+ // Generation 1 adds the type with PROPERTYMAP/PROPERTY/FIELD entries.
272+
+ // Generation 2 modifies the same type, re-emitting the same tokens with is_addition=false.
273+
+ // Before the fix, this crashed in apply_enclog_pass2 with assertion failures on
274+
+ // PROPERTYMAP, Field, and later prop==NULL in hot_reload_get_property.
275+
+ ApplyUpdateUtil.TestCase(static () =>
276+
+ {
277+
+ const string ns = "System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties";
278+
+ var assm = typeof(System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties.ExistingClass).Assembly;
279+
+
280+
+ // Baseline: only ExistingClass
281+
+ var existingTy = assm.GetType($"{ns}.ExistingClass");
282+
+ Assert.NotNull(existingTy);
283+
+ Assert.Null(assm.GetType($"{ns}.NewClassWithProperties"));
284+
+
285+
+ // Generation 1: adds NewClassWithProperties with properties
286+
+ ApplyUpdateUtil.ApplyUpdate(assm);
287+
+
288+
+ var newTy = assm.GetType($"{ns}.NewClassWithProperties");
289+
+ Assert.NotNull(newTy);
290+
+
291+
+ // Verify properties exist
292+
+ var titleProp = newTy.GetProperty("Title");
293+
+ Assert.NotNull(titleProp);
294+
+ Assert.NotNull(titleProp.GetGetMethod());
295+
+ Assert.NotNull(titleProp.GetSetMethod());
296+
+
297+
+ var priceProp = newTy.GetProperty("Price");
298+
+ Assert.NotNull(priceProp);
299+
+
300+
+ var isActiveProp = newTy.GetProperty("IsActive");
301+
+ Assert.NotNull(isActiveProp);
302+
+
303+
+ // Create instance and verify
304+
+ var obj = Activator.CreateInstance(newTy);
305+
+ Assert.Equal("Default", titleProp.GetValue(obj));
306+
+
307+
+ // Generation 2: modifies the same type (adds a method, changes default)
308+
+ // This re-emits PROPERTYMAP/PROPERTY/FIELD tokens with is_addition=false.
309+
+ // Before the fix, this would crash.
310+
+ ApplyUpdateUtil.ApplyUpdate(assm);
311+
+
312+
+ // Verify properties still work after gen 2
313+
+ var obj2 = Activator.CreateInstance(newTy);
314+
+ Assert.Equal("Updated", titleProp.GetValue(obj2));
315+
+
316+
+ // Verify the new method from gen 2
317+
+ var getSummary = newTy.GetMethod("GetSummary");
318+
+ Assert.NotNull(getSummary);
319+
+ });
320+
+ }
321+
+
322+
[ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsSupported))]
323+
public static void TestReflectionAddNewMethod()
324+
{
325+
diff --git a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj
326+
index c557f7e3b4a..891545bf721 100644
327+
--- a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj
328+
+++ b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj
329+
@@ -78,6 +78,7 @@
330+
<ProjectReference Include="ApplyUpdate\System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda\System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda.csproj" />
331+
<ProjectReference Include="ApplyUpdate\System.Reflection.Metadata.ApplyUpdate.Test.StaticLambdaRegression\System.Reflection.Metadata.ApplyUpdate.Test.StaticLambdaRegression.csproj" />
332+
<ProjectReference Include="ApplyUpdate\System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewType\System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewType.csproj" />
333+
+ <ProjectReference Include="ApplyUpdate\System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties\System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewTypeWithProperties.csproj" />
334+
<ProjectReference Include="ApplyUpdate\System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod\System.Reflection.Metadata.ApplyUpdate.Test.ReflectionAddNewMethod.csproj" />
335+
<ProjectReference Include="ApplyUpdate\System.Reflection.Metadata.ApplyUpdate.Test.ReflectionDeleteMember\System.Reflection.Metadata.ApplyUpdate.Test.ReflectionDeleteMember.csproj" />
336+
<ProjectReference Include="ApplyUpdate\System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField\System.Reflection.Metadata.ApplyUpdate.Test.GenericAddStaticField.csproj" />
1337
diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c
2338
index e5614bb0788..ff2ea665159 100644
3339
--- a/src/mono/mono/component/hot_reload.c

0 commit comments

Comments
 (0)