Skip to content

Commit ecb64e1

Browse files
authored
Merge pull request #282 from cicirello/refactor-prem-tests
Refactored tests of the Permutation class (suggestion of Sonatype Lift's technical debt scan)
2 parents 75e9556 + e2dd547 commit ecb64e1

14 files changed

+1706
-1363
lines changed
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
/*
2+
* JavaPermutationTools: A Java library for computation on permutations and sequences
3+
* Copyright 2005-2022 Vincent A. Cicirello, <https://www.cicirello.org/>.
4+
*
5+
* This file is part of JavaPermutationTools (https://jpt.cicirello.org/).
6+
*
7+
* JavaPermutationTools is free software: you can
8+
* redistribute it and/or modify it under the terms of the GNU
9+
* General Public License as published by the Free Software
10+
* Foundation, either version 3 of the License, or (at your
11+
* option) any later version.
12+
*
13+
* JavaPermutationTools is distributed in the hope
14+
* that it will be useful, but WITHOUT ANY WARRANTY; without even
15+
* the implied warranty of MERCHANTABILITY or FITNESS FOR A
16+
* PARTICULAR PURPOSE. See the GNU General Public License for more
17+
* details.
18+
*
19+
* You should have received a copy of the GNU General Public License
20+
* along with JavaPermutationTools. If not, see <http://www.gnu.org/licenses/>.
21+
*/
22+
package org.cicirello.permutations;
23+
24+
import java.util.SplittableRandom;
25+
import java.util.Random;
26+
import java.math.BigInteger;
27+
import org.junit.jupiter.api.*;
28+
import static org.junit.jupiter.api.Assertions.*;
29+
30+
/**
31+
* JUnit tests for the constructors and methods of the Permutation class.
32+
*/
33+
public class PermutationConstructorRelatedTests extends SharedTestHelpersPermutation {
34+
35+
// Set to false to enable chi square tests for randomness of constructor and
36+
// scramble, specifically for the constructor and scramble that uses ThreadLocalRandom
37+
// since it is not seedable. Tests passed repeatedly as of last update.
38+
// If that constructor or scramble is updated, then this flag should be set false to enable
39+
// tests (and reset true after passing).
40+
// Note: This doesn't disable those tests for the constructors/scramble methods
41+
// that use a source of randomness that is seedable.
42+
private static final boolean disableChiSquareTests = true;
43+
44+
@Test
45+
public void testZeroLengthPermutations() {
46+
// different ways of constructing 0 length permutations.
47+
Permutation p1 = new Permutation(0);
48+
Permutation p2 = new Permutation(new int[] {});
49+
Permutation p3 = new Permutation(0,0);
50+
Permutation copy = new Permutation(p1);
51+
52+
// the above 4 should all be equivalent, so check
53+
assertEquals(p1,p2);
54+
assertEquals(p1,p3);
55+
assertEquals(p1,copy);
56+
assertEquals(p2,p3);
57+
assertEquals(p2,copy);
58+
assertEquals(p3,copy);
59+
}
60+
61+
@Test
62+
public void testPermutationConstructor() {
63+
for (int n = 1; n <= 10; n++) {
64+
for (int i = 0; i < 10; i++) {
65+
Permutation p = new Permutation(n);
66+
validatePermutation(p, n);
67+
}
68+
}
69+
SplittableRandom r = new SplittableRandom();
70+
for (int n = 1; n <= 10; n++) {
71+
for (int i = 0; i < 10; i++) {
72+
Permutation p = new Permutation(n, r);
73+
validatePermutation(p, n);
74+
}
75+
}
76+
}
77+
78+
@Test
79+
public void testPermutationConstructorSpecific() {
80+
int fact = 1;
81+
for (int n = 1; n <= 6; n++) {
82+
fact *= n;
83+
for (int i = 0; i < fact; i++) {
84+
Permutation p = new Permutation(n, i);
85+
assertEquals(i, p.toInteger());
86+
assertEquals(BigInteger.valueOf(i), p.toBigInteger());
87+
validatePermutation(p, n);
88+
}
89+
}
90+
int n = 12;
91+
fact = 1;
92+
for (int i = 2; i <= n; i++) {
93+
fact *= i;
94+
}
95+
SplittableRandom r = new SplittableRandom();
96+
for (int i = 0; i < 100; i++) {
97+
int which = r.nextInt(fact);
98+
Permutation p = new Permutation(n, which);
99+
assertEquals(which, p.toInteger());
100+
assertEquals(BigInteger.valueOf(which), p.toBigInteger());
101+
validatePermutation(p, n);
102+
}
103+
}
104+
105+
@Test
106+
public void testPermutationConstructorSpecificBigInt() {
107+
int fact = 1;
108+
for (int n = 1; n <= 6; n++) {
109+
fact *= n;
110+
for (int i = 0; i < fact; i++) {
111+
BigInteger big = BigInteger.valueOf(i);
112+
Permutation p = new Permutation(n, big);
113+
assertEquals(i, p.toInteger());
114+
assertEquals(big, p.toBigInteger());
115+
validatePermutation(p, n);
116+
}
117+
}
118+
int n = 12;
119+
fact = 1;
120+
for (int i = 2; i <= n; i++) {
121+
fact *= i;
122+
}
123+
SplittableRandom r = new SplittableRandom();
124+
for (int i = 0; i < 100; i++) {
125+
int which = r.nextInt(fact);
126+
BigInteger bigWhich = BigInteger.valueOf(which);
127+
Permutation p = new Permutation(n, bigWhich);
128+
assertEquals(which, p.toInteger());
129+
assertEquals(bigWhich, p.toBigInteger());
130+
validatePermutation(p, n);
131+
}
132+
n = 20;
133+
BigInteger f = BigInteger.ONE;
134+
for (int i = 2; i <= n; i++) {
135+
f = f.multiply(BigInteger.valueOf(i));
136+
}
137+
for (int i = 0; i < 20; i++) {
138+
BigInteger bigWhich = new BigInteger(f.bitLength()-1, new Random(42));
139+
Permutation p = new Permutation(n, bigWhich);
140+
assertEquals(bigWhich, p.toBigInteger());
141+
validatePermutation(p, n);
142+
}
143+
}
144+
145+
@Test
146+
public void testToIntegerExceptions() {
147+
UnsupportedOperationException thrown = assertThrows(
148+
UnsupportedOperationException.class,
149+
() -> (new Permutation(13)).toInteger()
150+
);
151+
}
152+
153+
@Test
154+
public void testPermutationCopyConstructor() {
155+
for (int n = 1; n <= 10; n++) {
156+
for (int i = 0; i < 10; i++) {
157+
Permutation p = new Permutation(n);
158+
Permutation copy = new Permutation(p);
159+
assertEquals(p, copy);
160+
assertEquals(p.hashCode(), copy.hashCode());
161+
}
162+
}
163+
}
164+
165+
@Test
166+
public void testPermutationCopyMethod() {
167+
for (int n = 1; n <= 10; n++) {
168+
for (int i = 0; i < 10; i++) {
169+
Permutation p = new Permutation(n);
170+
Permutation copy = p.copy();
171+
assertEquals(p, copy);
172+
assertTrue(p != copy);
173+
assertEquals(p.hashCode(), copy.hashCode());
174+
}
175+
}
176+
}
177+
178+
@Test
179+
public void testPermutationEqualsSpecialCases() {
180+
Permutation p = new Permutation(5);
181+
assertTrue(p.equals(p));
182+
assertFalse(p.equals(null));
183+
assertFalse(p.equals("hello"));
184+
}
185+
186+
@Test
187+
public void testPermutationConstructorCopyPartial() {
188+
for (int n = 1; n <= 10; n++) {
189+
int[] forward = new int[n];
190+
int[] backward = new int[n];
191+
for (int i = 0; i < n; i++) {
192+
backward[n-1-i] = forward[i] = i;
193+
}
194+
Permutation p1 = new Permutation(forward);
195+
Permutation p2 = new Permutation(backward);
196+
for (int m = 0; m <= n; m++) {
197+
Permutation copy1 = new Permutation(p1, m);
198+
Permutation copy2 = new Permutation(p2, m);
199+
assertEquals(m, copy1.length());
200+
assertEquals(m, copy2.length());
201+
validatePermutation(copy1, m);
202+
validatePermutation(copy2, m);
203+
for (int i = 0; i < m; i++) {
204+
assertEquals(i, copy1.get(i));
205+
assertEquals(m-1-i, copy2.get(i));
206+
}
207+
}
208+
}
209+
}
210+
211+
@Test
212+
public void testPermutationEquals() {
213+
Permutation p = new Permutation(10);
214+
for (int n = 1; n < 10; n++) {
215+
Permutation partialCopy = new Permutation(p, n);
216+
assertNotEquals(p, partialCopy);
217+
}
218+
Permutation copy = new Permutation(p);
219+
assertEquals(p, copy);
220+
assertNotEquals(new Permutation(new int[] {0, 1, 2, 3}), new Permutation(new int[] {3, 1, 2, 0}));
221+
}
222+
223+
@Test
224+
public void testUniformityOfConstructors() {
225+
final int N = 12000;
226+
SplittableRandom r2 = new SplittableRandom(42);
227+
int tooHigh0 = 0;
228+
int tooHigh2 = 0;
229+
for (int k = 0; k < 100; k++) {
230+
int[] counts0 = new int[120];
231+
int[] counts2 = new int[120];
232+
for (int i = 0; i < N; i++) {
233+
Permutation p0 = new Permutation(5);
234+
Permutation p2 = new Permutation(5, r2);
235+
int j0 = p0.toInteger();
236+
int j2 = p2.toInteger();
237+
counts0[j0]++;
238+
counts2[j2]++;
239+
}
240+
if (chiSquare(counts0) > 146.567) tooHigh0++;
241+
if (chiSquare(counts2) > 146.567) tooHigh2++;
242+
}
243+
if (!disableChiSquareTests) {
244+
assertTrue(tooHigh0 <= 10);
245+
}
246+
assertTrue(tooHigh2 <= 10);
247+
}
248+
}

0 commit comments

Comments
 (0)