Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability for semantic key sequence.md generation #742

Merged
merged 12 commits into from
Oct 17, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -1865,6 +1865,11 @@ protected <T> T ifCatchNullSkipTest(Supplier<T> evaluator, String reason) {
return ifNullSkipTest(evaluatorResult, reason);
}

protected void mapSemanticKey(String keyPath, String keyName, String description,
String describedValue) {
SENT_CONFIG_DIFFERNATOR.mapSemanticKey(keyPath, keyName, description, describedValue);
}

/**
* Special exception to indicate that catching-loops should be terminated.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import java.util.Date;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.stream.Collectors;
import org.junit.Test;
import udmi.schema.Level;
Expand All @@ -39,6 +38,7 @@ public class PointsetSequences extends PointsetBase {

public static final String EXTRANEOUS_POINT = "extraneous_point";
private static final int DEFAULT_SAMPLE_RATE_SEC = 10;
public static final String POINTS_MAP_PATH = "pointset.points";

private boolean isErrorState(PointPointsetState pointState) {
return ofNullable(catchToNull(() -> pointState.status.level)).orElse(Level.INFO.value())
Expand Down Expand Up @@ -69,6 +69,8 @@ private boolean validPointEntry(Entry<String, PointPointsetEvent> point) {
public void pointset_request_extraneous() {
untilPointsetSanity();

mapSemanticKey(POINTS_MAP_PATH, EXTRANEOUS_POINT, "extraneous_point", "point configuration");

deviceConfig.pointset.points.put(EXTRANEOUS_POINT, new PointPointsetConfig());

try {
Expand Down Expand Up @@ -98,6 +100,7 @@ public void pointset_remove_point() {
String name = candidatePoints.get((int) Math.floor(Math.random() * candidatePoints.size()));

debug("Removing randomly selected test point " + name);
mapSemanticKey(POINTS_MAP_PATH, name, "random_point", "point configuration");
PointPointsetConfig removed = requireNonNull(deviceConfig.pointset.points.remove(name));

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
Expand All @@ -18,6 +19,8 @@
*/
public class ObjectDiffEngine {

private final Map<String, String> descriptions = new HashMap<>();
private final Map<String, String> describedValues = new HashMap<>();
private Map<String, Object> previous;
private boolean ignoreSemantics;

Expand Down Expand Up @@ -46,6 +49,8 @@ public List<String> computeChanges(Object updatedObject) {
* @param updatedObject new object state
*/
public void resetState(Object updatedObject) {
descriptions.clear();
describedValues.clear();
previous = extractDefinitions(updatedObject);
}

Expand All @@ -65,11 +70,13 @@ private Map<String, Object> traverseExtract(Object thing, boolean asValues) {
@SuppressWarnings("unchecked")
Map<String, Object> asMap = (Map<String, Object>) thing;
return asMap.keySet().stream()
.collect(Collectors.toMap(key -> key, key -> traverseExtract(asMap.get(key), asValues)));
.collect(Collectors.toMap(key -> key,
key -> traverseExtract(asMap.get(key), asValues)));
}
return Arrays.stream(thing.getClass().getFields())
.filter(field -> isNotNull(thing, field)).collect(
Collectors.toMap(Field::getName, field -> extractField(thing, field, asValues)));
Collectors.toMap(Field::getName,
field -> extractField(thing, field, asValues)));
}

private Object extractField(Object thing, Field field, boolean asValue) {
Expand Down Expand Up @@ -108,31 +115,45 @@ private boolean isBaseType(Object value) {
void accumulateDifference(String prefix, Map<String, Object> left, Map<String, Object> right,
List<String> updates) {
right.forEach((key, value) -> {
String describedKey = describedKey(prefix, key);
String describedValue = describeValue(prefix, key, semanticValue(value));
if (left != null && left.containsKey(key)) {
Object leftValue = left.get(key);
if (SemanticValue.equals(value, leftValue)) {
return;
}
if (isBaseType(value)) {
updates.add(String.format("Set `%s%s` = %s", prefix, key, semanticValue(value)));
updates.add(String.format("Set `%s` = %s", describedKey, describedValue));
} else {
String newPrefix = prefix + key + ".";
accumulateDifference(newPrefix, (Map<String, Object>) leftValue,
accumulateDifference((prefix + key) + ".", (Map<String, Object>) leftValue,
(Map<String, Object>) value, updates);
}
} else {
updates.add(String.format("Add `%s%s` = %s", prefix, key, semanticValue(value)));
updates.add(String.format("Add `%s` = %s", describedKey, describedValue));
}
});
if (left != null) {
left.forEach((key, value) -> {
if (!right.containsKey(key)) {
updates.add(String.format("Remove `%s%s`", prefix, key));
String describedKey = describedKey(prefix, key);
updates.add(String.format("Remove `%s`", describedKey));
}
});
}
}

private String describeValue(String prefix, String key, String value) {
String fullKey = prefix + key;
return descriptions.containsKey(fullKey) ? describedValues.get(fullKey) : value;
}

private String describedKey(String prefix, String key) {
String fullKey = prefix + key;
String keyPath = prefix.endsWith(".") ? prefix.substring(0, prefix.length() - 1) : prefix;
String formattedKey = String.format("%s[%s]", keyPath, descriptions.get(fullKey));
return descriptions.containsKey(fullKey) ? formattedKey : fullKey;
}

private String singleLine(String toJsonString) {
return Joiner.on(' ').join(
Arrays.stream(toJsonString.split("\n")).map(String::trim).collect(Collectors.toList()));
Expand Down Expand Up @@ -194,6 +215,21 @@ public List<String> diff(Object startObject, Object endObject) {
return updates;
}

/**
* Set up a semantic mapping for a key/value pair.
*
* @param keyPath path to container
* @param keyName key name
* @param description semantic description of key
* @param describedValue semantic description of value
*/
public void mapSemanticKey(String keyPath, String keyName, String description,
String describedValue) {
String fullKey = keyPath + "." + keyName;
descriptions.put(fullKey, description);
describedValues.put(fullKey, describedValue);
}

public boolean isInitialized() {
return previous != null;
}
Expand Down