| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 /** | |
| 6 * Tests for the toString methods on collections (including maps). | |
| 7 */ | |
| 8 | |
| 9 // TODO(jjb): seed random number generator when API allows it | |
| 10 | |
| 11 final int NUM_TESTS = 300; | |
| 12 final int MAX_COLLECTION_SIZE = 7; | |
| 13 | |
| 14 main() { | |
| 15 smokeTest(); | |
| 16 exactTest(); | |
| 17 inexactTest(); | |
| 18 } | |
| 19 | |
| 20 | |
| 21 /** | |
| 22 * Test a few simple examples. | |
| 23 */ | |
| 24 void smokeTest() { | |
| 25 // Non-const lists | |
| 26 Expect.equals([].toString(), '[]'); | |
| 27 Expect.equals([1].toString(), '[1]'); | |
| 28 Expect.equals(['Elvis'].toString(), '[Elvis]'); | |
| 29 Expect.equals([null].toString(), '[null]'); | |
| 30 Expect.equals([1, 2].toString(), '[1, 2]'); | |
| 31 Expect.equals(['I', 'II'].toString(), '[I, II]'); | |
| 32 Expect.equals([[1, 2], [3, 4], [5, 6]].toString(), '[[1, 2], [3, 4], [5, 6]]')
; | |
| 33 | |
| 34 // Const lists | |
| 35 Expect.equals((const[]).toString(), '[]'); | |
| 36 Expect.equals((const[1]).toString(), '[1]'); | |
| 37 Expect.equals((const['Elvis']).toString(), '[Elvis]'); | |
| 38 Expect.equals((const[null]).toString(), '[null]'); | |
| 39 Expect.equals((const[1, 2]).toString(), '[1, 2]'); | |
| 40 Expect.equals((const['I', 'II']).toString(), '[I, II]'); | |
| 41 Expect.equals((const[const[1, 2], const[3, 4], const[5, 6]]).toString(), | |
| 42 '[[1, 2], [3, 4], [5, 6]]'); | |
| 43 | |
| 44 // Non-const maps - Note that all keys are strings; the spec currently demands
this | |
| 45 Expect.equals({}.toString(), '{}'); | |
| 46 Expect.equals({'Elvis': 'King'}.toString(), '{Elvis: King}'); | |
| 47 Expect.equals({'Elvis': null}.toString(), '{Elvis: null}'); | |
| 48 Expect.equals({'I': 1, 'II': 2}.toString(), '{I: 1, II: 2}'); | |
| 49 Expect.equals({'X':{'I':1, 'II':2}, 'Y':{'III':3, 'IV':4}, 'Z':{'V':5, 'VI':6}
}.toString(), | |
| 50 '{X: {I: 1, II: 2}, Y: {III: 3, IV: 4}, Z: {V: 5, VI: 6}}'); | |
| 51 | |
| 52 // Const maps | |
| 53 Expect.equals(const{}.toString(), '{}'); | |
| 54 Expect.equals(const{'Elvis': 'King'}.toString(), '{Elvis: King}'); | |
| 55 Expect.equals({'Elvis': null}.toString(), '{Elvis: null}'); | |
| 56 Expect.equals(const{'I': 1, 'II': 2}.toString(), '{I: 1, II: 2}'); | |
| 57 Expect.equals(const{'X': const{'I': 1, 'II': 2}, 'Y': const{'III': 3, 'IV': 4}
, | |
| 58 'Z': const{'V': 5, 'VI': 6}}.toString(), | |
| 59 '{X: {I: 1, II: 2}, Y: {III: 3, IV: 4}, Z: {V: 5, VI: 6}}'); | |
| 60 } | |
| 61 | |
| 62 // SERIOUS "BASHER" TESTS | |
| 63 | |
| 64 /** | |
| 65 * Generate a bunch of random collections (including Maps), and test that | |
| 66 * there string form is as expected. The collections include collections | |
| 67 * as elements, keys, and values, and include recursive references. | |
| 68 * | |
| 69 * This test restricts itself to collections with well-defined iteration | |
| 70 * orders (i.e., no HashSet, HashMap). | |
| 71 */ | |
| 72 void exactTest() { | |
| 73 for (int i = 0; i < NUM_TESTS; i++) { | |
| 74 // Choose a size from 0 to MAX_COLLECTION_SIZE, favoring larger sizes | |
| 75 int size = Math.sqrt(random(MAX_COLLECTION_SIZE * MAX_COLLECTION_SIZE)).toIn
t(); | |
| 76 | |
| 77 StringBuffer stringRep = new StringBuffer(); | |
| 78 Object o = randomCollection(size, stringRep, exact:true); | |
| 79 Expect.equals(o.toString(), stringRep.toString()); | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 /** | |
| 84 * Generate a bunch of random collections (including Maps), and test that | |
| 85 * there string form is as expected. The collections include collections | |
| 86 * as elements, keys, and values, and include recursive references. | |
| 87 * | |
| 88 * This test includes collections with ill-defined iteration orders (i.e., | |
| 89 * HashSet, HashMap). As a consequence, it can't use equality tests on the | |
| 90 * string form. Instead, it performs equality tests on their "alphagrams." | |
| 91 * This might allow false positives, but it does give a fair amount of | |
| 92 * confidence. | |
| 93 */ | |
| 94 void inexactTest() { | |
| 95 for (int i = 0; i < NUM_TESTS; i++) { | |
| 96 // Choose a size from 0 to MAX_COLLECTION_SIZE, favoring larger sizes | |
| 97 int size = Math.sqrt(random(MAX_COLLECTION_SIZE * MAX_COLLECTION_SIZE)).toIn
t(); | |
| 98 | |
| 99 StringBuffer stringRep = new StringBuffer(); | |
| 100 Object o = randomCollection(size, stringRep, exact:false); | |
| 101 Expect.equals(alphagram(o.toString()), alphagram(stringRep.toString())); | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 /** | |
| 106 * Return a random collection (or Map) of the specified size, placing its | |
| 107 * string representation into the given string buffer. | |
| 108 * | |
| 109 * If exact is true, the returned collections will not be, and will not contain | |
| 110 * a collection with ill-defined iteration order (i.e., a HashSet or HashMap). | |
| 111 */ | |
| 112 Object randomCollection(int size, StringBuffer stringRep, [bool exact]) { | |
| 113 return randomCollectionHelper(size, exact, stringRep, []); | |
| 114 } | |
| 115 | |
| 116 /** | |
| 117 * Return a random collection (or map) of the specified size, placing its | |
| 118 * string representation into the given string buffer. The beingMade | |
| 119 * parameter is a list of collections currently under construction, i.e., | |
| 120 * candidates for recursive references. | |
| 121 * | |
| 122 * If exact is true, the returned collections will not be, and will not contain | |
| 123 * a collection with ill-defined iteration order (i.e., a HashSet or HashMap). | |
| 124 */ | |
| 125 Object randomCollectionHelper(int size, bool exact, StringBuffer stringRep, | |
| 126 List beingMade) { | |
| 127 double interfaceFrac = Math.random(); | |
| 128 | |
| 129 if (exact) { | |
| 130 if (interfaceFrac < 1/3) { | |
| 131 return randomList(size, exact, stringRep, beingMade); | |
| 132 } else if (interfaceFrac < 2/3) { | |
| 133 return randomQueue(size, exact, stringRep, beingMade); | |
| 134 } else { | |
| 135 return randomMap(size, exact, stringRep, beingMade); | |
| 136 } | |
| 137 } else { | |
| 138 if (interfaceFrac < 1/4) { | |
| 139 return randomList(size, exact, stringRep, beingMade); | |
| 140 } else if (interfaceFrac < 2/4) { | |
| 141 return randomQueue(size, exact, stringRep, beingMade); | |
| 142 } else if (interfaceFrac < 3/4) { | |
| 143 return randomSet(size, exact, stringRep, beingMade); | |
| 144 } else { | |
| 145 return randomMap(size, exact, stringRep, beingMade); | |
| 146 } | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 /** | |
| 151 * Return a random List of the specified size, placing its string | |
| 152 * representation into the given string buffer. The beingMade | |
| 153 * parameter is a list of collections currently under construction, i.e., | |
| 154 * candidates for recursive references. | |
| 155 * | |
| 156 * If exact is true, the returned collections will not be, and will not contain | |
| 157 * a collection with ill-defined iteration order (i.e., a HashSet or HashMap). | |
| 158 */ | |
| 159 List randomList(int size, bool exact, StringBuffer stringRep, List beingMade) { | |
| 160 return populateRandomCollection(size, exact, stringRep, beingMade, []); | |
| 161 } | |
| 162 | |
| 163 /** | |
| 164 * Like randomList, but returns a queue. | |
| 165 */ | |
| 166 Queue randomQueue(int size, bool exact, StringBuffer stringRep, List beingMade){ | |
| 167 return populateRandomCollection(size, exact, stringRep, beingMade, new Queue()
); | |
| 168 } | |
| 169 | |
| 170 /** | |
| 171 * Like randomList, but returns a Set. | |
| 172 */ | |
| 173 Set randomSet(int size, bool exact, StringBuffer stringRep, List beingMade) { | |
| 174 // Until we have LinkedHashSet, method will only be called with exact==true | |
| 175 return populateRandomSet(size, exact, stringRep, beingMade, new Set()); | |
| 176 } | |
| 177 | |
| 178 /** | |
| 179 * Like randomList, but returns a map. | |
| 180 */ | |
| 181 Map randomMap(int size, bool exact, StringBuffer stringRep, List beingMade) { | |
| 182 if (exact) { | |
| 183 return populateRandomMap(size, exact, stringRep, beingMade, | |
| 184 new LinkedHashMap()); | |
| 185 } else { | |
| 186 return populateRandomMap(size, exact, stringRep, beingMade, | |
| 187 randomBool() ? new Map() : new LinkedHashMap()); | |
| 188 } | |
| 189 } | |
| 190 | |
| 191 /** | |
| 192 * Populates the given empty collection with elements, emitting the string | |
| 193 * representation of the collection to stringRep. The beingMade parameter is | |
| 194 * a list of collections currently under construction, i.e., candidates for | |
| 195 * recursive references. | |
| 196 * | |
| 197 * If exact is true, the elements of the returned collections will not be, | |
| 198 * and will not contain a collection with ill-defined iteration order | |
| 199 * (i.e., a HashSet or HashMap). | |
| 200 */ | |
| 201 Collection populateRandomCollection(int size, bool exact, | |
| 202 StringBuffer stringRep, List beingMade, Collection coll) { | |
| 203 beingMade.add(coll); | |
| 204 stringRep.add(coll is List ? '[' : '{'); | |
| 205 | |
| 206 for (int i = 0; i < size; i++) { | |
| 207 if (i != 0) stringRep.add(', '); | |
| 208 coll.add(randomElement(random(size), exact, stringRep, beingMade)); | |
| 209 } | |
| 210 | |
| 211 stringRep.add(coll is List ? ']' : '}'); | |
| 212 beingMade.removeLast(); | |
| 213 return coll; | |
| 214 } | |
| 215 | |
| 216 /** Like populateRandomCollection, but for sets (elements must be hashable) */ | |
| 217 Set populateRandomSet(int size, bool exact, StringBuffer stringRep, | |
| 218 List beingMade, Set set) { | |
| 219 stringRep.add('{'); | |
| 220 | |
| 221 for (int i = 0; i < size; i++) { | |
| 222 if (i != 0) stringRep.add(', '); | |
| 223 set.add(i); | |
| 224 stringRep.add(i); | |
| 225 } | |
| 226 | |
| 227 stringRep.add('}'); | |
| 228 return set; | |
| 229 } | |
| 230 | |
| 231 | |
| 232 /** Like populateRandomCollection, but for maps. */ | |
| 233 Map populateRandomMap(int size, bool exact, StringBuffer stringRep, | |
| 234 List beingMade, Map map) { | |
| 235 beingMade.add(map); | |
| 236 stringRep.add('{'); | |
| 237 | |
| 238 for (int i = 0; i < size; i++) { | |
| 239 if (i != 0) stringRep.add(', '); | |
| 240 | |
| 241 int key = i; // Ensures no duplicates | |
| 242 stringRep.add(key); | |
| 243 stringRep.add(': '); | |
| 244 Object val = randomElement(random(size), exact, stringRep, beingMade); | |
| 245 map[key] = val; | |
| 246 } | |
| 247 | |
| 248 stringRep.add('}'); | |
| 249 beingMade.removeLast(); | |
| 250 return map; | |
| 251 } | |
| 252 | |
| 253 /** | |
| 254 * Generates a random element which can be an int, a collection, or a map, | |
| 255 * and emits it to StringRep. The beingMade parameter is a list of collections | |
| 256 * currently under construction, i.e., candidates for recursive references. | |
| 257 * | |
| 258 * If exact is true, the returned element will not be, and will not contain | |
| 259 * a collection with ill-defined iteration order (i.e., a HashSet or HashMap). | |
| 260 */ | |
| 261 Object randomElement(int size, bool exact, StringBuffer stringRep, | |
| 262 List beingMade) { | |
| 263 Object result; | |
| 264 double elementTypeFrac = Math.random(); | |
| 265 if (elementTypeFrac < 1/3) { | |
| 266 result = random(1000); | |
| 267 stringRep.add(result); | |
| 268 } else if (elementTypeFrac < 2/3) { | |
| 269 // Element Is a random (new) collection | |
| 270 result = randomCollectionHelper(size, exact, stringRep, beingMade); | |
| 271 } else { | |
| 272 // Element Is a random recursive ref | |
| 273 result = beingMade[random(beingMade.length)]; | |
| 274 if (result is List) | |
| 275 stringRep.add('[...]'); | |
| 276 else | |
| 277 stringRep.add('{...}'); | |
| 278 } | |
| 279 return result; | |
| 280 } | |
| 281 | |
| 282 /** Returns a random int on [0, max) */ | |
| 283 int random(int max) { | |
| 284 return (Math.random() * max).toInt(); | |
| 285 } | |
| 286 | |
| 287 /** Returns a random boolean value. */ | |
| 288 bool randomBool() { | |
| 289 return Math.random() < .5; | |
| 290 } | |
| 291 | |
| 292 /** Returns the alphabetized characters in a string. */ | |
| 293 String alphagram(String s) { | |
| 294 List<int> chars = s.charCodes(); | |
| 295 chars.sort((int a, int b) => a - b); | |
| 296 return new String.fromCharCodes(chars); | |
| 297 } | |
| OLD | NEW |