mirror of
https://github.com/danieldemus/openhab-core.git
synced 2026-07-29 12:34:22 +02:00
Add support for short-form metadata namespace in Item Yaml config (#5250)
* Support deserializing short-form metadata in YamlMetadataDTO So we can set `metadata: value` instead of ``` metadata: value: value ``` Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
This commit is contained in:
+6
@@ -19,12 +19,18 @@ import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.model.yaml.internal.util.YamlElementUtils;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
|
||||
/**
|
||||
* The {@link YamlMetadataDTO} is a data transfer object used to serialize a metadata for a particular namespace
|
||||
* in a YAML configuration file.
|
||||
*
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
* @author Jimmy Tanagra - Support scalar metadata namespace
|
||||
*/
|
||||
@JsonSerialize(using = YamlMetadataDTOSerializer.class)
|
||||
@JsonDeserialize(using = YamlMetadataDTODeserializer.class)
|
||||
public class YamlMetadataDTO {
|
||||
|
||||
public String value;
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2026 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.model.yaml.internal.items;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import com.fasterxml.jackson.core.ObjectCodec;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* Custom deserializer for {@link YamlMetadataDTO} that converts any YAML scalar
|
||||
* (string, integer, boolean, or float) into a metadata String {@code value} with an empty config.
|
||||
*
|
||||
* @author Jimmy Tanagra - Initial contribution
|
||||
*/
|
||||
class YamlMetadataDTODeserializer extends JsonDeserializer<YamlMetadataDTO> {
|
||||
|
||||
@Override
|
||||
public YamlMetadataDTO deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||
JsonToken token = p.currentToken();
|
||||
if (token == JsonToken.VALUE_STRING || token == JsonToken.VALUE_NUMBER_INT
|
||||
|| token == JsonToken.VALUE_NUMBER_FLOAT || token == JsonToken.VALUE_TRUE
|
||||
|| token == JsonToken.VALUE_FALSE) {
|
||||
YamlMetadataDTO dto = new YamlMetadataDTO();
|
||||
dto.value = p.getValueAsString("");
|
||||
return dto;
|
||||
}
|
||||
if (token == JsonToken.START_OBJECT) {
|
||||
ObjectCodec codec = p.getCodec();
|
||||
JsonNode node = codec.readTree(p);
|
||||
|
||||
YamlMetadataDTO dto = new YamlMetadataDTO();
|
||||
JsonNode valueNode = node.get("value");
|
||||
if (valueNode != null && !valueNode.isNull()) {
|
||||
dto.value = valueNode.asText();
|
||||
}
|
||||
|
||||
JsonNode configNode = node.get("config");
|
||||
if (configNode != null && !configNode.isNull()) {
|
||||
dto.config = codec.treeToValue(configNode, Map.class);
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
return (YamlMetadataDTO) ctxt.handleUnexpectedToken(YamlMetadataDTO.class, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlMetadataDTO getNullValue(DeserializationContext ctxt) {
|
||||
return new YamlMetadataDTO();
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2026 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.model.yaml.internal.items;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
/**
|
||||
* Custom serializer for {@link YamlMetadataDTO} that writes the namespace as a scalar
|
||||
* when its config is empty, otherwise writes as an object with value and config fields.
|
||||
*
|
||||
* @author Jimmy Tanagra - Initial contribution
|
||||
*/
|
||||
public class YamlMetadataDTOSerializer extends JsonSerializer<YamlMetadataDTO> {
|
||||
@Override
|
||||
public void serialize(YamlMetadataDTO value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
Map<?, ?> config = value.config;
|
||||
boolean configIsEmpty = (config == null || config.isEmpty());
|
||||
if (configIsEmpty) {
|
||||
gen.writeString(value.getValue());
|
||||
} else {
|
||||
gen.writeStartObject();
|
||||
gen.writeStringField("value", value.getValue());
|
||||
gen.writeObjectField("config", value.config);
|
||||
gen.writeEndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
+168
@@ -18,15 +18,21 @@ import static org.hamcrest.Matchers.contains;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -40,6 +46,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.openhab.core.model.yaml.YamlModelListener;
|
||||
import org.openhab.core.model.yaml.internal.items.YamlItemDTO;
|
||||
import org.openhab.core.model.yaml.test.FirstTypeDTO;
|
||||
import org.openhab.core.model.yaml.test.SecondTypeDTO;
|
||||
import org.openhab.core.service.WatchService;
|
||||
@@ -464,4 +471,165 @@ public class YamlModelRepositoryImplTest {
|
||||
assertThat(secondTypeElements, hasSize(1));
|
||||
assertThat(secondTypeElements, contains(new SecondTypeDTO("Second1", "Label1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObjectFormMetadataLoadingAndGeneration() throws IOException {
|
||||
Files.copy(SOURCE_PATH.resolve("itemWithObjectFormMetadata.yaml"), fullModelPath);
|
||||
|
||||
YamlModelRepositoryImpl modelRepository = new YamlModelRepositoryImpl(watchServiceMock);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
YamlModelListener<YamlItemDTO> itemListener = mock(YamlModelListener.class);
|
||||
when(itemListener.getElementClass()).thenReturn(YamlItemDTO.class);
|
||||
when(itemListener.isVersionSupported(anyInt())).thenReturn(true);
|
||||
when(itemListener.isDeprecated()).thenReturn(false);
|
||||
|
||||
modelRepository.addYamlModelListener(itemListener);
|
||||
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModelPath);
|
||||
|
||||
// Verify the listener was called
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<Collection<YamlItemDTO>> captor = ArgumentCaptor.forClass(Collection.class);
|
||||
verify(itemListener).addedModel(eq(MODEL_NAME), captor.capture());
|
||||
|
||||
// Verify that the valid item with object-form metadata was loaded
|
||||
Collection<YamlItemDTO> items = captor.getValue();
|
||||
assertThat(items, hasSize(1));
|
||||
|
||||
YamlItemDTO item = items.iterator().next();
|
||||
assertThat(item.name, is("ValidItem"));
|
||||
assertThat(item.metadata, is(notNullValue()));
|
||||
assertThat(item.metadata.keySet(), containsInAnyOrder("alexa", "homekit"));
|
||||
assertThat(item.metadata.get("alexa").value, is("Switchable"));
|
||||
assertThat(item.metadata.get("alexa").config, is(Map.of("setting1", "value1")));
|
||||
assertThat(item.metadata.get("homekit").value, is("Lighting"));
|
||||
assertThat(item.metadata.get("homekit").config, is(nullValue()));
|
||||
|
||||
// Verify YAML output contains object form metadata
|
||||
modelRepository.addElementsToBeGenerated("items", List.copyOf(items));
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
modelRepository.generateFileFormat("items", out);
|
||||
String yaml = out.toString();
|
||||
// Should contain object form metadata for 'alexa'
|
||||
assertThat(yaml, containsString("alexa:"));
|
||||
assertThat(yaml, containsString("value: Switchable"));
|
||||
assertThat(yaml, containsOnlyOnce("config:"));
|
||||
assertThat(yaml, containsString("setting1: value1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShortFormMetadataLoadingAndGeneration() throws IOException {
|
||||
Files.copy(SOURCE_PATH.resolve("itemWithShortFormMetadata.yaml"), fullModelPath);
|
||||
YamlModelRepositoryImpl modelRepository = new YamlModelRepositoryImpl(watchServiceMock);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
YamlModelListener<YamlItemDTO> itemListener = mock(YamlModelListener.class);
|
||||
when(itemListener.getElementClass()).thenReturn(YamlItemDTO.class);
|
||||
when(itemListener.isVersionSupported(anyInt())).thenReturn(true);
|
||||
when(itemListener.isDeprecated()).thenReturn(false);
|
||||
|
||||
modelRepository.addYamlModelListener(itemListener);
|
||||
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModelPath);
|
||||
|
||||
// Verify the listener was called
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<Collection<YamlItemDTO>> captor = ArgumentCaptor.forClass(Collection.class);
|
||||
verify(itemListener).addedModel(eq(MODEL_NAME), captor.capture());
|
||||
// Verify items were loaded with short-form metadata
|
||||
Collection<YamlItemDTO> items = captor.getValue();
|
||||
assertThat(items, hasSize(1));
|
||||
|
||||
YamlItemDTO item = items.iterator().next();
|
||||
assertThat(item.metadata, is(notNullValue()));
|
||||
assertThat(item.metadata.keySet(), containsInAnyOrder("alexa", "homekit"));
|
||||
// deserializer converts short-form to value field
|
||||
assertThat(item.metadata.get("alexa").value, is("Switchable"));
|
||||
assertThat(item.metadata.get("alexa").config, is(nullValue()));
|
||||
assertThat(item.metadata.get("homekit").value, is("Lighting"));
|
||||
assertThat(item.metadata.get("homekit").config, is(nullValue()));
|
||||
|
||||
// Verify YAML output contains short form metadata
|
||||
modelRepository.addElementsToBeGenerated("items", List.copyOf(items));
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
modelRepository.generateFileFormat("items", out);
|
||||
String yaml = out.toString();
|
||||
assertThat(yaml, containsString("alexa: Switchable"));
|
||||
assertThat(yaml, containsString("homekit: Lighting"));
|
||||
// Should not contain object form keys
|
||||
assertThat(yaml, not(containsString("value:")));
|
||||
assertThat(yaml, not(containsString("config:")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMixedFormMetadataLoadingAndGeneration() throws IOException {
|
||||
Files.copy(SOURCE_PATH.resolve("itemWithMixedFormMetadata.yaml"), fullModelPath);
|
||||
|
||||
YamlModelRepositoryImpl modelRepository = new YamlModelRepositoryImpl(watchServiceMock);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
YamlModelListener<YamlItemDTO> itemListener = mock(YamlModelListener.class);
|
||||
when(itemListener.getElementClass()).thenReturn(YamlItemDTO.class);
|
||||
when(itemListener.isVersionSupported(anyInt())).thenReturn(true);
|
||||
when(itemListener.isDeprecated()).thenReturn(false);
|
||||
|
||||
modelRepository.addYamlModelListener(itemListener);
|
||||
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModelPath);
|
||||
|
||||
// Verify the listener was called
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<Collection<YamlItemDTO>> captor = ArgumentCaptor.forClass(Collection.class);
|
||||
verify(itemListener).addedModel(eq(MODEL_NAME), captor.capture());
|
||||
|
||||
// Verify that the valid item with mixed-form metadata was loaded
|
||||
Collection<YamlItemDTO> items = captor.getValue();
|
||||
assertThat(items, hasSize(1));
|
||||
|
||||
YamlItemDTO item = items.iterator().next();
|
||||
assertThat(item.name, is("ValidItem"));
|
||||
assertThat(item.metadata, is(notNullValue()));
|
||||
assertThat(item.metadata.keySet(), containsInAnyOrder("alexa", "homekit", "matter"));
|
||||
assertThat(item.metadata.get("alexa").value, is("Switchable"));
|
||||
assertThat(item.metadata.get("alexa").config, is(Map.of("setting1", "value1")));
|
||||
assertThat(item.metadata.get("homekit").value, is("Lighting"));
|
||||
assertThat(item.metadata.get("homekit").config, is(nullValue()));
|
||||
assertThat(item.metadata.get("matter").value, is("OnOffLight"));
|
||||
assertThat(item.metadata.get("matter").config, is(nullValue()));
|
||||
|
||||
// Verify YAML output contains metadata in both forms
|
||||
modelRepository.addElementsToBeGenerated("items", List.copyOf(items));
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
modelRepository.generateFileFormat("items", out);
|
||||
String yaml = out.toString();
|
||||
// Should contain object form metadata for 'alexa'
|
||||
assertThat(yaml, containsString("alexa:"));
|
||||
assertThat(yaml, containsString("value: Switchable"));
|
||||
assertThat(yaml, containsOnlyOnce("config:"));
|
||||
assertThat(yaml, containsString("setting1: value1"));
|
||||
|
||||
// Should contain short form metadata for 'homekit' and 'matter'
|
||||
assertThat(yaml, containsString("homekit: Lighting"));
|
||||
assertThat(yaml, containsString("matter: OnOffLight"));
|
||||
}
|
||||
|
||||
private static Matcher<String> containsOnlyOnce(String substring) {
|
||||
return new TypeSafeMatcher<String>() {
|
||||
@Override
|
||||
protected boolean matchesSafely(String item) {
|
||||
return StringUtils.countMatches(item, substring) == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNullByDefault({})
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("string appearing exactly once: ").appendValue(substring);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNullByDefault({})
|
||||
protected void describeMismatchSafely(String item, Description mismatchDescription) {
|
||||
int count = StringUtils.countMatches(item, substring);
|
||||
mismatchDescription.appendText("was found ").appendValue(count).appendText(" times");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2026 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.model.yaml.internal.items;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
|
||||
/**
|
||||
* Tests for {@link YamlMetadataDTODeserializer}.
|
||||
*
|
||||
* @author Jimmy Tanagra - Initial contribution
|
||||
*/
|
||||
class YamlMetadataDTODeserializerTest {
|
||||
|
||||
private final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "string value", "123", "45.67", "true", "false" })
|
||||
void shouldDeserializeScalarAsValueWithEmptyConfig(String scalar) throws IOException {
|
||||
String yaml = "ns: " + scalar;
|
||||
YamlMetadataDTO dto = mapper.treeToValue(mapper.readTree(yaml).get("ns"), YamlMetadataDTO.class);
|
||||
assertNotNull(dto);
|
||||
assertEquals(scalar, dto.getValue());
|
||||
assertNull(dto.config);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDeserializeObjectWithValueAndConfig() throws IOException {
|
||||
String yaml = "ns: { value: bar, config: { a: 1, b: two } }";
|
||||
YamlMetadataDTO dto = mapper.treeToValue(mapper.readTree(yaml).get("ns"), YamlMetadataDTO.class);
|
||||
assertNotNull(dto);
|
||||
assertEquals("bar", dto.getValue());
|
||||
assertNotNull(dto.config);
|
||||
assertEquals(1, dto.config.get("a"));
|
||||
assertEquals("two", dto.config.get("b"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDeserializeObjectWithValueAndNoConfig() throws IOException {
|
||||
String yaml = "ns: { value: bar }";
|
||||
YamlMetadataDTO dto = mapper.treeToValue(mapper.readTree(yaml).get("ns"), YamlMetadataDTO.class);
|
||||
assertNotNull(dto);
|
||||
assertEquals("bar", dto.getValue());
|
||||
assertNull(dto.config);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDeserializeObjectWithNoValueAndConfig() throws IOException {
|
||||
String yaml = "ns: { config: { a: 1, b: two } }";
|
||||
YamlMetadataDTO dto = mapper.treeToValue(mapper.readTree(yaml).get("ns"), YamlMetadataDTO.class);
|
||||
assertNotNull(dto);
|
||||
assertEquals("", dto.getValue());
|
||||
assertNotNull(dto.config);
|
||||
assertEquals(1, dto.config.get("a"));
|
||||
assertEquals("two", dto.config.get("b"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDeserializeEmptyObjectAsEmptyDto() throws IOException {
|
||||
String yaml = "ns: { }";
|
||||
YamlMetadataDTO dto = mapper.treeToValue(mapper.readTree(yaml).get("ns"), YamlMetadataDTO.class);
|
||||
assertNotNull(dto);
|
||||
assertEquals("", dto.getValue());
|
||||
assertNull(dto.config);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "null", "", "''" })
|
||||
void shouldDeserializeNullAndEmptyStringAsEmptyDto(String scalar) throws IOException {
|
||||
String yaml = "ns: " + scalar;
|
||||
YamlMetadataDTO dto = mapper.treeToValue(mapper.readTree(yaml).get("ns"), YamlMetadataDTO.class);
|
||||
assertNotNull(dto);
|
||||
assertEquals("", dto.getValue());
|
||||
assertNull(dto.config);
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2026 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.model.yaml.internal.items;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
|
||||
/**
|
||||
* Tests for {@link YamlMetadataDTOSerializer}.
|
||||
*
|
||||
* @author Jimmy Tanagra - Initial contribution
|
||||
*/
|
||||
class YamlMetadataDTOSerializerTest {
|
||||
private final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
|
||||
|
||||
@Test
|
||||
void testSerializeScalarWhenConfigEmpty() throws Exception {
|
||||
YamlMetadataDTO dto = new YamlMetadataDTO();
|
||||
dto.value = "scalarValue";
|
||||
dto.config = null;
|
||||
String yaml = mapper.writeValueAsString(dto).trim();
|
||||
assertEquals("--- \"scalarValue\"", yaml);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSerializeScalarWhenConfigEmptyMap() throws Exception {
|
||||
YamlMetadataDTO dto = new YamlMetadataDTO();
|
||||
dto.value = "scalarValue";
|
||||
dto.config = new HashMap<>();
|
||||
String yaml = mapper.writeValueAsString(dto).trim();
|
||||
assertEquals("--- \"scalarValue\"", yaml);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSerializeObjectWhenConfigPresent() throws Exception {
|
||||
YamlMetadataDTO dto = new YamlMetadataDTO();
|
||||
dto.value = "objectValue";
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.put("foo", "bar");
|
||||
dto.config = config;
|
||||
String yaml = mapper.writeValueAsString(dto).trim();
|
||||
System.out.println("YAML output:\n" + yaml);
|
||||
// Check for document start and all expected fields
|
||||
assert yaml.startsWith("---");
|
||||
assert yaml.contains("value: \"objectValue\"");
|
||||
assert yaml.contains("config:");
|
||||
assert yaml.contains("foo: \"bar\"");
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
version: 1
|
||||
items:
|
||||
# This item has metadata in both short and object forms
|
||||
ValidItem:
|
||||
type: Switch
|
||||
metadata:
|
||||
alexa:
|
||||
value: Switchable
|
||||
config:
|
||||
setting1: value1
|
||||
homekit:
|
||||
value: Lighting
|
||||
matter: OnOffLight
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
version: 1
|
||||
items:
|
||||
# This item has the object-form metadata
|
||||
ValidItem:
|
||||
type: Switch
|
||||
metadata:
|
||||
alexa:
|
||||
value: Switchable
|
||||
config:
|
||||
setting1: value1
|
||||
homekit:
|
||||
value: Lighting
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
version: 1
|
||||
items:
|
||||
TestSwitch:
|
||||
type: Switch
|
||||
metadata:
|
||||
alexa: Switchable
|
||||
homekit: Lighting
|
||||
Reference in New Issue
Block a user