1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.text.cts; 18 19 import static android.text.TextUtils.SAFE_STRING_FLAG_FIRST_LINE; 20 import static android.text.TextUtils.SAFE_STRING_FLAG_SINGLE_LINE; 21 import static android.text.TextUtils.SAFE_STRING_FLAG_TRIM; 22 import static android.text.TextUtils.makeSafeForPresentation; 23 24 import static org.junit.Assert.assertEquals; 25 import static org.junit.Assert.assertTrue; 26 27 import org.junit.Test; 28 29 public class MakeSafeForPresentationTest { 30 private static final String LONG_STRING = "Lorem ipsum dolor sit amet, consectetur adipiscing " 31 + "elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim " 32 + "ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea " 33 + "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse " 34 + "cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " 35 + "proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; 36 37 private static final String VERY_LONG_STRING = LONG_STRING + LONG_STRING + LONG_STRING 38 + LONG_STRING + LONG_STRING + LONG_STRING + LONG_STRING + LONG_STRING + LONG_STRING 39 + LONG_STRING + LONG_STRING + LONG_STRING + LONG_STRING + LONG_STRING + LONG_STRING; 40 41 private static final int DEFAULT_MAX_LABEL_SIZE_PX = 500; 42 43 /** 44 * Convert a string into a list of code-points 45 */ 46 private static String strToCodePoints(String in) { 47 StringBuilder out = new StringBuilder(); 48 int offset = 0; 49 while (offset < in.length()) { 50 if (out.length() != 0) { 51 out.append(", "); 52 } 53 int charCount = Character.charCount(in.codePointAt(offset)); 54 out.append(Integer.toHexString(in.codePointAt(offset))).append("=\"") 55 .append(in.substring(offset, offset + charCount)).append("\""); 56 offset += charCount; 57 } 58 59 return out.toString(); 60 } 61 62 /** 63 * Assert that {@code a.equals(b)} and if not throw a nicely formatted error. 64 * 65 * @param a First string to compare 66 * @param b String to compare first string to 67 */ 68 private static void assertStringEquals(String a, CharSequence b) { 69 if (a.equals(b.toString())) { 70 return; 71 } 72 73 throw new AssertionError("[" + strToCodePoints(a) + "] != [" 74 + strToCodePoints(b.toString()) + "]"); 75 } 76 77 /** 78 * Make sure {@code abbreviated} is an abbreviation of {@code full}. 79 * 80 * @param full The non-abbreviated string 81 * @param abbreviated The abbreviated string 82 * @return {@code true} iff the string was abbreviated 83 */ 84 private static boolean isAbbreviation(String full, CharSequence abbreviated) { 85 String abbrStr = abbreviated.toString(); 86 int abbrLength = abbrStr.length(); 87 int offset = 0; 88 89 while (offset < abbrLength) { 90 final int abbrCodePoint = abbrStr.codePointAt(offset); 91 final int fullCodePoint = full.codePointAt(offset); 92 final int codePointLen = Character.charCount(abbrCodePoint); 93 94 if (abbrCodePoint != fullCodePoint) { 95 return (abbrLength == offset + codePointLen) 96 && (/* ellipses */8230 == (abbrStr.codePointAt(offset))); 97 } 98 99 offset += codePointLen; 100 } 101 102 return false; 103 } 104 105 @Test 106 public void removeIllegal() { 107 assertStringEquals("ab", makeSafeForPresentation("ab", 0, 0, 0)); 108 } 109 110 @Test 111 public void convertHTMLCharacters() { 112 assertStringEquals("a&b", makeSafeForPresentation("a&b", 0, 0, 0)); 113 } 114 115 @Test 116 public void convertHTMLGTAndLT() { 117 assertStringEquals("a<br>b", makeSafeForPresentation("a<br>b", 0, 0, 0)); 118 } 119 120 @Test 121 public void removeHTMLFormatting() { 122 assertStringEquals("ab", makeSafeForPresentation("a<b>b</>", 0, 0, 0)); 123 } 124 125 @Test 126 public void replaceImgTags() { 127 assertStringEquals("a\ufffcb", makeSafeForPresentation("a<img src=\"myimg.jpg\" />b", 0, 0, 128 0)); 129 } 130 131 @Test 132 public void replacePTags() { 133 assertStringEquals("a\n\nb\n\n", makeSafeForPresentation("a<p>b", 0, 0, 0)); 134 } 135 136 @Test 137 public void aTagIsIgnored() { 138 assertStringEquals("ab", makeSafeForPresentation("a<a href=\"foo.bar\">b</a>", 0, 0, 0)); 139 } 140 141 @Test 142 public void leadingAndMoreThanOneTrailingSpacesAreAlwaysTrimmed() { 143 assertStringEquals("ab ", makeSafeForPresentation(" ab ", 0, 0, 0)); 144 } 145 146 @Test 147 public void preIsIgnored() { 148 assertStringEquals("a b ", makeSafeForPresentation("<pre> a\n b </pre>", 0, 0, 0)); 149 } 150 151 @Test 152 public void removeSpecialNotHtmlCharacters() { 153 assertStringEquals("ab", makeSafeForPresentation("a\bb", 0, 0, 0)); 154 } 155 156 @Test 157 public void collapseInternalConsecutiveSpaces() { 158 assertStringEquals("a b", makeSafeForPresentation("a b", 0, 0, 0)); 159 } 160 161 @Test 162 public void replaceNonHtmlNewLineWithSpace() { 163 assertStringEquals("a b", makeSafeForPresentation("a\nb", 0, 0, 0)); 164 } 165 166 @Test 167 public void keepNewLines() { 168 assertStringEquals("a\nb", makeSafeForPresentation("a<br/>b", 0, 0, 0)); 169 } 170 171 @Test 172 public void removeNewLines() { 173 assertStringEquals("ab", makeSafeForPresentation("a<br/>b", 0, 0, 174 SAFE_STRING_FLAG_SINGLE_LINE)); 175 } 176 177 @Test 178 public void truncateAtNewLine() { 179 assertStringEquals("a", makeSafeForPresentation("a<br/>b", 0, 0, 180 SAFE_STRING_FLAG_FIRST_LINE)); 181 } 182 183 @Test 184 public void nbspIsTrimmed() { 185 /* 186 * A non breaking white space " " in HTML is not a white space according to 187 * Character.isWhitespace, but for clean string it is treated as shite-space 188 */ 189 assertStringEquals("a b", makeSafeForPresentation(" a b", 0, 0, 190 SAFE_STRING_FLAG_TRIM)); 191 } 192 193 @Test 194 public void trimFront() { 195 assertStringEquals("a b", makeSafeForPresentation("<br/> <br/> a b", 0, 0, 196 SAFE_STRING_FLAG_TRIM)); 197 } 198 199 @Test 200 public void trimAll() { 201 assertStringEquals("", makeSafeForPresentation(" <br/> <br/> ", 0, 0, 202 SAFE_STRING_FLAG_TRIM)); 203 } 204 205 @Test 206 public void trimEnd() { 207 assertStringEquals("a b", makeSafeForPresentation("a b <br/> <br/>", 0, 0, 208 SAFE_STRING_FLAG_TRIM)); 209 } 210 211 @Test 212 public void trimBoth() { 213 assertStringEquals("a b", makeSafeForPresentation("<br/> <br/> a b <br/> <br/>", 0, 0, 214 SAFE_STRING_FLAG_TRIM)); 215 } 216 217 @Test 218 public void ellipsizeShort() { 219 assertTrue(isAbbreviation(VERY_LONG_STRING, makeSafeForPresentation(VERY_LONG_STRING, 0, 220 DEFAULT_MAX_LABEL_SIZE_PX, 0))); 221 } 222 223 @Test 224 public void ellipsizeLong() { 225 assertTrue(isAbbreviation(VERY_LONG_STRING, makeSafeForPresentation(VERY_LONG_STRING, 0, 226 DEFAULT_MAX_LABEL_SIZE_PX * 20, 0))); 227 } 228 229 @Test 230 public void thousandDipLengthIs50Characters() { 231 assertEquals(50, makeSafeForPresentation(VERY_LONG_STRING, 0, 1000, 0).length(), 10); 232 } 233 234 @Test 235 public void ellipsizeShouldBeProportional() { 236 assertEquals(20, (float) makeSafeForPresentation(VERY_LONG_STRING, 0, 237 DEFAULT_MAX_LABEL_SIZE_PX * 20, 0).length() / makeSafeForPresentation( 238 VERY_LONG_STRING, 0, DEFAULT_MAX_LABEL_SIZE_PX, 0).length(), 3); 239 } 240 241 @Test 242 public void ignoreLastCharacters() { 243 assertEquals(42, makeSafeForPresentation(VERY_LONG_STRING, 42, 0, 0).length()); 244 } 245 246 @Test 247 public void ignoreLastCharactersShortStirng() { 248 assertEquals("abc", makeSafeForPresentation("abc", 42, 0, 0)); 249 } 250 251 @Test 252 public void ignoreLastCharactersWithTrim() { 253 assertEquals("abc", makeSafeForPresentation("abc ", 4, 0, SAFE_STRING_FLAG_TRIM)); 254 } 255 256 @Test 257 public void ignoreLastCharactersWithHtml() { 258 assertEquals("a\nbcd", makeSafeForPresentation("a<br />bcdef", 10, 0, 0)); 259 } 260 261 @Test 262 public void ignoreLastCharactersWithTrailingWhitespace() { 263 assertEquals("abc ", makeSafeForPresentation("abc ", 4, 0, 0)); 264 } 265 266 @Test(expected = IllegalArgumentException.class) 267 public void cannotKeepAndTruncateNewLines() { 268 makeSafeForPresentation("", 0, 0, 269 SAFE_STRING_FLAG_SINGLE_LINE | SAFE_STRING_FLAG_FIRST_LINE); 270 } 271 272 @Test(expected = IllegalArgumentException.class) 273 public void invalidFlags() { 274 makeSafeForPresentation("", 0, 0, 0xffff); 275 } 276 277 @Test(expected = IllegalArgumentException.class) 278 public void invalidEllipsizeDip() { 279 makeSafeForPresentation("", 0, -1, 0); 280 } 281 282 @Test(expected = IllegalArgumentException.class) 283 public void invalidMaxCharacters() { 284 makeSafeForPresentation("", -1, 0, 0); 285 } 286 287 @Test(expected = NullPointerException.class) 288 public void nullString() { 289 makeSafeForPresentation(null, 0, 0, 0); 290 } 291 } 292