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