Verify that the avatar ID belongs to an image of the Sone.
[Sone.git] / src / test / java / net / pterodactylus / sone / core / SoneParserTest.java
1 package net.pterodactylus.sone.core;
2
3 import static com.google.common.base.Objects.equal;
4 import static java.lang.String.format;
5 import static java.util.logging.Level.OFF;
6 import static org.hamcrest.MatcherAssert.assertThat;
7 import static org.hamcrest.Matchers.containsInAnyOrder;
8 import static org.hamcrest.Matchers.empty;
9 import static org.hamcrest.Matchers.is;
10 import static org.hamcrest.Matchers.notNullValue;
11 import static org.hamcrest.Matchers.nullValue;
12 import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
13 import static org.mockito.Matchers.anyString;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.when;
16
17 import java.io.InputStream;
18 import java.util.logging.Logger;
19
20 import net.pterodactylus.sone.core.SoneParser.DuplicateField;
21 import net.pterodactylus.sone.core.SoneParser.InvalidAvatarId;
22 import net.pterodactylus.sone.core.SoneParser.InvalidParentAlbum;
23 import net.pterodactylus.sone.core.SoneParser.InvalidProtocolVersion;
24 import net.pterodactylus.sone.core.SoneParser.InvalidXml;
25 import net.pterodactylus.sone.core.SoneParser.MalformedDimension;
26 import net.pterodactylus.sone.core.SoneParser.MalformedTime;
27 import net.pterodactylus.sone.core.SoneParser.MalformedXml;
28 import net.pterodactylus.sone.core.SoneParser.SoneTooNew;
29 import net.pterodactylus.sone.data.Client;
30 import net.pterodactylus.sone.data.Image;
31 import net.pterodactylus.sone.data.Post;
32 import net.pterodactylus.sone.data.PostReply;
33 import net.pterodactylus.sone.data.Profile.Field;
34 import net.pterodactylus.sone.data.Sone;
35 import net.pterodactylus.sone.database.Database;
36 import net.pterodactylus.sone.database.SoneBuilder.SoneCreated;
37 import net.pterodactylus.sone.database.memory.MemoryDatabase;
38
39 import com.google.common.base.Optional;
40 import org.hamcrest.Description;
41 import org.hamcrest.Matcher;
42 import org.hamcrest.TypeSafeMatcher;
43 import org.junit.Test;
44
45 /**
46  * Unit test for {@link SoneParser}.
47  *
48  * @author <a href="mailto:d.roden@xplosion.de">David Roden</a>
49  */
50 public class SoneParserTest {
51
52         static {
53                 Logger.getLogger("").setLevel(OFF);
54         }
55
56         private final Core core = mock(Core.class);
57         private final Database database = new MemoryDatabase(null);
58         private final Sone originalSone = database.newSoneBuilder().by("test").using(new Client("TestClient", "1.0")).build(Optional.<SoneCreated>absent());
59         private final SoneParser soneParser = new SoneParser();
60
61         public SoneParserTest() {
62                 Optional<Image> image = mock(Optional.class);
63                 when(core.getImage(anyString())).thenReturn(image);
64         }
65
66         @Test(expected = InvalidXml.class)
67         public void verifyThatAnInvalidXmlDocumentIsNotParsed() {
68                 soneParser.parseSone(database, originalSone, getXml("invalid-xml"));
69         }
70
71         @Test
72         public void verifyThatAMissingProtocolVersionDoesNotCauseAnError() {
73                 soneParser.parseSone(database, originalSone, getXml("missing-protocol-version"));
74         }
75
76         @Test(expected = InvalidProtocolVersion.class)
77         public void verifyThatANegativeProtocolVersionCausesAnError() {
78                 soneParser.parseSone(database, originalSone, getXml("negative-protocol-version"));
79         }
80
81         @Test(expected = SoneTooNew.class)
82         public void verifyThatATooLargeProtocolVersionCausesAnError() {
83                 soneParser.parseSone(database, originalSone, getXml("too-large-protocol-version"));
84         }
85
86         @Test(expected = MalformedXml.class)
87         public void verifyThatAMissingTimeCausesAnError() {
88                 soneParser.parseSone(database, originalSone, getXml("missing-time"));
89         }
90
91         @Test(expected = MalformedTime.class)
92         public void verifyThatAnInvalidTimeCausesAnError() {
93                 soneParser.parseSone(database, originalSone, getXml("invalid-time"));
94         }
95
96         @Test
97         public void verifyThatAMissingClientCausesTheOriginalClientToBeUsed() {
98                 Sone sone = soneParser.parseSone(database, originalSone, getXml("missing-client"));
99                 assertThat(sone, notNullValue());
100                 assertThat(sone.getClient(), notNullValue());
101                 assertThat(sone.getClient(), is(originalSone.getClient()));
102         }
103
104         @Test
105         public void verifyThatAnInvalidClientCausesTheOriginalClientToBeUsed() {
106                 Sone sone = soneParser.parseSone(database, originalSone, getXml("invalid-client"));
107                 assertThat(sone, notNullValue());
108                 assertThat(sone.getClient(), notNullValue());
109                 assertThat(sone.getClient(), is(originalSone.getClient()));
110         }
111
112         @Test(expected = MalformedXml.class)
113         public void verifyThatAMissingProfileCausesAnError() {
114                 soneParser.parseSone(database, originalSone, getXml("missing-profile"));
115         }
116
117         @Test(expected = MalformedXml.class)
118         public void verifyThatInvalidFieldsCauseAnError() {
119                 soneParser.parseSone(database, originalSone, getXml("invalid-field"));
120         }
121
122         @Test(expected = DuplicateField.class)
123         public void verifyThatDuplicateFieldsCauseAnError() {
124                 soneParser.parseSone(database, originalSone, getXml("duplicate-field"));
125         }
126
127         @Test(expected = InvalidAvatarId.class)
128         public void verifyThatAnInvalidAvatarIdCausesAnError() {
129                 soneParser.parseSone(database, originalSone, getXml("invalid-avatar"));
130         }
131
132         @Test
133         public void verifyThatMissingPostsDoNotCauseAnError() {
134                 soneParser.parseSone(database, originalSone, getXml("missing-posts"));
135         }
136
137         @Test(expected = MalformedXml.class)
138         public void verifyThatInvalidPostsCauseAnError() {
139                 soneParser.parseSone(database, originalSone, getXml("invalid-posts"));
140         }
141
142         @Test(expected = MalformedTime.class)
143         public void verifyThatAMalformedTimeCausesAnError() {
144                 soneParser.parseSone(database, originalSone, getXml("invalid-post-time"));
145         }
146
147         @Test
148         public void verifyThatMissingRepliesDoNotCauseAnError() {
149                 soneParser.parseSone(database, originalSone, getXml("missing-replies"));
150         }
151
152         @Test(expected = MalformedXml.class)
153         public void verifyThatInvalidRepliesCauseAnError() {
154                 soneParser.parseSone(database, originalSone, getXml("invalid-replies"));
155         }
156
157         @Test(expected = MalformedTime.class)
158         public void verifyThatAMalformedReplyTimeCausesAnError() {
159                 soneParser.parseSone(database, originalSone, getXml("invalid-reply-time"));
160         }
161
162         @Test
163         public void verifyThatAMissingPostLikesSectionDoesNotCauseAnError() {
164                 soneParser.parseSone(database, originalSone, getXml("missing-post-likes"));
165         }
166
167         @Test
168         public void verifyThatAMissingReplyLikesSectionDoesNotCauseAnError() {
169                 soneParser.parseSone(database, originalSone, getXml("missing-reply-likes"));
170         }
171
172         @Test
173         public void verifyThatMissingAlbumsSectionDoNotCauseAnError() {
174                 soneParser.parseSone(database, originalSone, getXml("missing-albums"));
175         }
176
177         @Test(expected = MalformedXml.class)
178         public void verifyThatAnInvalidAlbumCausesAnError() {
179                 soneParser.parseSone(database, originalSone, getXml("invalid-album"));
180         }
181
182         @Test(expected = InvalidParentAlbum.class)
183         public void verifyThatAnInvalidParentAlbumCausesAnError() {
184                 soneParser.parseSone(database, originalSone, getXml("invalid-parent-album"));
185         }
186
187         @Test(expected = MalformedXml.class)
188         public void verifyThatAnInvalidImageCausesAnError() {
189                 soneParser.parseSone(database, originalSone, getXml("invalid-image"));
190         }
191
192         @Test(expected = MalformedDimension.class)
193         public void verifyThatInvalidImageDimensionsCauseAnError() {
194                 soneParser.parseSone(database, originalSone, getXml("invalid-image-dimensions"));
195         }
196
197         @Test
198         public void verifyThatAnEmptyProfileIsParsedWithoutError() {
199                 Sone sone = soneParser.parseSone(database, originalSone, getXml("empty-profile"));
200                 assertThat(sone.getProfile().getFirstName(), nullValue());
201                 assertThat(sone.getProfile().getMiddleName(), nullValue());
202                 assertThat(sone.getProfile().getLastName(), nullValue());
203                 assertThat(sone.getProfile().getBirthYear(), nullValue());
204                 assertThat(sone.getProfile().getBirthMonth(), nullValue());
205                 assertThat(sone.getProfile().getBirthDay(), nullValue());
206                 assertThat(sone.getProfile().getAvatar(), nullValue());
207                 assertThat(sone.getProfile().getFields(), empty());
208         }
209
210         @Test
211         public void verifyThatTheCreatedSoneMeetsAllExpectations() {
212                 Sone sone = soneParser.parseSone(database, originalSone, getXml("complete"));
213                 assertThat(sone, notNullValue());
214                 assertThat(sone.getTime(), is(1382419919000L));
215                 assertThat(sone.getClient(), notNullValue());
216                 assertThat(sone.getClient().getName(), is("Sone"));
217                 assertThat(sone.getClient().getVersion(), is("0.8.7"));
218                 assertThat(sone.getProfile(), notNullValue());
219                 assertThat(sone.getProfile().getFirstName(), is("First"));
220                 assertThat(sone.getProfile().getMiddleName(), is("M."));
221                 assertThat(sone.getProfile().getLastName(), is("Last"));
222                 assertThat(sone.getProfile().getBirthYear(), is(2013));
223                 assertThat(sone.getProfile().getBirthMonth(), is(10));
224                 assertThat(sone.getProfile().getBirthDay(), is(22));
225                 assertThat(sone.getProfile().getAvatar(), is("96431abe-3add-11e3-8a46-67047503bf6d"));
226                 assertThat(sone.getProfile().getFields(), contains(
227                                 fieldMatcher("Field1", "Value1"),
228                                 fieldMatcher("Field2", "Value2")
229                 ));
230                 assertThat(sone.getPosts(), contains(
231                                 postMatcher("d8c9586e-3adb-11e3-bb31-171fc040e645", "0rpD4gL8mszav2trndhIdKIxvKUCNAe2kjA3dLV8CVU", 1382420181000L, "Hello, User!"),
232                                 postMatcher("bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3", null, 1382420140000L, "Hello, World!")
233                 ));
234                 assertThat(sone.getReplies(), containsInAnyOrder(
235                                 postReplyMatcher("f09fa448-3adb-11e3-a783-ab54a11aacc4", "bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3", 1382420224000L, "Talking to myself."),
236                                 postReplyMatcher("0a376440-3adc-11e3-8f45-c7cc157436a5", "11ebe86e-3adc-11e3-b7b9-7f2c88018a33", 1382420271000L, "Talking to somebody I can't see.")
237                 ));
238                 assertThat(sone.getLikedPostIds(), containsInAnyOrder(
239                                 "bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3",
240                                 "305d85e6-3adc-11e3-be45-8b53dd91f0af"
241                 ));
242                 assertThat(sone.getLikedReplyIds(), containsInAnyOrder(
243                                 "f09fa448-3adb-11e3-a783-ab54a11aacc4",
244                                 "3ba28960-3adc-11e3-93c7-6713d170f44c"
245                 ));
246         }
247
248         private Matcher<PostReply> postReplyMatcher(final String id, final String postId, final long time, final String text) {
249                 return new TypeSafeMatcher<PostReply>() {
250                         @Override
251                         protected boolean matchesSafely(PostReply postReply) {
252                                 return postReply.getId().equals(id) && postReply.getPostId().equals(postId) && (postReply.getTime() == time) && postReply.getText().equals(text);
253                         }
254
255                         @Override
256                         public void describeTo(Description description) {
257                                 description.appendText("PostReply(")
258                                                 .appendValue(id).appendText(", ")
259                                                 .appendValue(postId).appendText(", ")
260                                                 .appendValue(time).appendText(", ")
261                                                 .appendValue(text).appendText(")");
262                         }
263
264                         @Override
265                         protected void describeMismatchSafely(PostReply postReply, Description mismatchDescription) {
266                                 mismatchDescription.appendText("PostReply(")
267                                                 .appendValue(postReply.getId()).appendText(", ")
268                                                 .appendValue(postReply.getPostId()).appendText(", ")
269                                                 .appendValue(postReply.getTime()).appendText(", ")
270                                                 .appendValue(postReply.getText()).appendText(")");
271                         }
272                 };
273         }
274
275         private Matcher<Post> postMatcher(final String id, final String recipient, final long time, final String text) {
276                 return new TypeSafeMatcher<Post>() {
277                         @Override
278                         protected boolean matchesSafely(Post post) {
279                                 return post.getId().equals(id) && equal(post.getRecipientId().orNull(), recipient) && (post.getTime() == time) && post.getText().equals(text);
280                         }
281
282                         @Override
283                         public void describeTo(Description description) {
284                                 description.appendText("Post(")
285                                                 .appendValue(id).appendText(", ")
286                                                 .appendValue(recipient).appendText(", ")
287                                                 .appendValue(time).appendText(", ")
288                                                 .appendValue(text).appendText(")");
289                         }
290
291                         @Override
292                         protected void describeMismatchSafely(Post post, Description mismatchDescription) {
293                                 mismatchDescription.appendText("Post(")
294                                                 .appendValue(post.getId()).appendText(", ")
295                                                 .appendValue(post.getRecipientId().orNull()).appendText(", ")
296                                                 .appendValue(post.getTime()).appendText(", ")
297                                                 .appendValue(post.getText()).appendText(")");
298                         }
299                 };
300         }
301
302         private Matcher<Field> fieldMatcher(final String name, final String value) {
303                 return new TypeSafeMatcher<Field>() {
304                         @Override
305                         protected boolean matchesSafely(Field field) {
306                                 return field.getName().equals(name) && field.getValue().equals(value);
307                         }
308
309                         @Override
310                         public void describeTo(Description description) {
311                                 description.appendText("field named ").appendValue(name).appendText(" with value ").appendValue(value);
312                         }
313
314                         @Override
315                         protected void describeMismatchSafely(Field field, Description mismatchDescription) {
316                                 mismatchDescription.appendText("field named ").appendValue(field.getName()).appendText(" with value ").appendValue(field.getValue());
317                         }
318                 };
319         }
320
321         private InputStream getXml(String name) {
322                 return getClass().getResourceAsStream(format("/sone-parser/%s.xml", name));
323         }
324
325 }