#!/usr/bin/env python
#
# Copyright 2014 Google Inc. All Rights Reserved.
#
# Licensed 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.

"""Mock tests

Unit tests for the Mocks.
"""
from __future__ import absolute_import

__author__ = "jcgregorio@google.com (Joe Gregorio)"

import os
import unittest

import httplib2

from googleapiclient.discovery import build
from googleapiclient.errors import HttpError, UnexpectedBodyError, UnexpectedMethodError
from googleapiclient.http import HttpMock, RequestMockBuilder

DATA_DIR = os.path.join(os.path.dirname(__file__), "data")


def datafile(filename):
    return os.path.join(DATA_DIR, filename)


class Mocks(unittest.TestCase):
    def setUp(self):
        self.http = HttpMock(datafile("plus.json"), {"status": "200"})
        self.zoo_http = HttpMock(datafile("zoo.json"), {"status": "200"})

    def test_default_response(self):
        requestBuilder = RequestMockBuilder({})
        plus = build(
            "plus",
            "v1",
            http=self.http,
            requestBuilder=requestBuilder,
            static_discovery=False,
        )
        activity = plus.activities().get(activityId="tag:blah").execute()
        self.assertEqual({}, activity)

    def test_simple_response(self):
        requestBuilder = RequestMockBuilder(
            {"plus.activities.get": (None, '{"foo": "bar"}')}
        )
        plus = build(
            "plus",
            "v1",
            http=self.http,
            requestBuilder=requestBuilder,
            static_discovery=False,
        )

        activity = plus.activities().get(activityId="tag:blah").execute()
        self.assertEqual({"foo": "bar"}, activity)

    def test_unexpected_call(self):
        requestBuilder = RequestMockBuilder({}, check_unexpected=True)

        plus = build(
            "plus",
            "v1",
            http=self.http,
            requestBuilder=requestBuilder,
            static_discovery=False,
        )

        try:
            plus.activities().get(activityId="tag:blah").execute()
            self.fail("UnexpectedMethodError should have been raised")
        except UnexpectedMethodError:
            pass

    def test_simple_unexpected_body(self):
        requestBuilder = RequestMockBuilder(
            {"zoo.animals.insert": (None, '{"data": {"foo": "bar"}}', None)}
        )
        zoo = build(
            "zoo",
            "v1",
            http=self.zoo_http,
            requestBuilder=requestBuilder,
            static_discovery=False,
        )

        try:
            zoo.animals().insert(body="{}").execute()
            self.fail("UnexpectedBodyError should have been raised")
        except UnexpectedBodyError:
            pass

    def test_simple_expected_body(self):
        requestBuilder = RequestMockBuilder(
            {"zoo.animals.insert": (None, '{"data": {"foo": "bar"}}', "{}")}
        )
        zoo = build(
            "zoo",
            "v1",
            http=self.zoo_http,
            requestBuilder=requestBuilder,
            static_discovery=False,
        )

        try:
            zoo.animals().insert(body="").execute()
            self.fail("UnexpectedBodyError should have been raised")
        except UnexpectedBodyError:
            pass

    def test_simple_wrong_body(self):
        requestBuilder = RequestMockBuilder(
            {
                "zoo.animals.insert": (
                    None,
                    '{"data": {"foo": "bar"}}',
                    '{"data": {"foo": "bar"}}',
                )
            }
        )
        zoo = build(
            "zoo",
            "v1",
            http=self.zoo_http,
            requestBuilder=requestBuilder,
            static_discovery=False,
        )

        try:
            zoo.animals().insert(body='{"data": {"foo": "blah"}}').execute()
            self.fail("UnexpectedBodyError should have been raised")
        except UnexpectedBodyError:
            pass

    def test_simple_matching_str_body(self):
        requestBuilder = RequestMockBuilder(
            {
                "zoo.animals.insert": (
                    None,
                    '{"data": {"foo": "bar"}}',
                    '{"data": {"foo": "bar"}}',
                )
            }
        )
        zoo = build(
            "zoo",
            "v1",
            http=self.zoo_http,
            requestBuilder=requestBuilder,
            static_discovery=False,
        )

        activity = zoo.animals().insert(body={"data": {"foo": "bar"}}).execute()
        self.assertEqual({"foo": "bar"}, activity)

    def test_simple_matching_dict_body(self):
        requestBuilder = RequestMockBuilder(
            {
                "zoo.animals.insert": (
                    None,
                    '{"data": {"foo": "bar"}}',
                    {"data": {"foo": "bar"}},
                )
            }
        )
        zoo = build(
            "zoo",
            "v1",
            http=self.zoo_http,
            requestBuilder=requestBuilder,
            static_discovery=False,
        )

        activity = zoo.animals().insert(body={"data": {"foo": "bar"}}).execute()
        self.assertEqual({"foo": "bar"}, activity)

    def test_errors(self):
        errorResponse = httplib2.Response({"status": 500, "reason": "Server Error"})
        requestBuilder = RequestMockBuilder(
            {"plus.activities.list": (errorResponse, b"{}")}
        )
        plus = build(
            "plus",
            "v1",
            http=self.http,
            requestBuilder=requestBuilder,
            static_discovery=False,
        )

        try:
            activity = (
                plus.activities().list(collection="public", userId="me").execute()
            )
            self.fail("An exception should have been thrown")
        except HttpError as e:
            self.assertEqual(b"{}", e.content)
            self.assertEqual(500, e.resp.status)
            self.assertEqual("Server Error", e.resp.reason)


if __name__ == "__main__":
    unittest.main()
