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