+++ /dev/null
-/*
- * Sone - PartContainer.java - Copyright © 2010–2016 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.text;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Objects;
-
-import javax.annotation.Nonnull;
-
-/**
- * Part implementation that can contain an arbitrary amount of other parts.
- * Parts are added using the {@link #add(Part)} method and will be rendered in
- * the order they are added.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class PartContainer implements Part, Iterable<Part> {
-
- private final List<Part> parts = new ArrayList<Part>();
-
- public void add(@Nonnull Part part) {
- parts.add(Objects.requireNonNull(part));
- }
-
- @Nonnull
- public Part getPart(int index) {
- return parts.get(index);
- }
-
- public void removePart(int index) {
- parts.remove(index);
- }
-
- public int size() {
- return parts.size();
- }
-
- @Override
- @Nonnull
- public String getText() {
- StringBuilder partText = new StringBuilder();
- for (Part part : parts) {
- partText.append(part.getText());
- }
- return partText.toString();
- }
-
- @Override
- @Nonnull
- @SuppressWarnings("synthetic-access")
- public Iterator<Part> iterator() {
- return new Iterator<Part>() {
-
- private Deque<Iterator<Part>> partStack = new ArrayDeque<Iterator<Part>>();
- private Part nextPart;
- private boolean foundNextPart;
- private boolean noNextPart;
-
- {
- partStack.push(parts.iterator());
- }
-
- private void findNext() {
- if (foundNextPart) {
- return;
- }
- noNextPart = true;
- while (!partStack.isEmpty()) {
- Iterator<Part> parts = partStack.pop();
- if (parts.hasNext()) {
- nextPart = parts.next();
- partStack.push(parts);
- if (nextPart instanceof PartContainer) {
- partStack.push(((PartContainer) nextPart).iterator());
- } else {
- noNextPart = false;
- break;
- }
- }
- }
- foundNextPart = true;
- }
-
- @Override
- public boolean hasNext() {
- findNext();
- return !noNextPart;
- }
-
- @Override
- public Part next() {
- findNext();
- if (noNextPart) {
- throw new NoSuchElementException();
- }
- foundNextPart = false;
- return nextPart;
- }
-
- @Override
- public void remove() {
- /* ignore. */
- }
-
- };
- }
-
-}
import java.io.Reader;
import java.io.StringReader;
import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@Nonnull
@Override
public Iterable<Part> parse(@Nonnull String source, @Nullable SoneTextParserContext context) {
- PartContainer parts = new PartContainer();
+ List<Part> parts = new ArrayList<>();
try (Reader sourceReader = new StringReader(source);
BufferedReader bufferedReader = new BufferedReader(sourceReader)) {
String line;
throw new RuntimeException(ioe1);
}
for (int partIndex = parts.size() - 1; partIndex >= 0; --partIndex) {
- Part part = parts.getPart(partIndex);
+ Part part = parts.get(partIndex);
if (!(part instanceof PlainTextPart) || !"\n".equals(part.getText())) {
break;
}
- parts.removePart(partIndex);
+ parts.remove(partIndex);
}
return parts;
}
return Optional.fromNullable(earliestNextLink);
}
- private void renderSoneLink(PartContainer parts, String line) {
+ private void renderSoneLink(List<Part> parts, String line) {
if (line.length() >= (7 + 43)) {
String soneId = line.substring(7, 50);
Optional<Sone> sone = soneProvider.getSone(soneId);
}
}
- private void renderPostLink(PartContainer parts, String line) {
+ private void renderPostLink(List<Part> parts, String line) {
if (line.length() >= (7 + 36)) {
String postId = line.substring(7, 43);
Optional<Post> post = postProvider.getPost(postId);
}
}
- private void renderFreenetLink(PartContainer parts, String link, LinkType linkType, @Nullable SoneTextParserContext context) {
+ private void renderFreenetLink(List<Part> parts, String link, LinkType linkType, @Nullable SoneTextParserContext context) {
String name = link;
String linkWithoutParameters = link;
if (name.indexOf('?') > -1) {
}
}
- private void renderHttpLink(PartContainer parts, String link, LinkType linkType) {
+ private void renderHttpLink(List<Part> parts, String link, LinkType linkType) {
String name = link.substring(linkType == LinkType.HTTP ? 7 : 8);
int firstSlash = name.indexOf('/');
int lastSlash = name.lastIndexOf('/');
parts.add(new LinkPart(link, name));
}
- private void renderFreemailLink(PartContainer parts, String line) {
+ private void renderFreemailLink(List<Part> parts, String line) {
int separator = line.indexOf('@');
String freemailId = line.substring(separator + 1, separator + 53);
String identityId = Base64.encode(Base32.decode(freemailId));
+++ /dev/null
-package net.pterodactylus.sone.text;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-import org.junit.Test;
-
-/**
- * Unit test for {@link PartContainer}.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class PartContainerTest {
-
- private final PartContainer container = new PartContainer();
-
- @Test
- public void emptyContainerHasSizeZero() {
- assertThat(container.size(), is(0));
- }
-
- @Test(expected = NullPointerException.class)
- public void canNotAddNullPart() {
- container.add(null);
- }
-
- @Test
- public void containerWithSinglePartHasSizeOne() {
- container.add(mock(Part.class));
- assertThat(container.size(), is(1));
- }
-
- @Test
- public void containerWithSinglePartCanReturnPart() {
- Part part = mock(Part.class);
- container.add(part);
- assertThat(container.getPart(0), is(part));
- }
-
- @Test
- public void containerIsEmptyAfterPartIsAddedAndRemoved() {
- container.add(mock(Part.class));
- container.removePart(0);
- assertThat(container.size(), is(0));
- }
-
- @Test
- public void containerContainsSecondPartIfFirstPartIsRemoved() {
- container.add(mock(Part.class));
- Part part = mock(Part.class);
- container.add(part);
- container.removePart(0);
- assertThat(container.getPart(0), is(part));
- }
-
- @Test
- public void textOfContainerPartIsTextOfPartsConcatenated() {
- container.add(createPartWithText("first"));
- container.add(createPartWithText("second"));
- assertThat(container.getText(), is("firstsecond"));
- }
-
- private Part createPartWithText(String text) {
- Part part = mock(Part.class);
- when(part.getText()).thenReturn(text);
- return part;
- }
-
- @Test(expected = NoSuchElementException.class)
- public void emptyContainerIteratorThrowsOnNext() {
- container.iterator().next();
- }
-
- @Test
- public void iteratorIteratesPartsRecursivelyInCorrectOrder() {
- Part firstPart = mock(Part.class);
- PartContainer secondPart = new PartContainer();
- Part thirdPart = mock(Part.class);
- Part nestedFirstPart = mock(Part.class);
- Part nestedSecondPart = mock(Part.class);
- secondPart.add(nestedFirstPart);
- secondPart.add(nestedSecondPart);
- container.add(firstPart);
- container.add(secondPart);
- container.add(thirdPart);
- Iterator<Part> parts = container.iterator();
- assertThat(parts.next(), is(firstPart));
- assertThat(parts.next(), is(nestedFirstPart));
- assertThat(parts.next(), is(nestedSecondPart));
- assertThat(parts.next(), is(thirdPart));
- assertThat(parts.hasNext(), is(false));
- }
-
-}
import net.pterodactylus.sone.text.FreenetLinkPart
import net.pterodactylus.sone.text.LinkPart
import net.pterodactylus.sone.text.Part
-import net.pterodactylus.sone.text.PartContainer
import net.pterodactylus.sone.text.PlainTextPart
import net.pterodactylus.sone.text.PostPart
import net.pterodactylus.sone.text.SonePart
@Test
fun `multiple parts are rendered correctly`() {
- val parts = PartContainer()
- parts.add(PlainTextPart("te"))
- parts.add(PlainTextPart("xt"))
- assertThat(renderParts(parts), `is`("text"))
+ val parts = arrayOf(PlainTextPart("te"), PlainTextPart("xt"))
+ assertThat(renderParts(*parts), `is`("text"))
}
@Test