/
ZIndexTests.cs
279 lines (229 loc) · 6.71 KB
/
ZIndexTests.cs
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
using System.Collections;
using System.Collections.Generic;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Primitives;
using NSubstitute;
using Xunit;
namespace Microsoft.Maui.UnitTests.Layouts
{
[Category(TestCategory.Core, TestCategory.Layout)]
public class ZIndexTests
{
// These tests need a real collection to work with; we can't reasonably use a substitute here
class FakeLayout : ILayout, IList<IView>
{
public bool ClipsToBounds { get; set; }
#region IView stuff
public string AutomationId { get; }
public FlowDirection FlowDirection { get; }
public LayoutAlignment HorizontalLayoutAlignment { get; }
public LayoutAlignment VerticalLayoutAlignment { get; }
public Semantics Semantics { get; }
public IShape Clip { get; }
public IShadow Shadow { get; }
public bool IsEnabled { get; }
public bool IsFocused { get; set; }
public Visibility Visibility { get; }
public double Opacity { get; }
public Paint Background { get; }
public Rect Frame { get; set; }
public double Width { get; }
public double MinimumWidth { get; }
public double MaximumWidth { get; }
public double Height { get; }
public double MinimumHeight { get; }
public double MaximumHeight { get; }
public Thickness Margin { get; }
public IViewHandler Handler { get; set; }
public Size DesiredSize { get; }
public int ZIndex { get; }
public IElement Parent { get; }
public double TranslationX { get; }
public double TranslationY { get; }
public double Scale { get; }
public double ScaleX { get; }
public double ScaleY { get; }
public double Rotation { get; }
public double RotationX { get; }
public double RotationY { get; }
public double AnchorX { get; }
public double AnchorY { get; }
public bool IgnoreSafeArea { get; }
public Thickness Padding { get; }
public bool InputTransparent { get; set; }
IElementHandler IElement.Handler { get; set; }
public void InvalidateArrange()
{
throw new System.NotImplementedException();
}
public void InvalidateMeasure()
{
throw new System.NotImplementedException();
}
public Size Measure(double widthConstraint, double heightConstraint)
{
throw new System.NotImplementedException();
}
public bool Focus() => false;
public void Unfocus()
{
}
#endregion
#region IList stuff
IList<IView> _views = new List<IView>();
public int Count => _views.Count;
public bool IsReadOnly => _views.IsReadOnly;
public IView this[int index] { get => _views[index]; set => _views[index] = value; }
public void Add(IView item)
{
_views.Add(item);
}
public Size Arrange(Rect bounds)
{
throw new System.NotImplementedException();
}
public void Clear()
{
_views.Clear();
}
public bool Contains(IView item)
{
return _views.Contains(item);
}
public void CopyTo(IView[] array, int arrayIndex)
{
_views.CopyTo(array, arrayIndex);
}
public Size CrossPlatformArrange(Rect bounds)
{
throw new System.NotImplementedException();
}
public Size CrossPlatformMeasure(double widthConstraint, double heightConstraint)
{
throw new System.NotImplementedException();
}
public IEnumerator<IView> GetEnumerator()
{
return _views.GetEnumerator();
}
public int IndexOf(IView item)
{
return _views.IndexOf(item);
}
public void Insert(int index, IView item)
{
_views.Insert(index, item);
}
public bool Remove(IView item)
{
return _views.Remove(item);
}
public void RemoveAt(int index)
{
_views.RemoveAt(index);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_views).GetEnumerator();
}
#endregion
}
static IView CreateTestView(int zIndex = 0)
{
var view = Substitute.For<IView>();
view.ZIndex.Returns(zIndex);
return view;
}
[Fact]
public void LayoutHandlerIndexFollowsZOrder()
{
var layout = new FakeLayout();
var view0 = CreateTestView(zIndex: 10);
var view1 = CreateTestView(zIndex: 0);
layout.Add(view0);
layout.Add(view1);
Assert.Equal(0, layout.GetLayoutHandlerIndex(view1));
Assert.Equal(1, layout.GetLayoutHandlerIndex(view0));
}
[Fact]
public void LayoutHandlerIndexFollowsAddOrderWhenZIndexesAreEqual()
{
var layout = new FakeLayout();
var view0 = CreateTestView(zIndex: 0);
var view1 = CreateTestView(zIndex: 10);
var view2 = CreateTestView(zIndex: 10);
var view3 = CreateTestView(zIndex: 100);
layout.Add(view0);
layout.Add(view1);
layout.Add(view2);
layout.Add(view3);
Assert.Equal(0, layout.GetLayoutHandlerIndex(view0));
Assert.Equal(1, layout.GetLayoutHandlerIndex(view1));
Assert.Equal(2, layout.GetLayoutHandlerIndex(view2));
Assert.Equal(3, layout.GetLayoutHandlerIndex(view3));
}
[Fact]
public void ItemsOrderByZIndex()
{
var layout = new FakeLayout();
var view0 = CreateTestView(zIndex: 10);
var view1 = CreateTestView(zIndex: 0);
layout.Add(view0);
layout.Add(view1);
var zordered = layout.OrderByZIndex();
Assert.Equal(view1, zordered[0]);
Assert.Equal(view0, zordered[1]);
}
[Fact]
public void ZIndexUpdatePreservesAddOrderForEqualZIndexes()
{
var layout = new FakeLayout();
var view0 = CreateTestView(zIndex: 0);
var view1 = CreateTestView(zIndex: 5);
var view2 = CreateTestView(zIndex: 5);
var view3 = CreateTestView(zIndex: 10);
layout.Add(view0);
layout.Add(view1);
layout.Add(view2);
layout.Add(view3);
var zordered = layout.OrderByZIndex();
Assert.Equal(view0, zordered[0]);
Assert.Equal(view1, zordered[1]);
Assert.Equal(view2, zordered[2]);
Assert.Equal(view3, zordered[3]);
// Fake an update
view3.ZIndex.Returns(5);
zordered = layout.OrderByZIndex();
Assert.Equal(view0, zordered[0]);
Assert.Equal(view1, zordered[1]);
Assert.Equal(view2, zordered[2]);
Assert.Equal(view3, zordered[3]);
}
[Fact]
public void ZIndexUpdatePreservesAddOrderLotsOfEqualZIndexes()
{
// This tests the same thing as ZIndexUpdatePreservesAddOrderForEqualZIndexes,
// but for more views - since the sorting algorithm can change when the arrays
// are larger, we were running into situations where layouts with more controls
// were _not_ preserving the Add() order when sorting by z-index.
var layout = new FakeLayout();
int views = 100;
int iterations = 10;
var toAdd = new IView[views];
for (int n = 0; n < views; n++)
{
toAdd[n] = CreateTestView(zIndex: 0);
layout.Add(toAdd[n]);
}
for (int i = 0; i < iterations; i++)
{
var zordered = layout.OrderByZIndex();
for (int n = 0; n < zordered.Length; n++)
{
Assert.Equal(toAdd[n], zordered[n]);
}
}
}
}
}