<packaging>bundle</packaging>
<dependencies>
- <dependency>
- <groupId>com.github.mifmif</groupId>
- <artifactId>generex</artifactId>
- <version>1.0.2</version>
- <exclusions>
- <exclusion>
- <groupId>dk.brics.automaton</groupId>
- <artifactId>automaton</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
<dependency>
<groupId>dk.brics</groupId>
<artifactId>automaton</artifactId>
<instructions>
<Bundle-Name>Restconf OpenAPI Generator</Bundle-Name>
- <Embed-Dependency>generex, automaton</Embed-Dependency>
+ <Embed-Dependency>automaton</Embed-Dependency>
<Export-Package>
com.fasterxml.jackson.datatype.*
</Export-Package>
import com.fasterxml.jackson.databind.node.TextNode;
import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
-import com.mifmif.common.regex.Generex;
+import dk.brics.automaton.RegExp;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Collection;
private static final String INT32_FORMAT = "int32";
private static final String INT64_FORMAT = "int64";
private static final String BOOLEAN_TYPE = "boolean";
- // Special characters used in automaton inside Generex.
+ // Special characters used in Automaton.
// See https://www.brics.dk/automaton/doc/dk/brics/automaton/RegExp.html
private static final Pattern AUTOMATON_SPECIAL_CHARACTERS = Pattern.compile("[@&\"<>#~]");
+ // Adaptation from YANG regex to Automaton regex
+ // See https://github.com/mifmif/Generex/blob/master/src/main/java/com/mifmif/common/regex/Generex.java
+ private static final Map<String, String> PREDEFINED_CHARACTER_CLASSES = Map.of("\\\\d", "[0-9]",
+ "\\\\D", "[^0-9]", "\\\\s", "[ \t\n\f\r]", "\\\\S", "[^ \t\n\f\r]",
+ "\\\\w", "[a-zA-Z_0-9]", "\\\\W", "[^a-zA-Z_0-9]");
private Module topLevelModule;
if (type.getPatternConstraints().iterator().hasNext()) {
final PatternConstraint pattern = type.getPatternConstraints().iterator().next();
- String regex = pattern.getJavaPatternString();
- regex = regex.substring(1, regex.length() - 1);
- // Escape special characters to prevent issues inside Generex.
+ String regex = pattern.getRegularExpressionString();
+ // Escape special characters to prevent issues inside Automaton.
regex = AUTOMATON_SPECIAL_CHARACTERS.matcher(regex).replaceAll("\\\\$0");
+ for (final var charClass : PREDEFINED_CHARACTER_CLASSES.entrySet()) {
+ regex = regex.replaceAll(charClass.getKey(), charClass.getValue());
+ }
String defaultValue = "";
try {
- final Generex generex = new Generex(regex);
- defaultValue = generex.random();
+ final RegExp regExp = new RegExp(regex);
+ defaultValue = regExp.toAutomaton().getShortestExample(true);
} catch (IllegalArgumentException ex) {
LOG.warn("Cannot create example string for type: {} with regex: {}.", stringType.getQName(), regex);
}
*/
package org.opendaylight.restconf.openapi.impl;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
final var schemas = generator.convertToSchemas(module, CONTEXT, new DefinitionNames(), true);
assertNotNull(schemas);
}
+
+ @Test
+ public void testStringFromRegex() throws IOException {
+ final var module = CONTEXT.findModule("strings-from-regex").orElseThrow();
+ final var generator = new DefinitionGenerator();
+ final var jsonObject = generator.convertToSchemas(module, CONTEXT, new DefinitionNames(), true);
+ assertNotNull(jsonObject);
+
+ var properties = jsonObject.get("strings-from-regex_test").getProperties();
+ assertEquals("00:00:00:00:00:00", properties.get("mac-address").get("default").asText());
+ assertEquals("0000-00-00T00:00:00Z", properties.get("login-date-time").get("default").asText());
+ assertEquals("0.0.0.0", properties.get("ipv4-address").get("default").asText());
+ }
}
final Map<String, Path> paths = mountPointApi.getPaths();
assertNotNull(paths);
- assertEquals("Unexpected api list size", 26, paths.size());
+ assertEquals("Unexpected api list size", 27, paths.size());
final List<JsonNode> getOperations = new ArrayList<>();
final List<JsonNode> postOperations = new ArrayList<>();
Optional.ofNullable(path.getValue().getDelete()).ifPresent(deleteOperations::add);
}
- assertEquals("Unexpected GET paths size", 18, getOperations.size());
- assertEquals("Unexpected POST paths size", 24, postOperations.size());
- assertEquals("Unexpected PUT paths size", 16, putOperations.size());
- assertEquals("Unexpected PATCH paths size", 16, patchOperations.size());
- assertEquals("Unexpected DELETE paths size", 16, deleteOperations.size());
+ assertEquals("Unexpected GET paths size", 19, getOperations.size());
+ assertEquals("Unexpected POST paths size", 25, postOperations.size());
+ assertEquals("Unexpected PUT paths size", 17, putOperations.size());
+ assertEquals("Unexpected PATCH paths size", 17, patchOperations.size());
+ assertEquals("Unexpected DELETE paths size", 17, deleteOperations.size());
}
}
--- /dev/null
+module strings-from-regex {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:strings:regex";
+ prefix "str-rx";
+
+ typedef MacAddress {
+ type string {
+ pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+ }
+ }
+
+ typedef Date-Time {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[\+\-]\d{2}:\d{2})';
+ }
+ }
+
+ typedef ipv4-address {
+ type string {
+ pattern '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(%[\p{N}\p{L}]+)?';
+ }
+ }
+
+ container test {
+ leaf mac-address {
+ type MacAddress;
+ }
+ leaf login-date-time {
+ type Date-Time;
+ }
+ leaf ipv4-address {
+ type ipv4-address;
+ }
+ }
+}