Move album parsing to new configuration parser.
[Sone.git] / src / test / java / net / pterodactylus / sone / core / ConfigurationSoneParserTest.java
1 package net.pterodactylus.sone.core;
2
3 import static com.google.common.base.Optional.fromNullable;
4 import static com.google.common.base.Optional.of;
5 import static java.lang.System.currentTimeMillis;
6 import static java.util.UUID.randomUUID;
7 import static net.pterodactylus.sone.Matchers.isAlbum;
8 import static net.pterodactylus.sone.Matchers.isPost;
9 import static net.pterodactylus.sone.Matchers.isPostReply;
10 import static org.hamcrest.MatcherAssert.assertThat;
11 import static org.hamcrest.Matchers.contains;
12 import static org.hamcrest.Matchers.containsInAnyOrder;
13 import static org.hamcrest.Matchers.emptyIterable;
14 import static org.hamcrest.Matchers.hasSize;
15 import static org.hamcrest.Matchers.is;
16 import static org.hamcrest.Matchers.notNullValue;
17 import static org.hamcrest.Matchers.nullValue;
18 import static org.mockito.Matchers.any;
19 import static org.mockito.Matchers.anyString;
20 import static org.mockito.Matchers.eq;
21 import static org.mockito.Mockito.doAnswer;
22 import static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.when;
24
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.List;
28 import java.util.Set;
29 import java.util.concurrent.atomic.AtomicReference;
30
31 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidAlbumFound;
32 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidParentAlbumFound;
33 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostFound;
34 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostReplyFound;
35 import net.pterodactylus.sone.data.Album;
36 import net.pterodactylus.sone.data.Album.Modifier;
37 import net.pterodactylus.sone.data.Image;
38 import net.pterodactylus.sone.data.Post;
39 import net.pterodactylus.sone.data.PostReply;
40 import net.pterodactylus.sone.data.Profile;
41 import net.pterodactylus.sone.data.Profile.Field;
42 import net.pterodactylus.sone.data.Sone;
43 import net.pterodactylus.sone.database.AlbumBuilder;
44 import net.pterodactylus.sone.database.AlbumBuilderFactory;
45 import net.pterodactylus.sone.database.PostBuilder;
46 import net.pterodactylus.sone.database.PostBuilderFactory;
47 import net.pterodactylus.sone.database.PostReplyBuilder;
48 import net.pterodactylus.sone.database.PostReplyBuilderFactory;
49 import net.pterodactylus.util.config.Configuration;
50 import net.pterodactylus.util.config.ConfigurationException;
51 import net.pterodactylus.util.config.Value;
52
53 import com.google.common.base.Optional;
54 import org.hamcrest.Matchers;
55 import org.junit.Test;
56 import org.mockito.invocation.InvocationOnMock;
57 import org.mockito.stubbing.Answer;
58
59 /**
60  * Unit test for {@link ConfigurationSoneParser}.
61  *
62  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
63  */
64 public class ConfigurationSoneParserTest {
65
66         private final Configuration configuration = mock(Configuration.class);
67         private final Sone sone = mock(Sone.class);
68         private final ConfigurationSoneParser configurationSoneParser;
69
70         public ConfigurationSoneParserTest() {
71                 when(sone.getId()).thenReturn("1");
72                 configurationSoneParser =
73                                 new ConfigurationSoneParser(configuration, sone);
74         }
75
76         @Test
77         public void emptyProfileIsLoadedCorrectly() {
78                 setupEmptyProfile();
79                 Profile profile = configurationSoneParser.parseProfile();
80                 assertThat(profile, notNullValue());
81                 assertThat(profile.getFirstName(), nullValue());
82                 assertThat(profile.getMiddleName(), nullValue());
83                 assertThat(profile.getLastName(), nullValue());
84                 assertThat(profile.getBirthDay(), nullValue());
85                 assertThat(profile.getBirthMonth(), nullValue());
86                 assertThat(profile.getBirthYear(), nullValue());
87                 assertThat(profile.getFields(), emptyIterable());
88         }
89
90         private void setupEmptyProfile() {
91                 when(configuration.getStringValue(anyString())).thenReturn(
92                                 new TestValue<String>(null));
93                 when(configuration.getIntValue(anyString())).thenReturn(
94                                 new TestValue<Integer>(null));
95         }
96
97         @Test
98         public void filledProfileWithFieldsIsParsedCorrectly() {
99                 setupFilledProfile();
100                 Profile profile = configurationSoneParser.parseProfile();
101                 assertThat(profile, notNullValue());
102                 assertThat(profile.getFirstName(), is("First"));
103                 assertThat(profile.getMiddleName(), is("M."));
104                 assertThat(profile.getLastName(), is("Last"));
105                 assertThat(profile.getBirthDay(), is(18));
106                 assertThat(profile.getBirthMonth(), is(12));
107                 assertThat(profile.getBirthYear(), is(1976));
108                 final List<Field> fields = profile.getFields();
109                 assertThat(fields, hasSize(2));
110                 assertThat(fields.get(0).getName(), is("Field1"));
111                 assertThat(fields.get(0).getValue(), is("Value1"));
112                 assertThat(fields.get(1).getName(), is("Field2"));
113                 assertThat(fields.get(1).getValue(), is("Value2"));
114         }
115
116         private void setupFilledProfile() {
117                 setupString("Sone/1/Profile/FirstName", "First");
118                 setupString("Sone/1/Profile/MiddleName", "M.");
119                 setupString("Sone/1/Profile/LastName", "Last");
120                 setupInteger("Sone/1/Profile/BirthDay", 18);
121                 setupInteger("Sone/1/Profile/BirthMonth", 12);
122                 setupInteger("Sone/1/Profile/BirthYear", 1976);
123                 setupString("Sone/1/Profile/Fields/0/Name", "Field1");
124                 setupString("Sone/1/Profile/Fields/0/Value", "Value1");
125                 setupString("Sone/1/Profile/Fields/1/Name", "Field2");
126                 setupString("Sone/1/Profile/Fields/1/Value", "Value2");
127                 setupString("Sone/1/Profile/Fields/2/Name", null);
128         }
129
130         private void setupString(String nodeName, String value) {
131                 when(configuration.getStringValue(eq(nodeName))).thenReturn(
132                                 new TestValue<String>(value));
133         }
134
135         private void setupInteger(String nodeName, Integer value) {
136                 when(configuration.getIntValue(eq(nodeName))).thenReturn(
137                                 new TestValue<Integer>(value));
138         }
139
140         @Test
141         public void postsAreParsedCorrectly() {
142                 setupCompletePosts();
143                 PostBuilderFactory postBuilderFactory = createPostBuilderFactory();
144                 Collection<Post> posts =
145                                 configurationSoneParser.parsePosts(postBuilderFactory);
146                 assertThat(posts,
147                                 Matchers.<Post>containsInAnyOrder(
148                                                 isPost("P0", 1000L, "T0", Optional.<String>absent()),
149                                                 isPost("P1", 1001L, "T1",
150                                                                 of("1234567890123456789012345678901234567890123"))));
151         }
152
153         private PostBuilderFactory createPostBuilderFactory() {
154                 PostBuilderFactory postBuilderFactory =
155                                 mock(PostBuilderFactory.class);
156                 when(postBuilderFactory.newPostBuilder()).thenAnswer(
157                                 new Answer<PostBuilder>() {
158                                         @Override
159                                         public PostBuilder answer(InvocationOnMock invocation)
160                                         throws Throwable {
161                                                 return new TestPostBuilder();
162                                         }
163                                 });
164                 return postBuilderFactory;
165         }
166
167         private void setupCompletePosts() {
168                 setupPost("0", "P0", 1000L, "T0", null);
169                 setupPost("1", "P1", 1001L, "T1",
170                                 "1234567890123456789012345678901234567890123");
171                 setupPost("2", null, 0L, null, null);
172         }
173
174         private void setupPost(String postNumber, String postId, long time,
175                         String text, String recipientId) {
176                 setupString("Sone/1/Posts/" + postNumber + "/ID", postId);
177                 setupLong("Sone/1/Posts/" + postNumber + "/Time", time);
178                 setupString("Sone/1/Posts/" + postNumber + "/Text", text);
179                 setupString("Sone/1/Posts/" + postNumber + "/Recipient", recipientId);
180         }
181
182         private void setupLong(String nodeName, Long value) {
183                 when(configuration.getLongValue(eq(nodeName))).thenReturn(
184                                 new TestValue<Long>(value));
185         }
186
187         @Test(expected = InvalidPostFound.class)
188         public void postWithoutTimeIsRecognized() {
189                 setupPostWithoutTime();
190                 configurationSoneParser.parsePosts(createPostBuilderFactory());
191         }
192
193         private void setupPostWithoutTime() {
194                 setupPost("0", "P0", 0L, "T0", null);
195         }
196
197         @Test(expected = InvalidPostFound.class)
198         public void postWithoutTextIsRecognized() {
199                 setupPostWithoutText();
200                 configurationSoneParser.parsePosts(createPostBuilderFactory());
201         }
202
203         private void setupPostWithoutText() {
204                 setupPost("0", "P0", 1000L, null, null);
205         }
206
207         @Test
208         public void postWithInvalidRecipientIdIsRecognized() {
209                 setupPostWithInvalidRecipientId();
210                 Collection<Post> posts = configurationSoneParser.parsePosts(
211                                 createPostBuilderFactory());
212                 assertThat(posts, contains(
213                                 isPost("P0", 1000L, "T0", Optional.<String>absent())));
214         }
215
216         private void setupPostWithInvalidRecipientId() {
217                 setupPost("0", "P0", 1000L, "T0", "123");
218                 setupPost("1", null, 0L, null, null);
219         }
220
221         @Test
222         public void postRepliesAreParsedCorrectly() {
223                 setupPostReplies();
224                 PostReplyBuilderFactory postReplyBuilderFactory =
225                                 new PostReplyBuilderFactory() {
226                                         @Override
227                                         public PostReplyBuilder newPostReplyBuilder() {
228                                                 return new TestPostReplyBuilder();
229                                         }
230                                 };
231                 Collection<PostReply> postReplies =
232                                 configurationSoneParser.parsePostReplies(
233                                                 postReplyBuilderFactory);
234                 assertThat(postReplies, hasSize(2));
235                 assertThat(postReplies,
236                                 containsInAnyOrder(isPostReply("R0", "P0", 1000L, "T0"),
237                                                 isPostReply("R1", "P1", 1001L, "T1")));
238         }
239
240         private void setupPostReplies() {
241                 setupPostReply("0", "R0", "P0", 1000L, "T0");
242                 setupPostReply("1", "R1", "P1", 1001L, "T1");
243                 setupPostReply("2", null, null, 0L, null);
244         }
245
246         private void setupPostReply(String postReplyNumber, String postReplyId,
247                         String postId, long time, String text) {
248                 setupString("Sone/1/Replies/" + postReplyNumber + "/ID", postReplyId);
249                 setupString("Sone/1/Replies/" + postReplyNumber + "/Post/ID", postId);
250                 setupLong("Sone/1/Replies/" + postReplyNumber + "/Time", time);
251                 setupString("Sone/1/Replies/" + postReplyNumber + "/Text", text);
252         }
253
254         @Test(expected = InvalidPostReplyFound.class)
255         public void missingPostIdIsRecognized() {
256                 setupPostReplyWithMissingPostId();
257                 configurationSoneParser.parsePostReplies(null);
258         }
259
260         private void setupPostReplyWithMissingPostId() {
261                 setupPostReply("0", "R0", null, 1000L, "T0");
262         }
263
264         @Test(expected = InvalidPostReplyFound.class)
265         public void missingPostReplyTimeIsRecognized() {
266                 setupPostReplyWithMissingPostReplyTime();
267                 configurationSoneParser.parsePostReplies(null);
268         }
269
270         private void setupPostReplyWithMissingPostReplyTime() {
271                 setupPostReply("0", "R0", "P0", 0L, "T0");
272         }
273
274         @Test(expected = InvalidPostReplyFound.class)
275         public void missingPostReplyTextIsRecognized() {
276                 setupPostReplyWithMissingPostReplyText();
277                 configurationSoneParser.parsePostReplies(null);
278         }
279
280         private void setupPostReplyWithMissingPostReplyText() {
281                 setupPostReply("0", "R0", "P0", 1000L, null);
282         }
283
284         @Test
285         public void likedPostIdsParsedCorrectly() {
286                 setupLikedPostIds();
287                 Set<String> likedPostIds =
288                                 configurationSoneParser.parseLikedPostIds();
289                 assertThat(likedPostIds, containsInAnyOrder("P1", "P2", "P3"));
290         }
291
292         private void setupLikedPostIds() {
293                 setupString("Sone/1/Likes/Post/0/ID", "P1");
294                 setupString("Sone/1/Likes/Post/1/ID", "P2");
295                 setupString("Sone/1/Likes/Post/2/ID", "P3");
296                 setupString("Sone/1/Likes/Post/3/ID", null);
297         }
298
299         @Test
300         public void likedPostReplyIdsAreParsedCorrectly() {
301                 setupLikedPostReplyIds();
302                 Set<String> likedPostReplyIds =
303                                 configurationSoneParser.parseLikedPostReplyIds();
304                 assertThat(likedPostReplyIds, containsInAnyOrder("R1", "R2", "R3"));
305         }
306
307         private void setupLikedPostReplyIds() {
308                 setupString("Sone/1/Likes/Reply/0/ID", "R1");
309                 setupString("Sone/1/Likes/Reply/1/ID", "R2");
310                 setupString("Sone/1/Likes/Reply/2/ID", "R3");
311                 setupString("Sone/1/Likes/Reply/3/ID", null);
312         }
313
314         @Test
315         public void friendsAreParsedCorrectly() {
316                 setupFriends();
317                 Set<String> friends = configurationSoneParser.parseFriends();
318                 assertThat(friends, containsInAnyOrder("F1", "F2", "F3"));
319         }
320
321         private void setupFriends() {
322                 setupString("Sone/1/Friends/0/ID", "F1");
323                 setupString("Sone/1/Friends/1/ID", "F2");
324                 setupString("Sone/1/Friends/2/ID", "F3");
325                 setupString("Sone/1/Friends/3/ID", null);
326         }
327
328         @Test
329         public void topLevelAlbumsAreParsedCorrectly() {
330                 setupTopLevelAlbums();
331                 AlbumBuilderFactory albumBuilderFactory = createAlbumBuilderFactory();
332                 List<Album> topLevelAlbums =
333                                 configurationSoneParser.parseTopLevelAlbums(
334                                                 albumBuilderFactory);
335                 assertThat(topLevelAlbums, hasSize(2));
336                 Album firstAlbum = topLevelAlbums.get(0);
337                 assertThat(firstAlbum, isAlbum("A1", null, "T1", "D1", "I1"));
338                 assertThat(firstAlbum.getAlbums(), emptyIterable());
339                 assertThat(firstAlbum.getImages(), emptyIterable());
340                 Album secondAlbum = topLevelAlbums.get(1);
341                 assertThat(secondAlbum, isAlbum("A2", null, "T2", "D2", null));
342                 assertThat(secondAlbum.getAlbums(), hasSize(1));
343                 assertThat(secondAlbum.getImages(), emptyIterable());
344                 Album thirdAlbum = secondAlbum.getAlbums().get(0);
345                 assertThat(thirdAlbum, isAlbum("A3", "A2", "T3", "D3", "I3"));
346                 assertThat(thirdAlbum.getAlbums(), emptyIterable());
347                 assertThat(thirdAlbum.getImages(), emptyIterable());
348         }
349
350         private void setupTopLevelAlbums() {
351                 setupAlbum(0, "A1", null, "T1", "D1", "I1");
352                 setupAlbum(1, "A2", null, "T2", "D2", null);
353                 setupAlbum(2, "A3", "A2", "T3", "D3", "I3");
354                 setupAlbum(3, null, null, null, null, null);
355         }
356
357         private void setupAlbum(int albumNumber, String albumId,
358                         String parentAlbumId,
359                         String title, String description, String imageId) {
360                 final String albumPrefix = "Sone/1/Albums/" + albumNumber;
361                 setupString(albumPrefix + "/ID", albumId);
362                 setupString(albumPrefix + "/Title", title);
363                 setupString(albumPrefix + "/Description", description);
364                 setupString(albumPrefix + "/Parent", parentAlbumId);
365                 setupString(albumPrefix + "/AlbumImage", imageId);
366         }
367
368         private AlbumBuilderFactory createAlbumBuilderFactory() {
369                 AlbumBuilderFactory albumBuilderFactory =
370                                 mock(AlbumBuilderFactory.class);
371                 when(albumBuilderFactory.newAlbumBuilder()).thenAnswer(
372                                 new Answer<AlbumBuilder>() {
373                                         @Override
374                                         public AlbumBuilder answer(InvocationOnMock invocation) {
375                                                 return new TestAlbumBuilder();
376                                         }
377                                 });
378                 return albumBuilderFactory;
379         }
380
381         @Test(expected = InvalidAlbumFound.class)
382         public void albumWithInvalidTitleIsRecognized() {
383                 setupAlbum(0, "A1", null, null, "D1", "I1");
384                 configurationSoneParser.parseTopLevelAlbums(
385                                 createAlbumBuilderFactory());
386         }
387
388         @Test(expected = InvalidAlbumFound.class)
389         public void albumWithInvalidDescriptionIsRecognized() {
390                 setupAlbum(0, "A1", null, "T1", null, "I1");
391                 configurationSoneParser.parseTopLevelAlbums(
392                                 createAlbumBuilderFactory());
393         }
394
395         @Test(expected = InvalidParentAlbumFound.class)
396         public void albumWithInvalidParentIsRecognized() {
397                 setupAlbum(0, "A1", "A0", "T1", "D1", "I1");
398                 configurationSoneParser.parseTopLevelAlbums(
399                                 createAlbumBuilderFactory());
400         }
401
402         private static class TestValue<T> implements Value<T> {
403
404                 private final AtomicReference<T> value = new AtomicReference<T>();
405
406                 public TestValue(T originalValue) {
407                         value.set(originalValue);
408                 }
409
410                 @Override
411                 public T getValue() throws ConfigurationException {
412                         return value.get();
413                 }
414
415                 @Override
416                 public T getValue(T defaultValue) {
417                         final T realValue = value.get();
418                         return (realValue != null) ? realValue : defaultValue;
419                 }
420
421                 @Override
422                 public void setValue(T newValue) throws ConfigurationException {
423                         value.set(newValue);
424                 }
425
426         }
427
428         private static class TestPostBuilder implements PostBuilder {
429
430                 private final Post post = mock(Post.class);
431                 private String recipientId = null;
432
433                 @Override
434                 public PostBuilder copyPost(Post post) throws NullPointerException {
435                         return this;
436                 }
437
438                 @Override
439                 public PostBuilder from(String senderId) {
440                         final Sone sone = mock(Sone.class);
441                         when(sone.getId()).thenReturn(senderId);
442                         when(post.getSone()).thenReturn(sone);
443                         return this;
444                 }
445
446                 @Override
447                 public PostBuilder randomId() {
448                         when(post.getId()).thenReturn(randomUUID().toString());
449                         return this;
450                 }
451
452                 @Override
453                 public PostBuilder withId(String id) {
454                         when(post.getId()).thenReturn(id);
455                         return this;
456                 }
457
458                 @Override
459                 public PostBuilder currentTime() {
460                         when(post.getTime()).thenReturn(currentTimeMillis());
461                         return this;
462                 }
463
464                 @Override
465                 public PostBuilder withTime(long time) {
466                         when(post.getTime()).thenReturn(time);
467                         return this;
468                 }
469
470                 @Override
471                 public PostBuilder withText(String text) {
472                         when(post.getText()).thenReturn(text);
473                         return this;
474                 }
475
476                 @Override
477                 public PostBuilder to(String recipientId) {
478                         this.recipientId = recipientId;
479                         return this;
480                 }
481
482                 @Override
483                 public Post build() throws IllegalStateException {
484                         when(post.getRecipientId()).thenReturn(fromNullable(recipientId));
485                         return post;
486                 }
487
488         }
489
490         private static class TestPostReplyBuilder implements PostReplyBuilder {
491
492                 private final PostReply postReply = mock(PostReply.class);
493
494                 @Override
495                 public PostReplyBuilder to(String postId) {
496                         when(postReply.getPostId()).thenReturn(postId);
497                         return this;
498                 }
499
500                 @Override
501                 public PostReply build() throws IllegalStateException {
502                         return postReply;
503                 }
504
505                 @Override
506                 public PostReplyBuilder randomId() {
507                         when(postReply.getId()).thenReturn(randomUUID().toString());
508                         return this;
509                 }
510
511                 @Override
512                 public PostReplyBuilder withId(String id) {
513                         when(postReply.getId()).thenReturn(id);
514                         return this;
515                 }
516
517                 @Override
518                 public PostReplyBuilder from(String senderId) {
519                         Sone sone = mock(Sone.class);
520                         when(sone.getId()).thenReturn(senderId);
521                         when(postReply.getSone()).thenReturn(sone);
522                         return this;
523                 }
524
525                 @Override
526                 public PostReplyBuilder currentTime() {
527                         when(postReply.getTime()).thenReturn(currentTimeMillis());
528                         return this;
529                 }
530
531                 @Override
532                 public PostReplyBuilder withTime(long time) {
533                         when(postReply.getTime()).thenReturn(time);
534                         return this;
535                 }
536
537                 @Override
538                 public PostReplyBuilder withText(String text) {
539                         when(postReply.getText()).thenReturn(text);
540                         return this;
541                 }
542
543         }
544
545         private static class TestAlbumBuilder implements AlbumBuilder {
546
547                 private final Album album = mock(Album.class);
548                 private final List<Album> albums = new ArrayList<Album>();
549                 private final List<Image> images = new ArrayList<Image>();
550                 private Album parentAlbum;
551                 private String title;
552                 private String description;
553                 private String imageId;
554
555                 public TestAlbumBuilder() {
556                         when(album.getTitle()).thenAnswer(new Answer<String>() {
557                                 @Override
558                                 public String answer(InvocationOnMock invocation) {
559                                         return title;
560                                 }
561                         });
562                         when(album.getDescription()).thenAnswer(new Answer<String>() {
563                                 @Override
564                                 public String answer(InvocationOnMock invocation) {
565                                         return description;
566                                 }
567                         });
568                         when(album.getAlbumImage()).thenAnswer(new Answer<Image>() {
569                                 @Override
570                                 public Image answer(InvocationOnMock invocation) {
571                                         if (imageId == null) {
572                                                 return null;
573                                         }
574                                         Image image = mock(Image.class);
575                                         when(image.getId()).thenReturn(imageId);
576                                         return image;
577                                 }
578                         });
579                         when(album.getAlbums()).thenReturn(albums);
580                         when(album.getImages()).thenReturn(images);
581                         doAnswer(new Answer<Void>() {
582                                 @Override
583                                 public Void answer(InvocationOnMock invocation) {
584                                         albums.add((Album) invocation.getArguments()[0]);
585                                         ((Album) invocation.getArguments()[0]).setParent(album);
586                                         return null;
587                                 }
588                         }).when(album).addAlbum(any(Album.class));
589                         doAnswer(new Answer<Void>() {
590                                 @Override
591                                 public Void answer(InvocationOnMock invocation) {
592                                         images.add((Image) invocation.getArguments()[0]);
593                                         return null;
594                                 }
595                         }).when(album).addImage(any(Image.class));
596                         doAnswer(new Answer<Void>() {
597                                 @Override
598                                 public Void answer(InvocationOnMock invocation) {
599                                         parentAlbum = (Album) invocation.getArguments()[0];
600                                         return null;
601                                 }
602                         }).when(album).setParent(any(Album.class));
603                         when(album.getParent()).thenAnswer(new Answer<Album>() {
604                                 @Override
605                                 public Album answer(InvocationOnMock invocation) {
606                                         return parentAlbum;
607                                 }
608                         });
609                         when(album.modify()).thenReturn(new Modifier() {
610                                 @Override
611                                 public Modifier setTitle(String title) {
612                                         TestAlbumBuilder.this.title = title;
613                                         return this;
614                                 }
615
616                                 @Override
617                                 public Modifier setDescription(String description) {
618                                         TestAlbumBuilder.this.description = description;
619                                         return this;
620                                 }
621
622                                 @Override
623                                 public Modifier setAlbumImage(String imageId) {
624                                         TestAlbumBuilder.this.imageId = imageId;
625                                         return this;
626                                 }
627
628                                 @Override
629                                 public Album update() throws IllegalStateException {
630                                         return album;
631                                 }
632                         });
633                 }
634
635                 @Override
636                 public AlbumBuilder randomId() {
637                         when(album.getId()).thenReturn(randomUUID().toString());
638                         return this;
639                 }
640
641                 @Override
642                 public AlbumBuilder withId(String id) {
643                         when(album.getId()).thenReturn(id);
644                         return this;
645                 }
646
647                 @Override
648                 public AlbumBuilder by(Sone sone) {
649                         when(album.getSone()).thenReturn(sone);
650                         return this;
651                 }
652
653                 @Override
654                 public Album build() throws IllegalStateException {
655                         return album;
656                 }
657
658         }
659
660 }