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