text: #!/usr/bin/env python
  
  ##
  # 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
  #
  # https://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.
  
  """Test the protocol parsing logic."""
  
  from __future__ import absolute_import, division, print_function
  
  import unittest
  
  from avro import protocol
  
  
  class ExampleProtocol(object):
    def __init__(self, protocol_string, valid, name='', comment=''):
      self._protocol_string = protocol_string
      self._valid = valid
      self._name = name or protocol_string # default to schema_string for name
      self._comment = comment
  
    # read-only properties
    protocol_string = property(lambda self: self._protocol_string)
    valid = property(lambda self: self._valid)
    name = property(lambda self: self._name)
  
    # read/write properties
    def set_comment(self, new_comment): self._comment = new_comment
    comment = property(lambda self: self._comment, set_comment)
  
  #
  # Example Protocols
  #
  HELLO_WORLD = ExampleProtocol("""\
  {
    "namespace": "com.acme",
    "protocol": "HelloWorld",
  
    "types": [
      {"name": "Greeting", "type": "record", "fields": [
        {"name": "message", "type": "string"}]},
      {"name": "Curse", "type": "error", "fields": [
        {"name": "message", "type": "string"}]}
    ],
  
    "messages": {
      "hello": {
        "request": [{"name": "greeting", "type": "Greeting" }],
        "response": "Greeting",
        "errors": ["Curse"]
      }
    }
  }
      """, True)
  EXAMPLES = [
    HELLO_WORLD,
    ExampleProtocol("""\
  {"namespace": "org.apache.avro.test",
   "protocol": "Simple",
  
   "types": [
       {"name": "Kind", "type": "enum", "symbols": ["FOO","BAR","BAZ"]},
  
       {"name": "MD5", "type": "fixed", "size": 16},
  
       {"name": "TestRecord", "type": "record",
        "fields": [
            {"name": "name", "type": "string", "order": "ignore"},
            {"name": "kind", "type": "Kind", "order": "descending"},
            {"name": "hash", "type": "MD5"}
        ]
       },
  
       {"name": "TestError", "type": "error", "fields": [
           {"name": "message", "type": "string"}
        ]
       }
  
   ],
  
   "messages": {
  
       "hello": {
           "request": [{"name": "greeting", "type": "string"}],
           "response": "string"
       },
  
       "echo": {
           "request": [{"name": "record", "type": "TestRecord"}],
           "response": "TestRecord"
       },
  
       "add": {
           "request": [{"name": "arg1", "type": "int"}, {"name": "arg2", "type": "int"}],
           "response": "int"
       },
  
       "echoBytes": {
           "request": [{"name": "data", "type": "bytes"}],
           "response": "bytes"
       },
  
       "error": {
           "request": [],
           "response": "null",
           "errors": ["TestError"]
       }
   }
  
  }
      """, True),
    ExampleProtocol("""\
  {"namespace": "org.apache.avro.test.namespace",
   "protocol": "TestNamespace",
  
   "types": [
       {"name": "org.apache.avro.test.util.MD5", "type": "fixed", "size": 16},
       {"name": "TestRecord", "type": "record",
        "fields": [ {"name": "hash", "type": "org.apache.avro.test.util.MD5"} ]
       },
       {"name": "TestError", "namespace": "org.apache.avro.test.errors",
        "type": "error", "fields": [ {"name": "message", "type": "string"} ]
       }
   ],
  
   "messages": {
       "echo": {
           "request": [{"name": "record", "type": "TestRecord"}],
           "response": "TestRecord"
       },
  
       "error": {
           "request": [],
           "response": "null",
           "errors": ["org.apache.avro.test.errors.TestError"]
       }
  
   }
  
  }
      """, True),
  ExampleProtocol("""\
  {"namespace": "org.apache.avro.test.namespace",
   "protocol": "TestImplicitNamespace",
  
   "types": [
       {"name": "org.apache.avro.test.util.MD5", "type": "fixed", "size": 16},
       {"name": "ReferencedRecord", "type": "record",
         "fields": [ {"name": "foo", "type": "string"} ] },
       {"name": "TestRecord", "type": "record",
        "fields": [ {"name": "hash", "type": "org.apache.avro.test.util.MD5"},
                    {"name": "unqalified", "type": "ReferencedRecord"} ]
       },
       {"name": "TestError",
        "type": "error", "fields": [ {"name": "message", "type": "string"} ]
       }
   ],
  
   "messages": {
       "echo": {
           "request": [{"name": "qualified",
               "type": "org.apache.avro.test.namespace.TestRecord"}],
           "response": "TestRecord"
       },
  
       "error": {
           "request": [],
           "response": "null",
           "errors": ["org.apache.avro.test.namespace.TestError"]
       }
  
   }
  
  }
      """, True),
  ExampleProtocol("""\
  {"namespace": "org.apache.avro.test.namespace",
   "protocol": "TestNamespaceTwo",
  
   "types": [
       {"name": "org.apache.avro.test.util.MD5", "type": "fixed", "size": 16},
       {"name": "ReferencedRecord", "type": "record",
         "namespace": "org.apache.avro.other.namespace",
         "fields": [ {"name": "foo", "type": "string"} ] },
       {"name": "TestRecord", "type": "record",
        "fields": [ {"name": "hash", "type": "org.apache.avro.test.util.MD5"},
                    {"name": "qualified",
                      "type": "org.apache.avro.other.namespace.ReferencedRecord"}
                  ]
       },
       {"name": "TestError",
        "type": "error", "fields": [ {"name": "message", "type": "string"} ]
       }
   ],
  
   "messages": {
       "echo": {
           "request": [{"name": "qualified",
               "type": "org.apache.avro.test.namespace.TestRecord"}],
           "response": "TestRecord"
       },
  
       "error": {
           "request": [],
           "response": "null",
           "errors": ["org.apache.avro.test.namespace.TestError"]
       }
  
   }
  
  }
      """, True),
  ExampleProtocol("""\
  {"namespace": "org.apache.avro.test.namespace",
   "protocol": "TestValidRepeatedName",
  
   "types": [
       {"name": "org.apache.avro.test.util.MD5", "type": "fixed", "size": 16},
       {"name": "ReferencedRecord", "type": "record",
         "namespace": "org.apache.avro.other.namespace",
         "fields": [ {"name": "foo", "type": "string"} ] },
       {"name": "ReferencedRecord", "type": "record",
         "fields": [ {"name": "bar", "type": "double"} ] },
       {"name": "TestError",
        "type": "error", "fields": [ {"name": "message", "type": "string"} ]
       }
   ],
  
   "messages": {
       "echo": {
           "request": [{"name": "qualified",
               "type": "ReferencedRecord"}],
           "response": "org.apache.avro.other.namespace.ReferencedRecord"
       },
  
       "error": {
           "request": [],
           "response": "null",
           "errors": ["org.apache.avro.test.namespace.TestError"]
       }
  
   }
  
  }
      """, True),
  ExampleProtocol("""\
  {"namespace": "org.apache.avro.test.namespace",
   "protocol": "TestInvalidRepeatedName",
  
   "types": [
       {"name": "org.apache.avro.test.util.MD5", "type": "fixed", "size": 16},
       {"name": "ReferencedRecord", "type": "record",
         "fields": [ {"name": "foo", "type": "string"} ] },
       {"name": "ReferencedRecord", "type": "record",
         "fields": [ {"name": "bar", "type": "double"} ] },
       {"name": "TestError",
        "type": "error", "fields": [ {"name": "message", "type": "string"} ]
       }
   ],
  
   "messages": {
       "echo": {
           "request": [{"name": "qualified",
               "type": "ReferencedRecord"}],
           "response": "org.apache.avro.other.namespace.ReferencedRecord"
       },
  
       "error": {
           "request": [],
           "response": "null",
           "errors": ["org.apache.avro.test.namespace.TestError"]
       }
  
   }
  
  }
      """, False),
    ExampleProtocol("""\
  {"namespace": "org.apache.avro.test",
   "protocol": "BulkData",
  
   "types": [],
  
   "messages": {
  
       "read": {
           "request": [],
           "response": "bytes"
       },
  
       "write": {
           "request": [ {"name": "data", "type": "bytes"} ],
           "response": "null"
       }
  
   }
  
  }
      """, True),
    ExampleProtocol("""\
  {
    "protocol" : "API",
    "namespace" : "xyz.api",
    "types" : [ {
      "type" : "enum",
      "name" : "Symbology",
      "namespace" : "xyz.api.product",
      "symbols" : [ "OPRA", "CUSIP", "ISIN", "SEDOL" ]
    }, {
      "type" : "record",
      "name" : "Symbol",
      "namespace" : "xyz.api.product",
      "fields" : [ {
        "name" : "symbology",
        "type" : "xyz.api.product.Symbology"
      }, {
        "name" : "symbol",
        "type" : "string"
      } ]
    }, {
      "type" : "record",
      "name" : "MultiSymbol",
      "namespace" : "xyz.api.product",
      "fields" : [ {
        "name" : "symbols",
        "type" : {
          "type" : "map",
          "values" : "xyz.api.product.Symbol"
        }
      } ]
    } ],
    "messages" : {
    }
  }
      """, True),
  ]
  
  VALID_EXAMPLES = [e for e in EXAMPLES if e.valid]
  
  class TestProtocol(unittest.TestCase):
    def test_parse(self):
      num_correct = 0
      for example in EXAMPLES:
        try:
          protocol.parse(example.protocol_string)
          if example.valid:
            num_correct += 1
          else:
            self.fail("Parsed invalid protocol: %s" % (example.name,))
        except Exception as e:
          if not example.valid:
            num_correct += 1
          else:
            self.fail("Coudl not parse valid protocol: %s" % (example.name,))
  
      fail_msg = "Parse behavior correct on %d out of %d protocols." % \
        (num_correct, len(EXAMPLES))
      self.assertEqual(num_correct, len(EXAMPLES), fail_msg)
  
    def test_inner_namespace_set(self):
      print('')
      print('TEST INNER NAMESPACE')
      print('===================')
      print('')
      proto = protocol.parse(HELLO_WORLD.protocol_string)
      self.assertEqual(proto.namespace, "com.acme")
      greeting_type = proto.types_dict['Greeting']
      self.assertEqual(greeting_type.namespace, 'com.acme')
  
    def test_inner_namespace_not_rendered(self):
      proto = protocol.parse(HELLO_WORLD.protocol_string)
      self.assertEqual('com.acme.Greeting', proto.types[0].fullname)
      self.assertEqual('Greeting', proto.types[0].name)
      # but there shouldn't be 'namespace' rendered to json on the inner type
      self.assertFalse('namespace' in proto.to_json()['types'][0])
  
    def test_valid_cast_to_string_after_parse(self):
      """
      Test that the string generated by an Avro Protocol object
      is, in fact, a valid Avro protocol.
      """
      print('')
      print('TEST CAST TO STRING')
      print('===================')
      print('')
  
      num_correct = 0
      for example in VALID_EXAMPLES:
        protocol_data = protocol.parse(example.protocol_string)
        try:
          try:
            protocol.parse(str(protocol_data))
            debug_msg = "%s: STRING CAST SUCCESS" % example.name
            num_correct += 1
          except:
            debug_msg = "%s: STRING CAST FAILURE" % example.name
        finally:
          print(debug_msg)
  
      fail_msg = "Cast to string success on %d out of %d protocols" % \
        (num_correct, len(VALID_EXAMPLES))
      self.assertEqual(num_correct, len(VALID_EXAMPLES), fail_msg)
  
    def test_equivalence_after_round_trip(self):
      """
      1. Given a string, parse it to get Avro protocol "original".
      2. Serialize "original" to a string and parse that string
           to generate Avro protocol "round trip".
      3. Ensure "original" and "round trip" protocols are equivalent.
      """
      print('')
      print('TEST ROUND TRIP')
      print('===============')
      print('')
  
      num_correct = 0
      for example in VALID_EXAMPLES:
        original_protocol = protocol.parse(example.protocol_string)
        round_trip_protocol = protocol.parse(str(original_protocol))
  
        if original_protocol == round_trip_protocol:
          num_correct += 1
          debug_msg = "%s: ROUND TRIP SUCCESS" % example.name
        else:
          self.fail("Round trip failure: %s %s %s", (example.name, example.protocol_string, str(original_protocol)))
  
      fail_msg = "Round trip success on %d out of %d protocols" % \
        (num_correct, len(VALID_EXAMPLES))
      self.assertEqual(num_correct, len(VALID_EXAMPLES), fail_msg)
  
  if __name__ == '__main__':
    unittest.main()
  