-
-
Notifications
You must be signed in to change notification settings - Fork 94
Expand file tree
/
Copy pathIssue431_Add_structural_equality_comparison_to_LightExpression.cs
More file actions
212 lines (186 loc) · 7.36 KB
/
Issue431_Add_structural_equality_comparison_to_LightExpression.cs
File metadata and controls
212 lines (186 loc) · 7.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
using System;
using System.Linq;
using System.Reflection;
#if LIGHT_EXPRESSION
using static FastExpressionCompiler.LightExpression.Expression;
using FastExpressionCompiler.LightExpression;
namespace FastExpressionCompiler.LightExpression.IssueTests;
#else
using static System.Linq.Expressions.Expression;
namespace FastExpressionCompiler.IssueTests;
#endif
public struct Issue431_Add_structural_equality_comparison_to_LightExpression : ITestX
{
public static readonly ConstructorInfo CtorOfA = typeof(A).GetTypeInfo().DeclaredConstructors.First();
public static readonly ConstructorInfo CtorOfB = typeof(B).GetTypeInfo().DeclaredConstructors.First();
public static readonly PropertyInfo PropAProp = typeof(A).GetTypeInfo().DeclaredProperties.First(p => p.Name == "Prop");
public void Run(TestRun t)
{
Eq_simple_lambda(t);
Eq_lambda_with_parameters(t);
Eq_constants(t);
Eq_member_access(t);
Eq_method_call(t);
Eq_new_expression(t);
Eq_member_init(t);
Eq_new_array(t);
Eq_conditional(t);
Eq_block_with_variables(t);
Eq_try_catch(t);
Eq_loop_with_labels(t);
Eq_switch(t);
#if LIGHT_EXPRESSION
Eq_complex_lambda_round_trip(t);
#endif
NotEq_different_constants(t);
NotEq_different_types(t);
NotEq_different_parameters(t);
}
public void Eq_simple_lambda(TestContext t)
{
var e1 = Lambda<Func<int>>(Constant(42));
var e2 = Lambda<Func<int>>(Constant(42));
t.IsTrue(e1.EqualsTo(e2));
}
public void Eq_lambda_with_parameters(TestContext t)
{
var p1a = Parameter(typeof(int), "x");
var p1b = Parameter(typeof(int), "y");
var e1 = Lambda<Func<int, int, int>>(Add(p1a, p1b), p1a, p1b);
var p2a = Parameter(typeof(int), "x");
var p2b = Parameter(typeof(int), "y");
var e2 = Lambda<Func<int, int, int>>(Add(p2a, p2b), p2a, p2b);
t.IsTrue(e1.EqualsTo(e2));
}
public void Eq_constants(TestContext t)
{
t.IsTrue(Constant(42).EqualsTo(Constant(42)));
t.IsTrue(Constant("hello").EqualsTo(Constant("hello")));
t.IsTrue(Constant(null, typeof(string)).EqualsTo(Constant(null, typeof(string))));
}
public void Eq_member_access(TestContext t)
{
var prop = typeof(string).GetProperty(nameof(string.Length));
var p1 = Parameter(typeof(string), "s");
var p2 = Parameter(typeof(string), "s");
var e1 = Lambda<Func<string, int>>(Property(p1, prop), p1);
var e2 = Lambda<Func<string, int>>(Property(p2, prop), p2);
t.IsTrue(e1.EqualsTo(e2));
}
public void Eq_method_call(TestContext t)
{
var method = typeof(string).GetMethod(nameof(string.Concat), new[] { typeof(string), typeof(string) });
var p1 = Parameter(typeof(string), "a");
var p2 = Parameter(typeof(string), "b");
var pa = Parameter(typeof(string), "a");
var pb = Parameter(typeof(string), "b");
var e1 = Lambda<Func<string, string, string>>(Call(method, p1, p2), p1, p2);
var e2 = Lambda<Func<string, string, string>>(Call(method, pa, pb), pa, pb);
t.IsTrue(e1.EqualsTo(e2));
}
public void Eq_new_expression(TestContext t)
{
var ctor = typeof(B).GetConstructor(Type.EmptyTypes);
var e1 = New(ctor);
var e2 = New(ctor);
t.IsTrue(e1.EqualsTo(e2));
}
public void Eq_member_init(TestContext t)
{
var e1 = MemberInit(New(CtorOfA, New(CtorOfB)), Bind(PropAProp, New(CtorOfB)));
var e2 = MemberInit(New(CtorOfA, New(CtorOfB)), Bind(PropAProp, New(CtorOfB)));
t.IsTrue(e1.EqualsTo(e2));
}
public void Eq_new_array(TestContext t)
{
var e1 = NewArrayInit(typeof(int), Constant(1), Constant(2), Constant(3));
var e2 = NewArrayInit(typeof(int), Constant(1), Constant(2), Constant(3));
t.IsTrue(e1.EqualsTo(e2));
}
public void Eq_conditional(TestContext t)
{
var p1 = Parameter(typeof(int), "x");
var p2 = Parameter(typeof(int), "x");
var e1 = Lambda<Func<int, int>>(Condition(Equal(p1, Constant(0)), Constant(1), p1), p1);
var e2 = Lambda<Func<int, int>>(Condition(Equal(p2, Constant(0)), Constant(1), p2), p2);
t.IsTrue(e1.EqualsTo(e2));
}
public void Eq_block_with_variables(TestContext t)
{
var v1 = Variable(typeof(int), "i");
var v2 = Variable(typeof(int), "i");
var e1 = Block(new[] { v1 }, Assign(v1, Constant(5)), v1);
var e2 = Block(new[] { v2 }, Assign(v2, Constant(5)), v2);
t.IsTrue(e1.EqualsTo(e2));
}
public void Eq_try_catch(TestContext t)
{
var ex1 = Parameter(typeof(Exception), "ex");
var ex2 = Parameter(typeof(Exception), "ex");
var e1 = TryCatch(Constant(1), Catch(ex1, Constant(2)));
var e2 = TryCatch(Constant(1), Catch(ex2, Constant(2)));
t.IsTrue(e1.EqualsTo(e2));
}
public void Eq_loop_with_labels(TestContext t)
{
var brk1 = Label(typeof(void), "break");
var cnt1 = Label(typeof(void), "continue");
var brk2 = Label(typeof(void), "break");
var cnt2 = Label(typeof(void), "continue");
var e1 = Loop(Block(Break(brk1), Continue(cnt1)), brk1, cnt1);
var e2 = Loop(Block(Break(brk2), Continue(cnt2)), brk2, cnt2);
t.IsTrue(e1.EqualsTo(e2));
}
public void Eq_switch(TestContext t)
{
var p1 = Parameter(typeof(int), "x");
var p2 = Parameter(typeof(int), "x");
var e1 = Lambda<Func<int, int>>(
Switch(p1, Constant(-1), SwitchCase(Constant(10), Constant(1)), SwitchCase(Constant(20), Constant(2))),
p1);
var e2 = Lambda<Func<int, int>>(
Switch(p2, Constant(-1), SwitchCase(Constant(10), Constant(1)), SwitchCase(Constant(20), Constant(2))),
p2);
t.IsTrue(e1.EqualsTo(e2));
}
#if LIGHT_EXPRESSION
public void Eq_complex_lambda_round_trip(TestContext t)
{
var expr = Lambda<Func<object[], object>>(
MemberInit(
New(CtorOfA, New(CtorOfB)),
Bind(PropAProp, New(CtorOfB))),
Parameter(typeof(object[]), "p"));
var sysExpr = expr.ToLambdaExpression();
var restoredExpr = sysExpr.ToLightExpression<Func<object[], object>>();
t.IsTrue(expr.EqualsTo(restoredExpr));
}
#endif
public void NotEq_different_constants(TestContext t)
{
t.IsFalse(Constant(42).EqualsTo(Constant(43)));
t.IsFalse(Constant("a").EqualsTo(Constant("b")));
}
public void NotEq_different_types(TestContext t)
{
t.IsFalse(Constant(42).EqualsTo(Constant(42L)));
t.IsFalse(Default(typeof(int)).EqualsTo(Default(typeof(long))));
}
public void NotEq_different_parameters(TestContext t)
{
var p1 = Parameter(typeof(int), "x");
var p2 = Parameter(typeof(int), "y");
var e1 = Lambda<Func<int, int>>(p1, p1);
var e2 = Lambda<Func<int, int>>(p2, p2);
// When mapped by position in a lambda, different-named params ARE equal structurally (same position)
t.IsTrue(e1.EqualsTo(e2));
// But accessing a param outside its lambda context uses name comparison
t.IsFalse(p1.EqualsTo(p2));
}
public class A
{
public B Prop { get; set; }
public A(B b) { Prop = b; }
}
public class B { }
}