diff --git a/src/main/java/com/mabl/net/proxy/FindProxyDirective.java b/src/main/java/com/mabl/net/proxy/FindProxyDirective.java index d8006a2..79cf85e 100644 --- a/src/main/java/com/mabl/net/proxy/FindProxyDirective.java +++ b/src/main/java/com/mabl/net/proxy/FindProxyDirective.java @@ -47,6 +47,24 @@ public ConnectionType connectionType() { return connectionType; } + /** + * Tests whether this directive has connection type {@link ConnectionType#DIRECT}. + * + * @return true if this directive has a direct connection type; false otherwise. + */ + public boolean isDirect() { + return connectionType == ConnectionType.DIRECT; + } + + /** + * Tests whether this directive has connection type other than {@link ConnectionType#DIRECT}. + * + * @return true if this directive has a proxy connection type; false if the connection type is direct. + */ + public boolean isProxy() { + return !isDirect(); + } + /** * Gets the proxy and host component of the directive, e.g. "10.1.1.1:8080" * diff --git a/src/main/java/com/mabl/net/proxy/FindProxyResult.java b/src/main/java/com/mabl/net/proxy/FindProxyResult.java index fdb7c9f..2665d68 100644 --- a/src/main/java/com/mabl/net/proxy/FindProxyResult.java +++ b/src/main/java/com/mabl/net/proxy/FindProxyResult.java @@ -3,8 +3,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Random; import java.util.stream.Collectors; @@ -23,20 +25,6 @@ private FindProxyResult(final List directives) { this.directives = Collections.unmodifiableList(directives); } - @Override - public Iterator iterator() { - return directives.iterator(); - } - - /** - * Gets the number of proxy directives contained in this result. - * - * @return the number of directives. - */ - public int size() { - return directives.size(); - } - /** * Gets all proxy directives contained in this result. * @@ -55,6 +43,17 @@ public FindProxyDirective first() { return directives.get(0); } + /** + * Finds the first proxy directive in this result with a connection type other than {@link ConnectionType#DIRECT}. + * + * @return the first directive with a non-direct connection type, if any. + */ + public Optional firstProxy() { + return directives.stream() + .filter(directive -> directive.connectionType() != ConnectionType.DIRECT) + .findFirst(); + } + /** * Gets the proxy directive with the given index. * @@ -65,6 +64,21 @@ public FindProxyDirective get(final int index) { return directives.get(index); } + @Override + public Iterator iterator() { + return directives.iterator(); + } + + /** + * Creates a normalized copy of this {@link FindProxyResult} by removing all non-unique proxy directives + * while maintaining the original relative ordering of the directives. + * + * @return a normalized copy of this result. + */ + public FindProxyResult normalize() { + return new FindProxyResult(new ArrayList<>(new LinkedHashSet<>(directives))); + } + /** * Gets a random proxy directive from this result. * @@ -74,6 +88,15 @@ public FindProxyDirective random() { return get(random.nextInt(size())); } + /** + * Gets the number of proxy directives contained in this result. + * + * @return the number of directives. + */ + public int size() { + return directives.size(); + } + @Override public String toString() { return directives.stream() diff --git a/src/test/java/com/mabl/net/proxy/FindProxyResultTest.java b/src/test/java/com/mabl/net/proxy/FindProxyResultTest.java new file mode 100644 index 0000000..dfe1061 --- /dev/null +++ b/src/test/java/com/mabl/net/proxy/FindProxyResultTest.java @@ -0,0 +1,144 @@ +package com.mabl.net.proxy; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class FindProxyResultTest { + @Test + public void all() throws Exception { + final FindProxyResult result = FindProxyResult.parse("PROXY 10.0.0.1:8080; SOCKS 10.0.0.1:1080; DIRECT"); + final List directives = result.all(); + + final FindProxyDirective directive1 = directives.get(0); + assertEquals(ConnectionType.PROXY, directive1.connectionType()); + assertEquals("10.0.0.1:8080", directive1.proxyHostAndPort()); + + final FindProxyDirective directive2 = directives.get(1); + assertEquals(ConnectionType.SOCKS, directive2.connectionType()); + assertEquals("10.0.0.1:1080", directive2.proxyHostAndPort()); + + final FindProxyDirective directive3 = directives.get(2); + assertEquals(ConnectionType.DIRECT, directive3.connectionType()); + assertNull(directive3.proxyHostAndPort()); + } + + @Test + public void first() throws Exception { + final FindProxyResult result = FindProxyResult.parse("PROXY 10.0.0.1:8080; SOCKS 10.0.0.1:1080; DIRECT"); + final FindProxyDirective first = result.first(); + assertEquals(ConnectionType.PROXY, first.connectionType()); + assertEquals("10.0.0.1:8080", first.proxyHostAndPort()); + } + + @Test + public void firstProxyWithProxyPresent() throws Exception { + final FindProxyResult result = FindProxyResult.parse("DIRECT; PROXY 10.0.0.1:8080; SOCKS 10.0.0.1:1080"); + final Optional maybeFirstProxy = result.firstProxy(); + assertTrue(maybeFirstProxy.isPresent()); + final FindProxyDirective firstProxy = maybeFirstProxy.get(); + assertEquals(ConnectionType.PROXY, firstProxy.connectionType()); + assertEquals("10.0.0.1:8080", firstProxy.proxyHostAndPort()); + } + + @Test + public void firstProxyWithNoProxyPresent() throws Exception { + final FindProxyResult result = FindProxyResult.parse("DIRECT"); + final Optional maybeFirstProxy = result.firstProxy(); + assertFalse(maybeFirstProxy.isPresent()); + } + + @Test + public void get() throws Exception { + final FindProxyResult result = FindProxyResult.parse("PROXY 10.0.0.1:8080; SOCKS 10.0.0.1:1080; DIRECT"); + + final FindProxyDirective directive1 = result.get(0); + assertEquals(ConnectionType.PROXY, directive1.connectionType()); + assertEquals("10.0.0.1:8080", directive1.proxyHostAndPort()); + + final FindProxyDirective directive2 = result.get(1); + assertEquals(ConnectionType.SOCKS, directive2.connectionType()); + assertEquals("10.0.0.1:1080", directive2.proxyHostAndPort()); + + final FindProxyDirective directive3 = result.get(2); + assertEquals(ConnectionType.DIRECT, directive3.connectionType()); + assertNull(directive3.proxyHostAndPort()); + } + + @Test(expected = PacInterpreterException.class) + public void invalid() throws Exception { + FindProxyResult.parse("FOO"); + fail("Parsing should have failed"); + } + + @Test + public void iterator() throws Exception { + final FindProxyResult result = FindProxyResult.parse("PROXY 10.0.0.1:8080; SOCKS 10.0.0.1:1080; DIRECT"); + final List directives = new ArrayList<>(result.size()); + result.iterator().forEachRemaining(directives::add); + + final FindProxyDirective directive1 = directives.get(0); + assertEquals(ConnectionType.PROXY, directive1.connectionType()); + assertEquals("10.0.0.1:8080", directive1.proxyHostAndPort()); + + final FindProxyDirective directive2 = directives.get(1); + assertEquals(ConnectionType.SOCKS, directive2.connectionType()); + assertEquals("10.0.0.1:1080", directive2.proxyHostAndPort()); + + final FindProxyDirective directive3 = directives.get(2); + assertEquals(ConnectionType.DIRECT, directive3.connectionType()); + assertNull(directive3.proxyHostAndPort()); + } + + @Test + public void normalize() throws Exception { + final FindProxyResult result = FindProxyResult.parse("PROXY 10.0.0.1:8080; PROXY 10.0.0.1:8080; DIRECT; SOCKS 10.0.0.1:1080; DIRECT; DIRECT"); + assertEquals(6, result.size()); + + final FindProxyResult normalized = result.normalize(); + assertEquals(3, normalized.size()); + + final FindProxyDirective directive1 = normalized.get(0); + assertEquals(ConnectionType.PROXY, directive1.connectionType()); + assertEquals("10.0.0.1:8080", directive1.proxyHostAndPort()); + + final FindProxyDirective directive2 = normalized.get(1); + assertEquals(ConnectionType.DIRECT, directive2.connectionType()); + assertNull(directive2.proxyHostAndPort()); + + final FindProxyDirective directive3 = normalized.get(2); + assertEquals(ConnectionType.SOCKS, directive3.connectionType()); + assertEquals("10.0.0.1:1080", directive3.proxyHostAndPort()); + } + + @Test + public void random() throws Exception { + final FindProxyResult result = FindProxyResult.parse("PROXY 10.0.0.1:8080; SOCKS 10.0.0.1:1080; DIRECT"); + final Set directives = new HashSet<>(result.all()); + for (int ii = 0; ii < 10; ii++) { + assertTrue(directives.contains(result.random())); + } + } + + @Test + public void resultToString() throws Exception { + final FindProxyResult result = FindProxyResult.parse("PROXY 10.0.0.1:8080; SOCKS 10.0.0.1:1080; DIRECT "); + assertEquals("PROXY 10.0.0.1:8080; SOCKS 10.0.0.1:1080; DIRECT", result.toString()); + } + + @Test + public void size() throws Exception { + final FindProxyResult result = FindProxyResult.parse("PROXY 10.0.0.1:8080; SOCKS 10.0.0.1:1080; DIRECT"); + assertEquals(3, result.size()); + } +}