Extract an interface out of Sone.
[Sone.git] / src / test / java / net / pterodactylus / sone / text / SoneTextParserTest.java
1 /*
2  * Sone - SoneTextParserTest.java - Copyright © 2011–2013 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 java.io.IOException;
21 import java.io.StringReader;
22 import java.util.Arrays;
23 import java.util.Collection;
24
25 import com.google.common.base.Optional;
26
27 import junit.framework.TestCase;
28 import net.pterodactylus.sone.data.Sone;
29 import net.pterodactylus.sone.data.SoneImpl;
30 import net.pterodactylus.sone.database.SoneProvider;
31
32 /**
33  * JUnit test case for {@link SoneTextParser}.
34  *
35  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
36  */
37 public class SoneTextParserTest extends TestCase {
38
39         //
40         // ACTIONS
41         //
42
43         /**
44          * Tests basic plain-text operation of the parser.
45          *
46          * @throws IOException
47          *             if an I/O error occurs
48          */
49         @SuppressWarnings("static-method")
50         public void testPlainText() throws IOException {
51                 SoneTextParser soneTextParser = new SoneTextParser(null, null);
52                 Iterable<Part> parts;
53
54                 /* check basic operation. */
55                 parts = soneTextParser.parse(null, new StringReader("Test."));
56                 assertNotNull("Parts", parts);
57                 assertEquals("Part Text", "Test.", convertText(parts, PlainTextPart.class));
58
59                 /* check empty lines at start and end. */
60                 parts = soneTextParser.parse(null, new StringReader("\nTest.\n\n"));
61                 assertNotNull("Parts", parts);
62                 assertEquals("Part Text", "Test.", convertText(parts, PlainTextPart.class));
63
64                 /* check duplicate empty lines in the text. */
65                 parts = soneTextParser.parse(null, new StringReader("\nTest.\n\n\nTest."));
66                 assertNotNull("Parts", parts);
67                 assertEquals("Part Text", "Test.\n\nTest.", convertText(parts, PlainTextPart.class));
68         }
69
70         /**
71          * Tests parsing of KSK links.
72          *
73          * @throws IOException
74          *             if an I/O error occurs
75          */
76         @SuppressWarnings("static-method")
77         public void testKSKLinks() throws IOException {
78                 SoneTextParser soneTextParser = new SoneTextParser(null, null);
79                 Iterable<Part> parts;
80
81                 /* check basic links. */
82                 parts = soneTextParser.parse(null, new StringReader("KSK@gpl.txt"));
83                 assertNotNull("Parts", parts);
84                 assertEquals("Part Text", "[KSK@gpl.txt|gpl.txt|gpl.txt]", convertText(parts, FreenetLinkPart.class));
85
86                 /* check embedded links. */
87                 parts = soneTextParser.parse(null, new StringReader("Link is KSK@gpl.txt\u200b."));
88                 assertNotNull("Parts", parts);
89                 assertEquals("Part Text", "Link is [KSK@gpl.txt|gpl.txt|gpl.txt]\u200b.", convertText(parts, PlainTextPart.class, FreenetLinkPart.class));
90
91                 /* check embedded links and line breaks. */
92                 parts = soneTextParser.parse(null, new StringReader("Link is KSK@gpl.txt\nKSK@test.dat\n"));
93                 assertNotNull("Parts", parts);
94                 assertEquals("Part Text", "Link is [KSK@gpl.txt|gpl.txt|gpl.txt]\n[KSK@test.dat|test.dat|test.dat]", convertText(parts, PlainTextPart.class, FreenetLinkPart.class));
95         }
96
97         /**
98          * Test case for a bug that was discovered in 0.6.7.
99          *
100          * @throws IOException
101          *             if an I/O error occurs
102          */
103         @SuppressWarnings({ "synthetic-access", "static-method" })
104         public void testEmptyLinesAndSoneLinks() throws IOException {
105                 SoneTextParser soneTextParser = new SoneTextParser(new TestSoneProvider(), null);
106                 Iterable<Part> parts;
107
108                 /* check basic links. */
109                 parts = soneTextParser.parse(null, new StringReader("Some text.\n\nLink to sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU and stuff."));
110                 assertNotNull("Parts", parts);
111                 assertEquals("Part Text", "Some text.\n\nLink to [Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU] and stuff.", convertText(parts, PlainTextPart.class, SonePart.class));
112         }
113
114         /**
115          * Test for a bug discovered in Sone 0.8.4 where a plain “http://” would be
116          * parsed into a link.
117          *
118          * @throws IOException
119          *             if an I/O error occurs
120          */
121         @SuppressWarnings({ "synthetic-access", "static-method" })
122         public void testEmpyHttpLinks() throws IOException {
123                 SoneTextParser soneTextParser = new SoneTextParser(new TestSoneProvider(), null);
124                 Iterable<Part> parts;
125
126                 /* check empty http links. */
127                 parts = soneTextParser.parse(null, new StringReader("Some text. Empty link: http:// – nice!"));
128                 assertNotNull("Parts", parts);
129                 assertEquals("Part Text", "Some text. Empty link: http:// – nice!", convertText(parts, PlainTextPart.class));
130         }
131
132         //
133         // PRIVATE METHODS
134         //
135
136         /**
137          * Converts all given {@link Part}s into a string, validating that the
138          * part’s classes match only the expected classes.
139          *
140          * @param parts
141          *            The parts to convert to text
142          * @param validClasses
143          *            The valid classes; if no classes are given, all classes are
144          *            valid
145          * @return The converted text
146          */
147         private static String convertText(Iterable<Part> parts, Class<?>... validClasses) {
148                 StringBuilder text = new StringBuilder();
149                 for (Part part : parts) {
150                         assertNotNull("Part", part);
151                         boolean classValid = validClasses.length == 0;
152                         for (Class<?> validClass : validClasses) {
153                                 if (validClass.isAssignableFrom(part.getClass())) {
154                                         classValid = true;
155                                         break;
156                                 }
157                         }
158                         if (!classValid) {
159                                 fail("Part’s Class (" + part.getClass() + ") is not one of " + Arrays.toString(validClasses));
160                         }
161                         if (part instanceof PlainTextPart) {
162                                 text.append(((PlainTextPart) part).getText());
163                         } else if (part instanceof FreenetLinkPart) {
164                                 FreenetLinkPart freenetLinkPart = (FreenetLinkPart) part;
165                                 text.append('[').append(freenetLinkPart.getLink()).append('|').append(freenetLinkPart.isTrusted() ? "trusted|" : "").append(freenetLinkPart.getTitle()).append('|').append(freenetLinkPart.getText()).append(']');
166                         } else if (part instanceof LinkPart) {
167                                 LinkPart linkPart = (LinkPart) part;
168                                 text.append('[').append(linkPart.getLink()).append('|').append(linkPart.getTitle()).append('|').append(linkPart.getText()).append(']');
169                         } else if (part instanceof SonePart) {
170                                 SonePart sonePart = (SonePart) part;
171                                 text.append("[Sone|").append(sonePart.getSone().getId()).append(']');
172                         }
173                 }
174                 return text.toString();
175         }
176
177         /**
178          * Mock Sone provider.
179          *
180          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
181          */
182         private static class TestSoneProvider implements SoneProvider {
183
184                 /**
185                  * {@inheritDoc}
186                  */
187                 @Override
188                 public Optional<Sone> getSone(final String soneId) {
189                         return Optional.<Sone>of(new SoneImpl(soneId, false) {
190
191                                 /**
192                                  * {@inheritDoc}
193                                  */
194                                 @Override
195                                 public String getName() {
196                                         return soneId;
197                                 }
198                         });
199                 }
200
201                 /**
202                  * {@inheritDocs}
203                  */
204                 @Override
205                 public Collection<Sone> getSones() {
206                         return null;
207                 }
208
209                 /**
210                  * {@inheritDocs}
211                  */
212                 @Override
213                 public Collection<Sone> getLocalSones() {
214                         return null;
215                 }
216
217                 /**
218                  * {@inheritDocs}
219                  */
220                 @Override
221                 public Collection<Sone> getRemoteSones() {
222                         return null;
223                 }
224
225         }
226
227 }