1 package net.pterodactylus.sone.core;
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;
17 import java.io.InputStream;
18 import java.util.logging.Logger;
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;
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;
46 * Unit test for {@link SoneParser}.
48 * @author <a href="mailto:d.roden@xplosion.de">David Roden</a>
50 public class SoneParserTest {
53 Logger.getLogger("").setLevel(OFF);
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();
61 public SoneParserTest() {
62 Optional<Image> image = mock(Optional.class);
63 when(core.getImage(anyString())).thenReturn(image);
66 @Test(expected = InvalidXml.class)
67 public void verifyThatAnInvalidXmlDocumentIsNotParsed() {
68 soneParser.parseSone(database, originalSone, getXml("invalid-xml"));
72 public void verifyThatAMissingProtocolVersionDoesNotCauseAnError() {
73 soneParser.parseSone(database, originalSone, getXml("missing-protocol-version"));
76 @Test(expected = InvalidProtocolVersion.class)
77 public void verifyThatANegativeProtocolVersionCausesAnError() {
78 soneParser.parseSone(database, originalSone, getXml("negative-protocol-version"));
81 @Test(expected = SoneTooNew.class)
82 public void verifyThatATooLargeProtocolVersionCausesAnError() {
83 soneParser.parseSone(database, originalSone, getXml("too-large-protocol-version"));
86 @Test(expected = MalformedXml.class)
87 public void verifyThatAMissingTimeCausesAnError() {
88 soneParser.parseSone(database, originalSone, getXml("missing-time"));
91 @Test(expected = MalformedTime.class)
92 public void verifyThatAnInvalidTimeCausesAnError() {
93 soneParser.parseSone(database, originalSone, getXml("invalid-time"));
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()));
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()));
112 @Test(expected = MalformedXml.class)
113 public void verifyThatAMissingProfileCausesAnError() {
114 soneParser.parseSone(database, originalSone, getXml("missing-profile"));
117 @Test(expected = MalformedXml.class)
118 public void verifyThatInvalidFieldsCauseAnError() {
119 soneParser.parseSone(database, originalSone, getXml("invalid-field"));
122 @Test(expected = DuplicateField.class)
123 public void verifyThatDuplicateFieldsCauseAnError() {
124 soneParser.parseSone(database, originalSone, getXml("duplicate-field"));
127 @Test(expected = InvalidAvatarId.class)
128 public void verifyThatAnInvalidAvatarIdCausesAnError() {
129 soneParser.parseSone(database, originalSone, getXml("invalid-avatar"));
133 public void verifyThatMissingPostsDoNotCauseAnError() {
134 soneParser.parseSone(database, originalSone, getXml("missing-posts"));
137 @Test(expected = MalformedXml.class)
138 public void verifyThatInvalidPostsCauseAnError() {
139 soneParser.parseSone(database, originalSone, getXml("invalid-posts"));
142 @Test(expected = MalformedTime.class)
143 public void verifyThatAMalformedTimeCausesAnError() {
144 soneParser.parseSone(database, originalSone, getXml("invalid-post-time"));
148 public void verifyThatMissingRepliesDoNotCauseAnError() {
149 soneParser.parseSone(database, originalSone, getXml("missing-replies"));
152 @Test(expected = MalformedXml.class)
153 public void verifyThatInvalidRepliesCauseAnError() {
154 soneParser.parseSone(database, originalSone, getXml("invalid-replies"));
157 @Test(expected = MalformedTime.class)
158 public void verifyThatAMalformedReplyTimeCausesAnError() {
159 soneParser.parseSone(database, originalSone, getXml("invalid-reply-time"));
163 public void verifyThatAMissingPostLikesSectionDoesNotCauseAnError() {
164 soneParser.parseSone(database, originalSone, getXml("missing-post-likes"));
168 public void verifyThatAMissingReplyLikesSectionDoesNotCauseAnError() {
169 soneParser.parseSone(database, originalSone, getXml("missing-reply-likes"));
173 public void verifyThatMissingAlbumsSectionDoNotCauseAnError() {
174 soneParser.parseSone(database, originalSone, getXml("missing-albums"));
177 @Test(expected = MalformedXml.class)
178 public void verifyThatAnInvalidAlbumCausesAnError() {
179 soneParser.parseSone(database, originalSone, getXml("invalid-album"));
182 @Test(expected = InvalidParentAlbum.class)
183 public void verifyThatAnInvalidParentAlbumCausesAnError() {
184 soneParser.parseSone(database, originalSone, getXml("invalid-parent-album"));
187 @Test(expected = MalformedXml.class)
188 public void verifyThatAnInvalidImageCausesAnError() {
189 soneParser.parseSone(database, originalSone, getXml("invalid-image"));
192 @Test(expected = MalformedDimension.class)
193 public void verifyThatInvalidImageDimensionsCauseAnError() {
194 soneParser.parseSone(database, originalSone, getXml("invalid-image-dimensions"));
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());
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")
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!")
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.")
238 assertThat(sone.getLikedPostIds(), containsInAnyOrder(
239 "bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3",
240 "305d85e6-3adc-11e3-be45-8b53dd91f0af"
242 assertThat(sone.getLikedReplyIds(), containsInAnyOrder(
243 "f09fa448-3adb-11e3-a783-ab54a11aacc4",
244 "3ba28960-3adc-11e3-93c7-6713d170f44c"
248 private Matcher<PostReply> postReplyMatcher(final String id, final String postId, final long time, final String text) {
249 return new TypeSafeMatcher<PostReply>() {
251 protected boolean matchesSafely(PostReply postReply) {
252 return postReply.getId().equals(id) && postReply.getPostId().equals(postId) && (postReply.getTime() == time) && postReply.getText().equals(text);
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(")");
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(")");
275 private Matcher<Post> postMatcher(final String id, final String recipient, final long time, final String text) {
276 return new TypeSafeMatcher<Post>() {
278 protected boolean matchesSafely(Post post) {
279 return post.getId().equals(id) && equal(post.getRecipientId().orNull(), recipient) && (post.getTime() == time) && post.getText().equals(text);
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(")");
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(")");
302 private Matcher<Field> fieldMatcher(final String name, final String value) {
303 return new TypeSafeMatcher<Field>() {
305 protected boolean matchesSafely(Field field) {
306 return field.getName().equals(name) && field.getValue().equals(value);
310 public void describeTo(Description description) {
311 description.appendText("field named ").appendValue(name).appendText(" with value ").appendValue(value);
315 protected void describeMismatchSafely(Field field, Description mismatchDescription) {
316 mismatchDescription.appendText("field named ").appendValue(field.getName()).appendText(" with value ").appendValue(field.getValue());
321 private InputStream getXml(String name) {
322 return getClass().getResourceAsStream(format("/sone-parser/%s.xml", name));