Merge branch 'release-0.9.5'
[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 java.io.IOException;
21 import java.util.Arrays;
22 import java.util.Collection;
23
24 import net.pterodactylus.sone.data.Sone;
25 import net.pterodactylus.sone.data.impl.IdOnlySone;
26 import net.pterodactylus.sone.database.SoneProvider;
27
28 import com.google.common.base.Function;
29 import com.google.common.base.Optional;
30 import junit.framework.TestCase;
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("Test.", null);
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("\nTest.\n\n", null);
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("\nTest.\n\n\nTest.", null);
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("KSK@gpl.txt", null);
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("Link is KSK@gpl.txt\u200b.", null);
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("Link is KSK@gpl.txt\nKSK@test.dat\n", null);
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("Some text.\n\nLink to sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU and stuff.", null);
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("Some text. Empty link: http:// – nice!", null);
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                 @Override
185                 public Function<String, Optional<Sone>> soneLoader() {
186                         return new Function<String, Optional<Sone>>() {
187                                 @Override
188                                 public Optional<Sone> apply(String soneId) {
189                                         return getSone(soneId);
190                                 }
191                         };
192                 }
193
194                 /**
195                  * {@inheritDoc}
196                  */
197                 @Override
198                 public Optional<Sone> getSone(final String soneId) {
199                         return Optional.<Sone>of(new IdOnlySone(soneId));
200                 }
201
202                 /**
203                  * {@inheritDocs}
204                  */
205                 @Override
206                 public Collection<Sone> getSones() {
207                         return null;
208                 }
209
210                 /**
211                  * {@inheritDocs}
212                  */
213                 @Override
214                 public Collection<Sone> getLocalSones() {
215                         return null;
216                 }
217
218                 /**
219                  * {@inheritDocs}
220                  */
221                 @Override
222                 public Collection<Sone> getRemoteSones() {
223                         return null;
224                 }
225
226         }
227
228 }