147d431f63a66505a645f282416659a9758a91f1cBrett Chabot/*
247d431f63a66505a645f282416659a9758a91f1cBrett Chabot * Copyright 2001-2009 OFFIS, Tammo Freese
347d431f63a66505a645f282416659a9758a91f1cBrett Chabot *
447d431f63a66505a645f282416659a9758a91f1cBrett Chabot * Licensed under the Apache License, Version 2.0 (the "License");
547d431f63a66505a645f282416659a9758a91f1cBrett Chabot * you may not use this file except in compliance with the License.
647d431f63a66505a645f282416659a9758a91f1cBrett Chabot * You may obtain a copy of the License at
747d431f63a66505a645f282416659a9758a91f1cBrett Chabot *
847d431f63a66505a645f282416659a9758a91f1cBrett Chabot *     http://www.apache.org/licenses/LICENSE-2.0
947d431f63a66505a645f282416659a9758a91f1cBrett Chabot *
1047d431f63a66505a645f282416659a9758a91f1cBrett Chabot * Unless required by applicable law or agreed to in writing, software
1147d431f63a66505a645f282416659a9758a91f1cBrett Chabot * distributed under the License is distributed on an "AS IS" BASIS,
1247d431f63a66505a645f282416659a9758a91f1cBrett Chabot * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1347d431f63a66505a645f282416659a9758a91f1cBrett Chabot * See the License for the specific language governing permissions and
1447d431f63a66505a645f282416659a9758a91f1cBrett Chabot * limitations under the License.
1547d431f63a66505a645f282416659a9758a91f1cBrett Chabot */
1647d431f63a66505a645f282416659a9758a91f1cBrett Chabotpackage org.easymock.internal;
1747d431f63a66505a645f282416659a9758a91f1cBrett Chabot
1847d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport java.io.Serializable;
1947d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport java.lang.reflect.Method;
2047d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport java.util.ArrayList;
2147d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport java.util.List;
2247d431f63a66505a645f282416659a9758a91f1cBrett Chabot
2347d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport org.easymock.EasyMock;
2447d431f63a66505a645f282416659a9758a91f1cBrett Chabot
2547d431f63a66505a645f282416659a9758a91f1cBrett Chabotpublic class MocksBehavior implements IMocksBehavior, Serializable {
2647d431f63a66505a645f282416659a9758a91f1cBrett Chabot
2747d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private static final long serialVersionUID = 3265727009370529027L;
2847d431f63a66505a645f282416659a9758a91f1cBrett Chabot
2947d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private final List<UnorderedBehavior> behaviorLists = new ArrayList<UnorderedBehavior>();
3047d431f63a66505a645f282416659a9758a91f1cBrett Chabot
3147d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private final List<ExpectedInvocationAndResult> stubResults = new ArrayList<ExpectedInvocationAndResult>();
3247d431f63a66505a645f282416659a9758a91f1cBrett Chabot
3347d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private final boolean nice;
3447d431f63a66505a645f282416659a9758a91f1cBrett Chabot
3547d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private boolean checkOrder;
3647d431f63a66505a645f282416659a9758a91f1cBrett Chabot
3747d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private boolean isThreadSafe;
3847d431f63a66505a645f282416659a9758a91f1cBrett Chabot
3947d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private boolean shouldBeUsedInOneThread;
4047d431f63a66505a645f282416659a9758a91f1cBrett Chabot
4147d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private int position = 0;
4247d431f63a66505a645f282416659a9758a91f1cBrett Chabot
4347d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private transient volatile Thread lastThread;
4447d431f63a66505a645f282416659a9758a91f1cBrett Chabot
4547d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private LegacyMatcherProvider legacyMatcherProvider;
4647d431f63a66505a645f282416659a9758a91f1cBrett Chabot
4747d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public MocksBehavior(boolean nice) {
4847d431f63a66505a645f282416659a9758a91f1cBrett Chabot        this.nice = nice;
4947d431f63a66505a645f282416659a9758a91f1cBrett Chabot        this.isThreadSafe = !Boolean.valueOf(EasyMockProperties.getInstance()
5047d431f63a66505a645f282416659a9758a91f1cBrett Chabot                .getProperty(EasyMock.NOT_THREAD_SAFE_BY_DEFAULT));
5147d431f63a66505a645f282416659a9758a91f1cBrett Chabot        this.shouldBeUsedInOneThread = Boolean.valueOf(EasyMockProperties
5247d431f63a66505a645f282416659a9758a91f1cBrett Chabot                .getInstance().getProperty(
5347d431f63a66505a645f282416659a9758a91f1cBrett Chabot                        EasyMock.ENABLE_THREAD_SAFETY_CHECK_BY_DEFAULT));
5447d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
5547d431f63a66505a645f282416659a9758a91f1cBrett Chabot
5647d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public final void addStub(ExpectedInvocation expected, Result result) {
5747d431f63a66505a645f282416659a9758a91f1cBrett Chabot        stubResults.add(new ExpectedInvocationAndResult(expected, result));
5847d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
5947d431f63a66505a645f282416659a9758a91f1cBrett Chabot
6047d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public void addExpected(ExpectedInvocation expected, Result result,
6147d431f63a66505a645f282416659a9758a91f1cBrett Chabot            Range count) {
6247d431f63a66505a645f282416659a9758a91f1cBrett Chabot        if (legacyMatcherProvider != null) {
6347d431f63a66505a645f282416659a9758a91f1cBrett Chabot            expected = expected.withMatcher(legacyMatcherProvider
6447d431f63a66505a645f282416659a9758a91f1cBrett Chabot                    .getMatcher(expected.getMethod()));
6547d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
6647d431f63a66505a645f282416659a9758a91f1cBrett Chabot        addBehaviorListIfNecessary(expected);
6747d431f63a66505a645f282416659a9758a91f1cBrett Chabot        lastBehaviorList().addExpected(expected, result, count);
6847d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
6947d431f63a66505a645f282416659a9758a91f1cBrett Chabot
7047d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private final Result getStubResult(Invocation actual) {
7147d431f63a66505a645f282416659a9758a91f1cBrett Chabot        for (ExpectedInvocationAndResult each : stubResults) {
7247d431f63a66505a645f282416659a9758a91f1cBrett Chabot            if (each.getExpectedInvocation().matches(actual)) {
7347d431f63a66505a645f282416659a9758a91f1cBrett Chabot                return each.getResult();
7447d431f63a66505a645f282416659a9758a91f1cBrett Chabot            }
7547d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
7647d431f63a66505a645f282416659a9758a91f1cBrett Chabot        return null;
7747d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
7847d431f63a66505a645f282416659a9758a91f1cBrett Chabot
7947d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private void addBehaviorListIfNecessary(ExpectedInvocation expected) {
8047d431f63a66505a645f282416659a9758a91f1cBrett Chabot        if (behaviorLists.isEmpty()
8147d431f63a66505a645f282416659a9758a91f1cBrett Chabot                || !lastBehaviorList().allowsExpectedInvocation(expected,
8247d431f63a66505a645f282416659a9758a91f1cBrett Chabot                        checkOrder)) {
8347d431f63a66505a645f282416659a9758a91f1cBrett Chabot            behaviorLists.add(new UnorderedBehavior(checkOrder));
8447d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
8547d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
8647d431f63a66505a645f282416659a9758a91f1cBrett Chabot
8747d431f63a66505a645f282416659a9758a91f1cBrett Chabot    private UnorderedBehavior lastBehaviorList() {
8847d431f63a66505a645f282416659a9758a91f1cBrett Chabot        return behaviorLists.get(behaviorLists.size() - 1);
8947d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
9047d431f63a66505a645f282416659a9758a91f1cBrett Chabot
9147d431f63a66505a645f282416659a9758a91f1cBrett Chabot    @SuppressWarnings("deprecation")
9247d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public final Result addActual(Invocation actual) {
9347d431f63a66505a645f282416659a9758a91f1cBrett Chabot        int initialPosition = position;
9447d431f63a66505a645f282416659a9758a91f1cBrett Chabot
9547d431f63a66505a645f282416659a9758a91f1cBrett Chabot        while (position < behaviorLists.size()) {
9647d431f63a66505a645f282416659a9758a91f1cBrett Chabot            Result result = behaviorLists.get(position).addActual(actual);
9747d431f63a66505a645f282416659a9758a91f1cBrett Chabot            if (result != null) {
9847d431f63a66505a645f282416659a9758a91f1cBrett Chabot                return result;
9947d431f63a66505a645f282416659a9758a91f1cBrett Chabot            }
10047d431f63a66505a645f282416659a9758a91f1cBrett Chabot            if (!behaviorLists.get(position).verify()) {
10147d431f63a66505a645f282416659a9758a91f1cBrett Chabot                break;
10247d431f63a66505a645f282416659a9758a91f1cBrett Chabot            }
10347d431f63a66505a645f282416659a9758a91f1cBrett Chabot            position++;
10447d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
10547d431f63a66505a645f282416659a9758a91f1cBrett Chabot        Result stubOrNice = getStubResult(actual);
10647d431f63a66505a645f282416659a9758a91f1cBrett Chabot        if (stubOrNice == null && nice) {
10747d431f63a66505a645f282416659a9758a91f1cBrett Chabot            stubOrNice = Result.createReturnResult(RecordState
10847d431f63a66505a645f282416659a9758a91f1cBrett Chabot                    .emptyReturnValueFor(actual.getMethod().getReturnType()));
10947d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
11047d431f63a66505a645f282416659a9758a91f1cBrett Chabot
11147d431f63a66505a645f282416659a9758a91f1cBrett Chabot        int endPosition = position;
11247d431f63a66505a645f282416659a9758a91f1cBrett Chabot
11347d431f63a66505a645f282416659a9758a91f1cBrett Chabot        // Do not move the cursor in case of stub, nice or error
11447d431f63a66505a645f282416659a9758a91f1cBrett Chabot        position = initialPosition;
11547d431f63a66505a645f282416659a9758a91f1cBrett Chabot
11647d431f63a66505a645f282416659a9758a91f1cBrett Chabot        if (stubOrNice != null) {
11747d431f63a66505a645f282416659a9758a91f1cBrett Chabot            actual.validateCaptures();
11847d431f63a66505a645f282416659a9758a91f1cBrett Chabot            actual.clearCaptures();
11947d431f63a66505a645f282416659a9758a91f1cBrett Chabot            return stubOrNice;
12047d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
12147d431f63a66505a645f282416659a9758a91f1cBrett Chabot
12247d431f63a66505a645f282416659a9758a91f1cBrett Chabot        // Case where the loop was exited at the end of the behaviorLists
12347d431f63a66505a645f282416659a9758a91f1cBrett Chabot        if (endPosition == behaviorLists.size()) {
12447d431f63a66505a645f282416659a9758a91f1cBrett Chabot            endPosition--;
12547d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
12647d431f63a66505a645f282416659a9758a91f1cBrett Chabot
12747d431f63a66505a645f282416659a9758a91f1cBrett Chabot        // Loop all around the behaviors left to generate the message
12847d431f63a66505a645f282416659a9758a91f1cBrett Chabot        StringBuilder errorMessage = new StringBuilder(70 * (endPosition
12947d431f63a66505a645f282416659a9758a91f1cBrett Chabot                - initialPosition + 1)); // rough approximation of the length
13047d431f63a66505a645f282416659a9758a91f1cBrett Chabot        errorMessage.append("\n  Unexpected method call ").append(
13147d431f63a66505a645f282416659a9758a91f1cBrett Chabot                actual.toString(org.easymock.MockControl.EQUALS_MATCHER));
13247d431f63a66505a645f282416659a9758a91f1cBrett Chabot
13347d431f63a66505a645f282416659a9758a91f1cBrett Chabot        List<ErrorMessage> messages = new ArrayList<ErrorMessage>();
13447d431f63a66505a645f282416659a9758a91f1cBrett Chabot
13547d431f63a66505a645f282416659a9758a91f1cBrett Chabot        int matches = 0;
13647d431f63a66505a645f282416659a9758a91f1cBrett Chabot
13747d431f63a66505a645f282416659a9758a91f1cBrett Chabot        // First find how many match we have
13847d431f63a66505a645f282416659a9758a91f1cBrett Chabot        for (int i = initialPosition; i <= endPosition; i++) {
13947d431f63a66505a645f282416659a9758a91f1cBrett Chabot            List<ErrorMessage> thisListMessages = behaviorLists.get(i)
14047d431f63a66505a645f282416659a9758a91f1cBrett Chabot                    .getMessages(actual);
14147d431f63a66505a645f282416659a9758a91f1cBrett Chabot            messages.addAll(thisListMessages);
14247d431f63a66505a645f282416659a9758a91f1cBrett Chabot            for (ErrorMessage m : thisListMessages) {
14347d431f63a66505a645f282416659a9758a91f1cBrett Chabot                if (m.isMatching()) {
14447d431f63a66505a645f282416659a9758a91f1cBrett Chabot                    matches++;
14547d431f63a66505a645f282416659a9758a91f1cBrett Chabot                }
14647d431f63a66505a645f282416659a9758a91f1cBrett Chabot            }
14747d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
14847d431f63a66505a645f282416659a9758a91f1cBrett Chabot
14947d431f63a66505a645f282416659a9758a91f1cBrett Chabot        if (matches > 1) {
15047d431f63a66505a645f282416659a9758a91f1cBrett Chabot            errorMessage
15147d431f63a66505a645f282416659a9758a91f1cBrett Chabot                    .append(". Possible matches are marked with (+1):");
15247d431f63a66505a645f282416659a9758a91f1cBrett Chabot        } else {
15347d431f63a66505a645f282416659a9758a91f1cBrett Chabot            errorMessage.append(":");
15447d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
15547d431f63a66505a645f282416659a9758a91f1cBrett Chabot
15647d431f63a66505a645f282416659a9758a91f1cBrett Chabot        for (ErrorMessage m : messages) {
15747d431f63a66505a645f282416659a9758a91f1cBrett Chabot            m.appendTo(errorMessage, matches);
15847d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
15947d431f63a66505a645f282416659a9758a91f1cBrett Chabot
16047d431f63a66505a645f282416659a9758a91f1cBrett Chabot        // And finally throw the error
16147d431f63a66505a645f282416659a9758a91f1cBrett Chabot        throw new AssertionErrorWrapper(new AssertionError(errorMessage));
16247d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
16347d431f63a66505a645f282416659a9758a91f1cBrett Chabot
16447d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public void verify() {
16547d431f63a66505a645f282416659a9758a91f1cBrett Chabot        boolean verified = true;
16647d431f63a66505a645f282416659a9758a91f1cBrett Chabot
16747d431f63a66505a645f282416659a9758a91f1cBrett Chabot        for (UnorderedBehavior behaviorList : behaviorLists.subList(position,
16847d431f63a66505a645f282416659a9758a91f1cBrett Chabot                behaviorLists.size())) {
16947d431f63a66505a645f282416659a9758a91f1cBrett Chabot            if (!behaviorList.verify()) {
17047d431f63a66505a645f282416659a9758a91f1cBrett Chabot                verified = false;
17147d431f63a66505a645f282416659a9758a91f1cBrett Chabot            }
17247d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
17347d431f63a66505a645f282416659a9758a91f1cBrett Chabot        if (verified) {
17447d431f63a66505a645f282416659a9758a91f1cBrett Chabot            return;
17547d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
17647d431f63a66505a645f282416659a9758a91f1cBrett Chabot
17747d431f63a66505a645f282416659a9758a91f1cBrett Chabot        StringBuilder errorMessage = new StringBuilder(70 * (behaviorLists
17847d431f63a66505a645f282416659a9758a91f1cBrett Chabot                .size()
17947d431f63a66505a645f282416659a9758a91f1cBrett Chabot                - position + 1));
18047d431f63a66505a645f282416659a9758a91f1cBrett Chabot
18147d431f63a66505a645f282416659a9758a91f1cBrett Chabot        errorMessage.append("\n  Expectation failure on verify:");
18247d431f63a66505a645f282416659a9758a91f1cBrett Chabot        for (UnorderedBehavior behaviorList : behaviorLists.subList(position,
18347d431f63a66505a645f282416659a9758a91f1cBrett Chabot                behaviorLists.size())) {
18447d431f63a66505a645f282416659a9758a91f1cBrett Chabot            for (ErrorMessage m : behaviorList.getMessages(null)) {
18547d431f63a66505a645f282416659a9758a91f1cBrett Chabot                m.appendTo(errorMessage, 0);
18647d431f63a66505a645f282416659a9758a91f1cBrett Chabot            }
18747d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
18847d431f63a66505a645f282416659a9758a91f1cBrett Chabot
18947d431f63a66505a645f282416659a9758a91f1cBrett Chabot        throw new AssertionErrorWrapper(new AssertionError(errorMessage
19047d431f63a66505a645f282416659a9758a91f1cBrett Chabot                .toString()));
19147d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
19247d431f63a66505a645f282416659a9758a91f1cBrett Chabot
19347d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public void checkOrder(boolean value) {
19447d431f63a66505a645f282416659a9758a91f1cBrett Chabot        this.checkOrder = value;
19547d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
19647d431f63a66505a645f282416659a9758a91f1cBrett Chabot
19747d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public void makeThreadSafe(boolean isThreadSafe) {
19847d431f63a66505a645f282416659a9758a91f1cBrett Chabot        this.isThreadSafe = isThreadSafe;
19947d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
20047d431f63a66505a645f282416659a9758a91f1cBrett Chabot
20147d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public void shouldBeUsedInOneThread(boolean shouldBeUsedInOneThread) {
20247d431f63a66505a645f282416659a9758a91f1cBrett Chabot        this.shouldBeUsedInOneThread = shouldBeUsedInOneThread;
20347d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
20447d431f63a66505a645f282416659a9758a91f1cBrett Chabot
20547d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public boolean isThreadSafe() {
20647d431f63a66505a645f282416659a9758a91f1cBrett Chabot        return this.isThreadSafe;
20747d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
20847d431f63a66505a645f282416659a9758a91f1cBrett Chabot
20947d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public void checkThreadSafety() {
21047d431f63a66505a645f282416659a9758a91f1cBrett Chabot        if (!shouldBeUsedInOneThread) {
21147d431f63a66505a645f282416659a9758a91f1cBrett Chabot            return;
21247d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
21347d431f63a66505a645f282416659a9758a91f1cBrett Chabot        if (lastThread == null) {
21447d431f63a66505a645f282416659a9758a91f1cBrett Chabot            lastThread = Thread.currentThread();
21547d431f63a66505a645f282416659a9758a91f1cBrett Chabot        } else if(lastThread != Thread.currentThread()) {
21647d431f63a66505a645f282416659a9758a91f1cBrett Chabot            throw new AssertionErrorWrapper(new AssertionError(
21747d431f63a66505a645f282416659a9758a91f1cBrett Chabot                    "\n Mock isn't supposed to be called from multiple threads. Last: "
21847d431f63a66505a645f282416659a9758a91f1cBrett Chabot                            + lastThread +
21947d431f63a66505a645f282416659a9758a91f1cBrett Chabot                    " Current: " + Thread.currentThread()));
22047d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
22147d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
22247d431f63a66505a645f282416659a9758a91f1cBrett Chabot
22347d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public LegacyMatcherProvider getLegacyMatcherProvider() {
22447d431f63a66505a645f282416659a9758a91f1cBrett Chabot        if (legacyMatcherProvider == null) {
22547d431f63a66505a645f282416659a9758a91f1cBrett Chabot            legacyMatcherProvider = new LegacyMatcherProvider();
22647d431f63a66505a645f282416659a9758a91f1cBrett Chabot        }
22747d431f63a66505a645f282416659a9758a91f1cBrett Chabot        return legacyMatcherProvider;
22847d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
22947d431f63a66505a645f282416659a9758a91f1cBrett Chabot
23047d431f63a66505a645f282416659a9758a91f1cBrett Chabot    @SuppressWarnings("deprecation")
23147d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public void setDefaultMatcher(org.easymock.ArgumentsMatcher matcher) {
23247d431f63a66505a645f282416659a9758a91f1cBrett Chabot        getLegacyMatcherProvider().setDefaultMatcher(matcher);
23347d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
23447d431f63a66505a645f282416659a9758a91f1cBrett Chabot
23547d431f63a66505a645f282416659a9758a91f1cBrett Chabot    @SuppressWarnings("deprecation")
23647d431f63a66505a645f282416659a9758a91f1cBrett Chabot    public void setMatcher(Method method, org.easymock.ArgumentsMatcher matcher) {
23747d431f63a66505a645f282416659a9758a91f1cBrett Chabot        getLegacyMatcherProvider().setMatcher(method, matcher);
23847d431f63a66505a645f282416659a9758a91f1cBrett Chabot    }
23947d431f63a66505a645f282416659a9758a91f1cBrett Chabot}
240