#!/usr/bin/env python

import argparse
import os
import sys

# I want this:
#   ERROR: test_update_and_fetch (mitx.cms.djangoapps.contentstore.tests.test_course_settings.CourseDetailsViewTest)
# to become:
#   test --settings=cms.envs.test --pythonpath=. -s cms/djangoapps/contentstore/tests/test_course_settings.py:CourseDetailsViewTest.test_update_and_fetch

def find_full_path(path_to_file):
    """Find the full path where we only have a relative path from somewhere in the tree."""
    for subdir, dirs, files in os.walk("."):
        full = os.path.relpath(os.path.join(subdir, path_to_file))
        if os.path.exists(full):
            return full

def main(argv):
    parser = argparse.ArgumentParser(description="Run just one test")
    parser.add_argument('--nocapture', '-s', action='store_true', help="Don't capture stdout (any stdout output will be printed immediately)")
    parser.add_argument('--pdb', action='store_true', help="Use pdb for test errors")
    parser.add_argument('--pdb-fail', action='store_true', help="Use pdb for test failures")
    parser.add_argument('words', metavar="WORDS", nargs='+', help="The description of a test failure, like 'ERROR: test_set_missing_field (courseware.tests.test_model_data.TestStudentModuleStorage)'")

    args = parser.parse_args(argv)
    words = []
    # Collect all the words, ignoring what was quoted together, and get rid of parens.
    for argword in args.words:
        words.extend(w.strip("()") for w in argword.split())
    # If it starts with "ERROR:" or "FAIL:", just ignore that.
    if words[0].endswith(':'):
        del words[0]

    test_method = words[0]
    test_path = words[1].split('.')
    if test_path[0] == 'mitx':
        del test_path[0]
    test_class = test_path[-1]
    del test_path[-1]

    test_py_path = "%s.py" % ("/".join(test_path))
    test_py_path = find_full_path(test_py_path)
    test_spec = "%s:%s.%s" % (test_py_path, test_class, test_method)

    system = None
    if test_py_path.startswith('cms'):
        system = 'cms'
    elif test_py_path.startswith('lms'):
        system = 'lms'

    if system:
        # Run as a django test suite
        from django.core import management

        os.environ['DJANGO_SETTINGS_MODULE'] = system + '.envs.test'
        django_args = ["./manage.py", "test"]
        if args.nocapture:
            django_args.append("-s")
        if args.pdb:
            django_args.append("--pdb")
        if args.pdb_fail:
            django_args.append("--pdb-fail")
        django_args.append(test_spec)

        print " ".join(django_args)
        management.execute_from_command_line(django_args)
    else:
        # Run as a nose test suite
        import nose.core
        nose_args = ["nosetests"]
        if args.nocapture:
            nose_args.append("-s")
        nose_args.append(test_spec)
        print " ".join(nose_args)
        nose.core.main(argv=nose_args)


if __name__ == "__main__":
    main(sys.argv[1:])

@@ -1605,16 +1605,152 @@
 rds%5B0%5D%0A%0A
+    if len(words) == 1:%0A        test_path, test_method = words%5B0%5D.rsplit('.', 1)%0A        test_path = test_path.split('.')%0A    else:%0A    
     test
@@ -1764,24 +1764,28 @@
  = words%5B0%5D%0A
+    
     test_pat

Make runone work with more test output.