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