/* * * * Copyright 2010, Unitils.org * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * */ package org.unitils.mock.core; import org.unitils.mock.core.proxy.ProxyInvocation; import org.unitils.mock.report.ScenarioReport; import org.unitils.mock.report.impl.DefaultScenarioReport; import org.unitils.mock.report.impl.DetailedObservedInvocationsReport; import org.unitils.mock.report.impl.ObservedInvocationsReport; import org.unitils.mock.report.impl.SuggestedAssertsReport; import java.util.ArrayList; import java.util.List; import static org.unitils.mock.core.Scenario.VerificationStatus.*; import static org.unitils.util.ReflectionUtils.getSimpleMethodName; /** * @author Filip Neven * @author Tim Ducheyne * @author Kenny Claes */ public class Scenario { protected static enum VerificationStatus { UNVERIFIED, VERIFIED, VERIFIED_IN_ORDER } protected List<ObservedInvocation> observedInvocations = new ArrayList<ObservedInvocation>(); protected List<VerificationStatus> invocationVerificationStatuses = new ArrayList<VerificationStatus>(); protected Object testObject; public Scenario(Object testObject) { this.testObject = testObject; } public void reset() { observedInvocations.clear(); invocationVerificationStatuses.clear(); } public Object getTestObject() { return testObject; } public void setTestObject(Object testObject) { this.testObject = testObject; } public void addObservedMockInvocation(ObservedInvocation mockInvocation) { observedInvocations.add(mockInvocation); invocationVerificationStatuses.add(UNVERIFIED); } public List<ObservedInvocation> getObservedInvocations() { return observedInvocations; } public void assertNoMoreInvocations(StackTraceElement[] assertedAt) { List<ObservedInvocation> unexpectedInvocations = new ArrayList<ObservedInvocation>(); for (int i = 0; i < observedInvocations.size(); i++) { ObservedInvocation observedInvocation = observedInvocations.get(i); VerificationStatus invocationVerificationStatus = invocationVerificationStatuses.get(i); if (observedInvocation.getMockBehavior() == null && invocationVerificationStatus == UNVERIFIED) { unexpectedInvocations.add(observedInvocation); } } if (unexpectedInvocations.size() != 0) { AssertionError assertionError = new AssertionError(getNoMoreInvocationsErrorMessage(unexpectedInvocations, assertedAt[0])); assertionError.setStackTrace(assertedAt); throw assertionError; } } public void assertInvoked(BehaviorDefiningInvocation assertInvocation) { for (int i = 0; i < observedInvocations.size(); i++) { ObservedInvocation observedInvocation = observedInvocations.get(i); VerificationStatus invocationVerificationStatus = invocationVerificationStatuses.get(i); if (invocationVerificationStatus == UNVERIFIED && assertInvocation.matches(observedInvocation) != -1) { // Found a match that's not verified yet. Mark as verified and proceed. invocationVerificationStatuses.set(i, VERIFIED); return; } } AssertionError assertionError = new AssertionError(getAssertInvokedErrorMessage(assertInvocation, assertInvocation.getInvokedAt())); assertionError.setStackTrace(assertInvocation.getInvokedAtTrace()); throw assertionError; } public void assertInvokedInOrder(BehaviorDefiningInvocation assertInvocation) { ObservedInvocation matchingInvocation = null; for (int i = 0; i < observedInvocations.size(); i++) { ObservedInvocation observedInvocation = observedInvocations.get(i); VerificationStatus invocationVerificationStatus = invocationVerificationStatuses.get(i); if (matchingInvocation == null && invocationVerificationStatus == UNVERIFIED && assertInvocation.matches(observedInvocation) != -1) { // Found a match that's not verified yet. Mark as verified in order. invocationVerificationStatuses.set(i, VERIFIED_IN_ORDER); matchingInvocation = observedInvocation; continue; } // If we found a match, then check if there's no subsequent observed invocation that's already verified using assertInvokedInOrder() if (matchingInvocation != null && invocationVerificationStatus == VERIFIED_IN_ORDER) { AssertionError assertionError = new AssertionError(getInvokedOutOfOrderErrorMessage(matchingInvocation, observedInvocation, assertInvocation.getInvokedAt())); assertionError.setStackTrace(assertInvocation.getInvokedAtTrace()); throw assertionError; } } if (matchingInvocation == null) { AssertionError assertionError = new AssertionError(getAssertInvokedErrorMessage(assertInvocation, assertInvocation.getInvokedAt())); assertionError.setStackTrace(assertInvocation.getInvokedAtTrace()); throw assertionError; } } public void assertNotInvoked(BehaviorDefiningInvocation assertInvocation) { for (int i = 0; i < observedInvocations.size(); i++) { ObservedInvocation observedInvocation = observedInvocations.get(i); VerificationStatus invocationVerificationStatus = invocationVerificationStatuses.get(i); if (invocationVerificationStatus == UNVERIFIED && assertInvocation.matches(observedInvocation) != -1) { AssertionError assertionError = new AssertionError(getAssertNotInvokedErrorMessage(assertInvocation, observedInvocation, assertInvocation.getInvokedAtTrace())); assertionError.setStackTrace(assertInvocation.getInvokedAtTrace()); throw assertionError; } } } public String createFullReport() { ScenarioReport fullScenarioReport = new DefaultScenarioReport(); return fullScenarioReport.createReport(this); } public String createObservedInvocationsReport() { ObservedInvocationsReport observedInvocationsReport = new ObservedInvocationsReport(testObject); return observedInvocationsReport.createReport(this.getObservedInvocations()); } public String createDetailedObservedInvocationsReport() { DetailedObservedInvocationsReport observedInvocationsReport = new DetailedObservedInvocationsReport(testObject); return observedInvocationsReport.createReport(this.getObservedInvocations()); } public String createSuggestedAssertsReport() { SuggestedAssertsReport suggestedAssertsReport = new SuggestedAssertsReport(); return suggestedAssertsReport.createReport(testObject, getObservedInvocations()); } protected String getAssertNotInvokedErrorMessage(ProxyInvocation proxyInvocation, ObservedInvocation unexpectedInvocation, StackTraceElement[] assertedAt) { StringBuilder message = new StringBuilder(); message.append("Expected no invocation of "); message.append(getSimpleMethodName(proxyInvocation.getMethod())); message.append(", but it did occur.\nat "); message.append(unexpectedInvocation.getInvokedAt()); message.append("\n"); message.append(getAssertLocationIndication(assertedAt[0])); message.append("\n\n"); message.append(createFullReport()); return message.toString(); } protected String getAssertInvokedErrorMessage(ProxyInvocation proxyInvocation, StackTraceElement invokedAt) { StringBuilder message = new StringBuilder(); message.append("Expected invocation of "); message.append(getSimpleMethodName(proxyInvocation.getMethod())); message.append(", but it didn't occur.\n"); message.append(getAssertLocationIndication(invokedAt)); message.append("\n\n"); message.append(createFullReport()); return message.toString(); } protected String getInvokedOutOfOrderErrorMessage(ObservedInvocation matchingInvocation, ObservedInvocation outOfOrderInvocation, StackTraceElement assertedAt) { StringBuilder message = new StringBuilder(); message.append("Invocation of "); message.append(getSimpleMethodName(matchingInvocation.getMethod())); message.append(" was expected to be performed after "); message.append(getSimpleMethodName(outOfOrderInvocation.getMethod())); message.append(" but actually occurred before it.\n"); message.append(getAssertLocationIndication(assertedAt)); message.append("\n\n"); message.append(createFullReport()); return message.toString(); } protected String getNoMoreInvocationsErrorMessage(List<ObservedInvocation> unexpectedInvocations, StackTraceElement assertedAt) { StringBuilder message = new StringBuilder(); message.append("No more invocations expected, yet observed following calls:\n"); message.append(new ObservedInvocationsReport(testObject).createReport(unexpectedInvocations)); message.append(getAssertLocationIndication(assertedAt)); message.append("\n\n"); message.append(createFullReport()); return message.toString(); } protected String getAssertLocationIndication(StackTraceElement assertedAt) { return "asserted at " + assertedAt.toString(); } }