#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Tests for the Pyzotero module

This file is part of Pyzotero.

The MIT License (MIT)

Copyright (c) 2015 Stephan Hügel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""

import os
import unittest
import time

import httpretty
from dateutil import parser
from httpretty import HTTPretty

try:
    from pyzotero.pyzotero import zotero as z
except ModuleNotFoundError:
    from pyzotero import zotero as z

# Python 3 compatibility faffing
try:
    from urllib import urlencode
    from urllib import quote
    from urlparse import urlparse
    from urlparse import parse_qs
except ImportError:
    from urllib.parse import urlencode
    from urllib.parse import urlparse
    from urllib.parse import parse_qs
    from urllib.parse import quote


class ZoteroTests(unittest.TestCase):
    """ Tests for pyzotero
    """

    cwd = os.path.dirname(os.path.realpath(__file__))

    def get_doc(self, doc_name, cwd=cwd):
        """ return the requested test document """
        with open(os.path.join(cwd, "api_responses", "%s" % doc_name), "r") as f:
            return f.read()

    def setUp(self):
        """ Set stuff up
        """
        self.item_doc = self.get_doc("item_doc.json")
        self.items_doc = self.get_doc("items_doc.json")
        self.item_versions = self.get_doc("item_versions.json")
        self.collection_versions = self.get_doc("collection_versions.json")
        self.collections_doc = self.get_doc("collections_doc.json")
        self.collection_doc = self.get_doc("collection_doc.json")
        self.collection_tags = self.get_doc("collection_tags.json")
        self.citation_doc = self.get_doc("citation_doc.xml")
        # self.biblio_doc = self.get_doc('bib_doc.xml')
        self.attachments_doc = self.get_doc("attachments_doc.json")
        self.tags_doc = self.get_doc("tags_doc.json")
        self.groups_doc = self.get_doc("groups_doc.json")
        self.item_templt = self.get_doc("item_template.json")
        self.item_types = self.get_doc("item_types.json")
        self.item_fields = self.get_doc("item_fields.json")
        self.keys_response = self.get_doc("keys_doc.txt")
        self.creation_doc = self.get_doc("creation_doc.json")
        self.item_file = self.get_doc("item_file.pdf")

        # Add the item file to the mock response by default
        HTTPretty.enable()
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/items",
            content_type="application/json",
            body=self.items_doc,
        )

    @httpretty.activate
    def testFailWithoutCredentials(self):
        """ Instance creation should fail, because we're leaving out a
            credential
        """
        with self.assertRaises(z.ze.MissingCredentials):
            z.Zotero("myuserID")

    @httpretty.activate
    def testRequestBuilder(self):
        """ Should url-encode all added parameters
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        zot.add_parameters(limit=0, start=7)
        self.assertEqual(
            parse_qs("start=7&limit=100&format=json"), parse_qs(zot.url_params)
        )

    @httpretty.activate
    def testRequestBuilderLimitNone(self):
        """ Should skip limit = 100 param if limit is set to None
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        zot.add_parameters(limit=None, start=7)
        self.assertEqual(parse_qs("start=7&format=json"), parse_qs(zot.url_params))

    @httpretty.activate
    def testRequestBuilderLimitNegativeOne(self):
        """ Should skip limit = 100 param if limit is set to -1
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        zot.add_parameters(limit=-1, start=7)
        self.assertEqual(parse_qs("start=7&format=json"), parse_qs(zot.url_params))

    # @httpretty.activate
    # def testBuildQuery(self):
    #     """ Check that spaces etc. are being correctly URL-encoded and added
    #         to the URL parameters
    #     """
    #     orig = 'https://api.zotero.org/users/myuserID/tags/hi%20there/items?start=10&format=json'
    #     zot = z.Zotero('myuserID', 'user', 'myuserkey')
    #     zot.add_parameters(start=10)
    #     query_string = '/users/{u}/tags/hi there/items'
    #     query = zot._build_query(query_string)
    #     self.assertEqual(
    #         sorted(parse_qs(orig).items()),
    #         sorted(parse_qs(query).items()))

    @httpretty.activate
    def testParseItemJSONDoc(self):
        """ Should successfully return a list of item dicts, key should match
            input doc's zapi:key value, and author should have been correctly
            parsed out of the XHTML payload
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/items",
            content_type="application/json",
            body=self.item_doc,
        )
        items_data = zot.items()
        self.assertEqual(u"X42A7DEE", items_data["data"]["key"])
        self.assertEqual(
            u"Institute of Physics (Great Britain)",
            items_data["data"]["creators"][0]["name"],
        )
        self.assertEqual(u"book", items_data["data"]["itemType"])
        test_dt = parser.parse("2011-01-13T03:37:29Z")
        incoming_dt = parser.parse(items_data["data"]["dateModified"])
        self.assertEqual(test_dt, incoming_dt)

    @httpretty.activate
    def testBackoff(self):
        """ Test that backoffs are correctly processed
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/items",
            content_type="application/json",
            body=self.item_doc,
            adding_headers={"backoff": 0.2},
        )
        zot.items()
        self.assertTrue(zot.backoff)
        time.sleep(0.3)
        # Timer will have expired, triggering backoff reset
        self.assertFalse(zot.backoff)

    @httpretty.activate
    def testGetItemFile(self):
        """
        Should successfully return a binary string with a PDF content
        """
        zot = z.Zotero("myuserid", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserid/items/MYITEMID/file",
            content_type="application/pdf",
            body=self.item_file,
        )
        items_data = zot.file("myitemid")
        self.assertEqual(b"One very strange PDF\n", items_data)

    @httpretty.activate
    def testParseAttachmentsJSONDoc(self):
        """ Ensure that attachments are being correctly parsed """
        zot = z.Zotero("myuserid", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserid/items",
            content_type="application/json",
            body=self.attachments_doc,
        )
        attachments_data = zot.items()
        self.assertEqual(u"1641 Depositions", attachments_data["data"]["title"])

    @httpretty.activate
    def testParseKeysResponse(self):
        """ Check that parsing plain keys returned by format = keys works """
        zot = z.Zotero("myuserid", "user", "myuserkey")
        zot.url_params = "format=keys"
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserid/items?format=keys",
            content_type="text/plain",
            body=self.keys_response,
        )
        response = zot.items()
        self.assertEqual("JIFWQ4AN", response[:8].decode("utf-8"))

    @httpretty.activate
    def testParseItemVersionsResponse(self):
        """ Check that parsing version dict returned by format = versions works """
        zot = z.Zotero("myuserid", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserid/items?format=versions",
            content_type="application/json",
            body=self.item_versions,
        )
        iversions = zot.item_versions()
        self.assertEqual(iversions["RRK27C5F"], 4000)
        self.assertEqual(iversions["EAWCSKSF"], 4087)
        self.assertEqual(len(iversions), 2)

    @httpretty.activate
    def testParseCollectionVersionsResponse(self):
        """ Check that parsing version dict returned by format = versions works """
        zot = z.Zotero("myuserid", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserid/collections?format=versions",
            content_type="application/json",
            body=self.collection_versions,
        )
        iversions = zot.collection_versions()
        self.assertEqual(iversions["RRK27C5F"], 4000)
        self.assertEqual(iversions["EAWCSKSF"], 4087)
        self.assertEqual(len(iversions), 2)

    @httpretty.activate
    def testParseChildItems(self):
        """ Try and parse child items """
        zot = z.Zotero("myuserid", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserid/items/ABC123/children",
            content_type="application/json",
            body=self.items_doc,
        )
        items_data = zot.children("ABC123")
        self.assertEqual(u"NM66T6EF", items_data[0]["key"])

    @httpretty.activate
    def testCitUTF8(self):
        """ Ensure that unicode citations are correctly processed by Pyzotero
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        url = "https://api.zotero.org/users/myuserID/items/GW8V2CK7"
        HTTPretty.register_uri(
            HTTPretty.GET,
            url,
            content_type="application/atom+xml",
            body=self.citation_doc,
        )
        cit = zot.item("GW8V2CK7", content="citation", style="chicago-author-date")
        self.assertEqual(cit[0], u"<span>(Ans\\xe6lm and Tka\\u010dik 2014)</span>")

    # @httpretty.activate
    # def testParseItemAtomBibDoc(self):
    #     """ Should match a DIV with class = csl-entry
    #     """
    #     zot = z.Zotero('myuserID', 'user', 'myuserkey')
    #     zot.url_params = 'content=bib'
    #     HTTPretty.register_uri(
    #         HTTPretty.GET,
    #         'https://api.zotero.org/users/myuserID/items?content=bib&format=atom',
    #         content_type='application/atom+xml',
    #         body=self.biblio_doc)
    #     items_data = zot.items()
    #     self.assertEqual(
    #         items_data[0],
    #         u'<div class="csl-entry">Robert A. Caro. \u201cThe Power Broker\u202f: Robert Moses and the Fall of New York,\u201d 1974.</div>'
    #         )

    @httpretty.activate
    def testParseCollectionJSONDoc(self):
        """ Should successfully return a single collection dict,
            'name' key value should match input doc's name value
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/collections/KIMI8BSG",
            content_type="application/json",
            body=self.collection_doc,
        )
        collections_data = zot.collection("KIMI8BSG")
        self.assertEqual("LoC", collections_data["data"]["name"])

    @httpretty.activate
    def testParseCollectionTagsJSONDoc(self):
        """ Should successfully return a list of tags,
            which should match input doc's number of tag items and 'tag' values
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/collections/KIMI8BSG/tags",
            content_type="application/json",
            body=self.collection_tags,
        )
        collections_data = zot.collection_tags("KIMI8BSG")
        self.assertEqual(3, len(collections_data))
        for item in collections_data:
            self.assertTrue(item in ["apple", "banana", "cherry"])

    @httpretty.activate
    def testParseCollectionsJSONDoc(self):
        """ Should successfully return a list of collection dicts, key should
            match input doc's zapi:key value, and 'title' value should match
            input doc's title value
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/collections",
            content_type="application/json",
            body=self.collections_doc,
        )
        collections_data = zot.collections()
        self.assertEqual("LoC", collections_data[0]["data"]["name"])

    @httpretty.activate
    def testParseTagsJSON(self):
        """ Should successfully return a list of tags
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/tags?limit=1",
            content_type="application/json",
            body=self.tags_doc,
        )
        tags_data = zot.tags()
        self.assertEqual(u"Community / Economic Development", tags_data[0])

    @httpretty.activate
    def testParseGroupsJSONDoc(self):
        """ Should successfully return a list of group dicts, ID should match
            input doc's zapi:key value, and 'total_items' value should match
            input doc's zapi:numItems value
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/groups",
            content_type="application/json",
            body=self.groups_doc,
        )
        groups_data = zot.groups()
        self.assertEqual("smart_cities", groups_data[0]["data"]["name"])

    def testParamsReset(self):
        """ Should successfully reset URL parameters after a query string
            is built
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        zot.add_parameters(start=5, limit=10)
        zot._build_query("/whatever")
        zot.add_parameters(start=2)
        self.assertEqual(
            parse_qs("start=2&format=json&limit=100"), parse_qs(zot.url_params)
        )

    @httpretty.activate
    def testParamsBlankAfterCall(self):
        """ self.url_params should be blank after an API call
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/items",
            content_type="application/json",
            body=self.items_doc,
        )
        zot.items()
        self.assertEqual(None, zot.url_params)

    @httpretty.activate
    def testResponseForbidden(self):
        """ Ensure that an error is properly raised for 403
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/items",
            content_type="application/json",
            body=self.items_doc,
            status=403,
        )
        with self.assertRaises(z.ze.UserNotAuthorised):
            zot.items()

    @httpretty.activate
    def testResponseUnsupported(self):
        """ Ensure that an error is properly raised for 400
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/items",
            content_type="application/json",
            body=self.items_doc,
            status=400,
        )
        with self.assertRaises(z.ze.UnsupportedParams):
            zot.items()

    @httpretty.activate
    def testResponseNotFound(self):
        """ Ensure that an error is properly raised for 404
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/items",
            body=self.items_doc,
            content_type="application/json",
            status=404,
        )
        with self.assertRaises(z.ze.ResourceNotFound):
            zot.items()

    @httpretty.activate
    def testResponseMiscError(self):
        """ Ensure that an error is properly raised for unspecified errors
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/items",
            content_type="application/json",
            body=self.items_doc,
            status=500,
        )
        with self.assertRaises(z.ze.HTTPError):
            zot.items()

    @httpretty.activate
    def testGetItems(self):
        """ Ensure that we can retrieve a list of all items """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/itemTypes",
            content_type="application/json",
            body=self.item_types,
        )
        resp = zot.item_types()
        self.assertEqual(resp[0]["itemType"], "artwork")

    @httpretty.activate
    def testGetTemplate(self):
        """ Ensure that item templates are retrieved and converted into dicts
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/items/new?itemType=book",
            content_type="application/json",
            body=self.item_templt,
        )
        t = zot.item_template("book")
        self.assertEqual("book", t["itemType"])

    def testCreateCollectionError(self):
        """ Ensure that collection creation fails with the wrong dict
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        t = [{"foo": "bar"}]
        with self.assertRaises(z.ze.ParamNotPassed):
            t = zot.create_collections(t)

    @httpretty.activate
    def testNoApiKey(self):
        """ Ensure that pyzotero works when api_key is not set
        """
        zot = z.Zotero("myuserID", "user")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/items",
            content_type="application/json",
            body=self.item_doc,
        )
        items = zot.items()
        self.assertEqual(len(items), 6)  # this isn't a very good assertion

    # @httpretty.activate
    # def testUpdateItem(self):
    #     """ Test that we can update an item
    #         This test is a kludge; it only tests that the mechanism for
    #         internal key removal is OK, and that we haven't made any silly
    #         list/dict comprehension or genexpr errors
    #     """
    #     import json
    #     # first, retrieve an item
    #     zot = z.Zotero('myuserID', 'user', 'myuserkey')
    #     HTTPretty.register_uri(
    #         HTTPretty.GET,
    #         'https://api.zotero.org/users/myuserID/items',
    #         body=self.items_doc)
    #     items_data = zot.items()
    #     items_data['title'] = 'flibble'
    #     json.dumps(*zot._cleanup(items_data))

    @httpretty.activate
    def testCollectionCreation(self):
        """ Tests creation of a new collection
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.POST,
            "https://api.zotero.org/users/myuserID/collections",
            body=self.creation_doc,
            content_type="application/json",
            status=200,
        )
        # now let's test something
        resp = zot.create_collections([{"name": "foo", "key": "ABC123"}])
        self.assertTrue("ABC123", resp["success"]["0"])
        request = httpretty.last_request()
        self.assertFalse("If-Unmodified-Since-Version" in request.headers)

    @httpretty.activate
    def testCollectionCreationLastModified(self):
        """ Tests creation of a new collection with last_modified param
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.POST,
            "https://api.zotero.org/users/myuserID/collections",
            body=self.creation_doc,
            content_type="application/json",
            status=200,
        )
        # now let's test something
        resp = zot.create_collections(
            [{"name": "foo", "key": "ABC123"}], last_modified=5
        )
        self.assertEqual("ABC123", resp["success"]["0"])
        request = httpretty.last_request()
        self.assertEqual(request.headers["If-Unmodified-Since-Version"], "5")

    @httpretty.activate
    def testCollectionUpdate(self):
        """ Tests update of a collection
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.PUT,
            "https://api.zotero.org/users/myuserID/collections/ABC123",
            body="",
            content_type="application/json",
            status=200,
        )
        # now let's test something
        resp = zot.update_collection({"name": "foo", "key": "ABC123", "version": 3})
        self.assertEqual(True, resp)
        request = httpretty.last_request()
        self.assertEqual(request.headers["If-Unmodified-Since-Version"], "3")

    @httpretty.activate
    def testCollectionUpdateLastModified(self):
        """ Tests update of a collection with last_modified set
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.PUT,
            "https://api.zotero.org/users/myuserID/collections/ABC123",
            body="",
            content_type="application/json",
            status=200,
        )
        # now let's test something
        resp = zot.update_collection(
            {"name": "foo", "key": "ABC123", "version": 3}, last_modified=5
        )
        self.assertEqual(True, resp)
        request = httpretty.last_request()
        self.assertEqual(request.headers["If-Unmodified-Since-Version"], "5")

    @httpretty.activate
    def testItemCreation(self):
        """ Tests creation of a new item using a template
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/items/new?itemType=book",
            body=self.item_templt,
            content_type="application/json",
        )
        template = zot.item_template("book")
        httpretty.reset()
        HTTPretty.register_uri(
            HTTPretty.POST,
            "https://api.zotero.org/users/myuserID/items",
            body=self.creation_doc,
            content_type="application/json",
            status=200,
        )
        # now let's test something
        resp = zot.create_items([template])
        self.assertEqual("ABC123", resp["success"]["0"])
        request = httpretty.last_request()
        self.assertFalse("If-Unmodified-Since-Version" in request.headers)

    @httpretty.activate
    def testItemCreationLastModified(self):
        """ Checks 'If-Unmodified-Since-Version' header correctly set on create_items
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.POST,
            "https://api.zotero.org/users/myuserID/items",
            body=self.creation_doc,
            content_type="application/json",
            status=200,
        )
        # now let's test something
        zot.create_items([{"key": "ABC123"}], last_modified=5)
        request = httpretty.last_request()
        self.assertEqual(request.headers["If-Unmodified-Since-Version"], "5")

    @httpretty.activate
    def testItemUpdate(self):
        """ Tests item update using update_item
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        update = {"key": "ABC123", "version": 3, "itemType": "book"}
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/itemFields",
            body=self.item_fields,
            content_type="application/json",
        )
        HTTPretty.register_uri(
            HTTPretty.PATCH,
            "https://api.zotero.org/users/myuserID/items/ABC123",
            body="",
            content_type="application/json",
            status=204,
        )
        # now let's test something
        resp = zot.update_item(update)
        self.assertEqual(resp, True)
        request = httpretty.last_request()
        self.assertEqual(request.headers["If-Unmodified-Since-Version"], "3")

    @httpretty.activate
    def testItemUpdateLastModified(self):
        """ Tests item update using update_item with last_modified parameter
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        update = {"key": "ABC123", "version": 3, "itemType": "book"}
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/itemFields",
            body=self.item_fields,
            content_type="application/json",
        )
        HTTPretty.register_uri(
            HTTPretty.PATCH,
            "https://api.zotero.org/users/myuserID/items/ABC123",
            body="",
            content_type="application/json",
            status=204,
        )
        # now let's test something
        resp = zot.update_item(update, last_modified=5)
        self.assertEqual(resp, True)
        request = httpretty.last_request()
        self.assertEqual(request.headers["If-Unmodified-Since-Version"], "5")

    def testTooManyItems(self):
        """ Should fail because we're passing too many items
        """
        itms = [i for i in range(51)]
        zot = z.Zotero("myuserID", "user", "myuserkey")
        with self.assertRaises(z.ze.TooManyItems):
            zot.create_items(itms)

    @httpretty.activate
    def testRateLimitWithBackoff(self):
        """ Test 429 response handling when a backoff header is received
        """
        zot = z.Zotero("myuserID", "user", "myuserkey")
        HTTPretty.register_uri(
            HTTPretty.GET,
            "https://api.zotero.org/users/myuserID/items",
            status=429,
            adding_headers={"backoff": 10},
        )
        zot.items()
        self.assertTrue(zot.backoff)

    def tearDown(self):
        """ Tear stuff down
        """
        HTTPretty.disable()


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