1 module auxil.cursor_accumulator_test;
2 
3 import std;
4 
5 version(unittest)
6 import unit_threaded;
7 
8 import auxil.cursor_accumulator;
9 import auxil.cursor_test : sequence, LogRecord;
10 
11 version(unittest)
12 @Name("testForward")
13 unittest
14 {
15 	import auxil.cursor : Cursor;
16 
17 	const order = Cursor.Order.forward;
18 	LogRecord[] posLog;
19 	CursorAccumulator ca;
20 
21 	ca.start;
22 
23 	auto seq = sequence.dup;
24 	foreach(e; seq)
25 	{
26 		ca.begin(e);
27 		posLog ~= LogRecord(ca.position!order, e);
28 		ca.end(e);
29 	}
30 
31 	posLog.should.be == [
32 		LogRecord(0, 10),
33 		LogRecord(10, 21),
34 		LogRecord(31, 12),
35 		LogRecord(43, 13),
36 		LogRecord(56, 24),
37 		LogRecord(80, 15),
38 		LogRecord(95, 16),
39 		LogRecord(111, 17),
40 	];
41 
42 	// after traversing and before commit
43 	// fixedPosition equals to calcPosition result
44 	// and is the position of the next element after
45 	// the last one
46 	ca.csr.fixedPosition.should.be == 128;
47 	ca.csr.calcPosition!order.should.be == 128;
48 	ca.position!order.should.be == 128;
49 
50 	// we call it if we want to scroll further
51 	// so we need to store the current position
52 	ca.commit!order;
53 
54 	posLog.should.be == [
55 		LogRecord(0, 10),
56 		LogRecord(10, 21),
57 		LogRecord(31, 12),
58 		LogRecord(43, 13),
59 		LogRecord(56, 24),
60 		LogRecord(80, 15),
61 		LogRecord(95, 16),
62 		LogRecord(111, 17),
63 	];
64 
65 	// after commit fixedPosition is reset
66 	// and the current position returned by calcPosition
67 	// equals to the position of the last element
68 	// (not the next element after the last one)
69 	ca.csr.fixedPosition.should.be == 0;
70 	ca.csr.calcPosition!order.should.be == 111;
71 	ca.position!order.should.be == 111;
72 }
73 
74 version(unittest)
75 @Name("testBackward")
76 unittest
77 {
78 	import auxil.cursor : Cursor;
79 
80 	const order = Cursor.Order.backward;
81 	LogRecord[] posLog;
82 	auto seq = sequence.dup.retro;
83 	CursorAccumulator ca;
84 
85 	ca.start(sum(seq));
86 	foreach(e; seq)
87 	{
88 		ca.begin(e);
89 		posLog ~= LogRecord(ca.position!order, e);
90 		ca.end(e);
91 	}
92 
93 	posLog.should.be == [
94 		LogRecord(111, 17), 
95 		LogRecord( 95, 16), 
96 		LogRecord( 80, 15), 
97 		LogRecord( 56, 24), 
98 		LogRecord( 43, 13), 
99 		LogRecord( 31, 12), 
100 		LogRecord( 10, 21), 
101 		LogRecord(  0, 10)
102 	];
103 
104 	ca.csr.fixedPosition.should.be == 128;
105 	ca.csr.calcPosition!order.should.be == -10;
106 	ca.position!order.should.be == -10;
107 
108 	// we call it if we want to scroll further
109 	// so we need to store the current position
110 	ca.commit!order;
111 
112 	posLog.should.be == [
113 		LogRecord(111, 17), 
114 		LogRecord( 95, 16), 
115 		LogRecord( 80, 15), 
116 		LogRecord( 56, 24), 
117 		LogRecord( 43, 13), 
118 		LogRecord( 31, 12), 
119 		LogRecord( 10, 21), 
120 		LogRecord(  0, 10)
121 	];
122 
123 	// after commit fixedPosition is reset
124 	// and the current position returned by calcPosition
125 	// equals to the position of the last element
126 	// (not the next element after the last one)
127 	ca.csr.fixedPosition.should.be == 0;
128 	ca.csr.calcPosition!order.should.be == -10;
129 	ca.position!order.should.be == -10;
130 }
131 
132 version(unittest)
133 @Name("testTraversingForward")
134 unittest
135 {
136 	import auxil.cursor : Cursor;
137 
138 	const order = Cursor.Order.forward;
139 	LogRecord[] posLog;
140 	auto seq = sequence.dup;
141 	CursorAccumulator ca;
142 
143 	// start traversing
144 	ca.start;
145 
146 	// step #1 - scroll 3 first elements
147 	{
148 		posLog = null;
149 		foreach(e; seq[0..3])
150 		{
151 			ca.begin(e);
152 			posLog ~= LogRecord(ca.position!order, e);
153 			ca.end(e);
154 		}
155 
156 		// checks
157 		posLog.should.be == [
158 			LogRecord(0, 10),
159 			LogRecord(10, 21),
160 			LogRecord(31, 12),
161 		];
162 
163 		ca.position!order.should.be == 43;
164 		ca.csr.last_value.should.be == 12;
165 	}
166 
167 	// step #2 - scroll for the next 3 elements
168 	{
169 		posLog = null;
170 		foreach(e; seq[3..6])
171 		{
172 			ca.begin(e);
173 			posLog ~= LogRecord(ca.position!order, e);
174 			ca.end(e);
175 		}
176 
177 		// checks
178 		posLog.should.be == [
179 			LogRecord(43, 13),
180 			LogRecord(56, 24),
181 			LogRecord(80, 15),
182 		];
183 
184 		ca.position!order.should.be == 95;
185 		ca.csr.last_value.should.be == 15;
186 	}
187 
188 	// step #3 - scroll for the last two elements
189 	{
190 		posLog = null;
191 		foreach(e; seq[6..$])
192 		{
193 			ca.begin(e);
194 			posLog ~= LogRecord(ca.position!order, e);
195 			ca.end(e);
196 		}
197 
198 		// check
199 		posLog.should.be == [
200 			LogRecord(95, 16),
201 			LogRecord(111, 17),
202 		];
203 
204 		ca.position!order.should.be == 128;
205 		ca.csr.last_value.should.be == 17;
206 	}
207 
208 	// step #4 - scroll for the first two elements
209 	{
210 		ca.start;
211 		posLog = null;
212 		foreach(e; seq[0..2])
213 		{
214 			ca.begin(e);
215 			posLog ~= LogRecord(ca.position!order, e);
216 			ca.end(e);
217 		}
218 
219 		// check
220 		posLog.should.be == [
221 			LogRecord(0, 10),
222 			LogRecord(10, 21),
223 		];
224 
225 		ca.position!order.should.be == 31;
226 		ca.csr.last_value.should.be == 21;
227 	}
228 }
229 
230 version(unittest)
231 @Name("testTraversingBackward")
232 unittest
233 {
234 	import auxil.cursor : Cursor;
235 
236 	const order = Cursor.Order.backward;
237 	LogRecord[] posLog;
238 	auto seq = sequence.dup.retro;
239 	CursorAccumulator ca;
240 
241 	// start traversing
242 	ca.start(sum(seq));
243 
244 	// step #1 - scroll 3 first elements
245 	{
246 		posLog = null;
247 		foreach(e; seq[0..3])
248 		{
249 			ca.begin(e);
250 			posLog ~= LogRecord(ca.position!order, e);
251 			ca.end(e);
252 		}
253 
254 		// checks
255 		posLog.should.be == [
256 			LogRecord(111, 17), 
257 			LogRecord( 95, 16), 
258 			LogRecord( 80, 15),
259 		];
260 
261 		ca.csr.fixUp;
262 
263 writeln(ca.csr);
264 		ca.position!order.should.be == 80;
265 		ca.csr.last_value.should.be == 15;
266 	}
267 
268 	// step #2 - scroll for the next 3 elements
269 	{
270 		posLog = null;
271 		foreach(e; seq[3..6])
272 		{
273 			ca.begin(e);
274 			posLog ~= LogRecord(ca.position!order, e);
275 			ca.end(e);
276 		}
277 
278 		// checks
279 		posLog.should.be == [
280 			LogRecord(43, 13),
281 			LogRecord(56, 24),
282 			LogRecord(80, 15),
283 		];
284 
285 		ca.position!order.should.be == 95;
286 		ca.csr.last_value.should.be == 15;
287 	}
288 
289 	// step #3 - scroll for the last two elements
290 	{
291 		posLog = null;
292 		foreach(e; seq[6..$])
293 		{
294 			ca.begin(e);
295 			posLog ~= LogRecord(ca.position!order, e);
296 			ca.end(e);
297 		}
298 
299 		// check
300 		posLog.should.be == [
301 			LogRecord(95, 16),
302 			LogRecord(111, 17),
303 		];
304 
305 		ca.position!order.should.be == 128;
306 		ca.csr.last_value.should.be == 17;
307 	}
308 
309 	// step #4 - scroll for the first two elements
310 	{
311 		ca.start;
312 		posLog = null;
313 		foreach(e; seq[0..2])
314 		{
315 			ca.begin(e);
316 			posLog ~= LogRecord(ca.position!order, e);
317 			ca.end(e);
318 		}
319 
320 		// check
321 		posLog.should.be == [
322 			LogRecord(0, 10),
323 			LogRecord(10, 21),
324 		];
325 
326 		ca.position!order.should.be == 31;
327 		ca.csr.last_value.should.be == 21;
328 	}
329 }
330 
331 version(unittest)
332 @Name("testScrollingForward")
333 unittest
334 {
335 	import auxil.cursor : Cursor;
336 
337 	const order = Cursor.Order.forward;
338 	LogRecord[] posLog;
339 	auto seq = sequence.dup;
340 	CursorAccumulator ca;
341 
342 	// start scrolling
343 	ca.start;
344 
345 	// step 1
346 	{
347 		foreach(e; seq[0..$/2])
348 		{
349 			ca.begin(e);
350 			posLog ~= LogRecord(ca.position!order, e);
351 			ca.end(e);
352 		}
353 
354 		ca.position!order.should.be == 56;
355 		ca.csr.last_value.should.be == 13;
356 
357 		// commiting is the difference between scrolling and traversing
358 		ca.commit!order;
359 
360 		posLog.should.be == [
361 			LogRecord(0, 10),
362 			LogRecord(10, 21),
363 			LogRecord(31, 12),
364 			LogRecord(43, 13),
365 		];
366 
367 		ca.position!order.should.be == 43;
368 		ca.csr.last_value.should.be == 13;
369 		ca.csr.current_value.should.be == 13;
370 	}
371 
372 	// step 2
373 	{
374 		posLog = null;
375 
376 		foreach(e; seq[$/2-1..$]) // <= important that we start from the last element ($/2-1 not just $/2)
377 		{
378 			ca.begin(e);
379 			posLog ~= LogRecord(ca.position!order, e);
380 			ca.end(e);
381 		}
382 		ca.position!order.should.be == 128;
383 		ca.csr.last_value.should.be == 17;
384 		ca.csr.current_value.should.be == 17;
385 
386 		ca.commit!order;
387 
388 		posLog.should.be == [
389 			LogRecord(43, 13),
390 			LogRecord(56, 24),
391 			LogRecord(80, 15),
392 			LogRecord(95, 16),
393 			LogRecord(111, 17),
394 		];
395 
396 		ca.position!order.should.be == 111;
397 		ca.csr.last_value.should.be == 17;
398 		ca.csr.current_value.should.be == 17;
399 	}
400 }