import json
import optparse
import re
import sys
import time
import unittest.runner
import urllib2

from gaeunit_cli_support.helpers import DummyTest, DummyStdout

def main():
    parser = optparse.OptionParser(usage='%prog -u URL [options]',
                                   version='%prog 0.1.0')
    parser.add_option('-u', '--url', help='URL to access GAEUnit', dest='url')

    (options, args) = parser.parse_args(sys.argv)

    # TODO: allow for setting URL in an .rc file
    # TODO: validate URL
    url = options.url or 'http://localhost:8080/test'

    # Get a list of test call names from the server
    tests = get_tests(options.url)

    # Go!
    run_tests(options.url, tests)


def get_tests(url):
    """Get a list of test names given the GAEUnit access point"""

    u = urllib2.urlopen('%s/list' % url)
    dict = json.loads(u.read())

    # GAEUnit outputs a data structure like this:
    #
    # {
    #   "module": {
    #     "SomeTestClass": [
    #       "test_abc",
    #       "test_xyz"
    #     ]
    #   }
    # }
    #
    # We simply need a list of <module>.<class>.<method> strings.

    tests = []

    for module, classes in dict.iteritems():
      for klass, methods in classes.iteritems():
        for method in methods:
          tests.append("%s.%s.%s" % (module, klass, method))

    return tests


def run_tests(url, tests, stream=None):
    """Run a list of tests"""

    if not stream:
        stream = DummyStdout()

    # Use a standard unittest output mechanism
    result = unittest.runner.TextTestResult(stream=stream,
                                            descriptions=True,
                                            verbosity=1)

    # Pass this dummy object (standing in for unittest.TestCase) to the test
    # result object.
    dummy = DummyTest()

    # Start timing
    start_time = time.time()

    # TODO: mod GAEUnit to run multiple tests w/ single request
    # see unittest.loadTestsFromNames
    for test in tests:
        # Trigger the test run and receive results
        u = urllib2.urlopen('%s/run?name=%s' % (url, test))
        data = json.loads(u.read())

        # TODO: reproduce error properly
        if len(data['failures']) > 0:
            # Update the dummy test's description to describe the current test
            failure = data['failures'][0]

            dummy.testName = test
            dummy.shortDescription_ = failure['desc']

            # Fake exception description. Grab from the penultimate line of the
            # traceback string, minus the exception label at start.
            desc = failure['detail'].split("\n")[-2]
            desc = re.compile(r"^\w+: (.*)$").match(desc).group(1) or desc

            # Fake an exception tuple
            # TODO: spoof a traceback based on string contained in failure
            #   response
            exc = (AssertionError, desc, None)

            result.addFailure(dummy, exc)
        else:
            result.addSuccess(dummy)

    result.printErrors()

    totalTime = time.time() - start_time
    stream.writeln("Ran %d test%s in %.3fs\n" %
                   (len(tests), len(tests) != 1 and "s" or "", totalTime))

    expectedFails = unexpectedSuccesses = skipped = 0
    try:
        results = map(len, (result.expectedFailures,
                          result.unexpectedSuccesses,
                          result.skipped))
    except AttributeError:
        pass
    else:
        expectedFails, unexpectedSuccesses, skipped = results

    infos = []
    if not result.wasSuccessful():
        stream.write("FAILED")
        failed, errored = map(len, (result.failures, result.errors))
        if failed:
            infos.append("failures=%d" % failed)
        if errored:
            infos.append("errors=%d" % errored)
    else:
        stream.write("OK")
    if skipped:
        infos.append("skipped=%d" % skipped)
    if expectedFails:
        infos.append("expected failures=%d" % expectedFails)
    if unexpectedSuccesses:
        infos.append("unexpected successes=%d" % unexpectedSuccesses)

    if infos:
        stream.writeln(" (%s)" % (", ".join(infos),))
    else:
        stream.writeln()


if __name__ == '__main__':
    main()
@@ -296,83 +296,512 @@
 1.0'
-)%0A    parser.add_option('-u', '--url', help='URL to access GAEUnit'
+,%0A                                   add_help_option=False)%0A%0A    parser.add_option('--help', action='store_true', default=False, dest='help')%0A%0A    parser.add_option('-h', '--host',%0A                      help='The host (port included) which is running the GAE'%0A                           'instance',%0A                      default='http://localhost:8080', dest='host')%0A%0A    parser.add_option('-p', '--path', help=%22Relative path of GAEUnit endpoint%22,%0A                      default=get_default_path()
 , dest='
 url'
@@ -796,19 +796,20 @@
 , dest='
-url
+path
 ')%0A%0A    
@@ -863,131 +863,110 @@
     
-# TODO: allow for setting URL in an .rc file%0A    # TODO: validate URL%0A    url = options.url or 'http://localhost:8080/test'
+if options.help:%0A        print parser.format_help().strip()%0A        exit()%0A%0A    url = get_url(options)
 %0A%0A  
@@ -1037,24 +1037,16 @@
 t_tests(
-options.
 url)%0A%0A  
@@ -1067,24 +1067,16 @@
 n_tests(
-options.
 url, tes
@@ -1078,16 +1078,663 @@
 , tests)
+%0A%0A%0Adef get_default_path():%0A    %22%22%22Determine the default GAEUnit path option.%22%22%22%0A%0A    # Try to read from app.yaml; if we can't find it, return the GAEUnit%0A    # default '/test'%0A    try:%0A        gae_config_file = open('app.yaml', 'r')%0A    except IOError as e:%0A        return '/test'%0A%0A%0Adef get_url(options):%0A    %22%22%22Determine the GAEUnit URL given optparse's output.%22%22%22%0A%0A    # TODO: validate URL%0A    if options.host.startswith('http'):%0A        host = options.host%0A    else:%0A        host = 'http://%25s' %25 options.host%0A%0A    if options.path.startswith('/'):%0A        path = options.path%0A    else:%0A        path = '/%25s' %25 options.path%0A%0A    return host + path
 %0A%0A%0Adef g

Change -u option to -h + -p