text: #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  
  from __future__ import unicode_literals
  
  import copy
  import ecstasy
  import os
  import pytest
  import requests
  
  from collections import namedtuple
  
  import tests.paths
  import lnk.bitly.stats
  import lnk.bitly.info
  import lnk.config
  
  VERSION = 3
  API = 'https://api-ssl.bitly.com/v{0}'.format(VERSION)
  with open(os.path.join(tests.paths.TEST_PATH, 'bitly', 'token')) as source:
  	ACCESS_TOKEN = source.read()
  
  def request_stats(url, endpoint, timespan):
  	response = requests.get('{0}/link/{1}'.format(API, endpoint),
  							params=dict(units=timespan.span,
  										unit=timespan.unit,
  										access_token=ACCESS_TOKEN,
  										link=url))
  
  	e = endpoint if endpoint != 'clicks' else 'link_clicks'
  	data = response.json()['data'][e]
  
  	return {'timespan': timespan, 'data': data}
  
  @pytest.fixture(scope='module')
  def fixture(request):
  	Fixture = namedtuple('Fixture', [
  		'stats',
  		'info',
  		'endpoint',
  		'url',
  		'timespan_tuples',
  		'timespans',
  		'forever',
  		'first_level',
  		'second_level',
  		'forever_data',
  		'timespans_data',
  		'default_timespan'
  		])
  
  	endpoint = 'countries'
  	url = 'http://bit.ly/1V0HZR7'
  	timespan_tuples = [(4, 'month'), (3, 'week')]
  	timespans = [lnk.bitly.stats.Stats.Timespan(s, u) for s, u in timespan_tuples]
  	first_level = ecstasy.beautify(' <+> {0}', ecstasy.Color.Red)
  	second_level = ecstasy.beautify('   <-> {0}: {1}', ecstasy.Color.Yellow)
  	forever = lnk.bitly.stats.Stats.Timespan(-1, 'day')
  	forever_data = request_stats(url, endpoint, forever)
  	timespans_data = [request_stats(url, endpoint, i) for i in timespans]
  
  	default_timespan = lnk.bitly.stats.Stats.Timespan(1, 'month')
  	with lnk.config.Manager('bitly', write=True) as manager:
  		settings = manager['commands']['stats']['settings']
  		old = (settings['span'], settings['unit'])
  		settings['span'] = default_timespan.span
  		settings['unit'] = default_timespan.unit
  
  	stats = lnk.bitly.stats.Stats(raw=True)
  	info = lnk.bitly.info.Info(raw=True)
  
  	def finalize():
  		with lnk.config.Manager('bitly', write=True) as manager:
  			settings = manager['commands']['stats']['settings']
  			settings['span'] = old[0]
  			settings['unit'] = old[1]
  
  	request.addfinalizer(finalize)
  
  	return Fixture(stats,
  				   info,
  				   endpoint,
  				   url,
  				   timespan_tuples,
  				   timespans,
  				   forever,
  				   first_level,
  				   second_level,
  				   forever_data,
  				   timespans_data,
  				   default_timespan)
  
  
  def test_format_makes_lines_pretty(fixture):
  	result = fixture.stats.format(None, 'foo', 'bar', None)
  	expected = fixture.second_level.format('foo', 'bar')
  
  	assert result == expected
  
  
  def test_countries_leaves_countries_short(fixture):
  	result = fixture.stats.format('countries', 'DE', 123, False)
  	expected = fixture.second_level.format('DE', '123')
  
  	assert result == expected
  
  
  def test_format_expands_countries(fixture):
  	result = fixture.stats.format('countries', 'DE', 123, True)
  	expected = fixture.second_level.format('Germany', '123')
  
  	assert result == expected
  
  def test_format_handles_unknown_countries(fixture):
  	result = fixture.stats.format('countries', 'None', 123, True)
  	expected = fixture.second_level.format('Other', '123')
  
  	assert result == expected
  
  
  def test_format_title_cases_direct(fixture):
  	result = fixture.stats.format(None, 'direct', 666, None)
  	expected = fixture.second_level.format('Direct', '666')
  
  	assert result == expected
  
  def test_request_format_is_correct(fixture):
  	fixture.stats.queue.put((
  		fixture.url,
  		'countries',
  		fixture.forever,
  		{
  		'unit': fixture.forever.unit,
  		'units': fixture.forever.span,
  		'link': fixture.url
  		}))
  	results = {fixture.endpoint: []}
  	fixture.stats.request(results)
  	result = results[fixture.endpoint][0]
  
  	assert isinstance(result, dict)
  	assert 'timespan' in result
  	assert isinstance(result['timespan'], fixture.stats.Timespan)
  	assert 'data' in result
  	assert isinstance(result['data'], list)
  
  
  def test_requests_countries_well(fixture):
  	fixture.stats.queue.put((
  		fixture.url,
  		'countries',
  		fixture.forever,
  		{
  		'unit': fixture.forever.unit,
  		'units': fixture.forever.span,
  		'link': fixture.url
  		}))
  	result = {fixture.endpoint: []}
  	fixture.stats.request(result)
  	result = result[fixture.endpoint][0]
  
  	assert result == fixture.forever_data
  
  def test_requests_referrers_well(fixture):
  	fixture.stats.queue.put((
  		fixture.url,
  		'referrers',
  		fixture.forever,
  		{
  		'unit': fixture.forever.unit,
  		'units': fixture.forever.span,
  		'link': fixture.url
  		}))
  	result = {'referrers': []}
  	fixture.stats.request(result)
  	result = result['referrers'][0]
  	expected = request_stats(fixture.url, 'referrers', fixture.forever)
  
  	assert result == expected
  
  def test_requests_clicks_well(fixture):
  	fixture.stats.queue.put((
  		fixture.url,
  		'clicks',
  		fixture.forever,
  		{
  		'unit': fixture.forever.unit,
  		'units': fixture.forever.span,
  		'link': fixture.url
  		}))
  	result = {'clicks': []}
  	fixture.stats.request(result)
  	result = result['clicks'][0]
  	expected = request_stats(fixture.url, 'clicks', fixture.forever)
  
  	assert result == expected
  
  def test_requests_timespan_well(fixture):
  	fixture.stats.queue.put((
  		fixture.url,
  		fixture.endpoint,
  		fixture.timespans[0],
  		{
  		'unit': fixture.timespans[0].unit,
  		'units': fixture.timespans[0].span,
  		'link': fixture.url
  		}))
  	results = {fixture.endpoint: []}
  	fixture.stats.request(results)
  
  	assert results[fixture.endpoint][0] == fixture.timespans_data[0]
  
  
  def test_listify_sets_None_if_no_items(fixture):
  	data = copy.deepcopy(fixture.forever_data)
  	data['data'] = []
  	result = fixture.stats.listify(None, [data], False)
  	header = fixture.first_level.format('Since forever')
  	expected = ['{0}: None'.format(header)]
  
  	assert result == expected
  
  
  def test_listify_handles_clicks_well(fixture):
  	data = copy.deepcopy(fixture.forever_data)
  	data['data'] = 123
  	result = fixture.stats.listify(None, [data], False)
  	header = fixture.first_level.format('Since forever')
  	expected = ['{0}: 123'.format(header)]
  
  	assert result == expected
  
  
  def test_listify_handles_lists_well(fixture):
  	data = copy.deepcopy(fixture.forever_data)
  	result = fixture.stats.listify(None, [data], False)
  	header = fixture.first_level.format('Since forever')
  	expected = ['{0}:'.format(header)]
  	if fixture.forever_data['data']:
  		for i in fixture.forever_data['data']:
  			# A way of not having to pop the clicks
  			clicks = i['clicks']
  			keys = list(i.keys())
  			keys.remove('clicks')
  			assert len(keys) == 1
  			key = i[keys[0]]
  			line = fixture.second_level.format(key, clicks)
  			expected.append(line)
  	else:
  		expected[-1] += ' None'
  
  	assert result == expected
  
  
  def test_get_header_formats_timespans_well(fixture):
  	result = fixture.stats.get_header(4, 'weeks')
  	expected = fixture.first_level.format('Last 4 weeks:')
  
  	assert result == expected
  
  
  def test_get_header_handles_forever_well(fixture):
  	result = fixture.stats.get_header(-1, None)
  	expected = fixture.first_level.format('Since forever:')
  
  	assert result == expected
  
  
  def test_get_header_removes_unit_if_1(fixture):
  	result = fixture.stats.get_header(1, 'day')
  	expected = fixture.first_level.format('Last day:')
  
  	assert result == expected
  
  
  def test_get_header_handles_years_well(fixture):
  	result = fixture.stats.get_header(12, 'months')
  	expected = fixture.first_level.format('Last year:')
  
  	assert result == expected
  
  
  def test_get_header_adds_plural_s_if_multiple_years(fixture):
  	result = fixture.stats.get_header(24, 'months')
  	expected = fixture.first_level.format('Last 2 years:')
  
  	assert result == expected
  
  
  def test_lineify_formats_headers_well(fixture):
  
  	data = {fixture.endpoint: [copy.deepcopy(fixture.forever_data)]}
  	result = fixture.stats.lineify(data, False)
  
  	assert 'Countries:' in result
  
  
  def test_get_timespans_removes_duplicates(fixture):
  	timespans = list(fixture.timespan_tuples)
  	timespans += [fixture.timespan_tuples[0]] * 10
  	result = fixture.stats.get_timespans(timespans, False)
  
  	assert result == set(fixture.timespans)
  
  
  def test_get_timespans_picks_default_timespan_if_no_times(fixture):
  	result = fixture.stats.get_timespans([], False)
  
  	assert result == set([fixture.default_timespan])
  
  
  def test_get_timespans_handles_forever_well(fixture):
  	result = fixture.stats.get_timespans([], True)
  
  	assert result == set([fixture.forever])
  
  
  def test_get_timespans_handles_year_well(fixture):
  	result = fixture.stats.get_timespans(((1, 'year'),), False)
  	expected = set([fixture.stats.Timespan(12, 'months')])
  
  	assert result == expected
  
  
  def test_get_timespans_works(fixture):
  	result = fixture.stats.get_timespans(fixture.timespan_tuples, False)
  
  	assert result == set(fixture.timespans)
  
  
  def test_get_stats_works_for_single_endpoint(fixture):
  	result = fixture.stats.get_stats(fixture.url,
  									   [fixture.forever],
  									   [fixture.endpoint])
  	expected = {fixture.endpoint: [fixture.forever_data]}
  
  	assert result == expected
  
  def test_get_stats_works_for_many_timespans(fixture):
  	result = fixture.stats.get_stats(fixture.url,
  									   fixture.timespans,
  									   [fixture.endpoint])
  
  	assert isinstance(result, dict)
  	assert fixture.endpoint in result
  	assert isinstance(result[fixture.endpoint], list)
  
  	assert all(i in fixture.timespans_data for i in result[fixture.endpoint])
  
  
  def test_get_stats_handles_plural_s_in_timespan_well(fixture):
  	timespans = copy.deepcopy(fixture.timespans)
  	timespans[0] = fixture.stats.Timespan(timespans[0].span,
  										  timespans[0].unit + 's')
  	result = fixture.stats.get_stats(fixture.url,
  								  	   timespans,
  								       [fixture.endpoint])
  	expected = copy.deepcopy(fixture.timespans_data)
  	expected[0]['timespan'] = timespans[0]
  
  	assert isinstance(result, dict)
  	assert fixture.endpoint in result
  
  	result = result[fixture.endpoint]
  
  	assert isinstance(result, list)
  
  	for i, j in zip(expected, result):
  		i['data'].sort()
  		j['data'].sort()
  
  	assert all(i in expected for i in result)
  
  
  def test_get_stats_works_for_many_endpoints(fixture):
  	endpoints = ['clicks', 'referrers', 'countries']
  	result = fixture.stats.get_stats(fixture.url,
  									   [fixture.forever],
  									   endpoints)
  
  	expected = {fixture.endpoint: [fixture.forever_data]}
  	endpoints.remove(fixture.endpoint)
  	for endpoint in endpoints:
  		data = request_stats(fixture.url, endpoint, fixture.forever)
  		expected[endpoint] = [data]
  
  	assert result == expected
  
  
  def test_fetch_works_for_single_url(fixture):
  	result = fixture.stats.fetch([fixture.endpoint],
  								 [],
  								 fixture.timespan_tuples,
  								 False,
  								 None,
  								 False,
  								 False,
  								 [fixture.url])
  	expected = ['URL: {0}'.format(fixture.url)]
  	data = copy.deepcopy(fixture.timespans_data)
  	data = {fixture.endpoint: data}
  	expected += fixture.stats.lineify(data, False)
  
  	assert len(result) == 1
  	assert sorted(result[0]) == sorted(expected)
  
  
  def test_fetch_limits_well(fixture):
  	result = fixture.stats.fetch([fixture.endpoint],
  								 [],
  								 [],
  								 True,
  								 1,
  								 False,
  								 False,
  								 [fixture.url])
  	expected = ['URL: {0}'.format(fixture.url)]
  	data = copy.deepcopy(fixture.forever_data)
  	while len(data['data']) > 1:
  		data['data'].pop()
  	assert len(data['data']) == 1
  	data = {fixture.endpoint: [data]}
  	expected += fixture.stats.lineify(data, False)
  
  	assert len(result) <= 1
  	assert sorted(result[0]) == sorted(expected)
  
  def test_fetch_works_for_many_urls(fixture):
  	urls = [fixture.url, 'http://bit.ly/1Km6CB1']
  	result = fixture.stats.fetch([fixture.endpoint],
  								 [],
  								 [],
  								 True,
  								 None,
  								 False,
  								 False,
  								 urls)
  	first = ['URL: {0}'.format(fixture.url)]
  	data = {fixture.endpoint: [copy.deepcopy(fixture.forever_data)]}
  	first += fixture.stats.lineify(data, False)
  
  	second = ['URL: {0}'.format(urls[1])]
  	data = request_stats(urls[1], fixture.endpoint, fixture.forever)
  	data = {fixture.endpoint: [data]}
  	second += fixture.stats.lineify(data, False)
  
  	expected = [sorted(first), sorted(second)]
  
  	assert [sorted(i) for i in result] == expected
  
  
  def test_fetch_adds_info_well(fixture):
  	result = fixture.stats.fetch([fixture.endpoint],
  								 [],
  								 fixture.timespan_tuples,
  								 False,
  								 None,
  								 True,
  								 False,
  								 [fixture.url])
  	expected = fixture.info.fetch([], [], False, [fixture.url])[0]
  	data = {fixture.endpoint: fixture.timespans_data}
  	expected += fixture.stats.lineify(data, False)
  
  	assert len(result) == 1
  	assert sorted(result[0]) == sorted(expected)
  