from django.test.simple import DjangoTestSuiteRunner
from django.conf import settings
from django.core.urlresolvers import resolve, get_resolver

IGNORED_COVERAGE_URLS = getattr(settings, 'IGNORED_COVERAGE_URLS', [])

def get_configured_url_names(urllist=None):
    """Recurses through django url resolvers to get a full
    list of all url names"""
    if urllist is None:
        urllist = get_resolver(None).url_patterns
    unique_names = set()
    for entry in urllist:
        name = getattr(entry, 'name', None)
        if entry.regex.pattern in IGNORED_COVERAGE_URLS:
            continue
        if name is not None:
            unique_names.add(name)
        if hasattr(entry, 'url_patterns'):
            unique_names.update(get_configured_url_names(entry.url_patterns))
    return unique_names

unique_url_names = set()
class UrlMiddlewareLogger(object):
    def process_request(self, request):
        unique_url_names.add(resolve(request.path).url_name)

class CustomTestRunner(DjangoTestSuiteRunner):
    def __init__(self, *args, **kwargs):
        super(CustomTestRunner, self).__init__(*args, **kwargs)

    def run_tests(self, test_labels, **kwargs):
        # setup custom middleware class that records urls accessed
        orig_middleware = getattr(settings, 'MIDDLEWARE_CLASSES', [])
        middleware = tuple(list(orig_middleware) +
                           [__name__ + '.UrlMiddlewareLogger'])
        setattr(settings, 'MIDDLEWARE_CLASSES', middleware)
        
        test_results = super(CustomTestRunner, self).run_tests(test_labels, **kwargs)
        
        # reset middleware back to what it was
        setattr(settings, 'MIDDLEWARE_CLASSES', orig_middleware)
        
        configured_names = get_configured_url_names()
        missed_names = sorted(configured_names.difference(unique_url_names))
        hit_names = configured_names.intersection(unique_url_names)
        print '-----------------------------------------------------'
        print 'Status: %d of %d URLs hit in test suite' % (len(hit_names), len(configured_names))
        print '-----------------------------------------------------'
        if len(missed_names) > 0:
            print 'URL Names in URL Configuration not hit in test suite:'
            print '-----------------------------------------------------'
            for missed_name in missed_names:
                print '  ' + missed_name
        print
        
        return test_results