You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kp...@apache.org on 2018/03/29 17:54:43 UTC
qpid-interop-test git commit: QPIDIT-119: Generator for
amqp_complex_types_test,
which can generate Python and C++ data files from JSON at this point. RheaJs
and AmqpNetLite remain stubbed,
and will be completed later. A first version of the JSON test da
Repository: qpid-interop-test
Updated Branches:
refs/heads/master 7ec8c53a9 -> c1fb41599
QPIDIT-119: Generator for amqp_complex_types_test, which can generate Python and C++ data files from JSON at this point. RheaJs and AmqpNetLite remain stubbed, and will be completed later. A first version of the JSON test data files are also included, one each for arrays, lists and maps.
Project: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/commit/c1fb4159
Tree: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/tree/c1fb4159
Diff: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/diff/c1fb4159
Branch: refs/heads/master
Commit: c1fb41599b6046ca8fddb5a754d57191240b313c
Parents: 7ec8c53
Author: Kim van der Riet <kv...@localhost.localdomain>
Authored: Thu Mar 29 13:54:19 2018 -0400
Committer: Kim van der Riet <kv...@localhost.localdomain>
Committed: Thu Mar 29 13:54:19 2018 -0400
----------------------------------------------------------------------
.../amqp_complex_types_test/data_utils.hpp | 61 ++
.../src/amqp_complex_types_test/Receiver.py | 97 +++
.../src/amqp_complex_types_test/Sender.py | 113 +++
.../amqp_complex_types_test.array.json | 157 ++++
.../amqp_complex_types_test.list.json | 157 ++++
.../amqp_complex_types_test.map.json | 116 +++
.../amqp_complex_types_test_generator.py | 762 +++++++++++++++++++
7 files changed, 1463 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/c1fb4159/shims/qpid-proton-cpp/src/qpidit/amqp_complex_types_test/data_utils.hpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/amqp_complex_types_test/data_utils.hpp b/shims/qpid-proton-cpp/src/qpidit/amqp_complex_types_test/data_utils.hpp
new file mode 100644
index 0000000..2d0b3cb
--- /dev/null
+++ b/shims/qpid-proton-cpp/src/qpidit/amqp_complex_types_test/data_utils.hpp
@@ -0,0 +1,61 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef SRC_QPIDIT_DATA_UTILS_HPP_
+#define SRC_QPIDIT_DATA_UTILS_HPP_
+
+#include <sstream>
+#include <proton/types.hpp>
+
+namespace qpidit
+{
+ namespace amqp_complex_types_test
+ {
+
+ template<size_t N> static void hexStringToBytearray(proton::byte_array<N>& ba, const std::string& s, size_t fromArrayIndex = 0, size_t arrayLen = N) {
+ for (size_t i=0; i<arrayLen; ++i) {
+ ba[fromArrayIndex + i] = (char)std::strtoul(s.substr(2*i, 2).c_str(), NULL, 16);
+ }
+ }
+
+ static std::string hexStringToBinaryString(const std::string& s) {
+ std::ostringstream o;
+ for (size_t i=0; i<s.size(); i+=2) {
+ o << "\\x" << s.substr(i, 2);
+ }
+ return o.str();
+ }
+
+ static void setUuid(proton::uuid& val, const std::string& uuidStr) {
+ // Expected format: "00000000-0000-0000-0000-000000000000"
+ // ^ ^ ^ ^ ^
+ // start index -> 0 9 14 19 24
+ hexStringToBytearray(val, uuidStr.substr(0, 8), 0, 4);
+ hexStringToBytearray(val, uuidStr.substr(9, 4), 4, 2);
+ hexStringToBytearray(val, uuidStr.substr(14, 4), 6, 2);
+ hexStringToBytearray(val, uuidStr.substr(19, 4), 8, 2);
+ hexStringToBytearray(val, uuidStr.substr(24, 12), 10, 6);
+ }
+
+ } // namespace amqp_complex_types_test
+} // namespace qpidit
+
+#endif /* SRC_QPIDIT_DATA_UTILS_HPP_ */
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/c1fb4159/shims/qpid-proton-python/src/amqp_complex_types_test/Receiver.py
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-python/src/amqp_complex_types_test/Receiver.py b/shims/qpid-proton-python/src/amqp_complex_types_test/Receiver.py
new file mode 100644
index 0000000..c252239
--- /dev/null
+++ b/shims/qpid-proton-python/src/amqp_complex_types_test/Receiver.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+
+"""
+AMQP complex type test receiver shim for qpid-interop-test
+"""
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import json
+import os.path
+import signal
+import sys
+import traceback
+
+import proton
+import proton.handlers
+import proton.reactor
+
+class AmqpComplexTypesTestReceiver(proton.handlers.MessagingHandler):
+ """
+ Reciver shim for AMQP complex types test
+ This shim receives the number of messages supplied on the command-line and checks that they contain message
+ bodies of the exptected AMQP type. The values are then aggregated and returned.
+ """
+ def __init__(self, broker_url, queue_name, amqp_type, num_expected_messages_str):
+ super(AmqpComplexTypesTestReceiver, self).__init__()
+ self.broker_url = broker_url
+ self.queue_name = queue_name
+ self.received_value_list = []
+ self.amqp_type = amqp_type
+ self.expected = int(num_expected_messages_str)
+ self.received = 0
+ signal.signal(signal.SIGINT, self.signal_handler)
+ signal.signal(signal.SIGTERM, self.signal_handler)
+
+ def get_received_value_list(self):
+ """Return the received list of AMQP values"""
+ return self.received_value_list
+
+ def on_start(self, event):
+ """Event callback for when the client starts"""
+ connection = event.container.connect(url=self.broker_url, sasl_enabled=False, reconnect=False)
+ event.container.create_receiver(connection, source=self.queue_name)
+
+ def on_message(self, event):
+ """Event callback when a message is received by the client"""
+ if event.message.id and event.message.id < self.received:
+ return # ignore duplicate message
+ # ...
+ self.received += 1
+ if self.received >= self.expected:
+ event.receiver.close()
+ event.connection.close()
+
+ def on_transport_error(self, event):
+ print('Receiver: Broker not found at %s' % self.broker_url)
+
+ @staticmethod
+ def signal_handler(signal_number, _):
+ """Signal handler"""
+ if signal_number in [signal.SIGTERM, signal.SIGINT]:
+ print('Receiver: received signal %d, terminating' % signal_number)
+ sys.exit(1)
+
+# --- main ---
+# Args: 1: Broker address (ip-addr:port)
+# 2: Queue name
+# 3: AMQP complex type
+# 4: Test data reference list
+try:
+ RECEIVER = AmqpComplexTypesTestReceiver(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])
+ proton.reactor.Container(RECEIVER).run()
+ print(sys.argv[3])
+ print(json.dumps(RECEIVER.get_received_value_list()))
+except KeyboardInterrupt:
+ pass
+except Exception as exc:
+ print(os.path.basename(sys.argv[0]), 'EXCEPTION', exc)
+ print(traceback.format_exc())
+ sys.exit(1)
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/c1fb4159/shims/qpid-proton-python/src/amqp_complex_types_test/Sender.py
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-python/src/amqp_complex_types_test/Sender.py b/shims/qpid-proton-python/src/amqp_complex_types_test/Sender.py
new file mode 100644
index 0000000..fa2c49b
--- /dev/null
+++ b/shims/qpid-proton-python/src/amqp_complex_types_test/Sender.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+
+"""
+AMQP complex type test sender shim for qpid-interop-test
+"""
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import json
+import os.path
+import signal
+import sys
+import traceback
+
+import proton
+import proton.handlers
+import proton.reactor
+
+class AmqpComplexTypesTestSender(proton.handlers.MessagingHandler):
+ """
+ Sender shim for AMQP complex types test
+ This shim receives the AMQP type and a list of test values. Each value is sent in a message body of the appropriate
+ AMQP type. There is no returned value.
+ """
+ def __init__(self, broker_url, queue_name, amqp_type, test_value_list):
+ super(AmqpComplexTypesTestSender, self).__init__()
+ self.broker_url = broker_url
+ self.queue_name = queue_name
+ self.amqp_type = amqp_type
+ self.test_value_list = test_value_list
+ self.sent = 0
+ self.confirmed = 0
+ self.total = len(test_value_list)
+ signal.signal(signal.SIGINT, self.signal_handler)
+ signal.signal(signal.SIGTERM, self.signal_handler)
+
+ def on_start(self, event):
+ """Event callback for when the client starts"""
+ connection = event.container.connect(url=self.broker_url, sasl_enabled=False, reconnect=False)
+ event.container.create_sender(connection, target=self.queue_name)
+
+ def on_sendable(self, event):
+ """Event callback for when send credit is received, allowing the sending of messages"""
+ if self.sent == 0:
+ for test_value in self.test_value_list:
+ if event.sender.credit:
+ message = self.create_message(test_value)
+ if message is not None:
+ event.sender.send(message)
+ self.sent += 1
+ else:
+ event.connection.close()
+ return
+
+ def create_message(self, test_value):
+ """
+ Creates a single message with the test value translated from its string representation to the appropriate
+ AMQP value (set in self.amqp_type).
+ """
+ return proton.Message(id=(self.sent+1), body=test_value)
+
+ def on_accepted(self, event):
+ """Event callback for when a sent message is accepted by the broker"""
+ self.confirmed += 1
+ if self.confirmed == self.total:
+ event.connection.close()
+
+ def on_disconnected(self, event):
+ """Event callback for when the broker disconnects with the client"""
+ self.sent = self.confirmed
+
+ def on_transport_error(self, event):
+ print('Sender: Broker not found at %s' % self.broker_url)
+
+ @staticmethod
+ def signal_handler(signal_number, _):
+ """Signal handler"""
+ if signal_number in [signal.SIGTERM, signal.SIGINT]:
+ print('Sender: received signal %d, terminating' % signal_number)
+ sys.exit(1)
+
+
+# --- main ---
+# Args: 1: Broker address (ip-addr:port)
+# 2: Queue name
+# 3: AMQP type
+# 4: JSON list of test value references to use in test
+try:
+ SENDER = AmqpComplexTypesTestSender(sys.argv[1], sys.argv[2], sys.argv[3], json.loads(sys.argv[4]))
+ proton.reactor.Container(SENDER).run()
+except KeyboardInterrupt:
+ pass
+except Exception as exc:
+ print(os.path.basename(sys.argv[0]), 'EXCEPTION:', exc)
+ print(traceback.format_exc())
+ sys.exit(1)
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/c1fb4159/src/python/qpid_interop_test/amqp_complex_types_test.array.json
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/amqp_complex_types_test.array.json b/src/python/qpid_interop_test/amqp_complex_types_test.array.json
new file mode 100644
index 0000000..c43356e
--- /dev/null
+++ b/src/python/qpid_interop_test/amqp_complex_types_test.array.json
@@ -0,0 +1,157 @@
+[["array", []],
+ ["array", [["null", null],
+ ["null", null]]],
+ ["array", [["boolean", true],
+ ["boolean", false]]],
+ ["array", [["ubyte", 0],
+ ["ubyte", 127],
+ ["ubyte", 128],
+ ["ubyte", 255]]],
+ ["array", [["ushort", 0],
+ ["ushort", 255],
+ ["ushort", 256],
+ ["ushort", "0x7fff"],
+ ["ushort", "0x8000"],
+ ["ushort", "0xffff"]]],
+ ["array", [["uint", 0],
+ ["uint", 255],
+ ["uint", 256],
+ ["uint", "0x7fffffff"],
+ ["uint", "0x80000000"],
+ ["uint", "0xffffffff"]]],
+ ["array", [["ulong", 0],
+ ["ulong", 255],
+ ["ulong", 256],
+ ["ulong", "0x7fffffffffffffff"],
+ ["ulong", "0x8000000000000000"],
+ ["ulong", "0xffffffffffffffff"]]],
+ ["array", [["byte", -128],
+ ["byte", -1],
+ ["byte", 0],
+ ["byte", 255]]],
+ ["array", [["short", "-0x8000"],
+ ["short", -1],
+ ["short", 0],
+ ["short", "0x7fff"]]],
+ ["array", [["int", "-0x80000000"],
+ ["int", -1],
+ ["int", 0],
+ ["int", "0x7fffffff"]]],
+ ["array", [["long", "-0x8000000000000000"],
+ ["long", -128],
+ ["long", -1],
+ ["long", 0],
+ ["long", 127],
+ ["long", "0x7fffffffffffffff"]]],
+ ["array", [["float", 0.0],
+ ["float", 3.14159],
+ ["float", -2.71828],
+ ["float", "1.2345e+38"],
+ ["float", "-1.2345e-38"],
+ ["float", "inf"],
+ ["float", "-inf"],
+ ["float", "NaN"]]],
+ ["array", [["double", 0.0],
+ ["double", 3.141592653589793],
+ ["double", -2.71828182845905],
+ ["double", "1.23456789012345e308"],
+ ["double", "-1.23456789012345e-308"],
+ ["double", "inf"],
+ ["double", "-inf"],
+ ["double", "NaN"]]],
+ ["array", [["decimal32", "0x00000000"],
+ ["decimal32", "0x03020100"],
+ ["decimal32", "0xffffffff"]]],
+ ["array", [["decimal64", "0x0000000000000000"],
+ ["decimal64", "0x0706050403020100"],
+ ["decimal64", "0xffffffffffffffff"]]],
+ ["array", [["decimal128", "0x00000000000000000000000000000000"],
+ ["decimal128", "0x0f0e0d0c0b0a09080706050403020100"],
+ ["decimal128", "0xffffffffffffffffffffffffffffffff"]]],
+ ["array", [["char", " "],
+ ["char", "A"],
+ ["char", "z"],
+ ["char", "0"],
+ ["char", "9"],
+ ["char", "}"],
+ ["char", "0x00"],
+ ["char", "0x01"],
+ ["char", "0x7f"],
+ ["char", "0x80"],
+ ["char", "0xff"],
+ ["char", "0x16b5"],
+ ["char", "0x010203"],
+ ["char", "0x10ffff"],
+ ["char", "0xffffffff"]]],
+ ["array", [["timestamp", 0],
+ ["timestamp", "0xdc6be25480"],
+ ["timestamp", "0x1624e900fa5"]]],
+ ["array", [["uuid", "0x1"],
+ ["uuid", "00010203-0405-0607-0809-0a0b0c0d0e0f"],
+ ["uuid", "0x0f0e0d0c0b0a09080706050403020100"],
+ ["uuid", "68907a08-2a1b-4154-9733-2c0b9f4c5597"]]],
+ ["array", [["binary", ""],
+ ["binary", 123456],
+ ["binary", "0x0f0e0d0c0b0a09080706050403020100"],
+ ["binary", "Hello, world!"],
+ ["binary", "\\x01\\x02\\x03\\x04\\x05zyxwv\\x80\\x81\\xfe\\xff"],
+ ["binary", "The quick brown fox jumped over the lazy dog 0123456789."]]],
+ ["array", [["string", ""],
+ ["string", "Hello, world"],
+ ["string", "\"Hello, world\""],
+ ["string", "Charlie's peach"],
+ ["string", "The quick brown fox jumped over the lazy dog 0123456789."]]],
+ ["array", [["symbol", ""],
+ ["symbol", "myDomain.123"],
+ ["symbol", "domain.0123456789."]]],
+ ["array", [["array", []],
+ ["array", [["ubyte", 0],
+ ["ubyte", 1],
+ ["ubyte", 2],
+ ["ubyte", 3]]],
+ ["array", [["string", "This"],
+ ["string", "is"],
+ ["string", "arbitrary"]]]]],
+ ["array", [["list", []],
+ ["list", [["ubyte", 16],
+ ["ushort", 17],
+ ["uint", 18],
+ ["ulong", 19],
+ ["byte", 20],
+ ["short", 21],
+ ["int", 22],
+ ["long", 23]]],
+ ["list", [["float", 0.1234],
+ ["double", 0.12345678]]],
+ ["list", [["decimal32", "0x03020100"],
+ ["decimal64", "0x0706050403020100"],
+ ["decimal128", "0x0f0e0d0c0b0a09080706050403020100"]]],
+ ["list", [["char", "X"],
+ ["timestamp", "0xdc6be25480"],
+ ["uuid", "0x0f0e0d0c0b0a09080706050403020100"]]],
+ ["list", [["binary", "Hello, world"],
+ ["string", "Hello, world"],
+ ["symbol", "Hello, world"]]],
+ ["list", [["array", []],
+ ["array", [["byte", 1],
+ ["byte", 2]]]]],
+ ["list", [["list", []],
+ ["list", [["byte", 3],
+ ["string", "hello"]]]]],
+ ["list", [["map", []],
+ ["map", [["string", "key1"], ["byte", 4], ["uint", 10], ["float", 3.14]]]]]]],
+ ["array", [["map", []],
+ ["map", [["ubyte", 16], ["string", "sixteen"],
+ ["ushort", 17], ["string", "seventeen"],
+ ["uint", 18], ["string", "eighteen"],
+ ["ulong", 19], ["string", "nineteen"],
+ ["byte", 20], ["string", "twenty"],
+ ["short", 21], ["string", "twenty-one"],
+ ["int", 22], ["string", "twenty-two"],
+ ["long", 23], ["string", "twenty-three"]]],
+ ["map", [["float", 0.1234], ["binary", "hello"],
+ ["double", 0.12345678], ["binary", "world"]]],
+ ["map", [["string", "hello"], ["int", -25],
+ ["symbol", "world"], ["long", -12345678],
+ ["binary", "today\\x01\\x02"], ["byte", -7]]]]]
+]
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/c1fb4159/src/python/qpid_interop_test/amqp_complex_types_test.list.json
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/amqp_complex_types_test.list.json b/src/python/qpid_interop_test/amqp_complex_types_test.list.json
new file mode 100644
index 0000000..86de15f
--- /dev/null
+++ b/src/python/qpid_interop_test/amqp_complex_types_test.list.json
@@ -0,0 +1,157 @@
+[["list", []],
+ ["list", [["null", null],
+ ["null", null]]],
+ ["list", [["boolean", true],
+ ["boolean", false]]],
+ ["list", [["ubyte", 0],
+ ["ubyte", 127],
+ ["ubyte", 128],
+ ["ubyte", 255]]],
+ ["list", [["ushort", 0],
+ ["ushort", 255],
+ ["ushort", 256],
+ ["ushort", "0x7fff"],
+ ["ushort", "0x8000"],
+ ["ushort", "0xffff"]]],
+ ["list", [["uint", 0],
+ ["uint", 255],
+ ["uint", 256],
+ ["uint", "0x7fffffff"],
+ ["uint", "0x80000000"],
+ ["uint", "0xffffffff"]]],
+ ["list", [["ulong", 0],
+ ["ulong", 255],
+ ["ulong", 256],
+ ["ulong", "0x7fffffffffffffff"],
+ ["ulong", "0x8000000000000000"],
+ ["ulong", "0xffffffffffffffff"]]],
+ ["list", [["byte", -128],
+ ["byte", -1],
+ ["byte", 0],
+ ["byte", 255]]],
+ ["list", [["short", "-0x8000"],
+ ["short", -1],
+ ["short", 0],
+ ["short", "0x7fff"]]],
+ ["list", [["int", "-0x80000000"],
+ ["int", -1],
+ ["int", 0],
+ ["int", "0x7fffffff"]]],
+ ["list", [["long", "-0x8000000000000000"],
+ ["long", -128],
+ ["long", -1],
+ ["long", 0],
+ ["long", 127],
+ ["long", "0x7fffffffffffffff"]]],
+ ["list", [["float", 0.0],
+ ["float", 3.14159],
+ ["float", -2.71828],
+ ["float", "1.2345e+38"],
+ ["float", "-1.2345e-38"],
+ ["float", "inf"],
+ ["float", "-inf"],
+ ["float", "NaN"]]],
+ ["list", [["double", 0.0],
+ ["double", 3.141592653589793],
+ ["double", -2.71828182845905],
+ ["double", "1.23456789012345e308"],
+ ["double", "-1.23456789012345e-308"],
+ ["double", "inf"],
+ ["double", "-inf"],
+ ["double", "NaN"]]],
+ ["list", [["decimal32", "0x00000000"],
+ ["decimal32", "0x03020100"],
+ ["decimal32", "0xffffffff"]]],
+ ["list", [["decimal64", "0x0000000000000000"],
+ ["decimal64", "0x0706050403020100"],
+ ["decimal64", "0xffffffffffffffff"]]],
+ ["list", [["decimal128", "0x00000000000000000000000000000000"],
+ ["decimal128", "0x0f0e0d0c0b0a09080706050403020100"],
+ ["decimal128", "0xffffffffffffffffffffffffffffffff"]]],
+ ["list", [["char", " "],
+ ["char", "A"],
+ ["char", "z"],
+ ["char", "0"],
+ ["char", "9"],
+ ["char", "}"],
+ ["char", "0x00"],
+ ["char", "0x01"],
+ ["char", "0x7f"],
+ ["char", "0x80"],
+ ["char", "0xff"],
+ ["char", "0x16b5"],
+ ["char", "0x010203"],
+ ["char", "0x10ffff"],
+ ["char", "0xffffffff"]]],
+ ["list", [["timestamp", 0],
+ ["timestamp", "0xdc6be25480"],
+ ["timestamp", "0x1624e900fa5"]]],
+ ["list", [["uuid", "0x0"],
+ ["uuid", "00010203-0405-0607-0809-0a0b0c0d0e0f"],
+ ["uuid", "0x0f0e0d0c0b0a09080706050403020100"],
+ ["uuid", "68907a08-2a1b-4154-9733-2c0b9f4c5597"]]],
+ ["list", [["binary", ""],
+ ["binary", 12345],
+ ["binary", "0x0f0e0d0c0b0a09080706050403020100"],
+ ["binary", "Hello, world!"],
+ ["binary", "\\x01\\x02\\x03\\x04\\x05zyxwv\\x80\\x81\\xfe\\xff"],
+ ["binary", "The quick brown fox jumped over the lazy dog 0123456789."]]],
+ ["list", [["string", ""],
+ ["string", "Hello, world"],
+ ["string", "\"Hello, world\""],
+ ["string", "Charlie's peach"],
+ ["string", "The quick brown fox jumped over the lazy dog 0123456789."]]],
+ ["list", [["symbol", ""],
+ ["symbol", "myDomain.123"],
+ ["symbol", "domain.0123456789."]]],
+ ["list", [["array", []],
+ ["array", [["ubyte", 0],
+ ["ubyte", 1],
+ ["ubyte", 2],
+ ["ubyte", 3]]],
+ ["array", [["string", "This"],
+ ["string", "is"],
+ ["string", "stupid"]]]]],
+ ["list", [["list", []],
+ ["list", [["ubyte", 16],
+ ["ushort", 17],
+ ["uint", 18],
+ ["ulong", 19],
+ ["byte", 20],
+ ["short", 21],
+ ["int", 22],
+ ["long", 23]]],
+ ["list", [["float", 0.1234],
+ ["double", 0.12345678]]],
+ ["list", [["decimal32", "0x03020100"],
+ ["decimal64", "0x0706050403020100"],
+ ["decimal128", "0x0f0e0d0c0b0a09080706050403020100"]]],
+ ["list", [["char", "X"],
+ ["timestamp", "0xdc6be25480"],
+ ["uuid", "0x0f0e0d0c0b0a09080706050403020100"]]],
+ ["list", [["binary", "Hello, world"],
+ ["string", "Hello, world"],
+ ["symbol", "Hello, world"]]],
+ ["list", [["array", []],
+ ["array", [["byte", 1],
+ ["byte", 2]]]]],
+ ["list", [["list", []],
+ ["list", [["byte", 3],
+ ["string", "hello"]]]]],
+ ["list", [["map", []],
+ ["map", [["string", "key1"], ["byte", 4], ["uint", 10], ["float", 3.14]]]]]]],
+ ["list", [["map", []],
+ ["map", [["ubyte", 16], ["string", "sixteen"],
+ ["ushort", 17], ["string", "seventeen"],
+ ["uint", 18], ["string", "eighteen"],
+ ["ulong", 19], ["string", "nineteen"],
+ ["byte", 20], ["string", "twenty"],
+ ["short", 21], ["string", "twenty-one"],
+ ["int", 22], ["string", "twenty-two"],
+ ["long", 23], ["string", "twenty-three"]]],
+ ["map", [["float", 0.1234], ["binary", "hello"],
+ ["double", 0.12345678], ["binary", "world"]]],
+ ["map", [["string", "hello"], ["int", -25],
+ ["symbol", "world"], ["long", -12345678],
+ ["binary", "today\\x01\\x02"], ["byte", -7]]]]]
+]
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/c1fb4159/src/python/qpid_interop_test/amqp_complex_types_test.map.json
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/amqp_complex_types_test.map.json b/src/python/qpid_interop_test/amqp_complex_types_test.map.json
new file mode 100644
index 0000000..9a6cbb2
--- /dev/null
+++ b/src/python/qpid_interop_test/amqp_complex_types_test.map.json
@@ -0,0 +1,116 @@
+[["map", []],
+ ["map", [["null", null], ["null", null]]],
+ ["map", [["boolean", false], ["boolean", false],
+ ["boolean", true], ["boolean", true]]],
+ ["map", [["ubyte", 0], ["ubyte", 0],
+ ["ubyte", 127], ["ubyte", 127],
+ ["ubyte", 128], ["ubyte", 128],
+ ["ubyte", 255], ["ubyte", 255]]],
+ ["map", [["ushort", 0], ["ushort", 0],
+ ["ushort", 255], ["ushort", 255],
+ ["ushort", 256], ["ushort", 256],
+ ["ushort", "0x7fff"], ["ushort", "0x7fff"],
+ ["ushort", "0x8000"], ["ushort", "0x8000"],
+ ["ushort", "0xffff"], ["ushort", "0xffff"]]],
+ ["map", [["uint", 0], ["uint", 0],
+ ["uint", 255], ["uint", 255],
+ ["uint", 256], ["uint", 256],
+ ["uint", "0x7fffffff"], ["uint", "0x7fffffff"],
+ ["uint", "0x80000000"], ["uint", "0x80000000"],
+ ["uint", "0xffffffff"], ["uint", "0xffffffff"]]],
+ ["map", [["ulong", 0], ["ulong", 0],
+ ["ulong", 255], ["ulong", 255],
+ ["ulong", 256], ["ulong", 256],
+ ["ulong", "0x7fffffffffffffff"], ["ulong", "0x7fffffffffffffff"],
+ ["ulong", "0x8000000000000000"], ["ulong", "0x8000000000000000"],
+ ["ulong", "0xffffffffffffffff"], ["ulong", "0xffffffffffffffff"]]],
+ ["map", [["byte", -128], ["byte", -128],
+ ["byte", -1], ["byte", -1],
+ ["byte", 0], ["byte", 0],
+ ["byte", 255], ["byte", 255]]],
+ ["map", [["short", "-0x8000"], ["short", "-0x8000"],
+ ["short", -1], ["short", -1],
+ ["short", 0], ["short", 0],
+ ["short", "0x7fff"], ["short", "0x7fff"]]],
+ ["map", [["int", "-0x80000000"], ["int", "-0x80000000"],
+ ["int", -1], ["int", -1],
+ ["int", 0], ["int", 0],
+ ["int", "0x7fffffff"], ["int", "0x7fffffff"]]],
+ ["map", [["long", "-0x8000000000000000"], ["long", "-0x8000000000000000"],
+ ["long", -128], ["long", -128],
+ ["long", -1], ["long", -1],
+ ["long", 0], ["long", 0],
+ ["long", 127], ["long", 127],
+ ["long", "0x7fffffffffffffff"], ["long", "0x7fffffffffffffff"]]],
+ ["map", [["float", 0.0], ["float", 0.0],
+ ["float", 3.14159], ["float", 3.14159],
+ ["float", -2.71828], ["float", -2.71828],
+ ["float", "1.2345e+38"], ["float", "1.2345e+38"],
+ ["float", "-1.2345e-38"], ["float", "-1.2345e-38"],
+ ["float", "inf"], ["float", "inf"],
+ ["float", "-inf"], ["float", "-inf"],
+ ["float", "NaN"], ["float", "NaN"]]],
+ ["map", [["double", 0.0], ["double", 0.0],
+ ["double", 3.141592653589793], ["double", 3.141592653589793],
+ ["double", -2.71828182845905], ["double", -2.71828182845905],
+ ["double", "1.23456789012345e308"], ["double", "1.23456789012345e308"],
+ ["double", "-1.23456789012345e-308"], ["double", "-1.23456789012345e-308"],
+ ["double", "inf"], ["double", "inf"],
+ ["double", "-inf"], ["double", "-inf"],
+ ["double", "NaN"], ["double", "NaN"]]],
+ ["map", [["decimal32", "0x00000000"], ["decimal32", "0x00000000"],
+ ["decimal32", "0x03020100"], ["decimal32", "0x03020100"],
+ ["decimal32", "0xffffffff"], ["decimal32", "0xffffffff"]]],
+ ["map", [["decimal64", "0x0000000000000000"], ["decimal64", "0x0000000000000000"],
+ ["decimal64", "0x0706050403020100"], ["decimal64", "0x0706050403020100"],
+ ["decimal64", "0xffffffffffffffff"], ["decimal64", "0xffffffffffffffff"]]],
+ ["map", [["decimal128", "0x00000000000000000000000000000000"], ["decimal128", "0x00000000000000000000000000000000"],
+ ["decimal128", "0x0f0e0d0c0b0a09080706050403020100"], ["decimal128", "0x0f0e0d0c0b0a09080706050403020100"],
+ ["decimal128", "0xffffffffffffffffffffffffffffffff"], ["decimal128", "0xffffffffffffffffffffffffffffffff"]]],
+ ["map", [["char", " "], ["char", " "],
+ ["char", "A"], ["char", "A"],
+ ["char", "z"], ["char", "z"],
+ ["char", "0"], ["char", "0"],
+ ["char", "9"], ["char", "9"],
+ ["char", "}"], ["char", "}"],
+ ["char", "0x00"], ["char", "0x00"],
+ ["char", "0x01"], ["char", "0x01"],
+ ["char", "0x7f"], ["char", "0x7f"],
+ ["char", "0x80"], ["char", "0x80"],
+ ["char", "0xff"], ["char", "0xff"],
+ ["char", "0x16b5"], ["char", "0x16b5"],
+ ["char", "0x010203"], ["char", "0x010203"],
+ ["char", "0x10ffff"], ["char", "0x10ffff"],
+ ["char", "0xffffffff"], ["char", "0xffffffff"]]],
+ ["map", [["timestamp", 0], ["timestamp", 0],
+ ["timestamp", "0xdc6be25480"], ["timestamp", "0xdc6be25480"],
+ ["timestamp", "0x1624e900fa5"], ["timestamp", "0x1624e900fa5"]]],
+ ["map", [["uuid", "0x0"], ["uuid", "0x0"],
+ ["uuid", "00010203-0405-0607-0809-0a0b0c0d0e0f"], ["uuid", "00010203-0405-0607-0809-0a0b0c0d0e0f"],
+ ["uuid", "0x0f0e0d0c0b0a09080706050403020100"], ["uuid", "0x0f0e0d0c0b0a09080706050403020100"],
+ ["uuid", "68907a08-2a1b-4154-9733-2c0b9f4c5597"], ["uuid", "68907a08-2a1b-4154-9733-2c0b9f4c5597"]]],
+ ["map", [["binary", ""], ["binary", ""],
+ ["binary", 12345], ["binary", 12345],
+ ["binary", "0x0f0e0d0c0b0a09080706050403020100"], ["binary", "0x0f0e0d0c0b0a09080706050403020100"],
+ ["binary", "Hello, world!"], ["binary", "Hello, world!"],
+ ["binary", "\\x01\\x02\\x03\\x04\\x05zyxwv\\x80\\x81\\xfe\\xff"], ["binary", "\\x01\\x02\\x03\\x04\\x05zyxwv\\x80\\x81\\xfe\\xff"],
+ ["binary", "The quick brown fox jumped over the lazy dog 0123456789."], ["binary", "The quick brown fox jumped over the lazy dog 0123456789."]]],
+ ["map", [["string", ""], ["string", ""],
+ ["string", "Hello, world"], ["string", "Hello, world"],
+ ["string", "\"Hello, world\""], ["string", "\"Hello, world\""],
+ ["string", "Charlie's peach"], ["string", "Charlie's peach"],
+ ["string", "The quick brown fox jumped over the lazy dog 0123456789."], ["string", "The quick brown fox jumped over the lazy dog 0123456789."]]],
+ ["map", [["symbol", ""], ["symbol", ""],
+ ["symbol", "myDomain.123"], ["symbol", "myDomain.123"],
+ ["symbol", "domain.0123456789."], ["symbol", "domain.0123456789."]]],
+ ["map", [["string", "array01"], ["array", [["boolean", false],
+ ["boolean", true]]]]],
+ ["map", [["string", "list01"], ["list", [["boolean", false],
+ ["boolean", true],
+ ["ubyte", 0],
+ ["ubyte", 127],
+ ["ubyte", 128],
+ ["ubyte", 255]]]]],
+ ["map", [["string", "map01"], ["map", [["boolean", false], ["boolean", false],
+ ["boolean", true], ["boolean", true]]]]]
+]
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/c1fb4159/src/python/qpid_interop_test/amqp_complex_types_test_generator.py
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/amqp_complex_types_test_generator.py b/src/python/qpid_interop_test/amqp_complex_types_test_generator.py
new file mode 100644
index 0000000..5fdaec6
--- /dev/null
+++ b/src/python/qpid_interop_test/amqp_complex_types_test_generator.py
@@ -0,0 +1,762 @@
+#!/usr/bin/env python3
+
+"""
+Module to generate test data files for the AMQP complex types test
+"""
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import argparse
+import json
+import os.path
+import time
+from abc import abstractmethod
+
+COPYRIGHT_TEXT = u"""Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License."""
+
+DEFAULT_PATH = os.path.dirname(os.path.realpath(__file__))
+DEFAULT_JSON_BASE_NAME = u'amqp_complex_types_test'
+GENERATOR_TARGETS = [u'python', u'cpp', u'javascript', u'dotnet', u'ALL']
+AMQP_COMPEX_TYPES = [u'array', u'list', u'map', u'ALL']
+INDENT_LEVEL_SIZE = 4
+
+class JsonReader(object):
+ """Class to read the JSON data file"""
+ def __init__(self, args):
+ self.args = args
+
+ def generate(self):
+ """Generate the output files based on command-line argument choices"""
+ if self.args.gen == u'ALL':
+ gen_targets = GENERATOR_TARGETS[:-1]
+ else:
+ gen_targets = [self.args.gen]
+ gen_path = os.path.abspath(self.args.gen_dir)
+ for target in gen_targets:
+ target_file_name = None
+ if target == GENERATOR_TARGETS[0]: # Python
+ target_file_name = os.path.join(gen_path, u'%s.data.py' % self.args.json_base_name)
+ with PythonGenerator(target_file_name) as generator:
+ self._generate_target(target, generator)
+ elif target == GENERATOR_TARGETS[1]: # C++
+ target_file_name = os.path.join(gen_path, u'%s.data.cpp' % self.args.json_base_name)
+ with CppGenerator(target_file_name) as generator:
+ self._generate_target(target, generator)
+ elif target == GENERATOR_TARGETS[2]: # JavaScript
+ target_file_name = os.path.join(gen_path, u'%s.data.js' % self.args.json_base_name)
+ with JavaScriptGenerator(target_file_name) as generator:
+ self._generate_target(target, generator)
+ elif target == GENERATOR_TARGETS[3]: # DotNet
+ target_file_name = os.path.join(gen_path, u'%s.data.cs' % self.args.json_base_name)
+ with DotNetGenerator(target_file_name) as generator:
+ self._generate_target(target, generator)
+ else:
+ raise RuntimeError(u'Unknown target %s' % target)
+
+ def _generate_target(self, target, generator):
+ """Generate the output file for target type"""
+ print(u'_generate_target(t=%s g=%s)' % (target, generator.__class__.__name__))
+ generator.write_prefix()
+ if self.args.type == u'ALL':
+ amqp_test_types = AMQP_COMPEX_TYPES[:-1]
+ else:
+ amqp_test_types = [self.args.type]
+ # First parse
+ for amqp_test_type in amqp_test_types:
+ json_file_name = os.path.join(os.path.abspath(self.args.src_dir), u'%s.%s.json' %
+ (self.args.json_base_name, amqp_test_type))
+ print(u' * _generate_type(t=%s f=%s)' % (amqp_test_type, os.path.basename(json_file_name)))
+ generator.write_code(amqp_test_type, JsonReader._read_file(json_file_name))
+ generator.write_postfix()
+
+ @staticmethod
+ def _read_file(json_file_name):
+ """Read the file into a Python data structure"""
+ print(u'reading file %s' % os.path.basename(json_file_name))
+ json_file = open(json_file_name, u'r')
+ json_file_data = json_file.read()
+ json_file.close()
+ return json.loads(json_file_data)
+
+ @staticmethod
+ def _target_file_extension(target):
+ file_extension_map = {u'python': u'py',
+ u'cpp': u'cpp',
+ u'javascript': u'js',
+ u'dotnet': u'cs'}
+ if target in file_extension_map:
+ return file_extension_map[target]
+ raise RuntimeError(u'Unknown target: %s' % target)
+
+
+class Generator(object):
+ """Abstract code generator class"""
+ def __init__(self, target_file_name):
+ self.target_file = open(target_file_name, u'w')
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.target_file.close()
+
+ @abstractmethod
+ def write_prefix(self):
+ """Write comments, copyright, etc at top of file"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def write_code(self, amqp_test_type, json_data):
+ """Process data structure to write code"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def write_postfix(self):
+ """Write comments, any fixed items to the end of the source file"""
+ raise NotImplementedError
+
+class PythonGenerator(Generator):
+ """Python code generator"""
+
+ def write_prefix(self):
+ """Write comments, copyright, etc at top of Python source file"""
+ self.target_file.write(u'#!/usr/bin/env python\n\n')
+ self.target_file.write(u'"""Data used for qpid_interop_test.amqp_complex_types_test"""\n\n')
+ for line in iter(COPYRIGHT_TEXT.splitlines()):
+ self.target_file.write(u'# %s\n' % line)
+ self.target_file.write(u'\n# *** THIS IS A GENERATED FILE, DO NOT EDIT DIRECTLY ***\n')
+ self.target_file.write(u'# Generated by building qpid_interop_test\n')
+ self.target_file.write(u'# Generated: %s\n\n' % time.strftime(u'%Y-%m-%d %H:%M:%S', time.gmtime()))
+ self.target_file.write(u'import uuid\nimport proton\n\n')
+ self.target_file.write(u'TEST_DATA = {\n')
+
+ def write_code(self, amqp_test_type, json_data):
+ """Write Python code from json_data"""
+ hdr_line = u'=' * (19 + len(amqp_test_type))
+ self.target_file.write(u'\n # %s\n' % hdr_line)
+ self.target_file.write(u' # *** AMQP type: %s ***\n' % amqp_test_type)
+ self.target_file.write(u' # %s\n\n' % hdr_line)
+ self.target_file.write(u' \'%s\': [\n' % amqp_test_type)
+ for data_pair in json_data:
+ self._write_data_pair(2, data_pair)
+ self.target_file.write(u' ], # end: AMQP type %s\n' % amqp_test_type)
+
+ def _write_data_pair(self, indent_level, data_pair, separator=u',', eol=True):
+ """Write a JOSN pair ['amqp_type', value]"""
+ indent_str = u' ' * (indent_level * INDENT_LEVEL_SIZE)
+ eol_char = u'\n' if eol else u''
+ amqp_type, value = data_pair
+ if amqp_type == u'null':
+ self.target_file.write(u'%sNone%s%s' % (indent_str, separator, eol_char))
+ elif amqp_type == u'boolean':
+ self.target_file.write(u'%s%s%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'ubyte':
+ self.target_file.write(u'%sproton.ubyte(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'byte':
+ self.target_file.write(u'%sproton.byte(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'ushort':
+ self.target_file.write(u'%sproton.ushort(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'short':
+ self.target_file.write(u'%sproton.short(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'uint':
+ self.target_file.write(u'%sproton.uint(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'int':
+ self.target_file.write(u'%sproton.int32(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'ulong':
+ self.target_file.write(u'%sproton.ulong(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'long':
+ self.target_file.write(u'%sint(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'float':
+ if isinstance(value, str) and (value[-3:] == u'inf' or value[-3:] == u'NaN'):
+ self.target_file.write(u'%sproton.float32(\'%s\')%s%s' % (indent_str, value, separator, eol_char))
+ else:
+ self.target_file.write(u'%sproton.float32(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'double':
+ if isinstance(value, str) and (value[-3:] == u'inf' or value[-3:] == u'NaN'):
+ self.target_file.write(u'%sfloat(\'%s\')%s%s' % (indent_str, value, separator, eol_char))
+ else:
+ self.target_file.write(u'%sfloat(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'decimal32':
+ self.target_file.write(u'%sproton.decimal32(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'decimal64':
+ self.target_file.write(u'%sproton.decimal64(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'decimal128':
+ byte_itr = iter(value[2:])
+ self.target_file.write(u'%sproton.decimal128(b\'' % indent_str)
+ for char_ in byte_itr:
+ self.target_file.write(u'\\x%c%c' % (char_, next(byte_itr)))
+ self.target_file.write(u'\')%s%s' % (separator, eol_char))
+ elif amqp_type == u'char':
+ self.target_file.write(u'%sproton.char(u\'' % indent_str)
+ if len(value) == 1: # single char
+ self.target_file.write(value)
+ else:
+ byte_itr = iter(value[2:])
+ for char_ in byte_itr:
+ self.target_file.write(u'\\x%c%c' % (char_, next(byte_itr)))
+ self.target_file.write(u'\')%s%s' % (separator, eol_char))
+ elif amqp_type == u'timestamp':
+ self.target_file.write(u'%sproton.timestamp(%s)%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'uuid':
+ self.target_file.write(u'%suuid.UUID(' % indent_str)
+ if value[:2] == u'0x':
+ self.target_file.write(u'int=%s' % value)
+ else:
+ self.target_file.write(u'\'{%s}\'' % value)
+ self.target_file.write(u')%s%s' % (separator, eol_char))
+ elif amqp_type == u'binary':
+ if isinstance(value, str):
+ self.target_file.write(u'%sb\'' % indent_str)
+ if value[:2] == u'0x':
+ byte_itr = iter(value[2:])
+ for char_ in byte_itr:
+ self.target_file.write(u'\\x%c%c' % (char_, next(byte_itr)))
+ else:
+ for char_ in value:
+ if char_ == u'\'':
+ self.target_file.write(u'\\')
+ self.target_file.write(char_)
+ self.target_file.write(u'\'%s%s' % (separator, eol_char))
+ else:
+ self.target_file.write(u'%s%d%s%s' % (indent_str, value, separator, eol_char))
+ elif amqp_type == u'string':
+ self.target_file.write(u'%su\'' % indent_str)
+ for char_ in value:
+ if char_ == u'\'':
+ self.target_file.write(u'\\')
+ self.target_file.write(char_)
+ self.target_file.write(u'\'%s%s' % (separator, eol_char))
+ elif amqp_type == u'symbol':
+ self.target_file.write(u'%sproton.symbol(u\'' % indent_str)
+ for char_ in value:
+ if char_ == u'\'':
+ self.target_file.write(u'\\')
+ self.target_file.write(char_)
+ self.target_file.write(u'\')%s%s' % (separator, eol_char))
+ elif amqp_type == u'array':
+ if not isinstance(value, list):
+ raise RuntimeError(u'AMQP array value not a list, found %s' % type(value))
+ amqp_type = None
+ if value:
+ amqp_type = value[0][0]
+ self.target_file.write(u'%sproton.Array(proton.UNDESCRIBED, %s, [\n' %
+ (indent_str, PythonGenerator._proton_type_code(amqp_type)))
+ for value_data_pair in value:
+ if value_data_pair[0] != amqp_type:
+ raise RuntimeError(u'AMQP array of type %s has element of type %s' %
+ (amqp_type, value_data_pair[0]))
+ self._write_data_pair(indent_level+1, value_data_pair)
+ self.target_file.write(u'%s]),%s' % (indent_str, eol_char))
+ elif amqp_type == u'list':
+ if not isinstance(value, list):
+ raise RuntimeError(u'AMQP list value not a list, found %s' % type(value))
+ self.target_file.write(u'%s[\n' % indent_str)
+ for value_data_pair in value:
+ self._write_data_pair(indent_level+1, value_data_pair)
+ self.target_file.write(u'%s],%s' % (indent_str, eol_char))
+ elif amqp_type == u'map':
+ if not isinstance(value, list):
+ raise RuntimeError(u'AMQP map value not a list, found %s' % type(value))
+ if len(value) % 2 != 0:
+ raise RuntimeError(u'AMQP map value list not even, contains %d items' % len(value))
+ self.target_file.write(u'%s{\n' % indent_str)
+ # consume list in pairs (key, value)
+ value_iter = iter(value)
+ for value_data_pair in value_iter:
+ self._write_data_pair(indent_level+1, value_data_pair, separator=u': ', eol=False)
+ value_data_pair = next(value_iter)
+ self._write_data_pair(0, value_data_pair)
+ self.target_file.write(u'%s},%s' % (indent_str, eol_char))
+ else:
+ raise RuntimeError(u'Unknown AMQP type \'%s\'' % amqp_type)
+
+ @staticmethod
+ def _proton_type_code(amqp_type):
+ amqp_types = {
+ None: None,
+ u'null': u'proton.Data.NULL',
+ u'boolean': u'proton.Data.BOOL',
+ u'byte': u'proton.Data.BYTE',
+ u'ubyte': u'proton.Data.UBYTE',
+ u'short': u'proton.Data.SHORT',
+ u'ushort': u'proton.Data.USHORT',
+ u'int': u'proton.Data.INT',
+ u'uint': u'proton.Data.UINT',
+ u'char': u'proton.Data.CHAR',
+ u'long': u'proton.Data.LONG',
+ u'ulong': u'proton.Data.ULONG',
+ u'timestamp': u'proton.Data.TIMESTAMP',
+ u'float': u'proton.Data.FLOAT',
+ u'double': u'proton.Data.DOUBLE',
+ u'decimal32': u'proton.Data.DECIMAL32',
+ u'decimal64': u'proton.Data.DECIMAL64',
+ u'decimal128': u'proton.Data.DECIMAL128',
+ u'uuid': u'proton.Data.UUID',
+ u'binary': u'proton.Data.BINARY',
+ u'string': u'proton.Data.STRING',
+ u'symbol': u'proton.Data.SYMBOL',
+ u'described': u'proton.Data.DESCRIBED',
+ u'array': u'proton.Data.ARRAY',
+ u'list': u'proton.Data.LIST',
+ u'map': u'proton.Data.MAP'
+ }
+ return amqp_types[amqp_type]
+
+ def write_postfix(self):
+ """Write postfix at bottom of Python source file"""
+ self.target_file.write(u'}\n\n# <eof>\n')
+
+
+class CppGenerator(Generator):
+ """C++ code generator"""
+
+ def __init__(self, target_file_name):
+ super(CppGenerator, self).__init__(target_file_name)
+ self.d32_count = 0
+ self.d64_count = 0
+ self.d128_count = 0
+ self.ts_count = 0
+ self.uuid_count = 0
+ self.bin_count = 0
+ self.sym_count = 0
+ self.arr_count = 0
+ self.list_count = 0
+ self.map_count = 0
+
+ CODE_SEGMET_A = u'''#include <limits> // std::numeric_limits
+#include <map>
+#include <vector>
+
+#include "amqp_complex_types_test.data.hpp"
+
+namespace qpidit {
+ namespace amqp_complex_types_test {
+
+ typedef std::map<const std::string, const std::vector<proton::value> > TestDataMap_t;
+ typedef TestDataMap_t::const_iterator TestDataMapCitr_t;
+
+ class TestData {
+ public:
+ static bool initialize();
+ static bool initialized;
+ static TestDataMap_t s_data_map;
+ };
+
+ bool TestData::initialize() {
+'''
+
+ CODE_SEGMENT_B = u''' return true;
+ }
+
+ TestDataMap_t TestData::s_data_map;
+
+ bool TestData::initialized = TestData::initialize();
+ } // namespace amqp_complex_types_test
+} // namespace qpidit
+'''
+
+ PROTON_TYPES = [u'decimal32', u'decimal64', u'decimal128', u'timestamp', u'uuid', u'binary', u'symbol']
+ COMPLEX_TYPES = [u'array', u'list', u'map']
+
+
+ def write_prefix(self):
+ """Write comments, copyright, etc at top of C++ source file"""
+ self.target_file.write(u'/**\n * Data used for qpid_interop_test.amqp_complex_types_test\n */\n\n')
+ self.target_file.write(u'/*\n')
+ for line in iter(COPYRIGHT_TEXT.splitlines()):
+ self.target_file.write(u' * %s\n' % line)
+ self.target_file.write(u' */\n\n')
+ self.target_file.write(u'/*\n')
+ self.target_file.write(u' * THIS IS A GENERATED FILE, DO NOT EDIT DIRECTLY\n')
+ self.target_file.write(u' * Generated by building qpid_interop_test\n')
+ self.target_file.write(u' * Generated: %s\n' % time.strftime(u'%Y-%m-%d %H:%M:%S', time.gmtime()))
+ self.target_file.write(u' */\n\n')
+ self.target_file.write(CppGenerator.CODE_SEGMET_A)
+
+ def write_code(self, amqp_test_type, json_data):
+ """Write C++ code from json_data"""
+ indent_level = 3
+ indent_str = u' ' * (indent_level * INDENT_LEVEL_SIZE)
+ container_name = u'%s_list' % amqp_test_type
+ container_type = u'std::vector<proton::value>'
+ hdr_line = u'*' * (17 + len(amqp_test_type))
+ self.target_file.write(u'\n%s/*%s\n' % (indent_str, hdr_line))
+ self.target_file.write(u'%s*** AMQP type: %s ***\n' % (indent_str, amqp_test_type))
+ self.target_file.write(u'%s%s*/\n\n' % (indent_str, hdr_line))
+ self.target_file.write(u'%s%s %s;\n\n' % (indent_str, container_type, container_name))
+ self._pre_write_list(indent_level, container_name, json_data, True)
+ self.target_file.write(u'%ss_data_map.insert(std::pair<const std::string, %s >("%s", %s));\n\n' %
+ (indent_str, container_type, amqp_test_type, container_name))
+
+ def _pre_write_list(self, indent_level, container_name, value, push_flag=False):
+ """If a value in a list is a complex or proton type, write instances before the list itself is written"""
+ instance_name_list = []
+ for value_data_pair in value:
+ if value_data_pair[0] in CppGenerator.COMPLEX_TYPES:
+ self._write_complex_instance(indent_level, container_name, value_data_pair, instance_name_list,
+ push_flag)
+ elif value_data_pair[0] in CppGenerator.PROTON_TYPES:
+ self._write_proton_instance(indent_level, value_data_pair, instance_name_list)
+ return instance_name_list
+
+ def _write_complex_instance(self, indent_level, container_name, data_pair, instance_name_list, push_flag):
+ indent_str = u' ' * (indent_level * INDENT_LEVEL_SIZE)
+ amqp_type, value = data_pair
+ if amqp_type == u'array':
+ if not isinstance(value, list):
+ raise RuntimeError(u'AMQP array value not a list, found %s' % type(value))
+ inner_instance_name_list = self._pre_write_list(indent_level, container_name, value)
+ self.arr_count += 1
+ self.target_file.write(u'%sstd::vector<proton::value> array_%d = {' % (indent_str, self.arr_count))
+ instance_name_list.append(u'array_%d' % self.arr_count)
+ for value_data_pair in value:
+ self._write_data_pair(value_data_pair, inner_instance_name_list)
+ self.target_file.write(u'};\n')
+ if push_flag:
+ self.target_file.write(u'%s%s.push_back(array_%d);\n\n' % (indent_str, container_name, self.arr_count))
+ elif amqp_type == u'list':
+ if not isinstance(value, list):
+ raise RuntimeError(u'AMQP list value not a list, found %s' % type(value))
+ inner_instance_name_list = self._pre_write_list(indent_level, container_name, value)
+ self.list_count += 1
+ self.target_file.write(u'%sstd::vector<proton::value> list_%d = {' % (indent_str, self.list_count))
+ instance_name_list.append(u'list_%d' % self.list_count)
+ for value_data_pair in value:
+ self._write_data_pair(value_data_pair, inner_instance_name_list)
+ self.target_file.write(u'};\n')
+ if push_flag:
+ self.target_file.write(u'%s%s.push_back(list_%d);\n\n' % (indent_str, container_name, self.list_count))
+ elif amqp_type == u'map':
+ if not isinstance(value, list):
+ raise RuntimeError(u'AMQP map value not a list, found %s' % type(value))
+ if len(value) % 2 != 0:
+ raise RuntimeError(u'AMQP map value list not even, contains %d items' % len(value))
+ inner_instance_name_list = self._pre_write_list(indent_level, container_name, value)
+ self.map_count += 1
+ self.target_file.write(u'%sstd::vector<proton::value> map_%d = {' %
+ (indent_str, self.map_count))
+ instance_name_list.append(u'map_%d' % self.map_count)
+ # consume list in pairs (key, value)
+ value_iter = iter(value)
+ for value_data_pair in value_iter:
+ self._write_data_pair(value_data_pair, inner_instance_name_list)
+ value_data_pair = next(value_iter)
+ self._write_data_pair(value_data_pair, inner_instance_name_list)
+ self.target_file.write(u'};\n')
+ if push_flag:
+ self.target_file.write(u'%s%s.push_back(map_%d);\n\n' % (indent_str, container_name, self.map_count))
+
+ def _write_proton_instance(self, indent_level, data_pair, instance_name_list):
+ """
+ Proton types do not yet support literals. Write proton values as instances, place assigned variable name
+ onto instance_name_list so they can be placed into the AMQP complex type container.
+ """
+ indent_str = u' ' * (indent_level * INDENT_LEVEL_SIZE)
+ amqp_type, value = data_pair
+ if amqp_type == u'decimal32':
+ self.d32_count += 1
+ self.target_file.write(u'%sproton::decimal32 d32_%d;\n' % (indent_str, self.d32_count))
+ self.target_file.write(u'%shexStringToBytearray(d32_%d, "%s");\n' %
+ (indent_str, self.d32_count, value[2:]))
+ instance_name_list.append(u'd32_%d' % self.d32_count)
+ elif amqp_type == u'decimal64':
+ self.d64_count += 1
+ self.target_file.write(u'%sproton::decimal64 d64_%d;\n' % (indent_str, self.d64_count))
+ self.target_file.write(u'%shexStringToBytearray(d64_%d, "%s");\n' %
+ (indent_str, self.d64_count, value[2:]))
+ instance_name_list.append(u'd64_%d' % self.d64_count)
+ elif amqp_type == u'decimal128':
+ self.d128_count += 1
+ self.target_file.write(u'%sproton::decimal128 d128_%d;\n' % (indent_str, self.d128_count))
+ self.target_file.write(u'%shexStringToBytearray(d128_%d, "%s");\n' %
+ (indent_str, self.d128_count, value[2:]))
+ instance_name_list.append(u'd128_%d' % self.d128_count)
+ elif amqp_type == u'timestamp':
+ self.ts_count += 1
+ radix = 16 if isinstance(value, str) and len(value) > 2 and value[:2] == u'0x' else 10
+ if radix == 16: # hex string
+ self.target_file.write(u'%sproton::timestamp ts_%d(std::strtoul(' % (indent_str, self.ts_count) +
+ u'std::string("%s").data(), nullptr, 16));\n' % value[2:])
+ else:
+ self.target_file.write(u'%sproton::timestamp ts_%d(%s);\n' % (indent_str, self.ts_count, value))
+ instance_name_list.append(u'ts_%d' % self.ts_count)
+ elif amqp_type == u'uuid':
+ self.uuid_count += 1
+ self.target_file.write(u'%sproton::uuid uuid_%d;\n' % (indent_str, self.uuid_count))
+ if isinstance(value, str) and len(value) > 2 and value[:2] == u'0x': # Hex string "0x..."
+ # prefix hex strings < 32 chars (16 bytes) with 0s to make exactly 32 chars long
+ fill_size = 32 - len(value[2:])
+ uuid_hex_str = u'%s%s' % (u'0' * fill_size, value[2:])
+ self.target_file.write(u'%shexStringToBytearray(uuid_%d, "%s");\n' %
+ (indent_str, self.uuid_count, uuid_hex_str))
+ else: # UUID format "00000000-0000-0000-0000-000000000000"
+ self.target_file.write(u'%ssetUuid(uuid_%d, "%s");\n' % (indent_str, self.uuid_count, value))
+ instance_name_list.append(u'uuid_%d' % self.uuid_count)
+ elif amqp_type == u'binary':
+ self.bin_count += 1
+ if isinstance(value, int) or (isinstance(value, str) and len(value) > 2 and value[:2] == u'0x'): # numeric
+ hex_str = u'{:02x}'.format(value) if isinstance(value, int) else value[2:]
+ if len(hex_str) % 2 > 0: # make string even no. of hex chars, prefix with '0' if needed
+ hex_str = u'0%s' % hex_str
+ self.target_file.write(u'%sproton::binary bin_%d(hexStringToBinaryString("%s"));\n' %
+ (indent_str, self.bin_count, hex_str))
+ else: # string
+ self.target_file.write(u'%sproton::binary bin_%d("%s");\n' % (indent_str, self.bin_count, value))
+ instance_name_list.append(u'bin_%d' % self.bin_count)
+ elif amqp_type == u'symbol':
+ self.sym_count += 1
+ self.target_file.write(u'%sproton::symbol sym_%d("%s");\n' % (indent_str, self.sym_count, value))
+ instance_name_list.append(u'sym_%d' % self.sym_count)
+
+ def _write_data_pair(self, data_pair, instance_name_list=None):
+ """
+ Write a JOSN pair ['amqp_type', value]. If amqp_type is complex or a proton type, pop instance name from
+ intance_name_list (which has been previously declared).
+ """
+ amqp_type, value = data_pair
+ if amqp_type == u'null':
+ # TODO: Temporarily suppress use of nullptr until C++ binding issues are fixed, see PROTON-1818
+ #self.target_file.write(u'nullptr, ')
+ pass
+ elif amqp_type == u'boolean':
+ self.target_file.write(u'%s, ' % str(value).lower())
+ elif amqp_type == u'ubyte':
+ self.target_file.write(u'uint8_t(%s), ' % value)
+ elif amqp_type == u'byte':
+ self.target_file.write(u'int8_t(%s), ' % value)
+ elif amqp_type == u'ushort':
+ self.target_file.write(u'uint16_t(%s), ' % value)
+ elif amqp_type == u'short':
+ self.target_file.write(u'int16_t(%s), ' % value)
+ elif amqp_type == u'uint':
+ self.target_file.write(u'uint32_t(%s), ' % value)
+ elif amqp_type == u'int':
+ self.target_file.write(u'int32_t(%s), ' % value)
+ elif amqp_type == u'ulong':
+ self.target_file.write(u'uint64_t(%s), ' % value)
+ elif amqp_type == u'long':
+ self.target_file.write(u'int64_t(%s), ' % value)
+ elif amqp_type == u'float':
+ if isinstance(value, str):
+ if value == u'inf':
+ self.target_file.write(u'std::numeric_limits<float>::infinity(), ')
+ elif value == u'-inf':
+ self.target_file.write(u'-std::numeric_limits<float>::infinity(), ')
+ elif value == u'NaN':
+ self.target_file.write(u'std::numeric_limits<float>::quiet_NaN(), ')
+ else:
+ self.target_file.write(u'float(%s), ' % value)
+ else:
+ self.target_file.write(u'float(%s), ' % str(value))
+ elif amqp_type == u'double':
+ if isinstance(value, str):
+ if value == u'inf':
+ self.target_file.write(u'std::numeric_limits<double>::infinity(), ')
+ elif value == u'-inf':
+ self.target_file.write(u'-std::numeric_limits<double>::infinity(), ')
+ elif value == u'NaN':
+ self.target_file.write(u'std::numeric_limits<double>::quiet_NaN(), ')
+ else:
+ self.target_file.write(u'double(%s), ' % value)
+ else:
+ self.target_file.write(u'double(%s), ' % str(value))
+ elif amqp_type == u'decimal32':
+ if instance_name_list is not None:
+ self.target_file.write(u'%s, ' % instance_name_list.pop(0))
+ elif amqp_type == u'decimal64':
+ if instance_name_list is not None:
+ self.target_file.write(u'%s, ' % instance_name_list.pop(0))
+ elif amqp_type == u'decimal128':
+ if instance_name_list is not None:
+ self.target_file.write(u'%s, ' % instance_name_list.pop(0))
+ elif amqp_type == u'char':
+ if len(value) == 1: # single char
+ self.target_file.write(u'wchar_t(\'%s\'), ' % value)
+ else:
+ self.target_file.write(u'wchar_t(%s), ' % value)
+ elif amqp_type == u'timestamp':
+ if instance_name_list is not None:
+ self.target_file.write(u'%s, ' % instance_name_list.pop(0))
+ elif amqp_type == u'uuid':
+ if instance_name_list is not None:
+ self.target_file.write(u'%s, ' % instance_name_list.pop(0))
+ elif amqp_type == u'binary':
+ if instance_name_list is not None:
+ self.target_file.write(u'%s, ' % instance_name_list.pop(0))
+ elif amqp_type == u'string':
+ self.target_file.write(u'std::string("')
+ for char_ in value:
+ if char_ == u'\'' or char_ == u'"':
+ self.target_file.write(u'\\')
+ self.target_file.write(char_)
+ self.target_file.write(u'"), ')
+ elif amqp_type == u'symbol':
+ if instance_name_list is not None:
+ self.target_file.write(u'%s, ' % instance_name_list.pop(0))
+ elif amqp_type == u'array':
+ if instance_name_list is not None and instance_name_list:
+ self.target_file.write(u'%s, ' % instance_name_list.pop(0))
+ elif amqp_type == u'list':
+ if instance_name_list is not None and instance_name_list:
+ self.target_file.write(u'%s, ' % instance_name_list.pop(0))
+ elif amqp_type == u'map':
+ if instance_name_list is not None and instance_name_list:
+ self.target_file.write(u'%s, ' % instance_name_list.pop(0))
+
+ @staticmethod
+ def _cpp_type(amqp_type, amqp_sub_type=None):
+ cpp_types = {
+ None: u'NULL',
+ u'null': u'std::nullptr_t',
+ u'boolean': u'bool',
+ u'byte': u'int8_t',
+ u'ubyte': u'uint8_t',
+ u'short': u'int16_t',
+ u'ushort': u'uint16_t',
+ u'int': u'int32_t',
+ u'uint': u'uint32_t',
+ u'char': u'wchar_t',
+ u'long': u'int64_t',
+ u'ulong': u'uint64_t',
+ u'timestamp': u'proton::timestamp',
+ u'float': u'float',
+ u'double': u'double',
+ u'decimal32': u'proton::decimal32',
+ u'decimal64': u'proton::decimal64',
+ u'decimal128': u'proton::decimal128',
+ u'uuid': u'proton::uuid',
+ u'binary': u'proton::binary',
+ u'string': u'std::string',
+ u'symbol': u'proton::symbol',
+ u'described': u'proton::described',
+ u'array': u'std::vector<%s> ' % amqp_sub_type,
+ u'list': u'std::vector<proton::value> ',
+ u'map': u'std::vector<proton::value> '
+ }
+ return cpp_types[amqp_type]
+
+ def write_postfix(self):
+ """Write postfix at bottom of C++ source file"""
+ self.target_file.write(CppGenerator.CODE_SEGMENT_B)
+ self.target_file.write(u'// <eof>\n')
+
+
+class JavaScriptGenerator(Generator):
+ """JavaScript code generator"""
+
+ def write_prefix(self):
+ """Write comments, copyright, etc at top of JavaScript source file"""
+ self.target_file.write(u'#!/usr/bin/env node\n\n')
+ self.target_file.write(u'/*\n * Data used for qpid_interop_test.amqp_complex_types_test\n */\n\n')
+ self.target_file.write(u'/*\n')
+ for line in iter(COPYRIGHT_TEXT.splitlines()):
+ self.target_file.write(u' * %s\n' % line)
+ self.target_file.write(u' */\n\n')
+ self.target_file.write(u'/*\n')
+ self.target_file.write(u' * THIS IS A GENERATED FILE, DO NOT EDIT DIRECTLY\n')
+ self.target_file.write(u' * Generated by building qpid_interop_test\n')
+ self.target_file.write(u' * Generated: %s\n'% time.strftime(u'%Y-%m-%d %H:%M:%S', time.gmtime()))
+ self.target_file.write(u' */\n\n')
+
+ def write_code(self, amqp_test_type, json_data):
+ """Write JavaScript code from json_data"""
+ pass
+
+ def write_postfix(self):
+ """Write postfix at bottom of JavaScript source file"""
+ self.target_file.write()
+ self.target_file.write(u'// <eof>\n')
+
+
+class DotNetGenerator(Generator):
+ """DotNet code generator"""
+
+ def write_prefix(self):
+ """Write comments, copyright, etc at top of DotNet source file"""
+ self.target_file.write(u'/*\n * Data used for qpid_interop_test.amqp_complex_types_test\n */\n\n')
+ self.target_file.write(u'/*\n')
+ for line in iter(COPYRIGHT_TEXT.splitlines()):
+ self.target_file.write(u' * %s\n' % line)
+ self.target_file.write(u' */\n\n')
+ self.target_file.write(u'/*\n')
+ self.target_file.write(u' * THIS IS A GENERATED FILE, DO NOT EDIT DIRECTLY\n')
+ self.target_file.write(u' * Generated by building qpid_interop_test\n')
+ self.target_file.write(u' * Generated: %s\n'% time.strftime(u'%Y-%m-%d %H:%M:%S', time.gmtime()))
+ self.target_file.write(u' */\n\n')
+
+ def write_code(self, amqp_test_type, json_data):
+ """Write DotNet code from json_data"""
+ pass
+
+ def write_postfix(self):
+ """Write postfix at bottom of DotNet source file"""
+ self.target_file.write(u'// <eof>\n')
+
+
+class GeneratorOptions(object):
+ """Class to handle generator options"""
+ def __init__(self):
+ self._parser = argparse.ArgumentParser(description=u'AMQP Complex Types Test: test data generator')
+ self._parser.add_argument(u'--type', choices=AMQP_COMPEX_TYPES, default=u'ALL', metavar=u'TYPE',
+ help=u'AMQP complex type to test %s' % AMQP_COMPEX_TYPES)
+ self._parser.add_argument(u'--json-base-name', action=u'store', default=DEFAULT_JSON_BASE_NAME,
+ metavar=u'BASENAME',
+ help=u'JSON data file base name [%s]' % DEFAULT_JSON_BASE_NAME)
+ self._parser.add_argument(u'--gen', choices=GENERATOR_TARGETS, default=u'ALL', metavar=u'TARGET',
+ help=u'Generate for target %s' % GENERATOR_TARGETS)
+ self._parser.add_argument(u'--gen-dir', action=u'store', default=u'.', metavar=u'DIR',
+ help=u'Directory in which to generate source files [.]')
+ self._parser.add_argument(u'--src-dir', action=u'store', default=u'.', metavar=u'DIR',
+ help=u'Directory containing JSON data files [.]')
+
+ def args(self):
+ """Return the parsed args"""
+ return self._parser.parse_args()
+
+ def print_help(self, file=None):
+ """Print help"""
+ self._parser.print_help(file)
+
+ def print_usage(self, file=None):
+ """Print usage"""
+ self._parser.print_usage(file)
+
+
+#--- Main program start ---
+
+if __name__ == '__main__':
+ ARGS = GeneratorOptions()
+ READER = JsonReader(ARGS.args())
+ READER.generate()
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org