ff52581ace2381cd91f616544e4d79524b11fbc2
[Sone.git] / src / test / java / net / pterodactylus / sone / data / Mocks.java
1 /*
2  * Sone - Mocks.java - Copyright © 2013 David Roden
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.sone.data;
19
20 import static com.google.common.base.Optional.absent;
21 import static com.google.common.base.Optional.fromNullable;
22 import static com.google.common.base.Optional.of;
23 import static com.google.common.collect.ArrayListMultimap.create;
24 import static com.google.common.collect.Maps.newHashMap;
25 import static com.google.common.collect.Ordering.from;
26 import static java.util.Collections.emptySet;
27 import static org.mockito.Matchers.anyString;
28 import static org.mockito.Matchers.eq;
29 import static org.mockito.Mockito.doAnswer;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.when;
32
33 import java.net.URI;
34 import java.net.URISyntaxException;
35 import java.util.Collection;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39
40 import net.pterodactylus.sone.core.Core;
41 import net.pterodactylus.sone.data.impl.DefaultPostBuilder;
42 import net.pterodactylus.sone.data.impl.DefaultPostReplyBuilder;
43 import net.pterodactylus.sone.database.Database;
44 import net.pterodactylus.sone.database.PostReplyBuilder;
45 import net.pterodactylus.sone.web.WebInterface;
46 import net.pterodactylus.sone.web.page.FreenetRequest;
47
48 import freenet.clients.http.HTTPRequestImpl;
49 import freenet.support.api.HTTPRequest;
50
51 import com.google.common.base.Function;
52 import com.google.common.base.Optional;
53 import com.google.common.collect.FluentIterable;
54 import com.google.common.collect.HashMultimap;
55 import com.google.common.collect.Multimap;
56 import com.google.common.collect.Ordering;
57 import com.google.common.collect.SetMultimap;
58 import org.mockito.Matchers;
59 import org.mockito.invocation.InvocationOnMock;
60 import org.mockito.stubbing.Answer;
61
62 /**
63  * Mocks reusable in multiple tests.
64  *
65  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
66  */
67 public class Mocks {
68
69         private final Multimap<Sone, Post> sonePosts = create();
70         private final Map<String, Sone> sones = newHashMap();
71         private final Multimap<Post, PostReply> postReplies = create();
72         private final Multimap<String, Post> directedPosts = create();
73         private final SetMultimap<Post, Sone> postLikingSones = HashMultimap.create();
74         private final SetMultimap<PostReply, Sone> postReplyLikingSones = HashMultimap.create();
75         public final Database database;
76         public final Core core;
77         public final WebInterface webInterface;
78
79         public Mocks() {
80                 database = mockDatabase();
81                 core = mockCore(database);
82                 webInterface = mockWebInterface(core);
83                 when(database.getSone()).thenReturn(new Function<String, Optional<Sone>>() {
84                         @Override
85                         public Optional<Sone> apply(String soneId) {
86                                 return (soneId == null) ? Optional.<Sone>absent() : fromNullable(sones.get(soneId));
87                         }
88                 });
89                 when(core.getSones()).then(new Answer<Collection<Sone>>() {
90                         @Override
91                         public Collection<Sone> answer(InvocationOnMock invocation) throws Throwable {
92                                 return sones.values();
93                         }
94                 });
95                 when(core.getLocalSones()).then(new Answer<Collection<Sone>>() {
96                         @Override
97                         public Collection<Sone> answer(InvocationOnMock invocation) throws Throwable {
98                                 return FluentIterable.from(sones.values()).filter(Sone.LOCAL_SONE_FILTER).toList();
99                         }
100                 });
101                 when(database.getDirectedPosts(anyString())).then(new Answer<Collection<Post>>() {
102                         @Override
103                         public Collection<Post> answer(InvocationOnMock invocation) throws Throwable {
104                                 return directedPosts.get((String) invocation.getArguments()[0]);
105                         }
106                 });
107         }
108
109         private static Core mockCore(Database database) {
110                 Core core = mock(Core.class);
111                 when(core.getDatabase()).thenReturn(database);
112                 when(core.getSone(anyString())).thenReturn(Optional.<Sone>absent());
113                 return core;
114         }
115
116         private static Database mockDatabase() {
117                 Database database = mock(Database.class);
118                 when(database.getSone(anyString())).thenReturn(Optional.<Sone>absent());
119                 when(database.getPost(anyString())).thenReturn(Optional.<Post>absent());
120                 when(database.getPostReply(anyString())).thenReturn(Optional.<PostReply>absent());
121                 return database;
122         }
123
124         private static WebInterface mockWebInterface(Core core) {
125                 WebInterface webInterface = mock(WebInterface.class);
126                 when(webInterface.getCore()).thenReturn(core);
127                 return webInterface;
128         }
129
130         public SoneMocker mockSone(String id) {
131                 return new SoneMocker(id);
132         }
133
134         public PostMocker mockPost(Sone sone, String postId) {
135                 return new PostMocker(postId, sone);
136         }
137
138         public PostReplyMocker mockPostReply(Sone sone, String replyId) {
139                 return new PostReplyMocker(replyId, sone);
140         }
141
142         public FreenetRequest mockRequest(String path) throws URISyntaxException {
143                 HTTPRequest httpRequest = new HTTPRequestImpl(new URI(path), "GET");
144                 FreenetRequest request = mock(FreenetRequest.class);
145                 when(request.getHttpRequest()).thenReturn(httpRequest);
146                 return request;
147         }
148
149         public class SoneMocker {
150
151                 private final Sone mockedSone = mock(Sone.class);
152                 private final String id;
153                 private boolean local;
154                 private Optional<String> name = absent();
155                 private long time;
156                 private Profile profile = new Profile(mockedSone);
157                 private Collection<String> friends = emptySet();
158
159                 private SoneMocker(String id) {
160                         this.id = id;
161                 }
162
163                 public SoneMocker local() {
164                         local = true;
165                         return this;
166                 }
167
168                 public SoneMocker withName(String name) {
169                         this.name = fromNullable(name);
170                         return this;
171                 }
172
173                 public SoneMocker withTime(long time) {
174                         this.time = time;
175                         return this;
176                 }
177
178                 public SoneMocker withProfileName(String firstName, String middleName, String lastName) {
179                         profile.modify().setFirstName(firstName).setMiddleName(middleName).setLastName(lastName).update();
180                         return this;
181                 }
182
183                 public SoneMocker addProfileField(String fieldName, String fieldValue) {
184                         profile.setField(profile.addField(fieldName), fieldValue);
185                         return this;
186                 }
187
188                 public SoneMocker withFriends(Collection<String> friends) {
189                         this.friends = friends;
190                         return this;
191                 }
192
193                 public Sone create() {
194                         when(mockedSone.getId()).thenReturn(id);
195                         when(mockedSone.isLocal()).thenReturn(local);
196                         if (name.isPresent()) {
197                                 when(mockedSone.getName()).thenReturn(name.get());
198                         }
199                         when(mockedSone.getTime()).thenReturn(time);
200                         when(mockedSone.getProfile()).thenReturn(profile);
201                         if (local) {
202                                 when(mockedSone.newPostBuilder()).thenReturn(new DefaultPostBuilder(database, id));
203                                 when(mockedSone.newPostReplyBuilder(anyString())).then(new Answer<PostReplyBuilder>() {
204                                         @Override
205                                         public PostReplyBuilder answer(InvocationOnMock invocation) throws Throwable {
206                                                 return new DefaultPostReplyBuilder(database, id, (String) invocation.getArguments()[0]);
207                                         }
208                                 });
209                                 when(mockedSone.hasFriend(anyString())).thenReturn(false);
210                                 when(mockedSone.getFriends()).thenReturn(friends);
211                                 when(mockedSone.hasFriend(anyString())).then(new Answer<Boolean>() {
212                                         @Override
213                                         public Boolean answer(InvocationOnMock invocation) throws Throwable {
214                                                 return friends.contains(invocation.getArguments()[0]);
215                                         }
216                                 });
217                         } else {
218                                 when(mockedSone.newPostBuilder()).thenThrow(IllegalStateException.class);
219                                 when(mockedSone.newPostReplyBuilder(anyString())).thenThrow(IllegalStateException.class);
220                         }
221                         when(core.getSone(eq(id))).thenReturn(of(mockedSone));
222                         when(database.getSone(eq(id))).thenReturn(of(mockedSone));
223                         when(mockedSone.getPosts()).then(new Answer<List<Post>>() {
224                                 @Override
225                                 public List<Post> answer(InvocationOnMock invocationOnMock) throws Throwable {
226                                         return from(Post.TIME_COMPARATOR).sortedCopy(sonePosts.get(mockedSone));
227                                 }
228                         });
229                         when(mockedSone.toString()).thenReturn(String.format("Sone[%s]", id));
230                         sones.put(id, mockedSone);
231                         return mockedSone;
232                 }
233
234         }
235
236         public class PostMocker {
237
238                 private final Post post = mock(Post.class);
239                 private final String id;
240                 private final Sone sone;
241                 private Optional<String> recipientId = absent();
242                 private long time;
243                 private Optional<String> text = absent();
244
245                 public PostMocker(String id, Sone sone) {
246                         this.id = id;
247                         this.sone = sone;
248                 }
249
250                 public PostMocker withRecipient(String recipientId) {
251                         this.recipientId = fromNullable(recipientId);
252                         return this;
253                 }
254
255                 public PostMocker withTime(long time) {
256                         this.time = time;
257                         return this;
258                 }
259
260                 public PostMocker withText(String text) {
261                         this.text = fromNullable(text);
262                         return this;
263                 }
264
265                 public Post create() {
266                         when(post.getId()).thenReturn(id);
267                         when(post.getSone()).thenReturn(sone);
268                         when(post.getRecipientId()).thenReturn(recipientId);
269                         if (recipientId.isPresent()) {
270                                 directedPosts.put(recipientId.get(), post);
271                         }
272                         when(post.getTime()).thenReturn(time);
273                         if (text.isPresent()) {
274                                 when(post.getText()).thenReturn(text.get());
275                         }
276                         when(database.getPost(eq(id))).thenReturn(of(post));
277                         sonePosts.put(sone, post);
278                         when(post.getReplies()).then(new Answer<List<PostReply>>() {
279                                 @Override
280                                 public List<PostReply> answer(InvocationOnMock invocation) throws Throwable {
281                                         return Ordering.from(Reply.TIME_COMPARATOR).sortedCopy(postReplies.get(post));
282                                 }
283                         });
284                         doAnswer(new Answer<Void>() {
285                                 @Override
286                                 public Void answer(InvocationOnMock invocation) throws Throwable {
287                                         postLikingSones.put(post, (Sone) invocation.getArguments()[0]);
288                                         return null;
289                                 }
290                         }).when(post).like(Matchers.<Sone>any());
291                         doAnswer(new Answer<Void>() {
292                                 @Override
293                                 public Void answer(InvocationOnMock invocation) throws Throwable {
294                                         postLikingSones.remove(post, (Sone) invocation.getArguments()[0]);
295                                         return null;
296                                 }
297                         }).when(post).unlike(Matchers.<Sone>any());
298                         when(post.getLikes()).thenAnswer(new Answer<Set<Sone>>() {
299                                 @Override
300                                 public Set<Sone> answer(InvocationOnMock invocation) throws Throwable {
301                                         return postLikingSones.get(post);
302                                 }
303                         });
304                         return post;
305                 }
306
307         }
308
309         public class PostReplyMocker {
310
311                 private final PostReply postReply = mock(PostReply.class);
312                 private final String id;
313                 private final Sone sone;
314                 private Optional<Post> post = absent();
315                 private long time;
316                 private Optional<String> text = absent();
317
318                 public PostReplyMocker(String id, Sone sone) {
319                         this.id = id;
320                         this.sone = sone;
321                 }
322
323                 public PostReplyMocker inReplyTo(Post post) {
324                         this.post = fromNullable(post);
325                         return this;
326                 }
327
328                 public PostReplyMocker withTime(long time) {
329                         this.time = time;
330                         return this;
331                 }
332
333                 public PostReplyMocker withText(String text) {
334                         this.text = fromNullable(text);
335                         return this;
336                 }
337
338                 public PostReply create() {
339                         when(postReply.getId()).thenReturn(id);
340                         when(postReply.getSone()).thenReturn(sone);
341                         when(postReply.getTime()).thenReturn(time);
342                         when(database.getPostReply(eq(id))).thenReturn(of(postReply));
343                         if (post.isPresent()) {
344                                 postReplies.put(post.get(), postReply);
345                         }
346                         if (text.isPresent()) {
347                                 when(postReply.getText()).thenReturn(text.get());
348                         }
349                         doAnswer(new Answer<Void>() {
350                                 @Override
351                                 public Void answer(InvocationOnMock invocation) throws Throwable {
352                                         postReplyLikingSones.put(postReply, (Sone) invocation.getArguments()[0]);
353                                         return null;
354                                 }
355                         }).when(postReply).like(Matchers.<Sone>any());
356                         doAnswer(new Answer<Void>() {
357                                 @Override
358                                 public Void answer(InvocationOnMock invocation) throws Throwable {
359                                         postReplyLikingSones.remove(postReply, invocation.getArguments()[0]);
360                                         return null;
361                                 }
362                         }).when(postReply).unlike(Matchers.<Sone>any());
363                         when(postReply.getLikes()).thenAnswer(new Answer<Set<Sone>>() {
364                                 @Override
365                                 public Set<Sone> answer(InvocationOnMock invocation) throws Throwable {
366                                         return postReplyLikingSones.get(postReply);
367                                 }
368                         });
369                         return postReply;
370                 }
371         }
372
373 }