.. currentmodule:: kcrw.nprapi

Tests for :class:`StoryAPI`
---------------------------

This is a comprehensive set of unit tests for the kcrw.nprapi StoryAPI
class. Let's create an instance of the StoryAPI class and see how it
works::

    >>> from kcrw.nprapi import StoryAPI
    >>> api = StoryAPI('MY_KEY')

In order to make this a properly isolated unit test, we need to
isolate our code from the NPR API itself. Fortunately, we have a mock
url opener we can use for this purpose::

    >>> from kcrw.nprapi.mocks import MockNPROpener
    >>> api.opener = opener = MockNPROpener()

Now we can make requests without worrying about connecting to the NPR
service. Let's look at the URL that was generated by the query method,
by looking at our custom opener::


    >>> result = api.query(1)
    >>> opener.last_url
    'http://api.npr.org/query?apiKey=MY_KEY&id=1'

Note that the url was constructed to include the id and the api_key.
Let's take a look at what happens when we pass strings or lists as our
id::

    >>> result = api.query('1')
    >>> opener.last_url
    'http://api.npr.org/query?apiKey=MY_KEY&id=1'
    >>> result = api.query([1,2,'3'])
    >>> opener.last_url
    'http://api.npr.org/query?apiKey=MY_KEY&id=1%2C2%2C3'

Note that the multiple ids were concatanated into a comma separated
list and url quoted.  There is a special optional argument called 'fields',
which can take a list input:

    >>> result = api.query(1, fields=['a','b','c'])
    >>> opener.last_url
    'http://api.npr.org/query?fields=a%2Cb%2Cc&apiKey=MY_KEY&id=1'

Only certain input fields are allowed, any other input will be
ignored, as will any entries with a value of None:

    >>> result = api.query(1, nonsense=1, startDate=None, startNum=10)
    >>> opener.last_url
    'http://api.npr.org/query?apiKey=MY_KEY&startNum=10&id=1'

Changing the output_format changes the url to request a different
response output:

    >>> api.output_format = 'JSON'
    >>> result = api.query(1)
    >>> opener.last_url
    'http://api.npr.org/query?output=JSON&apiKey=MY_KEY&id=1'

The same is true when we create a new api instance and pass in the
output_format:

    >>> api = StoryAPI('MY_KEY', 'JSON')
    >>> api.opener = opener
    >>> result = api.query(2)
    >>> opener.last_url
    'http://api.npr.org/query?output=JSON&apiKey=MY_KEY&id=2'

Creating an instance with an unknown format results in an error:

    >>> api = StoryAPI('MY_KEY', 'nonsense')
    Traceback (most recent call last):
    ...
    AssertionError: Invalid output format

If we make a request that results in an error response, we get an
exception thrown that includes data from the XML error message:

    >>> api.query('error')
    Traceback (most recent call last):
    ...
    NPRError: XXX - Some Error!!

Additionally, if the response includes a warning message the message
will be logged:

    >>> result = api.query('warning')

Of course the default logging is silent, so let's add a more visible
logger:

    >>> import logging
    >>> import sys
    >>> npr_log = logging.getLogger('kcrw.nprapi')
    >>> npr_log.addHandler(logging.StreamHandler(sys.stdout))
    >>> result = api.query('warning')
    NPR API log: MY WARNING: 1000 - You have been warned
