diff --git a/tweed5/serde-extension/src/test/java/de/siphalor/tweed5/serde/extension/impl/ReadWriteExtensionImplTest.java b/tweed5/serde-extension/src/test/java/de/siphalor/tweed5/serde/extension/impl/ReadWriteExtensionImplTest.java index d829452..a34e99d 100644 --- a/tweed5/serde-extension/src/test/java/de/siphalor/tweed5/serde/extension/impl/ReadWriteExtensionImplTest.java +++ b/tweed5/serde-extension/src/test/java/de/siphalor/tweed5/serde/extension/impl/ReadWriteExtensionImplTest.java @@ -3,16 +3,23 @@ package de.siphalor.tweed5.serde.extension.impl; import de.siphalor.tweed5.core.api.container.ConfigContainer; import de.siphalor.tweed5.core.api.entry.CollectionConfigEntry; import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry; +import de.siphalor.tweed5.core.api.entry.ConfigEntry; +import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor; +import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor; +import de.siphalor.tweed5.core.api.entry.MutableStructuredConfigEntry; import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry; import de.siphalor.tweed5.core.impl.DefaultConfigContainer; import de.siphalor.tweed5.core.impl.entry.CollectionConfigEntryImpl; import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl; import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl; +import de.siphalor.tweed5.patchwork.api.Patchwork; import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension; import de.siphalor.tweed5.serde.hjson.HjsonLexer; import de.siphalor.tweed5.serde.hjson.HjsonReader; import de.siphalor.tweed5.serde.hjson.HjsonWriter; import de.siphalor.tweed5.serde_api.api.TweedDataVisitor; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -51,13 +58,21 @@ class ReadWriteExtensionImplTest { .apply(entryReaderWriter(booleanReaderWriter())) ).apply(entryReaderWriter(collectionReaderWriter())); + MutableStructuredConfigEntry> mapEntry = new TestMapConfigEntry<>( + configContainer, + (Class>)(Class) Map.class, + new SimpleConfigEntryImpl<>(configContainer, Integer.class) + .apply(entryReaderWriter(intReaderWriter())) + ).apply(entryReaderWriter(mutableStructuredReaderWriter())); + rootEntry = new StaticMapCompoundConfigEntryImpl<>( configContainer, ((Class>) (Class) Map.class), LinkedHashMap::new, sequencedMap(List.of( entry("int", intEntry), - entry("list", listEntry) + entry("list", listEntry), + entry("map", mapEntry) )) ).apply(entryReaderWriter(compoundReaderWriter())); @@ -71,6 +86,7 @@ class ReadWriteExtensionImplTest { Map value = new HashMap<>(); value.put("int", 123); value.put("list", Arrays.asList(true, false, true)); + value.put("map", sequencedMap(List.of(entry("a", 1), entry("b", 2)))); ReadWriteExtension readWriteExtension = configContainer.extension(ReadWriteExtension.class).orElseThrow(); assertDoesNotThrow(() -> readWriteExtension.write( @@ -88,6 +104,10 @@ class ReadWriteExtensionImplTest { \t\tfalse \t\ttrue \t] + \tmap: { + \t\ta: 1 + \t\tb: 2 + \t} } """ ); @@ -105,6 +125,10 @@ class ReadWriteExtensionImplTest { \t\tfalse \t\ttrue \t] + \tmap: { + \t\ta: 1 + \t\tb: 2 + \t} } """))), rootEntry, @@ -115,7 +139,8 @@ class ReadWriteExtensionImplTest { assertThat(result.hasValue()).isTrue(); assertThat(result.value()).isEqualTo(Map.of( "int", 123, - "list", Arrays.asList(true, false, true) + "list", Arrays.asList(true, false, true), + "map", Map.of("a", 1, "b", 2) )); } diff --git a/tweed5/serde-extension/src/test/java/de/siphalor/tweed5/serde/extension/impl/TestMapConfigEntry.java b/tweed5/serde-extension/src/test/java/de/siphalor/tweed5/serde/extension/impl/TestMapConfigEntry.java new file mode 100644 index 0000000..eed508f --- /dev/null +++ b/tweed5/serde-extension/src/test/java/de/siphalor/tweed5/serde/extension/impl/TestMapConfigEntry.java @@ -0,0 +1,87 @@ +package de.siphalor.tweed5.serde.extension.impl; + +import de.siphalor.tweed5.core.api.Arity; +import de.siphalor.tweed5.core.api.container.ConfigContainer; +import de.siphalor.tweed5.core.api.entry.BaseConfigEntry; +import de.siphalor.tweed5.core.api.entry.ConfigEntry; +import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor; +import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor; +import de.siphalor.tweed5.core.api.entry.MutableStructuredConfigEntry; +import de.siphalor.tweed5.core.api.entry.SubEntryKey; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class TestMapConfigEntry + extends BaseConfigEntry> + implements MutableStructuredConfigEntry> { + private final ConfigEntry valueEntry; + + public TestMapConfigEntry( + ConfigContainer container, + Class> valueClass, + ConfigEntry valueEntry + ) { + super(container, valueClass); + this.valueEntry = valueEntry; + } + + @Override + public @NonNull Map instantiateValue() { + return new LinkedHashMap<>(); + } + + @Override + public void set(Map value, String dataKey, Object subValue) { + value.put(dataKey, (V) subValue); + } + + @Override + public @Nullable ConfigEntry getEntry(String dataKey) { + return valueEntry; + } + + @Override + public Object get(Map value, String dataKey) { + return value.get(dataKey); + } + + @Override + public Map> subEntries() { + return Map.of(":value", valueEntry); + } + + @Override + public void visitInOrder(ConfigEntryVisitor visitor) { + if (visitor.enterStructuredEntry(this)) { + if (visitor.enterStructuredSubEntry(":value", Arity.ANY)) { + valueEntry.visitInOrder(visitor); + visitor.leaveStructuredSubEntry(":value", Arity.ANY); + } + visitor.leaveStructuredEntry(this); + } + } + + @Override + public void visitInOrder(ConfigEntryValueVisitor visitor, Map value) { + if (visitor.enterStructuredEntry(this, value)) { + value.forEach((key, subValue) -> { + SubEntryKey subEntryKey = SubEntryKey.addressable(":value", key, key); + if (visitor.enterSubEntry(subEntryKey)) { + valueEntry.visitInOrder(visitor, subValue); + visitor.leaveSubEntry(subEntryKey); + } + }); + visitor.leaveStructuredEntry(this, value); + } + } + + @Override + public Map deepCopy(Map value) { + Map copy = instantiateValue(); + value.forEach((key, subValue) -> copy.put(key, valueEntry.deepCopy(subValue))); + return copy; + } +}