1/*
2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24package selectionresolution;
25
26import java.util.Arrays;
27import java.util.HashSet;
28
29/**
30 * Representation of an expected result.
31 */
32public interface Result {
33    public static final Result ICCE = new Exception(IncompatibleClassChangeError.class);
34    public static final Result IAE  = new Exception(IllegalAccessError.class);
35    public static final Result NSME = new Exception(NoSuchMethodError.class);
36    public static final Result AME  = new Exception(AbstractMethodError.class);
37
38    // Factories
39
40    /**
41     * Create a result that expects the given class.
42     */
43    public static Result is(int id) {
44        return new Single(id);
45    }
46
47    /**
48     * Create a result that expects the given classes.
49     */
50    public static Result is(int... multiple) {
51        assert multiple.length > 0;
52
53        if (multiple.length == 1) {
54            return new Single(multiple[0]);
55        } else {
56            return new Any(multiple);
57        }
58    }
59
60    /**
61     * Create a result that expects the given exception to be thrown.
62     */
63    public static Result is(Class<? extends Throwable> exType) {
64        return new Exception(exType);
65    }
66
67    /**
68     * Create a result that expects the given exception to be thrown.
69     */
70    public static Result is(Throwable ex) {
71        return Result.is(ex.getClass());
72    }
73
74    public static final Result EMPTY = new Empty();
75
76    /**
77     * Create an empty Result.
78     */
79    public static Result empty() {
80        return EMPTY;
81    }
82
83
84    public boolean complyWith(int i);
85    public boolean complyWith(Throwable e);
86    public boolean complyWith(Result r);
87
88    static class Empty implements Result {
89        @Override
90        public boolean complyWith(int i) {
91            return false;
92        }
93
94        @Override
95        public boolean complyWith(Throwable e) {
96            return false;
97        }
98
99        @Override
100        public boolean complyWith(Result r) {
101            return false;
102        }
103    }
104
105    static class Single implements Result {
106        public int id;
107
108        public Single(int id) {
109            this.id = id;
110        }
111
112        @Override
113        public boolean complyWith(int i) {
114            return id == i;
115        }
116
117        @Override
118        public boolean complyWith(Throwable e) {
119            return false;
120        }
121
122        @Override
123        public boolean complyWith(Result r) {
124            if (r instanceof Single) {
125                return complyWith(((Single)r).id);
126            } else if (r instanceof Any) {
127                return r.complyWith(this);
128            }
129            return false;
130        }
131
132        @Override
133        public boolean equals(Object o) {
134            if (this == o) return true;
135            if (!(o instanceof Single)) return false;
136
137            Single single = (Single) o;
138
139            return (id == single.id);
140        }
141
142        @Override
143        public int hashCode() {
144            return id;
145        }
146
147        @Override
148        public String toString() {
149            final StringBuffer sb = new StringBuffer("Result=Single{");
150            sb.append("id=").append(id);
151            sb.append('}');
152            return sb.toString();
153        }
154    }
155
156    static class Any implements Result {
157        public int[] ids;
158        public Any(int[] ids) {
159            this.ids = ids;
160        }
161
162        @Override
163        public boolean complyWith(int i) {
164            return Arrays.stream(ids)
165                    .anyMatch(j -> j == i);
166        }
167
168        @Override
169        public boolean complyWith(Throwable e) {
170            return false;
171        }
172
173        @Override
174        public boolean complyWith(Result r) {
175            if (r instanceof Single) {
176                return complyWith(((Single)r).id);
177            }
178            if (r instanceof Any) {
179                return Arrays.equals(ids, ((Any) r).ids);
180            }
181            return false;
182        }
183
184        @Override
185        public boolean equals(Object o) {
186            if (this == o) return true;
187            if (o == null || getClass() != o.getClass()) return false;
188
189            Any any = (Any) o;
190
191            return Arrays.equals(ids, any.ids);
192        }
193
194        @Override
195        public int hashCode() {
196            return Arrays.hashCode(ids);
197        }
198
199        @Override
200        public String toString() {
201            final StringBuffer sb = new StringBuffer("Result=Any{");
202            sb.append("ids=");
203            if (ids == null) sb.append("null");
204            else {
205                sb.append('[');
206                for (int i = 0; i < ids.length; ++i)
207                    sb.append(i == 0 ? "" : ", ").append(ids[i]);
208                sb.append(']');
209            }
210            sb.append('}');
211            return sb.toString();
212        }
213    }
214
215    static class Exception implements Result {
216        public Class<? extends Throwable> exc;
217        public Exception(Class<? extends Throwable> e) {
218            this.exc = e;
219        }
220
221        @Override
222        public boolean complyWith(int i) {
223            return false;
224        }
225
226        @Override
227        public boolean complyWith(Throwable e) {
228            return exc.isAssignableFrom(e.getClass());
229        }
230
231        @Override
232        public boolean complyWith(Result r) {
233            if (r instanceof Exception) {
234                return exc.isAssignableFrom(((Exception) r).exc);
235            }
236            return false;
237        }
238
239        @Override
240        public boolean equals(Object o) {
241            if (this == o) return true;
242            if (!(o instanceof Exception)) return false;
243
244            Exception exception = (Exception) o;
245
246            return exc.equals(exception.exc);
247        }
248
249        @Override
250        public int hashCode() {
251            return exc.hashCode();
252        }
253
254        @Override
255        public String toString() {
256            final StringBuffer sb = new StringBuffer("Result=Exception{");
257            sb.append("exc=").append(exc);
258            sb.append('}');
259            return sb.toString();
260        }
261    }
262}
263