1/*
2 * Copyright 2001-2009 OFFIS, Tammo Freese
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.easymock.internal;
17
18import java.io.Serializable;
19import java.util.ArrayList;
20import java.util.List;
21
22public class UnorderedBehavior implements Serializable {
23
24    private static final long serialVersionUID = 2185791334636597469L;
25
26    private final List<ExpectedInvocationAndResults> results = new ArrayList<ExpectedInvocationAndResults>();
27
28    private final boolean checkOrder;
29
30    public UnorderedBehavior(boolean checkOrder) {
31        this.checkOrder = checkOrder;
32    }
33
34    public void addExpected(ExpectedInvocation expected, Result result,
35            Range count) {
36        for (ExpectedInvocationAndResults entry : results) {
37            if (entry.getExpectedInvocation().equals(expected)) {
38                entry.getResults().add(result, count);
39                return;
40            }
41        }
42        Results list = new Results();
43        list.add(result, count);
44        results.add(new ExpectedInvocationAndResults(expected, list));
45    }
46
47    public Result addActual(Invocation actual) {
48        for (ExpectedInvocationAndResults entry : results) {
49            try {
50                if (!entry.getExpectedInvocation().matches(actual)) {
51                    continue;
52                }
53                Result result = entry.getResults().next();
54                if (result != null) {
55                    // actual and expected matched, validate the capture
56                    actual.validateCaptures();
57                    return result;
58                }
59            }
60            finally {
61                // reset the capture (already validated or expected didn't
62                // matched)
63                actual.clearCaptures();
64            }
65        }
66        return null;
67    }
68
69    public boolean verify() {
70        for (ExpectedInvocationAndResults entry : results) {
71            if (!entry.getResults().hasValidCallCount()) {
72                return false;
73            }
74        }
75        return true;
76    }
77
78    public List<ErrorMessage> getMessages(Invocation invocation) {
79        List<ErrorMessage> messages = new ArrayList<ErrorMessage>(results
80                .size());
81        for (ExpectedInvocationAndResults entry : results) {
82            boolean unordered = !checkOrder;
83            boolean validCallCount = entry.getResults().hasValidCallCount();
84            boolean match = invocation != null
85                    && entry.getExpectedInvocation().matches(invocation);
86
87            if (unordered && validCallCount && !match) {
88                continue;
89            }
90
91            ErrorMessage message = new ErrorMessage(match, entry.toString(),
92                    entry.getResults()
93                    .getCallCount());
94            messages.add(message);
95        }
96        return messages;
97
98    }
99
100    public boolean allowsExpectedInvocation(ExpectedInvocation expected,
101            boolean checkOrder) {
102        if (this.checkOrder != checkOrder) {
103            return false;
104        } else if (results.isEmpty() || !this.checkOrder) {
105            return true;
106        } else {
107            ExpectedInvocation lastMethodCall = results.get(results.size() - 1)
108                    .getExpectedInvocation();
109            return lastMethodCall.equals(expected);
110        }
111    }
112
113}