Browse Source
* Fix DataGrid native aot crash when sorting. * Update DataGridSortDescription.cs * add customType test * does not crash when property type is not sortable. * check `RuntimeFeature.IsDynamicCodeSupported` to fallback to reflection implementionfixes/tcc-333
committed by
GitHub
2 changed files with 249 additions and 1 deletions
@ -0,0 +1,223 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel; |
||||
|
using System.Linq; |
||||
|
using Avalonia.Collections; |
||||
|
using Avalonia.Logging; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Avalonia.Controls.DataGridTests.Collections; |
||||
|
|
||||
|
public class NoStringTypeComparerTests |
||||
|
{ |
||||
|
public static IEnumerable<object[]> GetComparerForNotStringTypeParameters() |
||||
|
{ |
||||
|
yield return |
||||
|
[ |
||||
|
nameof(Item.IntProp1), |
||||
|
(object item, object value) => |
||||
|
{ |
||||
|
(item as Item)!.IntProp1 = (int)value; |
||||
|
}, |
||||
|
(object item) => (object)(item as Item)!.IntProp1, |
||||
|
new object[] { 2, 3, 1 }, |
||||
|
new object[] { 1, 2, 3 } |
||||
|
]; |
||||
|
yield return |
||||
|
[ |
||||
|
nameof(Item.IntProp2), |
||||
|
(object item, object value) => |
||||
|
{ |
||||
|
(item as Item)!.IntProp2 = (int?)value; |
||||
|
}, |
||||
|
(object item) => (object)(item as Item)!.IntProp2, |
||||
|
new object[] { 2, 3, null, 1 }, |
||||
|
new object[] { null, 1, 2, 3 } |
||||
|
]; |
||||
|
yield return |
||||
|
[ |
||||
|
nameof(Item.DoubleProp1), |
||||
|
(object item, object value) => |
||||
|
{ |
||||
|
(item as Item)!.DoubleProp1 = (double)value; |
||||
|
}, |
||||
|
(object item) => (object)(item as Item)!.DoubleProp1, |
||||
|
new object[] { 2.1, 3.1, 1.1 }, |
||||
|
new object[] { 1.1, 2.1, 3.1 } |
||||
|
]; |
||||
|
yield return |
||||
|
[ |
||||
|
nameof(Item.DoubleProp2), |
||||
|
(object item, object value) => |
||||
|
{ |
||||
|
(item as Item)!.DoubleProp2 = (double?)value; |
||||
|
}, |
||||
|
(object item) => (object)(item as Item)!.DoubleProp2, |
||||
|
new object[] { 2.1, 3.1, null, 1.1 }, |
||||
|
new object[] { null, 1.1, 2.1, 3.1 } |
||||
|
]; |
||||
|
yield return |
||||
|
[ |
||||
|
nameof(Item.DecimalProp1), |
||||
|
(object item, object value) => |
||||
|
{ |
||||
|
(item as Item)!.DecimalProp1 = (decimal)value; |
||||
|
}, |
||||
|
(object item) => (object)(item as Item)!.DecimalProp1, |
||||
|
new object[] { 2.1M, 3.1M, 1.1M }, |
||||
|
new object[] { 1.1M, 2.1M, 3.1M } |
||||
|
]; |
||||
|
yield return |
||||
|
[ |
||||
|
nameof(Item.DecimalProp2), |
||||
|
(object item, object value) => |
||||
|
{ |
||||
|
(item as Item)!.DecimalProp2 = (decimal?)value; |
||||
|
}, |
||||
|
(object item) => (object)(item as Item)!.DecimalProp2, |
||||
|
new object[] { 2.1M, 3.1M, null, 1.1M }, |
||||
|
new object[] { null, 1.1M, 2.1M, 3.1M } |
||||
|
]; |
||||
|
yield return |
||||
|
[ |
||||
|
nameof(Item.EnumProp1), |
||||
|
(object item, object value) => |
||||
|
{ |
||||
|
(item as Item)!.EnumProp1 = (LogEventLevel)value; |
||||
|
}, |
||||
|
(object item) => (object)(item as Item)!.EnumProp1, |
||||
|
new object[] { LogEventLevel.Information, LogEventLevel.Debug, LogEventLevel.Error }, |
||||
|
new object[] { LogEventLevel.Debug, LogEventLevel.Information, LogEventLevel.Error } |
||||
|
]; |
||||
|
yield return |
||||
|
[ |
||||
|
nameof(Item.EnumProp2), |
||||
|
(object item, object value) => |
||||
|
{ |
||||
|
(item as Item)!.EnumProp2 = (LogEventLevel?)value; |
||||
|
}, |
||||
|
(object item) => (object)(item as Item)!.EnumProp2, |
||||
|
new object[] |
||||
|
{ |
||||
|
LogEventLevel.Information, |
||||
|
LogEventLevel.Debug, |
||||
|
null, |
||||
|
LogEventLevel.Error |
||||
|
}, |
||||
|
new object[] |
||||
|
{ |
||||
|
null, |
||||
|
LogEventLevel.Debug, |
||||
|
LogEventLevel.Information, |
||||
|
LogEventLevel.Error |
||||
|
} |
||||
|
]; |
||||
|
yield return |
||||
|
[ |
||||
|
nameof(Item.CustomProp2), |
||||
|
(object item, object value) => |
||||
|
{ |
||||
|
(item as Item)!.CustomProp2 = (CustomType?)value; |
||||
|
}, |
||||
|
(object item) => (object)(item as Item)!.CustomProp2, |
||||
|
new object[] |
||||
|
{ |
||||
|
new CustomType() { Prop = 2 }, |
||||
|
new CustomType() { Prop = 3 }, |
||||
|
null, |
||||
|
new CustomType() { Prop = 1 } |
||||
|
}, |
||||
|
new object[] |
||||
|
{ |
||||
|
null, |
||||
|
new CustomType() { Prop = 1 }, |
||||
|
new CustomType() { Prop = 2 }, |
||||
|
new CustomType() { Prop = 3 } |
||||
|
} |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[MemberData(nameof(GetComparerForNotStringTypeParameters))] |
||||
|
public void GetComparerForNotStringType_Correctly_WhenSorting( |
||||
|
string pathName, |
||||
|
Action<object, object> setAction, |
||||
|
Func<object, object> getAction, |
||||
|
object[] orignal, |
||||
|
object[] ordered |
||||
|
) |
||||
|
{ |
||||
|
List<Item> items = new(); |
||||
|
for (int i = 0; i < orignal.Length; i++) |
||||
|
{ |
||||
|
var item = new Item(); |
||||
|
setAction(item, orignal[i]); |
||||
|
items.Add(item); |
||||
|
} |
||||
|
|
||||
|
//Ascending
|
||||
|
var sortDescription = DataGridSortDescription.FromPath( |
||||
|
pathName, |
||||
|
ListSortDirection.Ascending |
||||
|
); |
||||
|
sortDescription.Initialize(typeof(Item)); |
||||
|
var result = sortDescription.OrderBy(items).ToList(); |
||||
|
|
||||
|
for (int i = 0; i < ordered.Length; i++) |
||||
|
{ |
||||
|
Assert.Equal(ordered[i], getAction(result[i])); |
||||
|
} |
||||
|
|
||||
|
//Descending
|
||||
|
sortDescription = DataGridSortDescription.FromPath(pathName, ListSortDirection.Descending); |
||||
|
sortDescription.Initialize(typeof(Item)); |
||||
|
result = sortDescription.OrderBy(items).ToList(); |
||||
|
|
||||
|
ordered = ordered.Reverse().ToArray(); |
||||
|
for (int i = 0; i < ordered.Length; i++) |
||||
|
{ |
||||
|
Assert.Equal(ordered[i], getAction(result[i])); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private class Item |
||||
|
{ |
||||
|
public int IntProp1 { get; set; } |
||||
|
public int? IntProp2 { get; set; } |
||||
|
public double DoubleProp1 { get; set; } |
||||
|
public double? DoubleProp2 { get; set; } |
||||
|
|
||||
|
public decimal DecimalProp1 { get; set; } |
||||
|
public decimal? DecimalProp2 { get; set; } |
||||
|
|
||||
|
public LogEventLevel EnumProp1 { get; set; } |
||||
|
public LogEventLevel? EnumProp2 { get; set; } |
||||
|
public CustomType? CustomProp2 { get; set; } |
||||
|
} |
||||
|
|
||||
|
public struct CustomType : IComparable |
||||
|
{ |
||||
|
public int Prop { get; set; } |
||||
|
|
||||
|
public int CompareTo(object obj) |
||||
|
{ |
||||
|
if (obj is CustomType other) |
||||
|
{ |
||||
|
return Prop.CompareTo(other.Prop); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return 1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override bool Equals(object obj) |
||||
|
{ |
||||
|
if (obj is CustomType other) |
||||
|
{ |
||||
|
return Prop == other.Prop; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue