]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1102] Checkpoint: dhcpv6 and doc to do
authorFrancis Dupont <fdupont@isc.org>
Sat, 5 Sep 2020 15:57:39 +0000 (17:57 +0200)
committerFrancis Dupont <fdupont@isc.org>
Mon, 21 Sep 2020 10:36:02 +0000 (12:36 +0200)
src/bin/agent/agent_parser.yy
src/bin/agent/tests/parser_unittests.cc
src/bin/d2/d2_parser.yy
src/bin/d2/tests/parser_unittest.cc
src/bin/dhcp4/tests/parser_unittest.cc
src/bin/netconf/netconf_parser.yy
src/bin/netconf/parser_context.cc
src/bin/netconf/tests/parser_unittests.cc

index a17bd55611c359d4a7756eac18ef266f91e7d3ea..7e014ae8d0c13891aee2344584ec1fc89ade1a83 100644 (file)
@@ -180,11 +180,13 @@ map_content: %empty // empty map
 // covers all longer lists recursively.
 not_empty_map: STRING COLON value {
                   // map containing a single entry
+                  ctx.unique($1, ctx.loc2pos(@1));
                   ctx.stack_.back()->set($1, $3);
                   }
              | not_empty_map COMMA STRING COLON value {
                   // map consisting of a shorter map followed by
                   // comma and string:value
+                  ctx.unique($3, ctx.loc2pos(@3));
                   ctx.stack_.back()->set($3, $5);
                   }
              ;
