[*] Generalize the entry system by introducing "structured entries"
This commit is contained in:
@@ -1,62 +1,15 @@
|
||||
package de.siphalor.tweed5.defaultextensions.pather.api;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.impl.PathTrackingImpl;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
public class PathTracking {
|
||||
private final StringBuilder pathBuilder = new StringBuilder(256);
|
||||
private final Deque<Context> contextStack = new ArrayDeque<>(50);
|
||||
private final Deque<String> pathParts = new ArrayDeque<>(50);
|
||||
private final Deque<Integer> listIndexes = new ArrayDeque<>(10);
|
||||
|
||||
public @Nullable Context currentContext() {
|
||||
return contextStack.peek();
|
||||
public interface PathTracking {
|
||||
static PathTracking create() {
|
||||
return new PathTrackingImpl();
|
||||
}
|
||||
|
||||
public void popContext() {
|
||||
if (contextStack.pop() == Context.LIST) {
|
||||
listIndexes.pop();
|
||||
popPathPart();
|
||||
}
|
||||
}
|
||||
void pushPathPart(String pathPart);
|
||||
|
||||
public void pushMapContext() {
|
||||
contextStack.push(Context.MAP);
|
||||
}
|
||||
void popPathPart();
|
||||
|
||||
public void pushPathPart(String part) {
|
||||
pathParts.push(part);
|
||||
pathBuilder.append(".").append(part);
|
||||
}
|
||||
|
||||
public void popPathPart() {
|
||||
if (!pathParts.isEmpty()) {
|
||||
String poppedPart = pathParts.pop();
|
||||
pathBuilder.setLength(pathBuilder.length() - poppedPart.length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void pushListContext() {
|
||||
contextStack.push(Context.LIST);
|
||||
listIndexes.push(0);
|
||||
pushPathPart("0");
|
||||
}
|
||||
|
||||
public int incrementListIndex() {
|
||||
int index = listIndexes.pop() + 1;
|
||||
listIndexes.push(index);
|
||||
popPathPart();
|
||||
pushPathPart(Integer.toString(index));
|
||||
return index;
|
||||
}
|
||||
|
||||
public String currentPath() {
|
||||
return pathBuilder.toString();
|
||||
}
|
||||
|
||||
public enum Context {
|
||||
LIST, MAP,
|
||||
}
|
||||
String currentPath();
|
||||
}
|
||||
|
||||
@@ -8,64 +8,35 @@ import org.jspecify.annotations.Nullable;
|
||||
@RequiredArgsConstructor
|
||||
public class PathTrackingConfigEntryValueVisitor implements ConfigEntryValueVisitor {
|
||||
private final ConfigEntryValueVisitor delegate;
|
||||
private final PathTracking pathTracking;
|
||||
private final ValuePathTracking pathTracking;
|
||||
|
||||
@Override
|
||||
public <T extends @Nullable Object> void visitEntry(ConfigEntry<T> entry, T value) {
|
||||
delegate.visitEntry(entry, value);
|
||||
entryVisited();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean enterCollectionEntry(ConfigEntry<T> entry, T value) {
|
||||
boolean enter = delegate.enterCollectionEntry(entry, value);
|
||||
public <T> boolean enterStructuredEntry(ConfigEntry<T> entry, T value) {
|
||||
return delegate.enterStructuredEntry(entry, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterStructuredSubEntry(String entryKey, String valueKey) {
|
||||
boolean enter = delegate.enterStructuredSubEntry(entryKey, valueKey);
|
||||
if (enter) {
|
||||
pathTracking.pushListContext();
|
||||
pathTracking.pushPathPart(entryKey, valueKey);
|
||||
}
|
||||
return enter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void leaveCollectionEntry(ConfigEntry<T> entry, T value) {
|
||||
delegate.leaveCollectionEntry(entry, value);
|
||||
pathTracking.popContext();
|
||||
entryVisited();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean enterCompoundEntry(ConfigEntry<T> entry, T value) {
|
||||
boolean enter = delegate.enterCompoundEntry(entry, value);
|
||||
if (enter) {
|
||||
pathTracking.pushMapContext();
|
||||
}
|
||||
return enter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterCompoundSubEntry(String key) {
|
||||
boolean enter = delegate.enterCompoundSubEntry(key);
|
||||
if (enter) {
|
||||
pathTracking.pushPathPart(key);
|
||||
}
|
||||
return enter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveCompoundSubEntry(String key) {
|
||||
delegate.leaveCompoundSubEntry(key);
|
||||
public void leaveStructuredSubEntry(String entryKey, String valueKey) {
|
||||
delegate.leaveStructuredSubEntry(entryKey, valueKey);
|
||||
pathTracking.popPathPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void leaveCompoundEntry(ConfigEntry<T> entry, T value) {
|
||||
delegate.leaveCompoundEntry(entry, value);
|
||||
pathTracking.popContext();
|
||||
entryVisited();
|
||||
}
|
||||
|
||||
private void entryVisited() {
|
||||
if (pathTracking.currentContext() == PathTracking.Context.LIST) {
|
||||
pathTracking.incrementListIndex();
|
||||
}
|
||||
public <T> void leaveStructuredEntry(ConfigEntry<T> entry, T value) {
|
||||
delegate.leaveStructuredEntry(entry, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,37 +12,16 @@ public class PathTrackingConfigEntryVisitor implements ConfigEntryVisitor {
|
||||
@Override
|
||||
public void visitEntry(ConfigEntry<?> entry) {
|
||||
delegate.visitEntry(entry);
|
||||
entryVisited();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterCollectionEntry(ConfigEntry<?> entry) {
|
||||
boolean enter = delegate.enterCollectionEntry(entry);
|
||||
if (enter) {
|
||||
pathTracking.pushListContext();
|
||||
}
|
||||
return enter;
|
||||
public boolean enterStructuredEntry(ConfigEntry<?> entry) {
|
||||
return delegate.enterStructuredEntry(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveCollectionEntry(ConfigEntry<?> entry) {
|
||||
delegate.leaveCollectionEntry(entry);
|
||||
pathTracking.popContext();
|
||||
entryVisited();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterCompoundEntry(ConfigEntry<?> entry) {
|
||||
boolean enter = delegate.enterCompoundEntry(entry);
|
||||
if (enter) {
|
||||
pathTracking.pushMapContext();
|
||||
}
|
||||
return enter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterCompoundSubEntry(String key) {
|
||||
boolean enter = delegate.enterCompoundSubEntry(key);
|
||||
public boolean enterStructuredSubEntry(String key) {
|
||||
boolean enter = delegate.enterStructuredSubEntry(key);
|
||||
if (enter) {
|
||||
pathTracking.pushPathPart(key);
|
||||
}
|
||||
@@ -50,21 +29,13 @@ public class PathTrackingConfigEntryVisitor implements ConfigEntryVisitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveCompoundSubEntry(String key) {
|
||||
delegate.leaveCompoundSubEntry(key);
|
||||
public void leaveStructuredSubEntry(String key) {
|
||||
delegate.leaveStructuredSubEntry(key);
|
||||
pathTracking.popPathPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveCompoundEntry(ConfigEntry<?> entry) {
|
||||
delegate.leaveCompoundEntry(entry);
|
||||
pathTracking.popContext();
|
||||
entryVisited();
|
||||
}
|
||||
|
||||
private void entryVisited() {
|
||||
if (pathTracking.currentContext() == PathTracking.Context.LIST) {
|
||||
pathTracking.incrementListIndex();
|
||||
}
|
||||
public void leaveStructuredEntry(ConfigEntry<?> entry) {
|
||||
delegate.leaveStructuredEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,14 @@ import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataToken;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class PathTrackingDataReader implements TweedDataReader {
|
||||
private final TweedDataReader delegate;
|
||||
private final PathTracking pathTracking;
|
||||
private final ArrayDeque<Context> contextStack = new ArrayDeque<>(50);
|
||||
private final ArrayDeque<Integer> listIndexStack = new ArrayDeque<>(50);
|
||||
|
||||
@Override
|
||||
public TweedDataToken peekToken() throws TweedDataReadException {
|
||||
@@ -18,21 +22,35 @@ public class PathTrackingDataReader implements TweedDataReader {
|
||||
@Override
|
||||
public TweedDataToken readToken() throws TweedDataReadException {
|
||||
TweedDataToken token = delegate.readToken();
|
||||
if (token.isListValue()) {
|
||||
if (contextStack.peek() == Context.LIST) {
|
||||
int index = listIndexStack.pop() + 1;
|
||||
if (index != 0) {
|
||||
pathTracking.popPathPart();
|
||||
}
|
||||
pathTracking.pushPathPart(Integer.toString(index));
|
||||
listIndexStack.push(index);
|
||||
}
|
||||
}
|
||||
|
||||
if (token.isListStart()) {
|
||||
pathTracking.pushListContext();
|
||||
} else if (token.isListValue()) {
|
||||
pathTracking.incrementListIndex();
|
||||
contextStack.push(Context.LIST);
|
||||
listIndexStack.push(-1);
|
||||
} else if (token.isListEnd()) {
|
||||
pathTracking.popContext();
|
||||
contextStack.pop();
|
||||
int lastIndex = listIndexStack.pop();
|
||||
if (lastIndex >= 0) {
|
||||
pathTracking.popPathPart();
|
||||
}
|
||||
} else if (token.isMapStart()) {
|
||||
pathTracking.pushMapContext();
|
||||
contextStack.push(Context.MAP);
|
||||
pathTracking.pushPathPart("$");
|
||||
} else if (token.isMapEntryKey()) {
|
||||
pathTracking.popPathPart();
|
||||
pathTracking.pushPathPart(token.readAsString());
|
||||
} else if (token.isMapEnd()) {
|
||||
pathTracking.popPathPart();
|
||||
pathTracking.popContext();
|
||||
contextStack.pop();
|
||||
}
|
||||
return token;
|
||||
}
|
||||
@@ -41,4 +59,8 @@ public class PathTrackingDataReader implements TweedDataReader {
|
||||
public void close() throws Exception {
|
||||
delegate.close();
|
||||
}
|
||||
|
||||
private enum Context {
|
||||
LIST, MAP,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,14 @@ import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class PathTrackingDataVisitor implements TweedDataVisitor {
|
||||
private final TweedDataVisitor delegate;
|
||||
private final PathTracking pathTracking;
|
||||
private final ArrayDeque<Context> contextStack = new ArrayDeque<>(50);
|
||||
private final ArrayDeque<Integer> listIndexStack = new ArrayDeque<>(50);
|
||||
|
||||
@Override
|
||||
public void visitNull() {
|
||||
@@ -72,42 +76,50 @@ public class PathTrackingDataVisitor implements TweedDataVisitor {
|
||||
}
|
||||
|
||||
private void valueVisited() {
|
||||
if (pathTracking.currentContext() == PathTracking.Context.LIST) {
|
||||
pathTracking.incrementListIndex();
|
||||
} else {
|
||||
Context context = contextStack.peek();
|
||||
if (context == Context.MAP_ENTRY) {
|
||||
contextStack.pop();
|
||||
pathTracking.popPathPart();
|
||||
} else if (context == Context.LIST) {
|
||||
pathTracking.popPathPart();
|
||||
int index = listIndexStack.pop();
|
||||
listIndexStack.push(index + 1);
|
||||
pathTracking.pushPathPart(Integer.toString(index));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitListStart() {
|
||||
delegate.visitListStart();
|
||||
pathTracking.pushListContext();
|
||||
contextStack.push(Context.LIST);
|
||||
listIndexStack.push(0);
|
||||
pathTracking.pushPathPart("0");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitListEnd() {
|
||||
delegate.visitListEnd();
|
||||
pathTracking.popContext();
|
||||
contextStack.pop();
|
||||
listIndexStack.pop();
|
||||
pathTracking.popPathPart();
|
||||
valueVisited();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMapStart() {
|
||||
delegate.visitMapStart();
|
||||
pathTracking.pushMapContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMapEntryKey(String key) {
|
||||
delegate.visitMapEntryKey(key);
|
||||
pathTracking.pushPathPart(key);
|
||||
contextStack.push(Context.MAP_ENTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMapEnd() {
|
||||
delegate.visitMapEnd();
|
||||
pathTracking.popContext();
|
||||
valueVisited();
|
||||
}
|
||||
|
||||
@@ -115,4 +127,8 @@ public class PathTrackingDataVisitor implements TweedDataVisitor {
|
||||
public void visitDecoration(TweedDataDecoration decoration) {
|
||||
delegate.visitDecoration(decoration);
|
||||
}
|
||||
|
||||
private enum Context {
|
||||
LIST, MAP_ENTRY,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.siphalor.tweed5.defaultextensions.pather.api;
|
||||
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor(staticName = "create")
|
||||
public final class ValuePathTracking implements PathTracking {
|
||||
private final PathTracking entryPathTracking = PathTracking.create();
|
||||
private final PathTracking valuePathTracking = PathTracking.create();
|
||||
|
||||
@Override
|
||||
public void pushPathPart(String pathPart) {
|
||||
this.pushPathPart(pathPart, pathPart);
|
||||
}
|
||||
|
||||
public void pushPathPart(String entryPathPart, String valuePathPart) {
|
||||
entryPathTracking.pushPathPart(entryPathPart);
|
||||
valuePathTracking.pushPathPart(valuePathPart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popPathPart() {
|
||||
valuePathTracking.popPathPart();
|
||||
entryPathTracking.popPathPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String currentPath() {
|
||||
return valuePathTracking.currentPath();
|
||||
}
|
||||
|
||||
public String currentEntryPath() {
|
||||
return entryPathTracking.currentPath();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package de.siphalor.tweed5.defaultextensions.pather.impl;
|
||||
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
public class PathTrackingImpl implements PathTracking {
|
||||
private final StringBuilder pathBuilder = new StringBuilder(256);
|
||||
private final Deque<String> pathParts = new ArrayDeque<>(50);
|
||||
|
||||
@Override
|
||||
public void pushPathPart(String entryPathPart) {
|
||||
pathParts.push(entryPathPart);
|
||||
pathBuilder.append(".").append(entryPathPart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popPathPart() {
|
||||
if (!pathParts.isEmpty()) {
|
||||
String poppedPart = pathParts.pop();
|
||||
pathBuilder.setLength(pathBuilder.length() - poppedPart.length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String currentPath() {
|
||||
return pathBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||
import de.siphalor.tweed5.data.extension.api.*;
|
||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
||||
import de.siphalor.tweed5.dataapi.api.DelegatingTweedDataWriter;
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
||||
@@ -71,7 +70,7 @@ public class PatherExtensionImpl implements PatherExtension, ReadWriteRelatedExt
|
||||
return castedInner.read(reader, entry, context);
|
||||
}
|
||||
|
||||
pathTracking = new PathTracking();
|
||||
pathTracking = PathTracking.create();
|
||||
context.extensionsData().set(rwContextPathTrackingAccess, pathTracking);
|
||||
try {
|
||||
return castedInner.read(new PathTrackingDataReader(reader, pathTracking), entry, context);
|
||||
@@ -80,7 +79,7 @@ public class PatherExtensionImpl implements PatherExtension, ReadWriteRelatedExt
|
||||
if (exceptionPathTracking != null) {
|
||||
throw new TweedEntryReadException(
|
||||
"Exception while reading entry at "
|
||||
+ String.join("/", exceptionPathTracking.currentPath())
|
||||
+ exceptionPathTracking.currentPath()
|
||||
+ ": " + e.getMessage(),
|
||||
e
|
||||
);
|
||||
@@ -114,7 +113,7 @@ public class PatherExtensionImpl implements PatherExtension, ReadWriteRelatedExt
|
||||
return;
|
||||
}
|
||||
|
||||
pathTracking = new PathTracking();
|
||||
pathTracking = PathTracking.create();
|
||||
context.extensionsData().set(rwContextPathTrackingAccess, pathTracking);
|
||||
try {
|
||||
castedInner.write(new PathTrackingDataVisitor(writer, pathTracking), value, entry, context);
|
||||
@@ -123,7 +122,7 @@ public class PatherExtensionImpl implements PatherExtension, ReadWriteRelatedExt
|
||||
if (exceptionPathTracking != null) {
|
||||
throw new TweedEntryWriteException(
|
||||
"Exception while writing entry at "
|
||||
+ String.join("/", exceptionPathTracking.currentPath())
|
||||
+ exceptionPathTracking.currentPath()
|
||||
+ ": " + e.getMessage(),
|
||||
e
|
||||
);
|
||||
|
||||
@@ -20,6 +20,7 @@ import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingConfigEntryValueVisitor;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.pather.api.ValuePathTracking;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationProvidingExtension;
|
||||
@@ -177,7 +178,7 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
|
||||
@Override
|
||||
public <T> ValidationIssues validate(ConfigEntry<T> entry, @Nullable T value) {
|
||||
PathTracking pathTracking = new PathTracking();
|
||||
ValuePathTracking pathTracking = ValuePathTracking.create();
|
||||
ValidatingConfigEntryVisitor validatingVisitor = new ValidatingConfigEntryVisitor(pathTracking);
|
||||
|
||||
entry.visitInOrder(new PathTrackingConfigEntryValueVisitor(validatingVisitor, pathTracking), value);
|
||||
@@ -281,22 +282,12 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean enterCollectionEntry(ConfigEntry<T> entry, T value) {
|
||||
public <T> boolean enterStructuredEntry(ConfigEntry<T> entry, T value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void leaveCollectionEntry(ConfigEntry<T> entry, T value) {
|
||||
visitEntry(entry, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean enterCompoundEntry(ConfigEntry<T> entry, T value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void leaveCompoundEntry(ConfigEntry<T> entry, T value) {
|
||||
public <T> void leaveStructuredEntry(ConfigEntry<T> entry, T value) {
|
||||
visitEntry(entry, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package de.siphalor.tweed5.defaultextensions.pather.api;
|
||||
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataReadException;
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataToken;
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataTokens;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class PathTrackingDataReaderTest {
|
||||
@SneakyThrows
|
||||
@Test
|
||||
void test() {
|
||||
PathTracking pathTracking = PathTracking.create();
|
||||
TweedDataReader mockedDelegate = mock(TweedDataReader.class);
|
||||
|
||||
when(mockedDelegate.readToken()).thenReturn(
|
||||
TweedDataTokens.getMapStart(),
|
||||
TweedDataTokens.asMapEntryKey(new StringToken("key")),
|
||||
TweedDataTokens.asMapEntryValue(new StringToken("value")),
|
||||
TweedDataTokens.asMapEntryKey(new StringToken("list")),
|
||||
TweedDataTokens.asMapEntryValue(TweedDataTokens.getListStart()),
|
||||
TweedDataTokens.asListValue(new StringToken("first")),
|
||||
TweedDataTokens.asListValue(TweedDataTokens.getMapStart()),
|
||||
TweedDataTokens.asListValue(TweedDataTokens.getMapEnd()),
|
||||
TweedDataTokens.getListEnd(),
|
||||
TweedDataTokens.getMapEnd()
|
||||
);
|
||||
|
||||
var reader = new PathTrackingDataReader(mockedDelegate, pathTracking);
|
||||
|
||||
assertThat(reader.readToken()).isEqualTo(TweedDataTokens.getMapStart());
|
||||
assertThat(pathTracking.currentPath()).isEqualTo(".$");
|
||||
assertThat(reader.readToken().readAsString()).isEqualTo("key");
|
||||
assertThat(pathTracking.currentPath()).isEqualTo(".key");
|
||||
assertThat(reader.readToken().readAsString()).isEqualTo("value");
|
||||
assertThat(reader.readToken().readAsString()).isEqualTo("list");
|
||||
assertThat(pathTracking.currentPath()).isEqualTo(".list");
|
||||
assertThat(reader.readToken().isListStart()).isTrue();
|
||||
assertThat(pathTracking.currentPath()).isEqualTo(".list");
|
||||
assertThat(reader.readToken().readAsString()).isEqualTo("first");
|
||||
assertThat(reader.readToken().isMapStart()).isTrue();
|
||||
assertThat(pathTracking.currentPath()).startsWith(".list.1");
|
||||
assertThat(reader.readToken().isMapEnd()).isTrue();
|
||||
assertThat(reader.readToken().isListEnd()).isTrue();
|
||||
assertThat(pathTracking.currentPath()).isEqualTo(".list");
|
||||
assertThat(reader.readToken()).isEqualTo(TweedDataTokens.getMapEnd());
|
||||
assertThat(pathTracking.currentPath()).isEqualTo("");
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
static class StringToken implements TweedDataToken {
|
||||
private final String value;
|
||||
|
||||
@Override
|
||||
public boolean canReadAsString() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readAsString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user