#! /usr/bin/env python
#
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc.  All rights reserved.
# https://developers.google.com/protocol-buffers/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""Test for google.protobuf.json_format."""

__author__ = 'jieluo@google.com (Jie Luo)'

import json
import math
import sys

try:
  import unittest2 as unittest
except ImportError:
  import unittest
from google.protobuf import any_pb2
from google.protobuf import duration_pb2
from google.protobuf import field_mask_pb2
from google.protobuf import struct_pb2
from google.protobuf import timestamp_pb2
from google.protobuf import wrappers_pb2
from google.protobuf.internal import well_known_types
from google.protobuf import json_format
from google.protobuf.util import json_format_proto3_pb2


class JsonFormatBase(unittest.TestCase):

  def FillAllFields(self, message):
    message.int32_value = 20
    message.int64_value = -20
    message.uint32_value = 3120987654
    message.uint64_value = 12345678900
    message.float_value = float('-inf')
    message.double_value = 3.1415
    message.bool_value = True
    message.string_value = 'foo'
    message.bytes_value = b'bar'
    message.message_value.value = 10
    message.enum_value = json_format_proto3_pb2.BAR
    # Repeated
    message.repeated_int32_value.append(0x7FFFFFFF)
    message.repeated_int32_value.append(-2147483648)
    message.repeated_int64_value.append(9007199254740992)
    message.repeated_int64_value.append(-9007199254740992)
    message.repeated_uint32_value.append(0xFFFFFFF)
    message.repeated_uint32_value.append(0x7FFFFFF)
    message.repeated_uint64_value.append(9007199254740992)
    message.
repeated_uint64_value.append(9007199254740991)
    message.repeated_float_value.append(0)

    message.repeated_double_value.ap
pend(1E-15)
    message.repeated_double_value.append(float('inf'))
    message.repeated_bool_value.append(True)
    message.repeated_bool_value.append(False)
    message.repeated_string_value.append('Few symbols!#$,;')
    message.repeated_string_value.append('bar')
    message.repeated_bytes_value.append(b'foo')
    message.repeated_bytes_value.append(b'bar')
    message.repeated_message_value.add().value = 10
    message.repeated_message_value.add().value = 11
    message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
    message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
    self.message = message

  def CheckParseBack(self, message, parsed_message):
    json_format.Parse(json_format.MessageToJson(message),
                      parsed_message)
    self.assertEqual(message, parsed_message)

  def CheckError(self, text, error_message):
    message = json_format_proto3_pb2.TestMessage()
    self.assertRaisesRegexp(
        json_format.ParseError,
        error_message,
        json_format.Parse, text, message)


class JsonFormatTest(JsonFormatBase):

  def testEmptyMessageToJson(self):
    message = json_format_proto3_pb2.TestMessage()
    self.assertEqual(json_format.MessageToJson(message),
                     '{}')
    parsed_message = json_format_proto3_pb2.TestMessage()
    self.CheckParseBack(message, parsed_message)

  def testPartialMessageToJson(self):
    message = json_format_proto3_pb2.TestMessage(
        string_value='test',
        repeated_int32_value=[89, 4])
    self.assertEqual(json.loads(json_format.MessageToJson(message)),
                     json.loads('{"stringValue": "test", '
                                '"repeatedInt32Value": [89, 4]}'))
    parsed_message = json_format_proto3_pb2.TestMessage()
    self.CheckParseBack(message, parsed_message)

  def testAllFieldsToJson(self):
    message = json_format_proto3_pb2.TestMessage()
    text = ('{"int32Value": 20, '
            '"int64Value": "-20", '
            '"uint32Value": 3120987654,'
            '"uint64Value": "12345678900",'
            '"floatValue": "-Infinity",'
            '"doubleValue": 3.1415,'
            '"boolValue": true,'
            '"stringValue": "foo",'
            '"bytesValue": "YmFy",'
            '"messageValue": {"value": 10},'
            '"enumValue": "BAR",'
            '"repeatedInt32Value": [2147483647, -2147483648],'
            '"repeatedInt64Value": ["9007199254740992", "-9007199254740992"],'
            '"repeatedUint32Value": [268435455, 134217727],'
            '"repeatedUint64Value": ["9007199254740992", "9007199254740991"],'
            '"repeatedFloatValue": [0],'
            '"repeatedDoubleValue": [1e-15, "Infinity"],'
            '"repeatedBoolValue": [true, false],'
            '"repeatedStringValue": ["Few symbols!#$,;", "bar"],'
            '"repeatedBytesValue": ["Zm9v", "YmFy"],'
            '"repeatedMessageValue": [{"value": 10}, {"value": 11}],'
            '"repeatedEnumValue": ["FOO", "BAR"]'
            '}')
    self.FillAllFields(message)
    self.assertEqual(
        json.loads(json_format.MessageToJson(message)),
        json.loads(text))
    parsed_message = json_format_proto3_pb2.TestMessage()
    json_format.Parse(text, parsed_message)
    self.assertEqual(message, parsed_message)

  def testJsonEscapeString(self):
    message = json_format_proto3_pb2.TestMessage()
    if sys.version_info[0] < 3:
      message.string_value = '&\n<\"\r>\b\t\f\\\001/\xe2\x80\xa8\xe2\x80\xa9'
    else:
      message.string_value = '&\n<\"\r>\b\t\f\\\001/'
      message.string_value += (b'\xe2\x80\xa8\xe2\x80\xa9').decode('utf-8')
    self.assertEqual(
        json_format.MessageToJson(message),
        '{\n  "stringValue": '
        '"&\\n<\\\"\\r>\\b\\t\\f\\\\\\u0001/\\u2028\\u2029"\n}')
    parsed_message = json_format_proto3_pb2.TestMessage()
    self.CheckParseBack(message, parsed_message)
    text = u'{"int32Value": "\u0031"}'
    json_format.Parse(text, message)
    self.assertEqual(message.int32_value, 1)

  def testAlwaysSeriliaze(self):
    message = json_format_proto3_pb2.TestMessage(
        string_value='foo')
    self.assertEqual(
        json.loads(json_format.MessageToJson(message, True)),
        json.loads('{'
                   '"repeatedStringValue": [],'
                   '"stringValue": "foo",'
                   '"repeatedBoolValue": [],'
                   '"repeatedUint32Value": [],'
                   '"repeatedInt32Value": [],'
                   '"enumValue": "FOO",'
                   '"int32Value": 0,'
                   '"floatValue": 0,'
                   '"int64Value": "0",'
                   '"uint32Value": 0,'
                   '"repeatedBytesValue": [],'
                   '"repeatedUint64Value": [],'
                   '"repeatedDoubleValue": [],'
                   '"bytesValue": "",'
                   '"boolValue": false,'
                   '"repe