@@ -242,6 +244,7 @@ global_object: CONTROL_AGENT {
     // top level map (that's already on the stack) and put the new map
     // on the stack as well, so child elements will be able to add
     // themselves to it.
+    ctx.unique("Control-agent", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("Control-agent", m);
     ctx.stack_.push_back(m);
@@ -271,6 +274,7 @@ global_param: http_host
             ;
 
 http_host: HTTP_HOST {
+    ctx.unique("http-host", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr host(new StringElement($4, ctx.loc2pos(@4)));
@@ -279,6 +283,7 @@ http_host: HTTP_HOST {
 };
 
 http_port: HTTP_PORT COLON INTEGER {
+    ctx.unique("http-port", ctx.loc2pos(@1));
     ElementPtr prf(new IntElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("http-port", prf);
 };
@@ -337,6 +342,7 @@ comment: COMMENT {
 
 // --- hooks-libraries ---------------------------------------------------------
 hooks_libraries: HOOKS_LIBRARIES {
+    ctx.unique("hooks-libraries", ctx.loc2pos(@1));
     ElementPtr l(new ListElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("hooks-libraries", l);
     ctx.stack_.push_back(l);
@@ -372,6 +378,7 @@ hooks_param: library
            ;
 
 library: LIBRARY {
+    ctx.unique("library", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr lib(new StringElement($4, ctx.loc2pos(@4)));
@@ -380,6 +387,7 @@ library: LIBRARY {
 };
 
 parameters: PARAMETERS {
+    ctx.unique("parameters", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON map_value {
     ctx.stack_.back()->set("parameters", $4);
@@ -390,6 +398,7 @@ parameters: PARAMETERS {
 
 // --- control-sockets starts here ---------------------------------------------
 control_sockets: CONTROL_SOCKETS COLON LCURLY_BRACKET {
+    ctx.unique("control-sockets", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("control-sockets", m);
     ctx.stack_.push_back(m);
@@ -416,6 +425,7 @@ control_socket: dhcp4_server_socket
 
 // That's an entry for dhcp4 socket.
 dhcp4_server_socket: DHCP4_SERVER {
+    ctx.unique("dhcp4", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("dhcp4", m);
     ctx.stack_.push_back(m);
@@ -427,6 +437,7 @@ dhcp4_server_socket: DHCP4_SERVER {
 
 // That's an entry for dhcp6 socket.
 dhcp6_server_socket: DHCP6_SERVER {
+    ctx.unique("dhcp6", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("dhcp6", m);
     ctx.stack_.push_back(m);
@@ -438,6 +449,7 @@ dhcp6_server_socket: DHCP6_SERVER {
 
 // That's an entry for d2 socket.
 d2_server_socket: D2_SERVER {
+    ctx.unique("d2", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("d2", m);
     ctx.stack_.push_back(m);
@@ -462,6 +474,7 @@ control_socket_param: socket_name
 
 // This rule defines socket-name parameter.
 socket_name: SOCKET_NAME {
+    ctx.unique("socket-name", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr name(new StringElement($4, ctx.loc2pos(@4)));
@@ -471,6 +484,7 @@ socket_name: SOCKET_NAME {
 
 // This rule specifies socket type.
 socket_type: SOCKET_TYPE {
+    ctx.unique("socket-type", ctx.loc2pos(@1));
     ctx.enter(ctx.SOCKET_TYPE);
 } COLON socket_type_value {
     ctx.stack_.back()->set("socket-type", $4);
@@ -589,6 +603,7 @@ password: PASSWORD {
 // --- Loggers starts here -----------------------------------------------------
 
 loggers: LOGGERS {
+    ctx.unique("loggers", ctx.loc2pos(@1));
     ElementPtr l(new ListElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("loggers", l);
     ctx.stack_.push_back(l);
@@ -627,6 +642,7 @@ logger_param: name
             ;
 
 name: NAME {
+    ctx.unique("name", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr name(new StringElement($4, ctx.loc2pos(@4)));
@@ -635,11 +651,13 @@ name: NAME {
 };
 
 debuglevel: DEBUGLEVEL COLON INTEGER {
+    ctx.unique("debuglevel", ctx.loc2pos(@1));
     ElementPtr dl(new IntElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("debuglevel", dl);
 };
 
 severity: SEVERITY {
+    ctx.unique("severity", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
@@ -648,6 +666,7 @@ severity: SEVERITY {
 };
 
 output_options_list: OUTPUT_OPTIONS {
+    ctx.unique("output_options", ctx.loc2pos(@1));
     ElementPtr l(new ListElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("output_options", l);
     ctx.stack_.push_back(l);
@@ -681,6 +700,7 @@ output_params: output
              ;
 
 output: OUTPUT {
+    ctx.unique("output", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
@@ -689,21 +709,25 @@ output: OUTPUT {
 };
 
 flush: FLUSH COLON BOOLEAN {
+    ctx.unique("flush", ctx.loc2pos(@1));
     ElementPtr flush(new BoolElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("flush", flush);
 }
 
 maxsize: MAXSIZE COLON INTEGER {
+    ctx.unique("maxsize", ctx.loc2pos(@1));
     ElementPtr maxsize(new IntElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("maxsize", maxsize);
 }
 
 maxver: MAXVER COLON INTEGER {
+    ctx.unique("maxver", ctx.loc2pos(@1));
     ElementPtr maxver(new IntElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("maxver", maxver);
 }
 
 pattern: PATTERN {
+    ctx.unique("pattern", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
index 6369a898c60540e4e52f0ac1c45cf8d6d56b6df3..731c64a7b03e2e0c86d30e3e60a625ea904f4d2a 100644 (file)
@@ -619,6 +619,22 @@ TEST(ParserTest, errors) {
               "  \"comment\": \"second\" }}\n",
               ParserContext::PARSER_AGENT,
               "<string>:2.23: syntax error, unexpected \",\", expecting }");
+
+    // duplicate of not string entries
+    testError("{ \"Control-agent\":{\n"
+              " \"http-port\": 8000,\n"
+              " \"http-port\": 8001 }}\n",
+              ParserContext::PARSER_AGENT,
+              "<string>:3:2: duplicate http-port entries in "
+              "Control-agent map (previous at <string>:2:15)");
+
+    // duplicate of string entries
+    testError("{ \"Control-agent\":{\n"
+              " \"http-host\": \"127.0.0.1\",\n"
+              " \"http-host\": \"::1\" }}\n",
+              ParserContext::PARSER_AGENT,
+              "<string>:3:2: duplicate http-host entries in "
+              "Control-agent map (previous at <string>:2:15)");
 }
 
 // Check unicode escapes
index 6f25eedd6f06c19fd4f1558c98490f3645fb74c1..e2bb44b8c109a97a62bd41f9361577548a994bd2 100644 (file)
@@ -167,11 +167,13 @@ map_content: %empty // empty map
 
 not_empty_map: STRING COLON value {
                   // map containing a single entry
+                  ctx.unique($1, ctx.loc2pos(@1));
                   ctx.stack_.back()->set($1, $3);
                   }
              | not_empty_map COMMA STRING COLON value {
                   // map consisting of a shorter map followed by
                   // comma and string:value
+                  ctx.unique($3, ctx.loc2pos(@3));
                   ctx.stack_.back()->set($3, $5);
                   }
              ;
@@ -225,6 +227,7 @@ syntax_map: LCURLY_BRACKET {
 // --- dhcp ddns ---------------------------------------------
 // This represents the single top level entry, e.g. DhcpDdns.
 global_object: DHCPDDNS {
+    ctx.unique("DhcpDdns", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("DhcpDdns", m);
     ctx.stack_.push_back(m);
@@ -263,6 +266,7 @@ dhcpddns_param: ip_address
               ;
 
 ip_address: IP_ADDRESS {
+    ctx.unique("ip-address", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
@@ -271,6 +275,7 @@ ip_address: IP_ADDRESS {
 };
 
 port: PORT COLON INTEGER {
+    ctx.unique("port", ctx.loc2pos(@1));
     if ($3 <= 0 || $3 >= 65536 ) {
         error(@3, "port must be greater than zero but less than 65536");
     }
@@ -279,6 +284,7 @@ port: PORT COLON INTEGER {
 };
 
 dns_server_timeout: DNS_SERVER_TIMEOUT COLON INTEGER {
+    ctx.unique("dns-server-timeout", ctx.loc2pos(@1));
     if ($3 <= 0) {
         error(@3, "dns-server-timeout must be greater than zero");
     } else {
@@ -288,6 +294,7 @@ dns_server_timeout: DNS_SERVER_TIMEOUT COLON INTEGER {
 };
 
 ncr_protocol: NCR_PROTOCOL {
+    ctx.unique("ncr-protocol", ctx.loc2pos(@1));
     ctx.enter(ctx.NCR_PROTOCOL);
 } COLON ncr_protocol_value {
     ctx.stack_.back()->set("ncr-protocol", $4);
@@ -300,6 +307,7 @@ ncr_protocol_value:
   ;
 
 ncr_format: NCR_FORMAT {
+    ctx.unique("ncr-format", ctx.loc2pos(@1));
     ctx.enter(ctx.NCR_FORMAT);
 } COLON JSON {
     ElementPtr json(new StringElement("JSON", ctx.loc2pos(@4)));
@@ -360,6 +368,7 @@ comment: COMMENT {
 };
 
 forward_ddns : FORWARD_DDNS {
+    ctx.unique("forward-ddns", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("forward-ddns", m);
     ctx.stack_.push_back(m);
@@ -370,6 +379,7 @@ forward_ddns : FORWARD_DDNS {
 };
 
 reverse_ddns : REVERSE_DDNS {
+    ctx.unique("reverse-ddns", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("reverse-ddns", m);
     ctx.stack_.push_back(m);
@@ -394,6 +404,7 @@ ddns_mgr_param: ddns_domains
 
 // --- ddns-domains ----------------------------------------
 ddns_domains: DDNS_DOMAINS {
+    ctx.unique("ddns-domains", ctx.loc2pos(@1));
     ElementPtr l(new ListElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("ddns-domains", l);
     ctx.stack_.push_back(l);
@@ -447,6 +458,7 @@ ddns_domain_param: ddns_domain_name
 
 //  @todo NAME needs to be an FQDN sort of thing
 ddns_domain_name: NAME {
+    ctx.unique("name", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     if ($4 == "") {
@@ -459,6 +471,7 @@ ddns_domain_name: NAME {
 };
 
 ddns_domain_key_name: KEY_NAME {
+    ctx.unique("key-name", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     ElementPtr elem(new StringElement($4, ctx.loc2pos(@4)));
@@ -471,6 +484,7 @@ ddns_domain_key_name: KEY_NAME {
 
 // --- dns-servers ----------------------------------------
 dns_servers: DNS_SERVERS {
+    ctx.unique("dns-servers", ctx.loc2pos(@1));
     ElementPtr l(new ListElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("dns-servers", l);
     ctx.stack_.push_back(l);
@@ -519,6 +533,7 @@ dns_server_param: dns_server_hostname
               ;
 
 dns_server_hostname: HOSTNAME {
+    ctx.unique("hostname", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     if ($4 != "") {
@@ -531,6 +546,7 @@ dns_server_hostname: HOSTNAME {
 };
 
 dns_server_ip_address: IP_ADDRESS {
+    ctx.unique("ip-address", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
@@ -539,6 +555,7 @@ dns_server_ip_address: IP_ADDRESS {
 };
 
 dns_server_port: PORT COLON INTEGER {
+    ctx.unique("port", ctx.loc2pos(@1));
     if ($3 <= 0 || $3 >= 65536 ) {
         error(@3, "port must be greater than zero but less than 65536");
     }
@@ -553,6 +570,7 @@ dns_server_port: PORT COLON INTEGER {
 // --- tsig-keys ----------------------------------------
 // "tsig-keys" : [ ... ]
 tsig_keys: TSIG_KEYS {
+    ctx.unique("tsig-keys", ctx.loc2pos(@1));
     ElementPtr l(new ListElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("tsig-keys", l);
     ctx.stack_.push_back(l);
@@ -608,6 +626,7 @@ tsig_key_param: tsig_key_name
               ;
 
 tsig_key_name: NAME {
+    ctx.unique("name", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     if ($4 == "") {
@@ -620,6 +639,7 @@ tsig_key_name: NAME {
 };
 
 tsig_key_algorithm: ALGORITHM {
+    ctx.unique("algorithm", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     if ($4 == "") {
@@ -631,6 +651,7 @@ tsig_key_algorithm: ALGORITHM {
 };
 
 tsig_key_digest_bits: DIGEST_BITS COLON INTEGER {
+    ctx.unique("digest-bits", ctx.loc2pos(@1));
     if ($3 < 0 || ($3 > 0  && ($3 % 8 != 0))) {
         error(@3, "TSIG key digest-bits must either be zero or a positive, multiple of eight");
     }
@@ -639,6 +660,7 @@ tsig_key_digest_bits: DIGEST_BITS COLON INTEGER {
 };
 
 tsig_key_secret: SECRET {
+    ctx.unique("secret", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     if ($4 == "") {
@@ -655,6 +677,7 @@ tsig_key_secret: SECRET {
 // --- control socket ----------------------------------------
 
 control_socket: CONTROL_SOCKET {
+    ctx.unique("control-socket", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("control-socket", m);
     ctx.stack_.push_back(m);
@@ -676,6 +699,7 @@ control_socket_param: control_socket_type
                     ;
 
 control_socket_type: SOCKET_TYPE {
+    ctx.unique("socket-type", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     ElementPtr stype(new StringElement($4, ctx.loc2pos(@4)));
@@ -684,6 +708,7 @@ control_socket_type: SOCKET_TYPE {
 };
 
 control_socket_name: SOCKET_NAME {
+    ctx.unique("socket-name", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     ElementPtr name(new StringElement($4, ctx.loc2pos(@4)));
@@ -694,6 +719,7 @@ control_socket_name: SOCKET_NAME {
 // --- loggers entry -----------------------------------------
 
 loggers: LOGGERS {
+    ctx.unique("loggers", ctx.loc2pos(@1));
     ElementPtr l(new ListElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("loggers", l);
     ctx.stack_.push_back(l);
@@ -732,6 +758,7 @@ logger_param: name
             ;
 
 name: NAME {
+    ctx.unique("name", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     ElementPtr name(new StringElement($4, ctx.loc2pos(@4)));
@@ -740,10 +767,13 @@ name: NAME {
 };
 
 debuglevel: DEBUGLEVEL COLON INTEGER {
+    ctx.unique("debuglevel", ctx.loc2pos(@1));
     ElementPtr dl(new IntElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("debuglevel", dl);
 };
+
 severity: SEVERITY {
+    ctx.unique("severity", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
@@ -752,6 +782,7 @@ severity: SEVERITY {
 };
 
 output_options_list: OUTPUT_OPTIONS {
+    ctx.unique("output_options", ctx.loc2pos(@1));
     ElementPtr l(new ListElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("output_options", l);
     ctx.stack_.push_back(l);
@@ -785,6 +816,7 @@ output_params: output
              ;
 
 output: OUTPUT {
+    ctx.unique("output", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
@@ -793,21 +825,25 @@ output: OUTPUT {
 };
 
 flush: FLUSH COLON BOOLEAN {
+    ctx.unique("flush", ctx.loc2pos(@1));
     ElementPtr flush(new BoolElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("flush", flush);
 }
 
 maxsize: MAXSIZE COLON INTEGER {
+    ctx.unique("maxsize", ctx.loc2pos(@1));
     ElementPtr maxsize(new IntElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("maxsize", maxsize);
 }
 
 maxver: MAXVER COLON INTEGER {
+    ctx.unique("maxver", ctx.loc2pos(@1));
     ElementPtr maxver(new IntElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("maxver", maxver);
 }
 
 pattern: PATTERN {
+    ctx.unique("pattern", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORD);
 } COLON STRING {
     ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
index 54e0658f7f4146d964dfe9cdfbd8a6fb29055590..dc02f3c6ceeddc3e02d4453ea375775a4bde4c72 100644 (file)
@@ -563,6 +563,22 @@ TEST(ParserTest, errors) {
               "  \"comment\": \"second\" }}\n",
               D2ParserContext::PARSER_DHCPDDNS,
               "<string>:2.23: syntax error, unexpected \",\", expecting }");
+
+    // duplicate of not string entries
+    testError("{ \"DhcpDdns\":{\n"
+              "  \"port\": 53001,\n"
+              "  \"port\": 53002 }}\n",
+              D2ParserContext::PARSER_DHCPDDNS,
+              "<string>:3:3: duplicate port entries in "
+              "DhcpDdns map (previous at <string>:2:11)");
+
+    // duplicate of string entries
+    testError("{ \"DhcpDdns\":{\n"
+              "  \"ip-address\": \"127.0.0.1\",\n"
+              "  \"ip-address\": \"::1\" }}\n",
+              D2ParserContext::PARSER_DHCPDDNS,
+              "<string>:3:3: duplicate ip-address entries in "
+              "DhcpDdns map (previous at <string>:2:17)");
 }
 
 // Check unicode escapes
index 6374e7db219007972d48b348d1d49424b43b0b96..aa408e84eab5af571aded0c27c40e3cb4115b7bf 100644 (file)
@@ -616,6 +616,22 @@ TEST(ParserTest, errors) {
               "  \"comment\": \"second\" }}\n",
               Parser4Context::PARSER_DHCP4,
               "<string>:2.23: syntax error, unexpected \",\", expecting }");
+
+    // duplicate of not string entries
+    testError("{ \"Dhcp4\":{\n"
+              " \"subnet4\": [],\n"
+              " \"subnet4\": [] }}\n",
+              Parser4Context::PARSER_DHCP4,
+              "<string>:3:2: duplicate subnet4 entries in "
+              "Dhcp4 map (previous at <string>:2:2)");
+
+    // duplicate of string entries
+    testError("{\n"
+              " \"server-hostname\": \"nohost\",\n"
+              " \"server-hostname\": \"nofile\" }\n",
+              Parser4Context::PARSER_HOST_RESERVATION,
+              "<string>:3:2: duplicate server-hostname entries in "
+              "reservations map (previous at <string>:2:21)");
 }
 
 // Check unicode escapes
index 002b145a907eba9300104bbe0c50e4857702ee5e..c29bd307728813e0d7950cfbee42b31079075708 100644 (file)
@@ -179,11 +179,13 @@ map_content: %empty // empty map
 // covers all longer lists recursively.
 not_empty_map: STRING COLON value {
                   // map containing a single entry
+                  ctx.unique($1, ctx.loc2pos(@1));
                   ctx.stack_.back()->set($1, $3);
                   }
              | not_empty_map COMMA STRING COLON value {
                   // map consisting of a shorter map followed by
                   // comma and string:value
+                  ctx.unique($3, ctx.loc2pos(@3));
                   ctx.stack_.back()->set($3, $5);
                   }
              ;
@@ -277,16 +279,19 @@ global_param: boot_update
             ;
 
 boot_update: BOOT_UPDATE COLON BOOLEAN {
+    ctx.unique("boot-update", ctx.loc2pos(@1));
     ElementPtr flag(new BoolElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("boot-update", flag);
 };
 
 subscribe_changes: SUBSCRIBE_CHANGES COLON BOOLEAN {
+    ctx.unique("subscribe-changes", ctx.loc2pos(@1));
     ElementPtr flag(new BoolElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("subscribe-changes", flag);
 };
 
 validate_changes: VALIDATE_CHANGES COLON BOOLEAN {
+    ctx.unique("validate-changes", ctx.loc2pos(@1));
     ElementPtr flag(new BoolElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("validate-changes", flag);
 };
@@ -345,6 +350,7 @@ comment: COMMENT {
 
 // --- hooks-libraries ---------------------------------------------------------
 hooks_libraries: HOOKS_LIBRARIES {
+    ctx.unique("hooks-libraries", ctx.loc2pos(@1));
     ElementPtr l(new ListElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("hooks-libraries", l);
     ctx.stack_.push_back(l);
@@ -380,6 +386,7 @@ hooks_param: library
            ;
 
 library: LIBRARY {
+    ctx.unique("library", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr lib(new StringElement($4, ctx.loc2pos(@4)));
@@ -388,6 +395,7 @@ library: LIBRARY {
 };
 
 parameters: PARAMETERS {
+    ctx.unique("parameters", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON map_value {
     ctx.stack_.back()->set("parameters", $4);
@@ -398,6 +406,7 @@ parameters: PARAMETERS {
 
 // --- managed-servsers starts here ---------------------------------------------
 managed_servers: MANAGED_SERVERS COLON LCURLY_BRACKET {
+    ctx.unique("managed-servers", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("managed-servers", m);
     ctx.stack_.push_back(m);
@@ -427,6 +436,7 @@ server_entry: dhcp4_server
 
 // That's an entry for dhcp4 server.
 dhcp4_server: DHCP4_SERVER {
+    ctx.unique("dhcp4", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("dhcp4", m);
     ctx.stack_.push_back(m);
@@ -438,6 +448,7 @@ dhcp4_server: DHCP4_SERVER {
 
 // That's an entry for dhcp6 server.
 dhcp6_server: DHCP6_SERVER {
+    ctx.unique("dhcp6", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("dhcp6", m);
     ctx.stack_.push_back(m);
@@ -449,6 +460,7 @@ dhcp6_server: DHCP6_SERVER {
 
 // That's an entry for d2 server.
 d2_server: D2_SERVER {
+    ctx.unique("d2", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("d2", m);
     ctx.stack_.push_back(m);
@@ -460,6 +472,7 @@ d2_server: D2_SERVER {
 
 // That's an entry for ca server.
 ca_server: CA_SERVER {
+    ctx.unique("ca", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("ca", m);
     ctx.stack_.push_back(m);
@@ -487,6 +500,7 @@ managed_server_param: model
 
 // YANG model
 model: MODEL {
+    ctx.unique("model", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr model(new StringElement($4, ctx.loc2pos(@4)));
@@ -496,6 +510,7 @@ model: MODEL {
 
 // Control socket.
 control_socket: CONTROL_SOCKET {
+    ctx.unique("control-socket", ctx.loc2pos(@1));
     ElementPtr m(new MapElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("control-socket", m);
     ctx.stack_.push_back(m);
@@ -519,6 +534,7 @@ control_socket_param: socket_type
                     ;
 
 socket_type: SOCKET_TYPE {
+    ctx.unique("socket-type", ctx.loc2pos(@1));
     ctx.enter(ctx.SOCKET_TYPE);
 } COLON socket_type_value {
     ctx.stack_.back()->set("socket-type", $4);
@@ -532,6 +548,7 @@ socket_type_value : UNIX { $$ = ElementPtr(new StringElement("unix", ctx.loc2pos
                   ;
 // Unix name.
 socket_name: SOCKET_NAME {
+    ctx.unique("socket-name", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr name(new StringElement($4, ctx.loc2pos(@4)));
@@ -541,6 +558,7 @@ socket_name: SOCKET_NAME {
 
 // HTTP url.
 socket_url: SOCKET_URL {
+    ctx.unique("socket-url", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr url(new StringElement($4, ctx.loc2pos(@4)));
@@ -553,6 +571,7 @@ socket_url: SOCKET_URL {
 // --- Loggers starts here -----------------------------------------------------
 
 loggers: LOGGERS {
+    ctx.unique("loggers", ctx.loc2pos(@1));
     ElementPtr l(new ListElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("loggers", l);
     ctx.stack_.push_back(l);
@@ -591,6 +610,7 @@ logger_param: name
             ;
 
 name: NAME {
+    ctx.unique("name", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr name(new StringElement($4, ctx.loc2pos(@4)));
@@ -599,11 +619,13 @@ name: NAME {
 };
 
 debuglevel: DEBUGLEVEL COLON INTEGER {
+    ctx.unique("debuglevel", ctx.loc2pos(@1));
     ElementPtr dl(new IntElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("debuglevel", dl);
 };
 
 severity: SEVERITY {
+    ctx.unique("severity", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
@@ -612,6 +634,7 @@ severity: SEVERITY {
 };
 
 output_options_list: OUTPUT_OPTIONS {
+    ctx.unique("output_options", ctx.loc2pos(@1));
     ElementPtr l(new ListElement(ctx.loc2pos(@1)));
     ctx.stack_.back()->set("output_options", l);
     ctx.stack_.push_back(l);
@@ -645,6 +668,7 @@ output_params: output
              ;
 
 output: OUTPUT {
+    ctx.unique("output", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
@@ -653,21 +677,25 @@ output: OUTPUT {
 };
 
 flush: FLUSH COLON BOOLEAN {
+    ctx.unique("flush", ctx.loc2pos(@1));
     ElementPtr flush(new BoolElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("flush", flush);
 };
 
 maxsize: MAXSIZE COLON INTEGER {
+    ctx.unique("maxsize", ctx.loc2pos(@1));
     ElementPtr maxsize(new IntElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("maxsize", maxsize);
 };
 
 maxver: MAXVER COLON INTEGER {
+    ctx.unique("maxver", ctx.loc2pos(@1));
     ElementPtr maxver(new IntElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("maxver", maxver);
 };
 
 pattern: PATTERN {
+    ctx.unique("pattern", ctx.loc2pos(@1));
     ctx.enter(ctx.NO_KEYWORDS);
 } COLON STRING {
     ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
index 985d96084d2f7819082bc25aba098fe8f38bcdc3..f435e85c58f7cc27d171e93520e1a0d070ac6894 100644 (file)
@@ -159,7 +159,7 @@ ParserContext::contextName()
     case MANAGED_SERVERS:
         return ("managed-servers");
     case SERVER:
-        return ("managed-servers/*");
+        return ("managed-servers entry");
     case CONTROL_SOCKET:
         return ("control-socket");
     case SOCKET_TYPE:
index 83ee2b86082c2b744eb139e880b1f84a58edae1f..dfcb8a86903e99fa5b2c0c759246846d0d719587 100644 (file)
@@ -673,6 +673,24 @@ TEST(ParserTest, errors) {
               "  \"comment\": \"second\" }}\n",
               ParserContext::PARSER_NETCONF,
               "<string>:2.23: syntax error, unexpected \",\", expecting }");
+
+    // duplicate of not string entries
+    testError("{ \"Netconf\":{\n"
+              " \"boot-update\": true,\n"
+              " \"boot-update\": false }}\n",
+              ParserContext::PARSER_NETCONF,
+              "<string>:3:2: duplicate boot-update entries in "
+              "Netconf map (previous at <string>:2:17)");
+
+    // duplicate of string entries
+    testError("{ \"Netconf\":{\n"
+              "  \"managed-servers\": {\n"
+              "    \"d2\": {\n"
+              "      \"model\": \"foo\",\n"
+              "      \"model\": \"bar\" }}}}\n",
+              ParserContext::PARSER_NETCONF,
+              "<string>:5:7: duplicate model entries in "
+              "managed-servers entry map (previous at <string>:4:16)");
 }
 
 // Check unicode escapes