| 1 | package biz.xsoftware.mock.client; |
| 2 | |
| 3 | import java.util.ArrayList; |
| 4 | import java.util.HashMap; |
| 5 | import java.util.HashSet; |
| 6 | import java.util.List; |
| 7 | import java.util.Map; |
| 8 | import java.util.Set; |
| 9 | |
| 10 | |
| 11 | /** |
| 12 | * This is a super class for mock Objects. It has the following options |
| 13 | * <ol> |
| 14 | * <li>Guarantee order of events and that events happen on one object</li> |
| 15 | * <li>Guarantee events called with order not mattering on one object</li> |
| 16 | * <li>Guarantee order of events is correct between two objects(One mock obj. implements two interfaces)</li> |
| 17 | * </ol> |
| 18 | * This class will also return the parameters that were passed into the MockObject |
| 19 | * so they can be introspected in testing to make sure they were correct. |
| 20 | * |
| 21 | * The MockObject extending this class can also be told to throw exceptions on certain |
| 22 | * methods so we can test error leg behavior. |
| 23 | * |
| 24 | * Example of how to use |
| 25 | * MockActionListener implements ActionListener and extends this class |
| 26 | * The only method in MockActionListener |
| 27 | * is |
| 28 | * <PRE> |
| 29 | * public final static ACTION_METHOD = "actionPerformed method"; |
| 30 | * public void actionPerformed(ActionEvent evt) { |
| 31 | * super.methodCalled(ACTION_METHOD, evt); |
| 32 | * } |
| 33 | * </PRE> |
| 34 | * |
| 35 | * In the test, when you expect an ActionEvent, you can call |
| 36 | * <PRE> |
| 37 | * Object o = MockActionListener.expectEvent(ACTION_METHOD); |
| 38 | * ActionEvent evt = (ActionEvent)evt; |
| 39 | * assertNonNull(evt.getSource()); |
| 40 | * </PRE> |
| 41 | * |
| 42 | * Another useful behavior is throwing any type of exception using |
| 43 | * setExceptionOnMethod(String method, Throwable e). This can test |
| 44 | * robustness in a system to make sure listeners or services that |
| 45 | * throw exceptions don't affect your system, or at least affect |
| 46 | * your system in the proper way. |
| 47 | * |
| 48 | * @author Dean Hiller (dean@xsoftware.biz) |
| 49 | */ |
| 50 | public abstract class JsMockSuperclass implements JsMockObject { |
| 51 | |
| 52 | /** |
| 53 | * List of the current methods that have been called. |
| 54 | */ |
| 55 | private List methodsCalled = new ArrayList(); |
| 56 | |
| 57 | /** |
| 58 | * A map of queues, containing either |
| 59 | * 1. objects to return when methods are called |
| 60 | * 2. Behaviors to run which return objects to return |
| 61 | * 3. Exceptions to throw |
| 62 | */ |
| 63 | private Map methodToReturnVal = new HashMap(); |
| 64 | /** |
| 65 | * A map of default return values, which are used to return if the |
| 66 | * queue for the method is empty. |
| 67 | */ |
| 68 | private Map methodToDefaultRetVal = new HashMap(); |
| 69 | |
| 70 | private List ignoredMethods = new ArrayList(); |
| 71 | |
| 72 | /** |
| 73 | * Default wait time to wait for a method to be called once expectCall is |
| 74 | * called. |
| 75 | */ |
| 76 | public static final int DEFAULT_WAIT_TIME = 10000; |
| 77 | private int waitTime = DEFAULT_WAIT_TIME; |
| 78 | |
| 79 | private String id; |
| 80 | |
| 81 | /** |
| 82 | * Default constructor of superclass of all mockObjects with a delay of |
| 83 | * 10 seconds. This delay is the amount of time the mock object waits for |
| 84 | * a method to be called when a client calls expectCall. |
| 85 | */ |
| 86 | public JsMockSuperclass() { |
| 87 | } |
| 88 | /** |
| 89 | * The constructor to use to override the default delay({@link #DEFAULT_WAIT_TIME}) |
| 90 | * such that the mock object will give methods a longer time to be called |
| 91 | * before timing out to fail the test. |
| 92 | * |
| 93 | * @param delay The amount of time in milliseconds to wait for a method to be |
| 94 | * called. |
| 95 | */ |
| 96 | public JsMockSuperclass(int delay) { |
| 97 | waitTime = delay; |
| 98 | } |
| 99 | |
| 100 | public JsMockSuperclass(String id) { |
| 101 | this.id = id; |
| 102 | } |
| 103 | |
| 104 | public void setExpectTimeout(int delay) { |
| 105 | this.waitTime = delay; |
| 106 | } |
| 107 | public int getExpectTimeout() { |
| 108 | return waitTime; |
| 109 | } |
| 110 | |
| 111 | public void addIgnore(String method) |
| 112 | { |
| 113 | ignoreImpl(new String[] {method}); |
| 114 | } |
| 115 | |
| 116 | public void removeIgnore(String method) |
| 117 | { |
| 118 | removeIgnoreImpl(new String[] {method}); |
| 119 | } |
| 120 | |
| 121 | private void removeIgnoreImpl(String[] methods) |
| 122 | { |
| 123 | for(int i = 0; i < methods.length; i++) |
| 124 | { |
| 125 | String method = methods[i]; |
| 126 | ignoredMethods.remove(method); |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | private void ignoreImpl(String[] methods) |
| 131 | { |
| 132 | addIgnoredMethods(methods); |
| 133 | } |
| 134 | |
| 135 | private void addIgnoredMethods(String[] methods) { |
| 136 | if(methods == null) |
| 137 | return; |
| 138 | verifyMethodsExist(methods); |
| 139 | |
| 140 | for(int i = 0; i < methods.length; i++) |
| 141 | { |
| 142 | String method = methods[i]; |
| 143 | ignoredMethods.add(method); |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | /** |
| 148 | * Subclasses should call this method when a method on their interface |
| 149 | * is called. This method is for users to create subclasses and call so |
| 150 | * they don't have to wrap it in a try-catch block. |
| 151 | * |
| 152 | * @param method |
| 153 | * @param parameters |
| 154 | * @return whatever the client has specified using addReturnValue |
| 155 | */ |
| 156 | protected Object methodCalled(String method, Object p) { |
| 157 | try { |
| 158 | Object parameters = p; |
| 159 | if(!(parameters instanceof Object[])) { |
| 160 | parameters = new Object[] {parameters}; |
| 161 | } |
| 162 | return methodCalledImpl(method, (Object[])parameters); |
| 163 | } catch (Throwable e) { |
| 164 | if(e instanceof RuntimeException) |
| 165 | throw (RuntimeException)e; |
| 166 | throw new RuntimeException("Sorry, must wrap exception, unwrap in " + |
| 167 | "your mockobject, or have mockObject call methodCalledImpl instead", e); |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | protected synchronized Object methodCalledImpl(String method, Object[] parameters) throws Throwable { |
| 172 | //Since no notify and wait can be used in GWT mocklib, intern is not needed and can be commented out. |
| 173 | // method = method.intern(); |
| 174 | String params = ""; |
| 175 | if(parameters == null) { |
| 176 | params = "no params"; |
| 177 | } else { |
| 178 | Object[] array = parameters; |
| 179 | for(int i = 0; i < array.length-1; i++) { |
| 180 | params += array[i]+", "; |
| 181 | } |
| 182 | params += array[array.length-1]; |
| 183 | } |
| 184 | |
| 185 | System.out.println(id+"method called="+method+"("+params+") on obj="+this); |
| 186 | |
| 187 | //sometimes, the contract is for the "code" to give a parameter |
| 188 | //to a library and then modify the parameter after the library |
| 189 | //is done with it. This means the object the "code" gave to |
| 190 | //the MockObject will change out from under the MockObject and be |
| 191 | //corrupted meaning you can't write a test to test the contract |
| 192 | //without cloning the object so it can't be changed. |
| 193 | Object[] newParams = clone(method, parameters); |
| 194 | methodsCalled.add(new JsCalledMethod(method, newParams, new Throwable().fillInStackTrace())); |
| 195 | |
| 196 | // this.notifyAll(); |
| 197 | |
| 198 | return findNextAction(method, parameters); |
| 199 | } |
| 200 | |
| 201 | private Object findNextAction(String method, Object[] params) throws Throwable { |
| 202 | List l = (List)methodToReturnVal.get(method); |
| 203 | if(l == null) |
| 204 | { |
| 205 | return methodToDefaultRetVal.get(method); |
| 206 | } |
| 207 | |
| 208 | Object retVal = l.remove(0); |
| 209 | if(l.size()<=0) |
| 210 | methodToReturnVal.remove(method); |
| 211 | else if(retVal == null) |
| 212 | methodToDefaultRetVal.get(method); |
| 213 | |
| 214 | if(retVal instanceof JsBehavior) { |
| 215 | return ((JsBehavior)retVal).runMethod(params); |
| 216 | } else if(retVal instanceof Throwable) { |
| 217 | Throwable t = (Throwable)retVal; |
| 218 | t.fillInStackTrace(); |
| 219 | throw t; |
| 220 | } else |
| 221 | return retVal; |
| 222 | } |
| 223 | |
| 224 | // /** |
| 225 | // * @see biz.xsoftware.mock.JsMockObject#expectUnorderedCalls(java.lang.String[]) |
| 226 | // */ |
| 227 | // public synchronized JsCalledMethod[] expectUnorderedCalls(String[] methods) { |
| 228 | // if(methods == null) |
| 229 | // throw new IllegalArgumentException("methods cannot be null"); |
| 230 | // else if(methods.length <= 0) |
| 231 | // throw new IllegalArgumentException("methods.length must be >= 1"); |
| 232 | // for(int i = 0; i < methods.length; i++) { |
| 233 | // if(methods[i] == null) |
| 234 | // throw new IllegalArgumentException("None of values in methods " + |
| 235 | // "can be null, yet methods["+i+"] was null"); |
| 236 | // } |
| 237 | // |
| 238 | // Map expectedMethods = new HashMap(); |
| 239 | // for(int i = 0; i < methods.length; i++) { |
| 240 | // expectedMethods.put(methods[i], new Integer(i)); |
| 241 | // } |
| 242 | // |
| 243 | // Set ignorables = createIgnorableMap(ignoredMethods); |
| 244 | // JsCalledMethod[] retVal = new JsCalledMethod[methods.length]; |
| 245 | // |
| 246 | // List methodsCalledList = new ArrayList(); |
| 247 | // for(int i = 0; i < methods.length; i++) { |
| 248 | // if(ANY.equals(methods[i])) |
| 249 | // throw new IllegalArgumentException("The parameter 'methods' in " + |
| 250 | // "expectUnorderedCalls cannot contain MockSuperclass.ANY(use expectOrderedCalls instead)"); |
| 251 | // |
| 252 | // JsCalledMethod o = expectUnignoredCall(ANY, ignorables, methodsCalledList); |
| 253 | // if(o == null) { |
| 254 | // String reason = putTogetherReason(methods, ignorables, methodsCalledList, |
| 255 | // "timed out on next expected method\n"); |
| 256 | // throw new JsExpectFailedException("Timed out waiting for a method call\n" |
| 257 | // +reason, retVal, JsExpectFailedException.TIMED_OUT); |
| 258 | // } |
| 259 | // Integer index = (Integer)expectedMethods.remove(o.getMethodName()); |
| 260 | // if(index == null) { |
| 261 | // String reason = putTogetherReason(methods, ignorables, methodsCalledList, null); |
| 262 | // throw new JsExpectFailedException(reason, retVal, JsExpectFailedException.UNEXPECTED_CALL_BEFORE); |
| 263 | // } |
| 264 | // |
| 265 | // retVal[index.intValue()] = o; |
| 266 | // } |
| 267 | // |
| 268 | // LeftOverMethods leftOver = getLeftOverMethods(ignorables); |
| 269 | // if(leftOver != null) { |
| 270 | // String reason = putTogetherReason(methods, ignorables, methodsCalledList, "extra method(s)="+leftOver+"\n"); |
| 271 | // throw new JsExpectFailedException("There was a method called after your expected methods.\n"+reason, retVal |
| 272 | // , JsExpectFailedException.UNEXPECTED_CALL_AFTER); |
| 273 | // } |
| 274 | // |
| 275 | // return retVal; |
| 276 | // } |
| 277 | |
| 278 | private String getHowMethodWasCalled(JsCalledMethod method) { |
| 279 | // Throwable t = method.getHowItWasCalled(); |
| 280 | String retVal = "\nThe last method was="+method.getMethodName(); |
| 281 | retVal += "\nHere is a stack trace showing "; |
| 282 | retVal += "you how it was called...\n"; |
| 283 | retVal += "--------BEGIN="+method.getMethodName()+"---------------\n"; |
| 284 | retVal += "THIS DOES NOT WORK IN GWT(so it is commented out)\n"; |
| 285 | // StringWriter s = new StringWriter(); |
| 286 | // PrintWriter p = new PrintWriter(s); |
| 287 | // t.printStackTrace(p); |
| 288 | // retVal += s.toString(); |
| 289 | retVal += "--------END="+method.getMethodName() +"---------------\n"; |
| 290 | return retVal; |
| 291 | } |
| 292 | |
| 293 | private JsCalledMethod[] cleanup(JsCalledMethod[] methods, int size) { |
| 294 | JsCalledMethod[] retVal = new JsCalledMethod[size]; |
| 295 | for(int i = 0; i < retVal.length; i++) { |
| 296 | retVal[i] = methods[i]; |
| 297 | } |
| 298 | return retVal; |
| 299 | } |
| 300 | |
| 301 | /** |
| 302 | * @see biz.xsoftware.mock.JsMockObject#expect(java.lang.String) |
| 303 | */ |
| 304 | public JsCalledMethod expect(String method) { |
| 305 | return expectImpl(new String[] {method})[0]; |
| 306 | } |
| 307 | |
| 308 | /** |
| 309 | * @see biz.xsoftware.mock.JsMockObject#expect(java.lang.String[]) |
| 310 | */ |
| 311 | public synchronized JsCalledMethod[] expect(String[] methods) |
| 312 | { |
| 313 | return expectImpl(methods); |
| 314 | } |
| 315 | |
| 316 | private synchronized JsCalledMethod[] expectImpl(String[] methods) |
| 317 | { |
| 318 | return expectOrderedCalls(methods); |
| 319 | } |
| 320 | |
| 321 | /** |
| 322 | * @see biz.xsoftware.mock.JsMockObject#expectOrderedCalls(java.lang.String[]) |
| 323 | */ |
| 324 | private synchronized JsCalledMethod[] expectOrderedCalls(String[] methods) { |
| 325 | if(methods == null) |
| 326 | throw new IllegalArgumentException("methods cannot be null"); |
| 327 | else if(methods.length <= 0) |
| 328 | throw new IllegalArgumentException("methods.length must be >= 1"); |
| 329 | for(int i = 0; i < methods.length; i++) { |
| 330 | if(methods[i] == null) |
| 331 | throw new IllegalArgumentException("None of values in methods can be null, yet methods["+i+"] was null"); |
| 332 | } |
| 333 | |
| 334 | verifyMethodsExist(methods); |
| 335 | |
| 336 | Set ignorables = createIgnorableMap(ignoredMethods); |
| 337 | |
| 338 | List methodsCalledList = new ArrayList(); |
| 339 | JsCalledMethod[] retVal = new JsCalledMethod[methods.length]; |
| 340 | int i = 0; |
| 341 | for(; i < methods.length; i++) { |
| 342 | String method = methods[i]; |
| 343 | |
| 344 | JsCalledMethod o = null; |
| 345 | try { |
| 346 | o = expectUnignoredCall(method, ignorables, methodsCalledList); |
| 347 | } catch(JsExpectFailedException e) { |
| 348 | if(!JsExpectFailedException.UNEXPECTED_ON_NONE.equals(e.getReason())) { |
| 349 | throw e; |
| 350 | } |
| 351 | Object[] leftOver = e.getCalledMethods(); |
| 352 | throw new JsExpectFailedException(e.getMessage(), leftOver, e.getReason()); |
| 353 | } |
| 354 | if(o == null) { |
| 355 | String reason = putTogetherReason(methods, ignorables, methodsCalledList, |
| 356 | "timed out on next expected method\n"); |
| 357 | throw new JsExpectFailedException("Timed out waiting for call=" |
| 358 | +method+"\n"+reason, cleanup(retVal, i), JsExpectFailedException.TIMED_OUT); |
| 359 | } |
| 360 | retVal[i] = o; |
| 361 | if(!method.equals(o.getMethodName()) && !ANY.equals(method)) { |
| 362 | String reason = putTogetherReason(methods, ignorables, methodsCalledList, null); |
| 363 | reason += getHowMethodWasCalled(o); |
| 364 | throw new JsExpectFailedException(reason, cleanup(retVal, i), null); |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | LeftOverMethods leftOver = getLeftOverMethods(ignorables); |
| 369 | if(leftOver != null) { |
| 370 | String reason = putTogetherReason(methods, ignorables, methodsCalledList, "extra method(s)="+leftOver+"\n"); |
| 371 | reason += getHowMethodWasCalled(leftOver.getMethod(0)); |
| 372 | JsCalledMethod[] calledOnes = new JsCalledMethod[retVal.length+1]; |
| 373 | //System.arraycopy(retVal, 0, calledOnes, 0, retVal.length); |
| 374 | arraycopy(retVal, calledOnes); |
| 375 | calledOnes[retVal.length] = leftOver.getMethod(0); |
| 376 | throw new JsExpectFailedException("There was a method called after your expected methods.\n"+reason, calledOnes |
| 377 | , JsExpectFailedException.UNEXPECTED_CALL_AFTER); |
| 378 | } |
| 379 | return retVal; |
| 380 | } |
| 381 | private void arraycopy(JsCalledMethod[] retVal, JsCalledMethod[] calledOnes) { |
| 382 | for(int i = 0; i < retVal.length; i++) { |
| 383 | calledOnes[i] = retVal[i]; |
| 384 | } |
| 385 | } |
| 386 | private void verifyMethodsExist(String[] methods) { |
| 387 | for(int i = 0; i < methods.length; i++) { |
| 388 | verifyMethod(methods[i]); |
| 389 | } |
| 390 | } |
| 391 | private void verifyMethod(String method) { |
| 392 | //verifyMethod can't be done in GWT |
| 393 | return; |
| 394 | // if(MockObject.ANY.equals(method) || MockObject.NONE.equals(method)) |
| 395 | // return; |
| 396 | // Class[] classes = getClasses(); |
| 397 | // if(classes == null) |
| 398 | // return; |
| 399 | // |
| 400 | // String classNames = ""; |
| 401 | // for(int i = 0; i < classes.length; i++) { |
| 402 | // //FINEST LOG..... |
| 403 | // //System.out.println("class="+classes[i].getName()); |
| 404 | // if(methodExistInThisClass(method, classes[i])) |
| 405 | // return; |
| 406 | // classNames += "\n"+classes[i]; |
| 407 | // } |
| 408 | // |
| 409 | // throw new IllegalArgumentException("method='"+method+"' is not a method on any of the" + |
| 410 | // "\nfollowing Classes/Interfaces"+classNames); |
| 411 | } |
| 412 | |
| 413 | // private boolean methodExistInThisClass(String method, Class c) { |
| 414 | // return true; |
| 415 | // //This does not work in GWT testing..... |
| 416 | // Method[] methods = c.getMethods(); |
| 417 | // for(int i = 0; i < methods.length; i++) { |
| 418 | // if(log.isLoggable(Level.FINEST)) |
| 419 | // log.finest("method in class='"+methods[i].getName()+"' expected='"+method+"'"); |
| 420 | // if(method.equals(methods[i].getName())) |
| 421 | // return true; |
| 422 | // } |
| 423 | // return false; |
| 424 | // } |
| 425 | |
| 426 | private String putTogetherReason(String[] methods, Set ignorables, List methodsCalled, String lastLine) { |
| 427 | String reason = "\nMethods you expected...\n"; |
| 428 | for(int i = 0; i < methods.length; i++) { |
| 429 | reason += "method["+i+"]="+methods[i]+"\n"; |
| 430 | } |
| 431 | reason += "Methods you ignored...\n"; |
| 432 | //String[] ignored = (String[])ignorables.toArray(new String[0]); |
| 433 | Object[] ignored = ignorables.toArray(); |
| 434 | if(ignored.length <= 0) |
| 435 | reason += "no ignored methods\n"; |
| 436 | for(int i = 0; i < ignored.length; i++) { |
| 437 | reason += "ignored["+i+"]="+ignored[i]+"\n"; |
| 438 | } |
| 439 | reason += "\nMethods that were called...\n"; |
| 440 | for(int i = 0; i < methodsCalled.size(); i++) { |
| 441 | if(ignorables.contains(methodsCalled.get(i))) |
| 442 | reason += "method["+i+"](ignored)="; |
| 443 | else |
| 444 | reason += "method["+i+"]="; |
| 445 | reason += methodsCalled.get(i)+"\n"; |
| 446 | } |
| 447 | if(lastLine == null) |
| 448 | reason += "(possibly more but we quit after finding unexpected methods)\n"; |
| 449 | else |
| 450 | reason += lastLine+"\n"; |
| 451 | |
| 452 | |
| 453 | return reason; |
| 454 | } |
| 455 | |
| 456 | protected synchronized JsCalledMethod expectUnignoredCall(String m, Set ignorables, List calledMethods) { |
| 457 | |
| 458 | String method = m; |
| 459 | if(method == null) |
| 460 | method = NONE; |
| 461 | |
| 462 | //kind of dangerous if used with multiple threads because we might miss |
| 463 | //a bad event coming in, but if you keep using the same listener for every test |
| 464 | //the problem should still manifest itself in a |
| 465 | //different test case which sucks but works. |
| 466 | if(method.equals(NONE)) { |
| 467 | System.out.println("method expected="+NONE+" on obj="+this); |
| 468 | |
| 469 | // we have to strip out all of the ignored methods from methodsCalled |
| 470 | //CalledMethod[] methods = (CalledMethod[])methodsCalled.toArray(new CalledMethod[0]); |
| 471 | Object[] methods = methodsCalled.toArray(); |
| 472 | for(int i = 0; i < methods.length; i++) |
| 473 | { |
| 474 | JsCalledMethod calledMethod = (JsCalledMethod)methods[i]; |
| 475 | if(ignorables.contains(calledMethod.getMethodName())) |
| 476 | { |
| 477 | while(methodsCalled.contains(calledMethod)) |
| 478 | { |
| 479 | methodsCalled.remove(calledMethod); |
| 480 | } |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | LeftOverMethods leftOver = getLeftOverMethods(ignorables); |
| 485 | if(leftOver != null) { |
| 486 | String reason = "You were expecting no methods to be called, but method(s) not\n" |
| 487 | +"in the ignore list were called earlier. method(s)="+leftOver; |
| 488 | reason += getHowMethodWasCalled(leftOver.getMethod(0)); |
| 489 | throw new JsExpectFailedException(reason, leftOver.getMethods(), JsExpectFailedException.UNEXPECTED_ON_NONE); |
| 490 | } |
| 491 | return new JsCalledMethod(NONE, null, null); |
| 492 | } |
| 493 | |
| 494 | return waitForUnignoredCall(method, ignorables, calledMethods); |
| 495 | } |
| 496 | |
| 497 | private JsCalledMethod waitForUnignoredCall( |
| 498 | String logM, Set ignorables, List calledMethods) { |
| 499 | |
| 500 | long waitTime2 = waitTime+50; |
| 501 | // long currentTime; |
| 502 | //only while waitTime is greater than 50 milliseconds |
| 503 | while(waitTime2 >= 50) { |
| 504 | //if there are no methods called yet, since we can't wait like mocklib, throw an exception |
| 505 | //as all testing will have to happen on test thread!!! |
| 506 | if(methodsCalled.size() <= 0) { |
| 507 | return null; |
| 508 | // currentTime = System.currentTimeMillis(); |
| 509 | // System.out.println("method expected(not called yet-waiting)="+logM+" on obj="+this+" wait="+waitTime2); |
| 510 | // this.wait(waitTime2); |
| 511 | // long waitedOnWait = System.currentTimeMillis() - currentTime; |
| 512 | // waitTime2 -= waitedOnWait; |
| 513 | } |
| 514 | |
| 515 | //check for new methods to be called now...if no non-ignorable methods, then |
| 516 | //continue while loop. |
| 517 | for(int i = 0; i < methodsCalled.size(); i++) { |
| 518 | JsCalledMethod calledMethod = (JsCalledMethod)methodsCalled.remove(0); |
| 519 | calledMethods.add(calledMethod); |
| 520 | if(!ignorables.contains(calledMethod.getMethodName())) { |
| 521 | System.out.println("method expected and was called="+logM+" on obj="+this); |
| 522 | return calledMethod; |
| 523 | } |
| 524 | } |
| 525 | } |
| 526 | |
| 527 | //return null means timeout.... |
| 528 | return null; |
| 529 | } |
| 530 | |
| 531 | private Set createIgnorableMap(List ignorableMethods) { |
| 532 | Set ignorables = new HashSet(); |
| 533 | if(ignorableMethods != null) { |
| 534 | for(int i = 0; i < ignorableMethods.size(); i++) |
| 535 | { |
| 536 | String method = (String)ignorableMethods.get(i); |
| 537 | ignorables.add(method); |
| 538 | } |
| 539 | } |
| 540 | return ignorables; |
| 541 | } |
| 542 | private LeftOverMethods getLeftOverMethods(Set ignorables) { |
| 543 | List leftOver = new ArrayList(); |
| 544 | for(int i = 0; i < methodsCalled.size(); i++) { |
| 545 | JsCalledMethod o = (JsCalledMethod)methodsCalled.get(i); |
| 546 | if(o != null && !ignorables.contains(o.getMethodName())) { |
| 547 | leftOver.add(o); |
| 548 | } |
| 549 | } |
| 550 | if(leftOver.size() <= 0) |
| 551 | return null; |
| 552 | |
| 553 | Object[] m = new Object[0]; |
| 554 | //m = (CalledMethod[])leftOver.toArray(m); |
| 555 | m = leftOver.toArray(); |
| 556 | return new LeftOverMethods(m); |
| 557 | } |
| 558 | |
| 559 | private class LeftOverMethods { |
| 560 | |
| 561 | private Object[] leftOver; |
| 562 | public LeftOverMethods(Object[] m) { |
| 563 | leftOver = m; |
| 564 | } |
| 565 | |
| 566 | public Object[] getMethods() |
| 567 | { |
| 568 | return leftOver; |
| 569 | } |
| 570 | |
| 571 | public int getCalledMethodCount() { |
| 572 | return leftOver.length; |
| 573 | } |
| 574 | public JsCalledMethod getMethod(int index) { |
| 575 | return (JsCalledMethod)leftOver[index]; |
| 576 | } |
| 577 | |
| 578 | public String toString() { |
| 579 | String retVal = ""; |
| 580 | for(int i = 0; i < leftOver.length; i++) { |
| 581 | retVal+="\n"+leftOver[i]; |
| 582 | } |
| 583 | return retVal; |
| 584 | } |
| 585 | } |
| 586 | /** |
| 587 | * @see biz.xsoftware.mock.JsMockObject#addThrowException(java.lang.String, java.lang.Throwable) |
| 588 | */ |
| 589 | public synchronized void addThrowException(String method, Throwable e) { |
| 590 | if(method == null) |
| 591 | throw new IllegalArgumentException("method parameter cannot be null"); |
| 592 | else if(e == null) |
| 593 | throw new IllegalArgumentException("e parameter to this method cannot be null"); |
| 594 | List l = (List)methodToReturnVal.get(method); |
| 595 | if(l == null) { |
| 596 | l = new ArrayList(); |
| 597 | methodToReturnVal.put(method, l); |
| 598 | } |
| 599 | l.add(e); |
| 600 | } |
| 601 | |
| 602 | /** |
| 603 | * @see biz.xsoftware.mock.JsMockObject#addReturnValue(java.lang.String, java.lang.Object) |
| 604 | */ |
| 605 | public synchronized void addReturnValue(String method, Object o) { |
| 606 | if(method == null) |
| 607 | throw new IllegalArgumentException("method parameter cannot be null"); |
| 608 | List l = (List)methodToReturnVal.get(method); |
| 609 | if(l == null) { |
| 610 | l = new ArrayList(); |
| 611 | methodToReturnVal.put(method, l); |
| 612 | } |
| 613 | l.add(o); |
| 614 | } |
| 615 | |
| 616 | public void setDefaultReturnValue(String method, Object o) { |
| 617 | methodToDefaultRetVal.put(method, o); |
| 618 | } |
| 619 | |
| 620 | /** |
| 621 | * This is the method that calls the cloner to clone |
| 622 | * objects like ByteBuffer that can change after |
| 623 | * they are called. |
| 624 | * |
| 625 | * @param o |
| 626 | */ |
| 627 | private Object[] clone(String method, Object[] params) { |
| 628 | if(params == null) |
| 629 | return null; |
| 630 | |
| 631 | //check if the next object is a Behavior object |
| 632 | List actions = (List)methodToReturnVal.get(method); |
| 633 | if(actions != null) { |
| 634 | Object action = actions.get(0); |
| 635 | if(action instanceof JsBehavior) { |
| 636 | JsBehavior behavior = (JsBehavior)action; |
| 637 | return behavior.clone(params); |
| 638 | } |
| 639 | } |
| 640 | |
| 641 | return params; |
| 642 | } |
| 643 | |
| 644 | public void addBehavior(String method, JsBehavior behavior) { |
| 645 | if(method == null) |
| 646 | throw new IllegalArgumentException("method parameter cannot be null"); |
| 647 | List l = (List)methodToReturnVal.get(method); |
| 648 | if(l == null) { |
| 649 | l = new ArrayList(); |
| 650 | methodToReturnVal.put(method, l); |
| 651 | } |
| 652 | l.add(behavior); |
| 653 | } |
| 654 | } |