Remove useless non-null asserts
[Sone.git] / src / test / java / net / pterodactylus / sone / text / SoneTextParserTest.java
1 /*
2  * Sone - SoneTextParserTest.java - Copyright © 2011–2016 David Roden
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.sone.text;
19
20 import static org.hamcrest.MatcherAssert.assertThat;
21 import static org.hamcrest.Matchers.is;
22 import static org.hamcrest.Matchers.isIn;
23 import static org.hamcrest.Matchers.notNullValue;
24
25 import java.io.IOException;
26 import java.util.Collection;
27
28 import net.pterodactylus.sone.data.Post;
29 import net.pterodactylus.sone.data.Sone;
30 import net.pterodactylus.sone.data.impl.IdOnlySone;
31 import net.pterodactylus.sone.database.PostProvider;
32 import net.pterodactylus.sone.database.SoneProvider;
33
34 import com.google.common.base.Function;
35 import com.google.common.base.Optional;
36 import org.junit.Test;
37
38 /**
39  * JUnit test case for {@link SoneTextParser}.
40  *
41  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
42  */
43 public class SoneTextParserTest {
44
45         private final SoneTextParser soneTextParser = new SoneTextParser(null, null);
46
47         @SuppressWarnings("static-method")
48         @Test
49         public void testPlainText() throws IOException {
50                 /* check basic operation. */
51                 Iterable<Part> parts = soneTextParser.parse("Test.", null);
52                 assertThat("Part Text", convertText(parts, PlainTextPart.class), is("Test."));
53
54                 /* check empty lines at start and end. */
55                 parts = soneTextParser.parse("\nTest.\n\n", null);
56                 assertThat("Part Text", convertText(parts, PlainTextPart.class), is("Test."));
57
58                 /* check duplicate empty lines in the text. */
59                 parts = soneTextParser.parse("\nTest.\n\n\nTest.", null);
60                 assertThat("Part Text", convertText(parts, PlainTextPart.class), is("Test.\n\nTest."));
61         }
62
63         @Test
64         public void consecutiveLinesAreSeparatedByLinefeed() {
65                 Iterable<Part> parts = soneTextParser.parse("Text.\nText", null);
66                 assertThat("Part Text", convertText(parts), is("Text.\nText"));
67         }
68
69         @Test
70         public void freenetLinksHaveTheFreenetPrefixRemoved() {
71                 Iterable<Part> parts = soneTextParser.parse("freenet:KSK@gpl.txt", null);
72                 assertThat("Part Text", convertText(parts), is("[KSK@gpl.txt|gpl.txt|gpl.txt]"));
73         }
74
75         @Test
76         public void onlyTheFirstItemInALineIsPrefixedWithALineBreak() {
77                 Iterable<Part> parts = soneTextParser.parse("Text.\nKSK@gpl.txt and KSK@gpl.txt", null);
78                 assertThat("Part Text", convertText(parts), is("Text.\n[KSK@gpl.txt|gpl.txt|gpl.txt] and [KSK@gpl.txt|gpl.txt|gpl.txt]"));
79         }
80
81         @Test
82         public void soneLinkWithTooShortSoneIdIsRenderedAsPlainText() {
83                 Iterable<Part> parts = soneTextParser.parse("sone://too-short", null);
84                 assertThat("Part Text", convertText(parts), is("sone://too-short"));
85         }
86
87         @Test
88         public void soneLinkIsRenderedCorrectlyIfSoneIsNotPresent() {
89                 SoneTextParser parser = new SoneTextParser(new AbsentSoneProvider(), null);
90                 Iterable<Part> parts = parser.parse("sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU", null);
91                 assertThat("Part Text", convertText(parts), is("[Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU]"));
92         }
93
94         @Test
95         public void postLinkIsRenderedAsPlainTextIfPostIdIsTooShort() {
96                 Iterable<Part> parts = soneTextParser.parse("post://too-short", null);
97                 assertThat("Part Text", convertText(parts), is("post://too-short"));
98         }
99
100         @Test
101         public void postLinkIsRenderedCorrectlyIfPostIsPresent() {
102                 SoneTextParser parser = new SoneTextParser(null, new TestPostProvider());
103                 Iterable<Part> parts = parser.parse("post://f3757817-b45a-497a-803f-9c5aafc10dc6", null);
104                 assertThat("Part Text", convertText(parts), is("[Post|f3757817-b45a-497a-803f-9c5aafc10dc6|text]"));
105         }
106
107         @Test
108         public void postLinkIsRenderedAsPlainTextIfPostIsAbsent() {
109                 SoneTextParser parser = new SoneTextParser(null, new AbsentPostProvider());
110                 Iterable<Part> parts = parser.parse("post://f3757817-b45a-497a-803f-9c5aafc10dc6", null);
111                 assertThat("Part Text", convertText(parts), is("post://f3757817-b45a-497a-803f-9c5aafc10dc6"));
112         }
113
114         @Test
115         public void nameOfFreenetLinkDoesNotContainUrlParameters() {
116                 Iterable<Part> parts = soneTextParser.parse("KSK@gpl.txt?max-size=12345", null);
117                 assertThat("Part Text", convertText(parts), is("[KSK@gpl.txt?max-size=12345|gpl.txt|gpl.txt]"));
118         }
119
120         @Test
121         public void trailingSlashInFreenetLinkIsRemovedForName() {
122                 Iterable<Part> parts = soneTextParser.parse("KSK@gpl.txt/", null);
123                 assertThat("Part Text", convertText(parts), is("[KSK@gpl.txt/|gpl.txt|gpl.txt]"));
124         }
125
126         @Test
127         public void lastMetaStringOfFreenetLinkIsUsedAsName() {
128                 Iterable<Part> parts = soneTextParser.parse("CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/COPYING", null);
129                 assertThat("Part Text", convertText(parts), is("[CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/COPYING|COPYING|COPYING]"));
130         }
131
132         @Test
133         public void freenetLinkWithoutMetaStringsAndDocNameGetsFirstNineCharactersOfKeyAsName() {
134                 Iterable<Part> parts = soneTextParser.parse("CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8", null);
135                 assertThat("Part Text", convertText(parts), is("[CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8|CHK@qM1nm|CHK@qM1nm]"));
136         }
137
138         @Test
139         public void malformedKeyIsRenderedAsPlainText() {
140                 Iterable<Part> parts = soneTextParser.parse("CHK@qM1nmgU", null);
141                 assertThat("Part Text", convertText(parts), is("CHK@qM1nmgU"));
142         }
143
144         @Test
145         public void httpsLinkHasItsPathsShortened() {
146                 Iterable<Part> parts = soneTextParser.parse("https://test.test/some-long-path/file.txt", null);
147                 assertThat("Part Text", convertText(parts), is("[https://test.test/some-long-path/file.txt|test.test/…/file.txt|test.test/…/file.txt]"));
148         }
149
150         @Test
151         public void httpLinksHaveTheirLastSlashRemoved() {
152                 Iterable<Part> parts = soneTextParser.parse("http://test.test/test/", null);
153                 assertThat("Part Text", convertText(parts), is("[http://test.test/test/|test.test/…|test.test/…]"));
154         }
155
156         @Test
157         public void wwwPrefixIsRemovedForHostnameWithTwoDotsAndNoPath() {
158                 Iterable<Part> parts = soneTextParser.parse("http://www.test.test", null);
159                 assertThat("Part Text", convertText(parts), is("[http://www.test.test|test.test|test.test]"));
160         }
161
162         @Test
163         public void wwwPrefixIsRemovedForHostnameWithTwoDotsAndAPath() {
164                 Iterable<Part> parts = soneTextParser.parse("http://www.test.test/test.html", null);
165                 assertThat("Part Text", convertText(parts), is("[http://www.test.test/test.html|test.test/test.html|test.test/test.html]"));
166         }
167
168         @Test
169         public void hostnameIsKeptIntactIfNotBeginningWithWww() {
170                 Iterable<Part> parts = soneTextParser.parse("http://test.test.test/test.html", null);
171                 assertThat("Part Text", convertText(parts), is("[http://test.test.test/test.html|test.test.test/test.html|test.test.test/test.html]"));
172         }
173
174         @Test
175         public void hostnameWithOneDotButNoSlashIsKeptIntact() {
176                 Iterable<Part> parts = soneTextParser.parse("http://test.test", null);
177                 assertThat("Part Text", convertText(parts), is("[http://test.test|test.test|test.test]"));
178         }
179
180         @Test
181         public void urlParametersAreRemovedForHttpLinks() {
182                 Iterable<Part> parts = soneTextParser.parse("http://test.test?foo=bar", null);
183                 assertThat("Part Text", convertText(parts), is("[http://test.test?foo=bar|test.test|test.test]"));
184         }
185
186         @Test
187         public void emptyStringIsParsedCorrectly() {
188                 Iterable<Part> parts = soneTextParser.parse("", null);
189                 assertThat("Part Text", convertText(parts), is(""));
190         }
191
192         @Test
193         public void linksAreParsedInCorrectOrder() {
194                 Iterable<Part> parts = soneTextParser.parse("KSK@ CHK@", null);
195                 assertThat("Part Text", convertText(parts), is("KSK@ CHK@"));
196         }
197
198         @Test
199         public void sskLinkWithoutContextIsNotTrusted() {
200                 Iterable<Part> parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", null);
201                 assertThat("Part Text", convertText(parts), is("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test|test]"));
202         }
203
204         @Test
205         public void sskLinkWithContextWithoutSoneIsNotTrusted() {
206                 SoneTextParserContext context = new SoneTextParserContext(null);
207                 Iterable<Part> parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", context);
208                 assertThat("Part Text", convertText(parts), is("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test|test]"));
209         }
210
211         @Test
212         public void sskLinkWithContextWithDifferentSoneIsNotTrusted() {
213                 SoneTextParserContext context = new SoneTextParserContext(new IdOnlySone("DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU"));
214                 Iterable<Part> parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", context);
215                 assertThat("Part Text", convertText(parts), is("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test|test]"));
216         }
217
218         @Test
219         public void sskLinkWithContextWithCorrectSoneIsTrusted() {
220                 SoneTextParserContext context = new SoneTextParserContext(new IdOnlySone("qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU"));
221                 Iterable<Part> parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", context);
222                 assertThat("Part Text", convertText(parts), is("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|trusted|test|test]"));
223         }
224
225         @Test
226         public void uskLinkWithContextWithCorrectSoneIsTrusted() {
227                 SoneTextParserContext context = new SoneTextParserContext(new IdOnlySone("qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU"));
228                 Iterable<Part> parts = soneTextParser.parse("USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0", context);
229                 assertThat("Part Text", convertText(parts), is("[USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|trusted|test|test]"));
230         }
231
232         @SuppressWarnings("static-method")
233         @Test
234         public void testKSKLinks() throws IOException {
235                 /* check basic links. */
236                 Iterable<Part> parts = soneTextParser.parse("KSK@gpl.txt", null);
237                 assertThat("Part Text", convertText(parts, FreenetLinkPart.class), is("[KSK@gpl.txt|gpl.txt|gpl.txt]"));
238
239                 /* check embedded links. */
240                 parts = soneTextParser.parse("Link is KSK@gpl.txt\u200b.", null);
241                 assertThat("Part Text", convertText(parts, PlainTextPart.class, FreenetLinkPart.class), is("Link is [KSK@gpl.txt|gpl.txt|gpl.txt]\u200b."));
242
243                 /* check embedded links and line breaks. */
244                 parts = soneTextParser.parse("Link is KSK@gpl.txt\nKSK@test.dat\n", null);
245                 assertThat("Part Text", convertText(parts, PlainTextPart.class, FreenetLinkPart.class), is("Link is [KSK@gpl.txt|gpl.txt|gpl.txt]\n[KSK@test.dat|test.dat|test.dat]"));
246         }
247
248         @SuppressWarnings({ "synthetic-access", "static-method" })
249         @Test
250         public void testEmptyLinesAndSoneLinks() throws IOException {
251                 SoneTextParser soneTextParser = new SoneTextParser(new TestSoneProvider(), null);
252
253                 /* check basic links. */
254                 Iterable<Part> parts = soneTextParser.parse("Some text.\n\nLink to sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU and stuff.", null);
255                 assertThat("Part Text", convertText(parts, PlainTextPart.class, SonePart.class), is("Some text.\n\nLink to [Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU] and stuff."));
256         }
257
258         @SuppressWarnings({ "synthetic-access", "static-method" })
259         @Test
260         public void testEmpyHttpLinks() throws IOException {
261                 SoneTextParser soneTextParser = new SoneTextParser(new TestSoneProvider(), null);
262
263                 /* check empty http links. */
264                 Iterable<Part> parts = soneTextParser.parse("Some text. Empty link: http:// – nice!", null);
265                 assertThat("Part Text", convertText(parts, PlainTextPart.class), is("Some text. Empty link: http:// – nice!"));
266         }
267
268         @Test
269         public void httpLinkWithoutParensEndsAtNextClosingParen() {
270                 Iterable<Part> parts = soneTextParser.parse("Some text (and a link: http://example.sone/abc) – nice!", null);
271                 assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("Some text (and a link: [http://example.sone/abc|example.sone/abc|example.sone/abc]) – nice!"));
272         }
273
274         @Test
275         public void uskLinkEndsAtFirstNonNumericNonSlashCharacterAfterVersionNumber() {
276                 Iterable<Part> parts = soneTextParser.parse("Some link (USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0). Nice", null);
277                 assertThat("Part Text", convertText(parts), is("Some link ([USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|test|test]). Nice"));
278         }
279
280         @Test
281         public void httpLinkWithOpenedAndClosedParensEndsAtNextClosingParen() {
282                 Iterable<Part> parts = soneTextParser.parse("Some text (and a link: http://example.sone/abc_(def)) – nice!", null);
283                 assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("Some text (and a link: [http://example.sone/abc_(def)|example.sone/abc_(def)|example.sone/abc_(def)]) – nice!"));
284         }
285
286         @Test
287         public void punctuationIsIgnoredAtEndOfLinkBeforeWhitespace() {
288                 Iterable<Part> parts = soneTextParser.parse("Some text and a link: http://example.sone/abc. Nice!", null);
289                 assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("Some text and a link: [http://example.sone/abc|example.sone/abc|example.sone/abc]. Nice!"));
290         }
291
292         @Test
293         public void multiplePunctuationCharactersAreIgnoredAtEndOfLinkBeforeWhitespace() {
294                 Iterable<Part> parts = soneTextParser.parse("Some text and a link: http://example.sone/abc... Nice!", null);
295                 assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("Some text and a link: [http://example.sone/abc|example.sone/abc|example.sone/abc]... Nice!"));
296         }
297
298         @Test
299         public void commasAreIgnoredAtEndOfLinkBeforeWhitespace() {
300                 Iterable<Part> parts = soneTextParser.parse("Some text and a link: http://example.sone/abc, nice!", null);
301                 assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("Some text and a link: [http://example.sone/abc|example.sone/abc|example.sone/abc], nice!"));
302         }
303
304         @Test
305         public void exclamationMarksAreIgnoredAtEndOfLinkBeforeWhitespace() {
306                 Iterable<Part> parts = soneTextParser.parse("A link: http://example.sone/abc!", null);
307                 assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("A link: [http://example.sone/abc|example.sone/abc|example.sone/abc]!"));
308         }
309
310         @Test
311         public void questionMarksAreIgnoredAtEndOfLinkBeforeWhitespace() {
312                 Iterable<Part> parts = soneTextParser.parse("A link: http://example.sone/abc?", null);
313                 assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("A link: [http://example.sone/abc|example.sone/abc|example.sone/abc]?"));
314         }
315
316         /**
317          * Converts all given {@link Part}s into a string, validating that the
318          * part’s classes match only the expected classes.
319          *
320          * @param parts
321          *            The parts to convert to text
322          * @param validClasses
323          *            The valid classes; if no classes are given, all classes are
324          *            valid
325          * @return The converted text
326          */
327         private static String convertText(Iterable<Part> parts, Class<?>... validClasses) {
328                 StringBuilder text = new StringBuilder();
329                 for (Part part : parts) {
330                         assertThat("Part", part, notNullValue());
331                         if (validClasses.length != 0) {
332                                 assertThat("Part’s class", part.getClass(), isIn(validClasses));
333                         }
334                         if (part instanceof PlainTextPart) {
335                                 text.append(((PlainTextPart) part).getText());
336                         } else if (part instanceof FreenetLinkPart) {
337                                 FreenetLinkPart freenetLinkPart = (FreenetLinkPart) part;
338                                 text.append('[').append(freenetLinkPart.getLink()).append('|').append(freenetLinkPart.isTrusted() ? "trusted|" : "").append(freenetLinkPart.getTitle()).append('|').append(freenetLinkPart.getText()).append(']');
339                         } else if (part instanceof LinkPart) {
340                                 LinkPart linkPart = (LinkPart) part;
341                                 text.append('[').append(linkPart.getLink()).append('|').append(linkPart.getTitle()).append('|').append(linkPart.getText()).append(']');
342                         } else if (part instanceof SonePart) {
343                                 SonePart sonePart = (SonePart) part;
344                                 text.append("[Sone|").append(sonePart.getSone().getId()).append(']');
345                         } else if (part instanceof PostPart) {
346                                 PostPart postPart = (PostPart) part;
347                                 text.append("[Post|").append(postPart.getPost().getId()).append("|").append(postPart.getPost().getText()).append("]");
348                         }
349                 }
350                 return text.toString();
351         }
352
353         /**
354          * Mock Sone provider.
355          *
356          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
357          */
358         private static class TestSoneProvider implements SoneProvider {
359
360                 @Override
361                 public Function<String, Optional<Sone>> soneLoader() {
362                         return new Function<String, Optional<Sone>>() {
363                                 @Override
364                                 public Optional<Sone> apply(String soneId) {
365                                         return getSone(soneId);
366                                 }
367                         };
368                 }
369
370                 /**
371                  * {@inheritDoc}
372                  */
373                 @Override
374                 public Optional<Sone> getSone(final String soneId) {
375                         return Optional.<Sone>of(new IdOnlySone(soneId));
376                 }
377
378                 /**
379                  * {@inheritDocs}
380                  */
381                 @Override
382                 public Collection<Sone> getSones() {
383                         return null;
384                 }
385
386                 /**
387                  * {@inheritDocs}
388                  */
389                 @Override
390                 public Collection<Sone> getLocalSones() {
391                         return null;
392                 }
393
394                 /**
395                  * {@inheritDocs}
396                  */
397                 @Override
398                 public Collection<Sone> getRemoteSones() {
399                         return null;
400                 }
401
402         }
403
404         private static class AbsentSoneProvider extends TestSoneProvider {
405
406                 @Override
407                 public Optional<Sone> getSone(String soneId) {
408                         return Optional.absent();
409                 }
410
411         }
412
413         private static class TestPostProvider implements PostProvider {
414
415                 @Override
416                 public Optional<Post> getPost(final String postId) {
417                         return Optional.<Post>of(new Post() {
418                                 @Override
419                                 public String getId() {
420                                         return postId;
421                                 }
422
423                                 @Override
424                                 public boolean isLoaded() {
425                                         return false;
426                                 }
427
428                                 @Override
429                                 public Sone getSone() {
430                                         return null;
431                                 }
432
433                                 @Override
434                                 public Optional<String> getRecipientId() {
435                                         return null;
436                                 }
437
438                                 @Override
439                                 public Optional<Sone> getRecipient() {
440                                         return null;
441                                 }
442
443                                 @Override
444                                 public long getTime() {
445                                         return 0;
446                                 }
447
448                                 @Override
449                                 public String getText() {
450                                         return "text";
451                                 }
452
453                                 @Override
454                                 public boolean isKnown() {
455                                         return false;
456                                 }
457
458                                 @Override
459                                 public Post setKnown(boolean known) {
460                                         return null;
461                                 }
462                         });
463                 }
464
465                 @Override
466                 public Collection<Post> getPosts(String soneId) {
467                         return null;
468                 }
469
470                 @Override
471                 public Collection<Post> getDirectedPosts(String recipientId) {
472                         return null;
473                 }
474
475         }
476
477         private static class AbsentPostProvider extends TestPostProvider {
478
479                 @Override
480                 public Optional<Post> getPost(String postId) {
481                         return Optional.absent();
482                 }
483
484         }
485
486 }