xref: /aosp_15_r20/external/stg/order_test.cc (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
1*9e3b08aeSAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2*9e3b08aeSAndroid Build Coastguard Worker // -*- mode: C++ -*-
3*9e3b08aeSAndroid Build Coastguard Worker //
4*9e3b08aeSAndroid Build Coastguard Worker // Copyright 2021-2024 Google LLC
5*9e3b08aeSAndroid Build Coastguard Worker //
6*9e3b08aeSAndroid Build Coastguard Worker // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7*9e3b08aeSAndroid Build Coastguard Worker // "License"); you may not use this file except in compliance with the
8*9e3b08aeSAndroid Build Coastguard Worker // License.  You may obtain a copy of the License at
9*9e3b08aeSAndroid Build Coastguard Worker //
10*9e3b08aeSAndroid Build Coastguard Worker //     https://llvm.org/LICENSE.txt
11*9e3b08aeSAndroid Build Coastguard Worker //
12*9e3b08aeSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
13*9e3b08aeSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
14*9e3b08aeSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*9e3b08aeSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
16*9e3b08aeSAndroid Build Coastguard Worker // limitations under the License.
17*9e3b08aeSAndroid Build Coastguard Worker //
18*9e3b08aeSAndroid Build Coastguard Worker // Author: Giuliano Procida
19*9e3b08aeSAndroid Build Coastguard Worker 
20*9e3b08aeSAndroid Build Coastguard Worker #include "order.h"
21*9e3b08aeSAndroid Build Coastguard Worker 
22*9e3b08aeSAndroid Build Coastguard Worker #include <cstddef>
23*9e3b08aeSAndroid Build Coastguard Worker #include <optional>
24*9e3b08aeSAndroid Build Coastguard Worker #include <random>
25*9e3b08aeSAndroid Build Coastguard Worker #include <sstream>
26*9e3b08aeSAndroid Build Coastguard Worker #include <string>
27*9e3b08aeSAndroid Build Coastguard Worker #include <tuple>
28*9e3b08aeSAndroid Build Coastguard Worker #include <utility>
29*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
30*9e3b08aeSAndroid Build Coastguard Worker 
31*9e3b08aeSAndroid Build Coastguard Worker #include <catch2/catch.hpp>
32*9e3b08aeSAndroid Build Coastguard Worker 
33*9e3b08aeSAndroid Build Coastguard Worker namespace Test {
34*9e3b08aeSAndroid Build Coastguard Worker 
35*9e3b08aeSAndroid Build Coastguard Worker // Safe for small k!
Factorial(size_t k)36*9e3b08aeSAndroid Build Coastguard Worker size_t Factorial(size_t k) {
37*9e3b08aeSAndroid Build Coastguard Worker   size_t count = 1;
38*9e3b08aeSAndroid Build Coastguard Worker   for (size_t i = 1; i <= k; ++i) {
39*9e3b08aeSAndroid Build Coastguard Worker     count *= i;
40*9e3b08aeSAndroid Build Coastguard Worker   }
41*9e3b08aeSAndroid Build Coastguard Worker   return count;
42*9e3b08aeSAndroid Build Coastguard Worker }
43*9e3b08aeSAndroid Build Coastguard Worker 
44*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("hand-curated permutation") {
45*9e3b08aeSAndroid Build Coastguard Worker   std::vector<std::string> data = {"emily", "george", "rose", "ted"};
46*9e3b08aeSAndroid Build Coastguard Worker   std::vector<size_t> permutation = {2, 1, 3, 0};
47*9e3b08aeSAndroid Build Coastguard Worker   const std::vector<std::string> expected = {"rose", "george", "ted", "emily"};
48*9e3b08aeSAndroid Build Coastguard Worker   const std::vector<size_t> identity = {0, 1, 2, 3};
49*9e3b08aeSAndroid Build Coastguard Worker   stg::Permute(data, permutation);
50*9e3b08aeSAndroid Build Coastguard Worker   CHECK(data == expected);
51*9e3b08aeSAndroid Build Coastguard Worker   CHECK(permutation == identity);
52*9e3b08aeSAndroid Build Coastguard Worker }
53*9e3b08aeSAndroid Build Coastguard Worker 
54*9e3b08aeSAndroid Build Coastguard Worker template <typename G>
MakePermutation(size_t k,G & gen)55*9e3b08aeSAndroid Build Coastguard Worker std::vector<size_t> MakePermutation(size_t k, G& gen) {
56*9e3b08aeSAndroid Build Coastguard Worker   std::vector<size_t> result(k);
57*9e3b08aeSAndroid Build Coastguard Worker   for (size_t i = 0; i < k; ++i) {
58*9e3b08aeSAndroid Build Coastguard Worker     result[i] = i;
59*9e3b08aeSAndroid Build Coastguard Worker   }
60*9e3b08aeSAndroid Build Coastguard Worker   for (size_t i = 0; i < k; ++i) {
61*9e3b08aeSAndroid Build Coastguard Worker     // pick one of [i, k)
62*9e3b08aeSAndroid Build Coastguard Worker     std::uniform_int_distribution<size_t> toss(i, k - 1);
63*9e3b08aeSAndroid Build Coastguard Worker     const auto pick = toss(gen);
64*9e3b08aeSAndroid Build Coastguard Worker     using std::swap;
65*9e3b08aeSAndroid Build Coastguard Worker     swap(result[i], result[pick]);
66*9e3b08aeSAndroid Build Coastguard Worker   }
67*9e3b08aeSAndroid Build Coastguard Worker   return result;
68*9e3b08aeSAndroid Build Coastguard Worker }
69*9e3b08aeSAndroid Build Coastguard Worker 
70*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("randomly-generated permutations") {
71*9e3b08aeSAndroid Build Coastguard Worker   std::ranlux48 gen;
72*9e3b08aeSAndroid Build Coastguard Worker   auto seed = gen();
73*9e3b08aeSAndroid Build Coastguard Worker   // NOTES:
74*9e3b08aeSAndroid Build Coastguard Worker   //   Permutations of size 6 are plenty big enough to shake out bugs.
75*9e3b08aeSAndroid Build Coastguard Worker   ///  There are k! permutations of size k. Testing costs are O(k).
76*9e3b08aeSAndroid Build Coastguard Worker   for (size_t k = 0; k < 7; ++k) {
77*9e3b08aeSAndroid Build Coastguard Worker     const auto count = Factorial(k);
78*9e3b08aeSAndroid Build Coastguard Worker     INFO("testing with " << count << " permutations of size " << k);
79*9e3b08aeSAndroid Build Coastguard Worker     std::vector<size_t> identity(k);
80*9e3b08aeSAndroid Build Coastguard Worker     for (size_t i = 0; i < k; ++i) {
81*9e3b08aeSAndroid Build Coastguard Worker       identity[i] = i;
82*9e3b08aeSAndroid Build Coastguard Worker     }
83*9e3b08aeSAndroid Build Coastguard Worker     for (size_t n = 0; n < count; ++n, ++seed) {
84*9e3b08aeSAndroid Build Coastguard Worker       gen.seed(seed);
85*9e3b08aeSAndroid Build Coastguard Worker       auto permutation = MakePermutation(k, gen);
86*9e3b08aeSAndroid Build Coastguard Worker       std::ostringstream os;
87*9e3b08aeSAndroid Build Coastguard Worker       os << "permutation of " << k << " numbers generated using seed " << seed;
88*9e3b08aeSAndroid Build Coastguard Worker       GIVEN(os.str()) {
89*9e3b08aeSAndroid Build Coastguard Worker         // NOTE: We could test with something other than [0, k) as the data, but
90*9e3b08aeSAndroid Build Coastguard Worker         // let's just say "parametric polymorphism" and move on.
91*9e3b08aeSAndroid Build Coastguard Worker         auto permutation_copy = permutation;
92*9e3b08aeSAndroid Build Coastguard Worker         auto identity_copy = identity;
93*9e3b08aeSAndroid Build Coastguard Worker         stg::Permute(identity_copy, permutation_copy);
94*9e3b08aeSAndroid Build Coastguard Worker         for (size_t i = 0; i < k; ++i) {
95*9e3b08aeSAndroid Build Coastguard Worker           // permutation_copy should be the identity
96*9e3b08aeSAndroid Build Coastguard Worker           CHECK(permutation_copy[i] == i);
97*9e3b08aeSAndroid Build Coastguard Worker           // identity_copy should now be the same as permutation
98*9e3b08aeSAndroid Build Coastguard Worker           CHECK(identity_copy[i] == permutation[i]);
99*9e3b08aeSAndroid Build Coastguard Worker         }
100*9e3b08aeSAndroid Build Coastguard Worker       }
101*9e3b08aeSAndroid Build Coastguard Worker     }
102*9e3b08aeSAndroid Build Coastguard Worker   }
103*9e3b08aeSAndroid Build Coastguard Worker }
104*9e3b08aeSAndroid Build Coastguard Worker 
105*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("randomly-generating ordering sequences, fully-matching") {
106*9e3b08aeSAndroid Build Coastguard Worker   std::ranlux48 gen;
107*9e3b08aeSAndroid Build Coastguard Worker   auto seed = gen();
108*9e3b08aeSAndroid Build Coastguard Worker   // NOTES:
109*9e3b08aeSAndroid Build Coastguard Worker   //   Permutations of size 6 are plenty big enough to shake out bugs.
110*9e3b08aeSAndroid Build Coastguard Worker   ///  There are k! permutations of size k. Testing costs are O(k^2).
111*9e3b08aeSAndroid Build Coastguard Worker   for (size_t k = 0; k < 7; ++k) {
112*9e3b08aeSAndroid Build Coastguard Worker     const auto count = Factorial(k);
113*9e3b08aeSAndroid Build Coastguard Worker     INFO("testing with " << count << " random orderings of size " << k);
114*9e3b08aeSAndroid Build Coastguard Worker     for (size_t n = 0; n < count; ++n, ++seed) {
115*9e3b08aeSAndroid Build Coastguard Worker       gen.seed(seed);
116*9e3b08aeSAndroid Build Coastguard Worker       const auto order1 = MakePermutation(k, gen);
117*9e3b08aeSAndroid Build Coastguard Worker       const auto order2 = MakePermutation(k, gen);
118*9e3b08aeSAndroid Build Coastguard Worker       std::ostringstream os;
119*9e3b08aeSAndroid Build Coastguard Worker       os << "orderings of " << k << " numbers generated using seed " << seed;
120*9e3b08aeSAndroid Build Coastguard Worker       GIVEN(os.str()) {
121*9e3b08aeSAndroid Build Coastguard Worker         const auto combined = stg::CombineOrders(order1, order2, k);
122*9e3b08aeSAndroid Build Coastguard Worker         // combined should be identical to order2
123*9e3b08aeSAndroid Build Coastguard Worker         CHECK(combined == order2);
124*9e3b08aeSAndroid Build Coastguard Worker       }
125*9e3b08aeSAndroid Build Coastguard Worker     }
126*9e3b08aeSAndroid Build Coastguard Worker   }
127*9e3b08aeSAndroid Build Coastguard Worker }
128*9e3b08aeSAndroid Build Coastguard Worker 
129*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("randomly-generating ordering sequences, disjoint") {
130*9e3b08aeSAndroid Build Coastguard Worker   std::ranlux48 gen;
131*9e3b08aeSAndroid Build Coastguard Worker   auto seed = gen();
132*9e3b08aeSAndroid Build Coastguard Worker   // NOTES:
133*9e3b08aeSAndroid Build Coastguard Worker   //   Orderings of size 4 are plenty big enough to shake out bugs.
134*9e3b08aeSAndroid Build Coastguard Worker   ///  There are k! permutations of size k. Testing costs are O(k^2).
135*9e3b08aeSAndroid Build Coastguard Worker   for (size_t k = 0; k < 5; ++k) {
136*9e3b08aeSAndroid Build Coastguard Worker     const auto count = Factorial(k);
137*9e3b08aeSAndroid Build Coastguard Worker     INFO("testing with " << count << " random orderings of size " << k);
138*9e3b08aeSAndroid Build Coastguard Worker     for (size_t n = 0; n < count; ++n, ++seed) {
139*9e3b08aeSAndroid Build Coastguard Worker       gen.seed(seed);
140*9e3b08aeSAndroid Build Coastguard Worker       const auto order1 = MakePermutation(k, gen);
141*9e3b08aeSAndroid Build Coastguard Worker       auto order2 = MakePermutation(k, gen);
142*9e3b08aeSAndroid Build Coastguard Worker       for (size_t i = 0; i < k; ++i) {
143*9e3b08aeSAndroid Build Coastguard Worker         order2[i] += k;
144*9e3b08aeSAndroid Build Coastguard Worker       }
145*9e3b08aeSAndroid Build Coastguard Worker       std::ostringstream os;
146*9e3b08aeSAndroid Build Coastguard Worker       os << "orderings of " << k << " numbers generated using seed " << seed;
147*9e3b08aeSAndroid Build Coastguard Worker       GIVEN(os.str()) {
148*9e3b08aeSAndroid Build Coastguard Worker         const auto combined = stg::CombineOrders(order1, order2, 2 * k);
149*9e3b08aeSAndroid Build Coastguard Worker         for (size_t i = 0; i < k; ++i) {
150*9e3b08aeSAndroid Build Coastguard Worker           // order1 should appear as the first part
151*9e3b08aeSAndroid Build Coastguard Worker           CHECK(combined[i] == order1[i]);
152*9e3b08aeSAndroid Build Coastguard Worker           // order2 should appear as the second part
153*9e3b08aeSAndroid Build Coastguard Worker           CHECK(combined[i + k] == order2[i]);
154*9e3b08aeSAndroid Build Coastguard Worker         }
155*9e3b08aeSAndroid Build Coastguard Worker       }
156*9e3b08aeSAndroid Build Coastguard Worker     }
157*9e3b08aeSAndroid Build Coastguard Worker   }
158*9e3b08aeSAndroid Build Coastguard Worker }
159*9e3b08aeSAndroid Build Coastguard Worker 
160*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("randomly-generating ordering sequences, single overlap") {
161*9e3b08aeSAndroid Build Coastguard Worker   std::ranlux48 gen;
162*9e3b08aeSAndroid Build Coastguard Worker   auto seed = gen();
163*9e3b08aeSAndroid Build Coastguard Worker   // NOTES:
164*9e3b08aeSAndroid Build Coastguard Worker   //   Orderings of size 4 are plenty big enough to shake out bugs.
165*9e3b08aeSAndroid Build Coastguard Worker   ///  There are k! permutations of size k. Testing costs are O(k^2).
166*9e3b08aeSAndroid Build Coastguard Worker   for (size_t k = 1; k < 5; ++k) {
167*9e3b08aeSAndroid Build Coastguard Worker     const auto count = Factorial(k);
168*9e3b08aeSAndroid Build Coastguard Worker     INFO("testing with " << count << " random orderings of size " << k);
169*9e3b08aeSAndroid Build Coastguard Worker     for (size_t n = 0; n < count; ++n, ++seed) {
170*9e3b08aeSAndroid Build Coastguard Worker       gen.seed(seed);
171*9e3b08aeSAndroid Build Coastguard Worker       const auto order1 = MakePermutation(k, gen);
172*9e3b08aeSAndroid Build Coastguard Worker       auto order2 = MakePermutation(k, gen);
173*9e3b08aeSAndroid Build Coastguard Worker       for (size_t i = 0; i < k; ++i) {
174*9e3b08aeSAndroid Build Coastguard Worker         order2[i] += k - 1;
175*9e3b08aeSAndroid Build Coastguard Worker       }
176*9e3b08aeSAndroid Build Coastguard Worker       const auto pivot = k - 1;
177*9e3b08aeSAndroid Build Coastguard Worker       std::ostringstream os;
178*9e3b08aeSAndroid Build Coastguard Worker       os << "orderings of " << k << " numbers generated using seed " << seed;
179*9e3b08aeSAndroid Build Coastguard Worker       GIVEN(os.str()) {
180*9e3b08aeSAndroid Build Coastguard Worker         const auto combined = stg::CombineOrders(order1, order2, 2 * k - 1);
181*9e3b08aeSAndroid Build Coastguard Worker         CHECK(combined.size() == 2 * k - 1);
182*9e3b08aeSAndroid Build Coastguard Worker         // order1 pre, order2 pre, pivot, order1 post, order2 post
183*9e3b08aeSAndroid Build Coastguard Worker         size_t ix = 0;
184*9e3b08aeSAndroid Build Coastguard Worker         size_t ix1 = 0;
185*9e3b08aeSAndroid Build Coastguard Worker         size_t ix2 = 0;
186*9e3b08aeSAndroid Build Coastguard Worker         while (order1[ix1] != pivot) {
187*9e3b08aeSAndroid Build Coastguard Worker           CHECK(combined[ix++] == order1[ix1++]);
188*9e3b08aeSAndroid Build Coastguard Worker         }
189*9e3b08aeSAndroid Build Coastguard Worker         while (order2[ix2] != pivot) {
190*9e3b08aeSAndroid Build Coastguard Worker           CHECK(combined[ix++] == order2[ix2++]);
191*9e3b08aeSAndroid Build Coastguard Worker         }
192*9e3b08aeSAndroid Build Coastguard Worker         ++ix1;
193*9e3b08aeSAndroid Build Coastguard Worker         ++ix2;
194*9e3b08aeSAndroid Build Coastguard Worker         CHECK(combined[ix++] == pivot);
195*9e3b08aeSAndroid Build Coastguard Worker         while (ix1 < k) {
196*9e3b08aeSAndroid Build Coastguard Worker           CHECK(combined[ix++] == order1[ix1++]);
197*9e3b08aeSAndroid Build Coastguard Worker         }
198*9e3b08aeSAndroid Build Coastguard Worker         while (ix2 < k) {
199*9e3b08aeSAndroid Build Coastguard Worker           CHECK(combined[ix++] == order2[ix2++]);
200*9e3b08aeSAndroid Build Coastguard Worker         }
201*9e3b08aeSAndroid Build Coastguard Worker       }
202*9e3b08aeSAndroid Build Coastguard Worker     }
203*9e3b08aeSAndroid Build Coastguard Worker   }
204*9e3b08aeSAndroid Build Coastguard Worker }
205*9e3b08aeSAndroid Build Coastguard Worker 
206*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("hand-curated ordering sequences") {
207*9e3b08aeSAndroid Build Coastguard Worker   using Sequence = std::vector<std::string>;
208*9e3b08aeSAndroid Build Coastguard Worker   // NOTES:
209*9e3b08aeSAndroid Build Coastguard Worker   //   The output sequence MUST include the second sequence as a subsequence.
210*9e3b08aeSAndroid Build Coastguard Worker   //   The first sequence's ordering is respected as far as possible.
211*9e3b08aeSAndroid Build Coastguard Worker   const std::vector<std::tuple<Sequence, Sequence, Sequence>> cases = {
212*9e3b08aeSAndroid Build Coastguard Worker     {{"rose", "george", "emily"}, {"george", "ted", "emily"},
213*9e3b08aeSAndroid Build Coastguard Worker       {"rose", "george", "ted", "emily"}},
214*9e3b08aeSAndroid Build Coastguard Worker     {{}, {}, {}},
215*9e3b08aeSAndroid Build Coastguard Worker     {{"a"}, {}, {"a"}},
216*9e3b08aeSAndroid Build Coastguard Worker     {{}, {"a"}, {"a"}},
217*9e3b08aeSAndroid Build Coastguard Worker     {{"a", "z"}, {}, {"a", "z"}},
218*9e3b08aeSAndroid Build Coastguard Worker     {{}, {"a", "z"}, {"a", "z"}},
219*9e3b08aeSAndroid Build Coastguard Worker     {{"a", "b", "c"}, {"c", "d"}, {"a", "b", "c", "d"}},
220*9e3b08aeSAndroid Build Coastguard Worker     {{"a", "b", "d"}, {"b", "c", "d"}, {"a", "b", "c", "d"}},
221*9e3b08aeSAndroid Build Coastguard Worker     {{"a", "c", "d"}, {"a", "b", "c"}, {"a", "b", "c", "d"}},
222*9e3b08aeSAndroid Build Coastguard Worker     {{"b", "c", "d"}, {"a", "b"}, {"a", "b", "c", "d"}},
223*9e3b08aeSAndroid Build Coastguard Worker     {{"z", "a", "q"}, {"a", "z"}, {"a", "z", "q"}},
224*9e3b08aeSAndroid Build Coastguard Worker   };
225*9e3b08aeSAndroid Build Coastguard Worker   for (const auto& [order1, order2, expected] : cases) {
226*9e3b08aeSAndroid Build Coastguard Worker     const auto combined = stg::CombineOrders(order1, order2, expected.size());
227*9e3b08aeSAndroid Build Coastguard Worker     CHECK(combined == expected);
228*9e3b08aeSAndroid Build Coastguard Worker   }
229*9e3b08aeSAndroid Build Coastguard Worker }
230*9e3b08aeSAndroid Build Coastguard Worker 
231*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("hand-curated reorderings with input order randomisation") {
232*9e3b08aeSAndroid Build Coastguard Worker   using Constraint = std::pair<std::optional<size_t>, std::optional<size_t>>;
233*9e3b08aeSAndroid Build Coastguard Worker   using Constraints = std::vector<Constraint>;
234*9e3b08aeSAndroid Build Coastguard Worker   // NOTES:
235*9e3b08aeSAndroid Build Coastguard Worker   //   item removed at position x: {x}, {}
236*9e3b08aeSAndroid Build Coastguard Worker   //   item added at position y: {}, {y}
237*9e3b08aeSAndroid Build Coastguard Worker   //   item modified at positions x and y: {x}, {y}
238*9e3b08aeSAndroid Build Coastguard Worker   //   input item order should be irrelevant to output order
239*9e3b08aeSAndroid Build Coastguard Worker   const std::vector<std::pair<Constraints, Constraints>> cases = {
240*9e3b08aeSAndroid Build Coastguard Worker     {
241*9e3b08aeSAndroid Build Coastguard Worker       {
242*9e3b08aeSAndroid Build Coastguard Worker         {{2}, {2}},  // emily
243*9e3b08aeSAndroid Build Coastguard Worker         {{1}, {0}},  // george
244*9e3b08aeSAndroid Build Coastguard Worker         {{0}, {}},   // rose
245*9e3b08aeSAndroid Build Coastguard Worker         {{}, {1}},   // ted
246*9e3b08aeSAndroid Build Coastguard Worker       },
247*9e3b08aeSAndroid Build Coastguard Worker       {
248*9e3b08aeSAndroid Build Coastguard Worker         {{0}, {}},   // rose
249*9e3b08aeSAndroid Build Coastguard Worker         {{1}, {0}},  // george
250*9e3b08aeSAndroid Build Coastguard Worker         {{}, {1}},   // ted
251*9e3b08aeSAndroid Build Coastguard Worker         {{2}, {2}},  // emily
252*9e3b08aeSAndroid Build Coastguard Worker       },
253*9e3b08aeSAndroid Build Coastguard Worker     },
254*9e3b08aeSAndroid Build Coastguard Worker     {{}, {}},
255*9e3b08aeSAndroid Build Coastguard Worker     {{{{0}, {0}}}, {{{0}, {0}}}},
256*9e3b08aeSAndroid Build Coastguard Worker     {{{{0}, {}}}, {{{0}, {}}}},
257*9e3b08aeSAndroid Build Coastguard Worker     {{{{}, {0}}}, {{{}, {0}}}},
258*9e3b08aeSAndroid Build Coastguard Worker     {{{{}, {2}}, {{}, {1}}, {{}, {0}}},
259*9e3b08aeSAndroid Build Coastguard Worker      {{{}, {0}}, {{}, {1}}, {{}, {2}}}},
260*9e3b08aeSAndroid Build Coastguard Worker     {{{{2}, {}}, {{1}, {}}, {{0}, {}}},
261*9e3b08aeSAndroid Build Coastguard Worker      {{{0}, {}}, {{1}, {}}, {{2}, {}}}},
262*9e3b08aeSAndroid Build Coastguard Worker     // int b; int c; -> int b; int a; int c
263*9e3b08aeSAndroid Build Coastguard Worker     {{{{}, {1}}, {{0}, {0}}, {{1}, {2}}},
264*9e3b08aeSAndroid Build Coastguard Worker      {{{0}, {0}}, {{}, {1}}, {{1}, {2}}}},
265*9e3b08aeSAndroid Build Coastguard Worker   };
266*9e3b08aeSAndroid Build Coastguard Worker   std::ranlux48 gen;
267*9e3b08aeSAndroid Build Coastguard Worker   auto seed = gen();
268*9e3b08aeSAndroid Build Coastguard Worker   for (const auto& [given, expected] : cases) {
269*9e3b08aeSAndroid Build Coastguard Worker     const auto k = given.size();
270*9e3b08aeSAndroid Build Coastguard Worker     const auto count = Factorial(k);
271*9e3b08aeSAndroid Build Coastguard Worker     INFO("testing with " << count << " random input orderings");
272*9e3b08aeSAndroid Build Coastguard Worker     for (size_t n = 0; n < count; ++n, ++seed) {
273*9e3b08aeSAndroid Build Coastguard Worker       gen.seed(seed);
274*9e3b08aeSAndroid Build Coastguard Worker       std::ostringstream os;
275*9e3b08aeSAndroid Build Coastguard Worker       os << "permutation of " << k << " items generated using seed " << seed;
276*9e3b08aeSAndroid Build Coastguard Worker       GIVEN(os.str()) {
277*9e3b08aeSAndroid Build Coastguard Worker         auto permutation = MakePermutation(k, gen);
278*9e3b08aeSAndroid Build Coastguard Worker         auto copy = given;
279*9e3b08aeSAndroid Build Coastguard Worker         stg::Permute(copy, permutation);
280*9e3b08aeSAndroid Build Coastguard Worker         stg::Reorder(copy);
281*9e3b08aeSAndroid Build Coastguard Worker         CHECK(copy == expected);
282*9e3b08aeSAndroid Build Coastguard Worker       }
283*9e3b08aeSAndroid Build Coastguard Worker     }
284*9e3b08aeSAndroid Build Coastguard Worker   }
285*9e3b08aeSAndroid Build Coastguard Worker }
286*9e3b08aeSAndroid Build Coastguard Worker 
287*9e3b08aeSAndroid Build Coastguard Worker }  // namespace Test
288