|
13 | 13 |
|
14 | 14 | import java.util.Arrays;
|
15 | 15 |
|
| 16 | +import static org.hamcrest.CoreMatchers.is; |
16 | 17 | import static org.hamcrest.Matchers.containsString;
|
| 18 | +import static org.hamcrest.Matchers.hasLength; |
17 | 19 | import static org.hamcrest.Matchers.not;
|
18 | 20 | import static org.hamcrest.Matchers.sameInstance;
|
19 | 21 |
|
@@ -73,6 +75,122 @@ public void testGetCloseableCharsAfterSecureStringClosed() {
|
73 | 75 | assertThat(e.getMessage(), containsString("already been closed"));
|
74 | 76 | }
|
75 | 77 |
|
| 78 | + public void testEquals() { |
| 79 | + final String string = randomAlphaOfLengthBetween(8, 128); |
| 80 | + final SecureString secureString = new SecureString(string.toCharArray()); |
| 81 | + final StringBuilder stringBuilder = new StringBuilder(string); |
| 82 | + |
| 83 | + assertThat(secureString.equals(string), is(true)); |
| 84 | + assertThat(secureString.equals(stringBuilder), is(true)); |
| 85 | + |
| 86 | + final int split = randomIntBetween(1, string.length() - 1); |
| 87 | + final String altString = string.substring(0, split) + randomAlphanumericOfLength(1) + string.substring(split); |
| 88 | + assertThat(secureString.equals(altString), is(false)); |
| 89 | + } |
| 90 | + |
| 91 | + public void testStartsWith() { |
| 92 | + final String str = randomAlphanumericOfLength(16); |
| 93 | + final SecureString secStr = new SecureString(str.toCharArray()); |
| 94 | + for (int i = 0; i <= str.length(); i++) { |
| 95 | + final String substr = str.substring(0, i); |
| 96 | + assertThat(secStr.startsWith(substr), is(true)); |
| 97 | + assertThat(secStr.startsWith(new SecureString(substr.toCharArray())), is(true)); |
| 98 | + assertThat(secStr.startsWith(new StringBuilder(substr)), is(true)); |
| 99 | + |
| 100 | + if (i != 0) { |
| 101 | + assertThat(secStr.startsWith(randomValueOtherThan(substr, () -> randomAlphanumericOfLength(substr.length()))), is(false)); |
| 102 | + if (i > 1) { |
| 103 | + final int suffixLength = randomIntBetween(1, i - 1); |
| 104 | + final String altStr = substr.substring(0, i - suffixLength) + randomValueOtherThan( |
| 105 | + substr.substring(i - suffixLength), |
| 106 | + () -> randomAlphanumericOfLength(suffixLength) |
| 107 | + ); |
| 108 | + assertThat(altStr, hasLength(substr.length())); |
| 109 | + assertThat(secStr.startsWith(altStr), is(false)); |
| 110 | + } |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + assertThat(secStr.startsWith(str + randomAlphanumericOfLength(1)), is(false)); |
| 115 | + } |
| 116 | + |
| 117 | + public void testRegionMatches() { |
| 118 | + // Matching text |
| 119 | + assertRegionMatch(true, "abc", 0, "012abc789", 3, 3); |
| 120 | + assertRegionMatch(true, "abc", 0, "abc789", 0, 3); |
| 121 | + assertRegionMatch(true, "abc", 0, "012abc", 3, 3); |
| 122 | + assertRegionMatch(true, "XYabcZ", 2, "012abc789", 3, 3); |
| 123 | + assertRegionMatch(true, "XYabcZ", 2, "abc789", 0, 3); |
| 124 | + assertRegionMatch(true, "XYabcZ", 2, "012abc", 3, 3); |
| 125 | + assertRegionMatch(true, "XYabcZ", 2, "abc", 0, 3); |
| 126 | + |
| 127 | + // Bad region boundaries |
| 128 | + assertRegionMatch(false, "abc", -1, "abc", 0, 3); |
| 129 | + assertRegionMatch(false, "abc", 0, "abc", -1, 3); |
| 130 | + assertRegionMatch(false, "abc", 0, "abc", 0, 4); |
| 131 | + assertRegionMatch(false, "abc", 0, "ab", 0, 3); |
| 132 | + assertRegionMatch(false, "abc", 0, "Xab", 1, 3); |
| 133 | + |
| 134 | + // Mismatched text |
| 135 | + assertRegionMatch(false, "abc", 0, "012", 0, 3); |
| 136 | + assertRegionMatch(false, "012abc", 3, "012", 0, 3); |
| 137 | + assertRegionMatch(false, "abc012", 0, "012", 0, 3); |
| 138 | + assertRegionMatch(false, "012abc789", 3, "012", 0, 3); |
| 139 | + assertRegionMatch(false, "abc", 0, "xyz012", 3, 3); |
| 140 | + assertRegionMatch(false, "012abc", 3, "xyz012", 3, 3); |
| 141 | + assertRegionMatch(false, "abc012", 0, "xyz012", 3, 3); |
| 142 | + assertRegionMatch(false, "012abc789", 3, "xyz012", 3, 3); |
| 143 | + assertRegionMatch(false, "abc", 0, "012xyz", 0, 3); |
| 144 | + assertRegionMatch(false, "012abc", 3, "012xyz", 0, 3); |
| 145 | + assertRegionMatch(false, "abc012", 0, "012xyz", 0, 3); |
| 146 | + assertRegionMatch(false, "012abc789", 3, "012xyz", 0, 3); |
| 147 | + assertRegionMatch(false, "abc", 0, "abc012xyz", 3, 3); |
| 148 | + assertRegionMatch(false, "012abc", 3, "abc012xyz", 3, 3); |
| 149 | + assertRegionMatch(false, "abc012", 0, "abc012xyz", 3, 3); |
| 150 | + assertRegionMatch(false, "012abc789", 3, "abc012xyz", 3, 3); |
| 151 | + |
| 152 | + // Zero length always matches |
| 153 | + assertRegionMatch( |
| 154 | + true, |
| 155 | + randomAlphanumericOfLength(12), |
| 156 | + randomIntBetween(0, 12), |
| 157 | + randomAlphanumericOfLength(8), |
| 158 | + randomIntBetween(0, 8), |
| 159 | + 0 |
| 160 | + ); |
| 161 | + |
| 162 | + // Random chars |
| 163 | + final String shared = randomAlphanumericOfLength(randomIntBetween(4, 64)); |
| 164 | + final String rand1 = randomAlphaOfLengthBetween(0, 256); |
| 165 | + final String rand2 = randomAlphaOfLengthBetween(0, 256); |
| 166 | + assertRegionMatch( |
| 167 | + true, |
| 168 | + rand1 + shared + randomAlphaOfLengthBetween(0, 256), |
| 169 | + rand1.length(), |
| 170 | + rand2 + shared + randomAlphaOfLengthBetween(0, 256), |
| 171 | + rand2.length(), |
| 172 | + shared.length() |
| 173 | + ); |
| 174 | + assertRegionMatch( |
| 175 | + false, |
| 176 | + rand1 + shared + randomAlphaOfLengthBetween(0, 256), |
| 177 | + rand1.length(), |
| 178 | + rand2 + randomValueOtherThan(shared, () -> randomAlphanumericOfLength(shared.length())) + randomAlphaOfLengthBetween(0, 256), |
| 179 | + rand2.length(), |
| 180 | + shared.length() |
| 181 | + ); |
| 182 | + } |
| 183 | + |
| 184 | + private void assertRegionMatch(final boolean expected, String a, int offsetA, String b, int offsetB, int len) { |
| 185 | + // First check that our test strings match using the standard `String` version |
| 186 | + assert a.regionMatches(offsetA, b, offsetB, len) == expected |
| 187 | + : "Bad test case [" + a + "][" + offsetA + "] vs [" + b + "][" + offsetB + "] : " + len + " == " + expected; |
| 188 | + |
| 189 | + // Test a-vs-b and b-vs-a because these operations should be identical |
| 190 | + assertThat(new SecureString(a.toCharArray()).regionMatches(offsetA, b, offsetB, len), is(expected)); |
| 191 | + assertThat(new SecureString(b.toCharArray()).regionMatches(offsetB, a, offsetA, len), is(expected)); |
| 192 | + } |
| 193 | + |
76 | 194 | private void assertSecureStringEqualToChars(char[] expected, SecureString secureString) {
|
77 | 195 | int pos = 0;
|
78 | 196 | for (int i : secureString.chars().toArray()) {
|
|
0 commit comments