Skip to content

Commit

Permalink
Feat: URL and URI decoder. #160
Browse files Browse the repository at this point in the history
  • Loading branch information
credmond-git committed Mar 2, 2024
1 parent d002e78 commit a123aec
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.github.gestalt.config.decoder;

import org.github.gestalt.config.entity.ValidationError;
import org.github.gestalt.config.node.ConfigNode;
import org.github.gestalt.config.reflect.TypeCapture;
import org.github.gestalt.config.tag.Tags;
import org.github.gestalt.config.utils.GResultOf;

import java.net.URI;
import java.net.URISyntaxException;

/**
* Decode a URL.
*
* @author <a href="mailto:colin.redmond@outlook.com"> Colin Redmond </a> (c) 2024.
*/
public final class URIDecoder extends LeafDecoder<URI> {

@Override
public Priority priority() {
return Priority.MEDIUM;
}

@Override
public String name() {
return "URI";
}

@Override
public boolean canDecode(String path, Tags tags, ConfigNode node, TypeCapture<?> type) {
return URI.class.isAssignableFrom(type.getRawType());
}

@Override
protected GResultOf<URI> leafDecode(String path, ConfigNode node) {
var value = node.getValue().orElse("");
try {
return GResultOf.result(new URI(value));
} catch (URISyntaxException e) {
return GResultOf.errors(new ValidationError.ErrorDecodingException(path, node, name(), e.getLocalizedMessage()));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.github.gestalt.config.decoder;

import org.github.gestalt.config.entity.ValidationError;
import org.github.gestalt.config.node.ConfigNode;
import org.github.gestalt.config.reflect.TypeCapture;
import org.github.gestalt.config.tag.Tags;
import org.github.gestalt.config.utils.GResultOf;

import java.net.MalformedURLException;
import java.net.URL;

/**
* Decode a URL.
*
* @author <a href="mailto:colin.redmond@outlook.com"> Colin Redmond </a> (c) 2024.
*/
public final class URLDecoder extends LeafDecoder<URL> {

@Override
public Priority priority() {
return Priority.MEDIUM;
}

@Override
public String name() {
return "URL";
}

@Override
public boolean canDecode(String path, Tags tags, ConfigNode node, TypeCapture<?> type) {
return URL.class.isAssignableFrom(type.getRawType());
}

@Override
protected GResultOf<URL> leafDecode(String path, ConfigNode node) {
var value = node.getValue().orElse("");
try {
return GResultOf.result(new URL(value));
} catch (MalformedURLException e) {
return GResultOf.errors(new ValidationError.ErrorDecodingException(path, node, name(), e.getLocalizedMessage()));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ org.github.gestalt.config.decoder.SequencedSetDecoder
org.github.gestalt.config.decoder.ShortDecoder
org.github.gestalt.config.decoder.StringDecoder
org.github.gestalt.config.decoder.StringConstructorDecoder
org.github.gestalt.config.decoder.URLDecoder
org.github.gestalt.config.decoder.URIDecoder
org.github.gestalt.config.decoder.UUIDDecoder
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.github.gestalt.config.decoder;

import org.github.gestalt.config.entity.ValidationLevel;
import org.github.gestalt.config.exceptions.GestaltConfigurationException;
import org.github.gestalt.config.lexer.SentenceLexer;
import org.github.gestalt.config.node.ConfigNodeService;
import org.github.gestalt.config.node.LeafNode;
import org.github.gestalt.config.path.mapper.StandardPathMapper;
import org.github.gestalt.config.reflect.TypeCapture;
import org.github.gestalt.config.tag.Tags;
import org.github.gestalt.config.utils.GResultOf;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.net.URI;
import java.util.Collections;
import java.util.Date;
import java.util.List;

class URIDecoderTest {

ConfigNodeService configNodeService;
SentenceLexer lexer;
DecoderService decoderService;

@BeforeEach
void setup() throws GestaltConfigurationException {
configNodeService = Mockito.mock(ConfigNodeService.class);
lexer = Mockito.mock(SentenceLexer.class);
decoderService = new DecoderRegistry(Collections.singletonList(new UUIDDecoder()), configNodeService, lexer,
List.of(new StandardPathMapper()));
}


@Test
void name() {
URIDecoder decoder = new URIDecoder();
Assertions.assertEquals("URI", decoder.name());
}

@Test
void priority() {
URIDecoder decoder = new URIDecoder();
Assertions.assertEquals(Priority.MEDIUM, decoder.priority());
}

@Test
void canDecode() {
URIDecoder longDecoder = new URIDecoder();

Assertions.assertTrue(longDecoder.canDecode("", Tags.of(), new LeafNode(""), TypeCapture.of(URI.class)));
Assertions.assertTrue(longDecoder.canDecode("", Tags.of(), new LeafNode(""), new TypeCapture<URI>() {
}));
Assertions.assertFalse(longDecoder.canDecode("", Tags.of(), new LeafNode(""), TypeCapture.of(long.class)));

Assertions.assertFalse(longDecoder.canDecode("", Tags.of(), new LeafNode(""), TypeCapture.of(String.class)));
Assertions.assertFalse(longDecoder.canDecode("", Tags.of(), new LeafNode(""), TypeCapture.of(Date.class)));
Assertions.assertFalse(longDecoder.canDecode("", Tags.of(), new LeafNode(""), new TypeCapture<List<Long>>() {
}));
Assertions.assertFalse(longDecoder.canDecode("", Tags.of(), new LeafNode(""), new TypeCapture<List<URI>>() {
}));
}

@Test
void decode() {
URIDecoder decoder = new URIDecoder();

String uri = "http://www.google.com";
GResultOf<URI> result = decoder.decode("db.port", Tags.of(), new LeafNode(uri),
TypeCapture.of(URI.class), new DecoderContext(decoderService, null));
Assertions.assertTrue(result.hasResults());
Assertions.assertFalse(result.hasErrors());
Assertions.assertEquals(uri, result.results().toString());
Assertions.assertEquals(0, result.getErrors().size());
}

@Test
void decodeInvalidNode() {
URIDecoder decoder = new URIDecoder();

String uri = "http://www.google.com[]";
GResultOf<URI> result = decoder.decode("db.port", Tags.of(), new LeafNode(uri),
TypeCapture.of(URI.class), new DecoderContext(decoderService, null));
Assertions.assertFalse(result.hasResults());
Assertions.assertTrue(result.hasErrors());
Assertions.assertNull(result.results());
Assertions.assertNotNull(result.getErrors());
Assertions.assertEquals(ValidationLevel.ERROR, result.getErrors().get(0).level());
Assertions.assertEquals("Unable to decode a URI on path: db.port, from node: LeafNode{value='http://www.google.com[]'}, " +
"with reason: Illegal character in hostname at index 21: http://www.google.com[]",
result.getErrors().get(0).description());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package org.github.gestalt.config.decoder;

import org.github.gestalt.config.entity.ValidationLevel;
import org.github.gestalt.config.exceptions.GestaltConfigurationException;
import org.github.gestalt.config.lexer.SentenceLexer;
import org.github.gestalt.config.node.ConfigNodeService;
import org.github.gestalt.config.node.LeafNode;
import org.github.gestalt.config.path.mapper.StandardPathMapper;
import org.github.gestalt.config.reflect.TypeCapture;
import org.github.gestalt.config.tag.Tags;
import org.github.gestalt.config.utils.GResultOf;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.net.URI;
import java.net.URL;
import java.util.Collections;
import java.util.Date;
import java.util.List;


class URLDecoderTest {

ConfigNodeService configNodeService;
SentenceLexer lexer;
DecoderService decoderService;

@BeforeEach
void setup() throws GestaltConfigurationException {
configNodeService = Mockito.mock(ConfigNodeService.class);
lexer = Mockito.mock(SentenceLexer.class);
decoderService = new DecoderRegistry(Collections.singletonList(new UUIDDecoder()), configNodeService, lexer,
List.of(new StandardPathMapper()));
}


@Test
void name() {
URLDecoder decoder = new URLDecoder();
Assertions.assertEquals("URL", decoder.name());
}

@Test
void priority() {
URLDecoder decoder = new URLDecoder();
Assertions.assertEquals(Priority.MEDIUM, decoder.priority());
}

@Test
void canDecode() {
URLDecoder longDecoder = new URLDecoder();

Assertions.assertTrue(longDecoder.canDecode("", Tags.of(), new LeafNode(""), TypeCapture.of(URL.class)));
Assertions.assertTrue(longDecoder.canDecode("", Tags.of(), new LeafNode(""), new TypeCapture<URL>() {
}));
Assertions.assertFalse(longDecoder.canDecode("", Tags.of(), new LeafNode(""), TypeCapture.of(long.class)));

Assertions.assertFalse(longDecoder.canDecode("", Tags.of(), new LeafNode(""), TypeCapture.of(String.class)));
Assertions.assertFalse(longDecoder.canDecode("", Tags.of(), new LeafNode(""), TypeCapture.of(Date.class)));
Assertions.assertFalse(longDecoder.canDecode("", Tags.of(), new LeafNode(""), new TypeCapture<List<Long>>() {
}));
Assertions.assertFalse(longDecoder.canDecode("", Tags.of(), new LeafNode(""), new TypeCapture<List<URL>>() {
}));
}

@Test
void decode() {
URLDecoder decoder = new URLDecoder();

String url = "http://www.google.com";
GResultOf<URL> result = decoder.decode("db.port", Tags.of(), new LeafNode(url),
TypeCapture.of(URI.class), new DecoderContext(decoderService, null));
Assertions.assertTrue(result.hasResults());
Assertions.assertFalse(result.hasErrors());
Assertions.assertEquals(url, result.results().toString());
Assertions.assertEquals(0, result.getErrors().size());
}

@Test
void decodeInvalidNode() {
URLDecoder decoder = new URLDecoder();

String uri = "8080:www.google.com";
GResultOf<URL> result = decoder.decode("db.port", Tags.of(), new LeafNode(uri),
TypeCapture.of(URI.class), new DecoderContext(decoderService, null));
Assertions.assertFalse(result.hasResults());
Assertions.assertTrue(result.hasErrors());
Assertions.assertNull(result.results());
Assertions.assertNotNull(result.getErrors());
Assertions.assertEquals(ValidationLevel.ERROR, result.getErrors().get(0).level());
Assertions.assertEquals("Unable to decode a URL on path: db.port, from node: LeafNode{value='8080:www.google.com'}, " +
"with reason: no protocol: 8080:www.google.com",
result.getErrors().get(0).description());
}
}

0 comments on commit a123aec

Please sign in to comment.