try {
final var automaton = new RegExp(regex).toAutomaton();
if (minLength > 0) {
- defaultValue = prepareExample(defaultValue, automaton.getInitialState(), minLength, maxLength);
+ defaultValue = prepareExample(List.of(new ExampleCandidate(
+ defaultValue, automaton.getInitialState())), minLength, maxLength);
} else {
defaultValue = automaton.getShortestExample(true);
}
return STRING_TYPE;
}
- private static String prepareExample(final String strMatch, final State state, final int minLength,
+ private static String prepareExample(final List<ExampleCandidate> candidates, final int minLength,
final int maxLength) {
- final var transitions = state.getSortedTransitions(false);
+ final var nextCandidates = new ArrayList<ExampleCandidate>();
+ for (var candidate : candidates) {
+ final var string = candidate.string();
+ final var state = candidate.state();
- if (state.isAccept() && strMatch.length() >= minLength) {
- return strMatch;
- }
+ if (string.length() >= minLength && state.isAccept()) {
+ return candidate.string();
+ }
- if (transitions.isEmpty()) {
- return strMatch;
+ if (string.length() < maxLength) {
+ final var transitions = state.getSortedTransitions(false);
+ transitions.forEach(t -> nextCandidates.add(
+ new ExampleCandidate(string + t.getMin(), t.getDest())));
+ }
}
- // Always choose the first transition and the minimum character
- final var firstTransition = transitions.get(0);
- final var firstChar = firstTransition.getMin();
- final var result = prepareExample(strMatch + firstChar, firstTransition.getDest(), minLength, maxLength);
-
- if (minLength <= result.length() && result.length() <= maxLength) {
- return result;
+ if (nextCandidates.isEmpty()) {
+ // If no string satisfies the length & regex constraints, return the first
+ return candidates.getFirst().string();
}
- // If the resulting string does not satisfy the length constraints, return the current string
- return strMatch;
+ return prepareExample(nextCandidates, minLength, maxLength);
+ }
+
+ private record ExampleCandidate(String string, State state) {
}
}
--- /dev/null
+/*
+ * Copyright (c) 2024 Verizon and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.openapi.impl;
+
+import java.util.stream.Stream;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+class NC1386Test extends AbstractDocumentTest {
+ @BeforeAll
+ static void beforeAll() {
+ initializeClass("/nc1386/");
+ }
+
+ /**
+ * Tests the swagger document that is result of the call to the '/moduleName' endpoint.
+ */
+ @ParameterizedTest
+ @MethodSource
+ void getDocByModuleTest(final String moduleName, final String revision, final String jsonPath)
+ throws Exception {
+ final var expectedJson = getExpectedDoc("nc1386-document/" + jsonPath);
+ final var moduleDoc = getDocByModule(moduleName, revision);
+ JSONAssert.assertEquals(expectedJson, moduleDoc, IGNORE_ORDER);
+ }
+
+ private static Stream<Arguments> getDocByModuleTest() {
+ // moduleName, revision, jsonPath
+ return Stream.of(
+ Arguments.of("regex1", "2024-09-12", "regex1.json"),
+ Arguments.of("regex2", "2024-09-12", "regex2.json"),
+ Arguments.of("regex3", "2024-09-12", "regex3.json")
+ );
+ }
+}
--- /dev/null
+{
+ "openapi": "3.0.3",
+ "info": {
+ "version": "1.0.0",
+ "title": "regex1",
+ "description": "We are providing full API for configurational data which can be edited (by POST, PUT, PATCH and DELETE).\nFor operational data we only provide GET API.\n\nFor majority of request you can see only config data in examples. That's because we can show only one example\nper request. The exception when you can see operational data in example is when data are representing\noperational (config false) container with no config data in it."
+ },
+ "servers": [
+ {
+ "url": "http://localhost:8181/"
+ }
+ ],
+ "paths": {
+ "/rests/data": {
+ "post": {
+ "description": "\n\nNote:\nIn example payload, you can see only the first data node child of the resource to be created, following the\nguidelines of RFC 8040, which allows us to create only one resource in POST request.\n",
+ "summary": "POST - Controller - regex1 - regex1",
+ "requestBody": {
+ "description": "cntr",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "cntr": {
+ "$ref": "#/components/schemas/regex1_cntr",
+ "type": "object"
+ }
+ }
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/regex1_cntr"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Created"
+ }
+ },
+ "tags": [
+ "Controller regex1"
+ ],
+ "parameters": []
+ }
+ },
+ "/rests/data/regex1:cntr": {
+ "put": {
+ "description": "",
+ "summary": "PUT - regex1 - Controller - cntr",
+ "requestBody": {
+ "description": "cntr",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "regex1:cntr": {
+ "$ref": "#/components/schemas/regex1_cntr",
+ "type": "object"
+ }
+ }
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/regex1_cntr"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "204": {
+ "description": "Updated"
+ }
+ },
+ "tags": [
+ "Controller regex1"
+ ],
+ "parameters": []
+ },
+ "patch": {
+ "description": "",
+ "summary": "PATCH - regex1 - Controller - cntr",
+ "requestBody": {
+ "description": "cntr",
+ "content": {
+ "application/yang-data+json": {
+ "schema": {
+ "properties": {
+ "regex1:cntr": {
+ "$ref": "#/components/schemas/regex1_cntr",
+ "type": "object"
+ }
+ }
+ }
+ },
+ "application/yang-data+xml": {
+ "schema": {
+ "$ref": "#/components/schemas/regex1_cntr"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "OK"
+ },
+ "204": {
+ "description": "Updated"
+ }
+ },
+ "tags": [
+ "Controller regex1"
+ ],
+ "parameters": []
+ },
+ "delete": {
+ "description": "",
+ "summary": "DELETE - Controller - regex1 - cntr",
+ "responses": {
+ "204": {
+ "description": "Deleted"
+ }
+ },
+ "tags": [
+ "Controller regex1"
+ ],
+ "parameters": []
+ },
+ "get": {
+ "description": "",
+ "summary": "GET - Controller - regex1 - cntr",
+ "responses": {
+ "200": {
+ "description": "200",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/regex1_cntr"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "properties": {
+ "cntr": {
+ "$ref": "#/components/schemas/regex1_cntr",
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "Controller regex1"
+ ],
+ "parameters": [
+ {
+ "name": "content",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "enum": [
+ "config",
+ "nonconfig",
+ "all"
+ ],
+ "type": "string"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "regex1_cntr": {
+ "title": "regex1_cntr",
+ "type": "object",
+ "properties": {
+ "lf": {
+ "description": "",
+ "type": "string",
+ "example": "0",
+ "minLength": 1,
+ "maxLength": 100
+ }
+ },
+ "xml": {
+ "name": "cntr",
+ "namespace": "urn:regex1"
+ }
+ }
+ },
+ "securitySchemes": {
+ "basicAuth": {
+ "scheme": "basic",
+ "type": "http"
+ }
+ }
+ },
+ "security": [
+ {
+ "basicAuth": []
+ }
+ ]
+}
--- /dev/null
+{
+ "openapi": "3.0.3",
+ "info": {
+ "version": "1.0.0",
+ "title": "regex2",
+ "description": "We are providing full API for configurational data which can be edited (by POST, PUT, PATCH and DELETE).\nFor operational data we only provide GET API.\n\nFor majority of request you can see only config data in examples. That's because we can show only one example\nper request. The exception when you can see operational data in example is when data are representing\noperational (config false) container with no config data in it."
+ },
+ "servers": [
+ {
+ "url": "http://localhost:8181/"
+ }
+ ],
+ "paths": {
+ "/rests/data": {
+ "post": {
+ "description": "\n\nNote:\nIn example payload, you can see only the first data node child of the resource to be created, following the\nguidelines of RFC 8040, which allows us to create only one resource in POST request.\n",
+ "summary": "POST - Controller - regex2 - regex2",
+ "requestBody": {
+ "description": "cntr",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "cntr": {
+ "$ref": "#/components/schemas/regex2_cntr",
+ "type": "object"
+ }
+ }
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/regex2_cntr"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Created"
+ }
+ },
+ "tags": [
+ "Controller regex2"
+ ],
+ "parameters": []
+ }
+ },
+ "/rests/data/regex2:cntr": {
+ "put": {
+ "description": "",
+ "summary": "PUT - regex2 - Controller - cntr",
+ "requestBody": {
+ "description": "cntr",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "regex2:cntr": {
+ "$ref": "#/components/schemas/regex2_cntr",
+ "type": "object"
+ }
+ }
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/regex2_cntr"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "204": {
+ "description": "Updated"
+ }
+ },
+ "tags": [
+ "Controller regex2"
+ ],
+ "parameters": []
+ },
+ "patch": {
+ "description": "",
+ "summary": "PATCH - regex2 - Controller - cntr",
+ "requestBody": {
+ "description": "cntr",
+ "content": {
+ "application/yang-data+json": {
+ "schema": {
+ "properties": {
+ "regex2:cntr": {
+ "$ref": "#/components/schemas/regex2_cntr",
+ "type": "object"
+ }
+ }
+ }
+ },
+ "application/yang-data+xml": {
+ "schema": {
+ "$ref": "#/components/schemas/regex2_cntr"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "OK"
+ },
+ "204": {
+ "description": "Updated"
+ }
+ },
+ "tags": [
+ "Controller regex2"
+ ],
+ "parameters": []
+ },
+ "delete": {
+ "description": "",
+ "summary": "DELETE - Controller - regex2 - cntr",
+ "responses": {
+ "204": {
+ "description": "Deleted"
+ }
+ },
+ "tags": [
+ "Controller regex2"
+ ],
+ "parameters": []
+ },
+ "get": {
+ "description": "",
+ "summary": "GET - Controller - regex2 - cntr",
+ "responses": {
+ "200": {
+ "description": "200",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/regex2_cntr"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "properties": {
+ "cntr": {
+ "$ref": "#/components/schemas/regex2_cntr",
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "Controller regex2"
+ ],
+ "parameters": [
+ {
+ "name": "content",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "enum": [
+ "config",
+ "nonconfig",
+ "all"
+ ],
+ "type": "string"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "regex2_cntr": {
+ "title": "regex2_cntr",
+ "type": "object",
+ "properties": {
+ "lf": {
+ "description": "",
+ "type": "string",
+ "example": "A",
+ "minLength": 1,
+ "maxLength": 100
+ }
+ },
+ "xml": {
+ "name": "cntr",
+ "namespace": "urn:regex2"
+ }
+ }
+ },
+ "securitySchemes": {
+ "basicAuth": {
+ "scheme": "basic",
+ "type": "http"
+ }
+ }
+ },
+ "security": [
+ {
+ "basicAuth": []
+ }
+ ]
+}
--- /dev/null
+{
+ "openapi": "3.0.3",
+ "info": {
+ "version": "1.0.0",
+ "title": "regex3",
+ "description": "We are providing full API for configurational data which can be edited (by POST, PUT, PATCH and DELETE).\nFor operational data we only provide GET API.\n\nFor majority of request you can see only config data in examples. That's because we can show only one example\nper request. The exception when you can see operational data in example is when data are representing\noperational (config false) container with no config data in it."
+ },
+ "servers": [
+ {
+ "url": "http://localhost:8181/"
+ }
+ ],
+ "paths": {
+ "/rests/data": {
+ "post": {
+ "description": "\n\nNote:\nIn example payload, you can see only the first data node child of the resource to be created, following the\nguidelines of RFC 8040, which allows us to create only one resource in POST request.\n",
+ "summary": "POST - Controller - regex3 - regex3",
+ "requestBody": {
+ "description": "cntr",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "cntr": {
+ "$ref": "#/components/schemas/regex3_cntr",
+ "type": "object"
+ }
+ }
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/regex3_cntr"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Created"
+ }
+ },
+ "tags": [
+ "Controller regex3"
+ ],
+ "parameters": []
+ }
+ },
+ "/rests/data/regex3:cntr": {
+ "put": {
+ "description": "",
+ "summary": "PUT - regex3 - Controller - cntr",
+ "requestBody": {
+ "description": "cntr",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "regex3:cntr": {
+ "$ref": "#/components/schemas/regex3_cntr",
+ "type": "object"
+ }
+ }
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/regex3_cntr"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "204": {
+ "description": "Updated"
+ }
+ },
+ "tags": [
+ "Controller regex3"
+ ],
+ "parameters": []
+ },
+ "patch": {
+ "description": "",
+ "summary": "PATCH - regex3 - Controller - cntr",
+ "requestBody": {
+ "description": "cntr",
+ "content": {
+ "application/yang-data+json": {
+ "schema": {
+ "properties": {
+ "regex3:cntr": {
+ "$ref": "#/components/schemas/regex3_cntr",
+ "type": "object"
+ }
+ }
+ }
+ },
+ "application/yang-data+xml": {
+ "schema": {
+ "$ref": "#/components/schemas/regex3_cntr"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "OK"
+ },
+ "204": {
+ "description": "Updated"
+ }
+ },
+ "tags": [
+ "Controller regex3"
+ ],
+ "parameters": []
+ },
+ "delete": {
+ "description": "",
+ "summary": "DELETE - Controller - regex3 - cntr",
+ "responses": {
+ "204": {
+ "description": "Deleted"
+ }
+ },
+ "tags": [
+ "Controller regex3"
+ ],
+ "parameters": []
+ },
+ "get": {
+ "description": "",
+ "summary": "GET - Controller - regex3 - cntr",
+ "responses": {
+ "200": {
+ "description": "200",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/regex3_cntr"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "properties": {
+ "cntr": {
+ "$ref": "#/components/schemas/regex3_cntr",
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "Controller regex3"
+ ],
+ "parameters": [
+ {
+ "name": "content",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "enum": [
+ "config",
+ "nonconfig",
+ "all"
+ ],
+ "type": "string"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "regex3_cntr": {
+ "title": "regex3_cntr",
+ "type": "object",
+ "properties": {
+ "lf": {
+ "description": "",
+ "type": "string",
+ "example": "A-0",
+ "minLength": 3,
+ "maxLength": 250
+ }
+ },
+ "xml": {
+ "name": "cntr",
+ "namespace": "urn:regex3"
+ }
+ }
+ },
+ "securitySchemes": {
+ "basicAuth": {
+ "scheme": "basic",
+ "type": "http"
+ }
+ }
+ },
+ "security": [
+ {
+ "basicAuth": []
+ }
+ ]
+}
--- /dev/null
+module regex1 {
+ namespace "urn:regex1";
+ prefix "re1";
+ revision 2024-09-12 {
+ description "Initial revision.";
+ }
+
+ container cntr {
+ leaf lf {
+ type string {
+ length "1..100";
+ pattern "[A-Z]*[0-9]";
+ }
+ }
+ }
+}
--- /dev/null
+module regex2 {
+ namespace "urn:regex2";
+ prefix "re2";
+ revision 2024-09-12 {
+ description "Initial revision.";
+ }
+
+ container cntr {
+ leaf lf {
+ type string {
+ length "1..100";
+ pattern "[0-9]*[A-Z]";
+ }
+ }
+ }
+}
--- /dev/null
+module regex3 {
+ namespace "urn:regex3";
+ prefix "re3";
+ revision 2024-09-12 {
+ description "Initial revision.";
+ }
+
+ container cntr {
+ leaf lf {
+ type string {
+ length "3..250";
+ pattern "([a-zA-Z]([a-zA-Z0-9_.-]*)([a-zA-Z0-9]))";
+ }
+ }
+ }
+}