1
+import 'dart:math';
2
+
3
+import 'package:bitcoin_base/bitcoin_base.dart';
4
+import 'package:cw_bitcoin/output_ordering.dart';
5
+import 'package:flutter_test/flutter_test.dart';
6
+
7
+void main() {
8
+ group('orderOutputs', () {
9
+ test('none preserves the given order', () {
10
+ final outputs = [0, 1, 2, 3, 4];
11
+ expect(orderOutputs(outputs, BitcoinOrdering.none), outputs);
12
+ });
13
+
14
+ test('does not mutate the input list', () {
15
+ final outputs = [0, 1, 2, 3, 4];
16
+ orderOutputs(outputs, BitcoinOrdering.shuffle, rng: Random(1));
17
+ expect(outputs, [0, 1, 2, 3, 4]);
18
+ });
19
+
20
+ test('returns a new list instance', () {
21
+ final outputs = [0, 1, 2];
22
+ expect(identical(orderOutputs(outputs, BitcoinOrdering.none), outputs), isFalse);
23
+ });
24
+
25
+ test('shuffle preserves the multiset of outputs', () {
26
+ final outputs = [0, 1, 2, 3, 4, 5, 6, 7];
27
+ final shuffled = orderOutputs(outputs, BitcoinOrdering.shuffle, rng: Random(7));
28
+ expect(shuffled.length, outputs.length);
29
+ expect(shuffled.toSet(), outputs.toSet());
30
+ });
31
+
32
+ test('shuffle is deterministic for a given seed', () {
33
+ final outputs = [0, 1, 2, 3, 4, 5];
34
+ final a = orderOutputs(outputs, BitcoinOrdering.shuffle, rng: Random(42));
35
+ final b = orderOutputs(outputs, BitcoinOrdering.shuffle, rng: Random(42));
36
+ expect(a, b);
37
+ });
38
+
39
+ test('shuffle does not keep the change output deterministically last', () {
40
+ // Last element (99) models the change output, appended last today.
41
+ final outputs = [0, 1, 2, 3, 99];
42
+ final changePositions = <int>{};
43
+ for (var seed = 0; seed < 50; seed++) {
44
+ final shuffled = orderOutputs(outputs, BitcoinOrdering.shuffle, rng: Random(seed));
45
+ changePositions.add(shuffled.indexOf(99));
46
+ }
47
+ // Across seeds the change lands in more than one position, and not always last.
48
+ expect(changePositions.length, greaterThan(1));
49
+ expect(changePositions, isNot(equals({outputs.length - 1})));
50
+ });
51
+ });
52
+}