from unittest import TestCase
from nappingcat import app
from nappingcat.exceptions import NappingCatException, NappingCatUnhandled
import StringIO
import os
import random
import sys
import fudge

class TestOfApp(TestCase):
    # TODO: refactor these three methods into a common super-class
    def setUp(self):
        fudge.clear_expectations()
        self.patched_apis = []
        self.original_os_environ = os.environ
        self.original_sys_argv = sys.argv

    def tearDown(self):
        fudge.verify()
        for patched in self.patched_apis:
            patched.restore()
        os.environ = self.original_os_environ
        sys.argv = self.original_sys_argv

    def patch(self, *args, **kwargs):
        self.patched_apis.append(fudge.patch_object(*args, **kwargs))

    def test_calls_main_on_provided_instance(self):
        random_user = 'user-%d' % random.randint(100, 200)
        sys.argv = ['_ignored', random_user]
        random_ssh_command = 'execute %d' % random.randint(100, 200)
        os.environ['SSH_ORIGINAL_COMMAND'] = random_ssh_command

        fake_instance = fudge.Fake()
        fake_instance.expects('main').with_args(
            user=random_user,
            original_command=random_ssh_command
        )
        fake_instance.logger = fudge.Fake().provides('good')
        fudge.clear_calls()

        app.App.run(instance=fake_instance)

    def test_main_raises_unhandled(self):
        self.assertRaises(NappingCatUnhandled, app.App().main)

    def test_run_calls_good_on_sucess(self):
        random_test = 'rand-%d' % random.randint(1,100)

        fake_good = fudge.Fake('app.logs.ColorLogger.good', expect_call=True).with_args(random_test)
        self.patch(app.logs.ColorLogger, 'good', fake_good)
        fudge.clear_calls()

        class SubApp(app.App):
            def main(*args, **kwargs):
                return random_test

        # TODO: document what these are? [command, user]?
        sys.argv = [random.randint(1,100), random.randint(1,100)]
        SubApp.run()

    def test_run_calls_bad_on_failure(self):
        random_test = 'rand-%d' % random.randint(1,100)

        fake_bad = fudge.Fake('app.logs.ColorLogger.bad', expect_call=True).with_args(random_test)
        self.patch(app.logs.ColorLogger, 'bad', fake_bad)

        class SubApp(app.App):
            def main(*args, **kwargs):
                raise NappingCatException(random_test)

        # TODO: document what these are? [command, user]?
        sys.argv = [random.randint(1,100), random.randint(1,100)]
        SubApp.run()

    def test_run_delegates_to_app_instance_main(self):
        random_test = 'rand-%d' % random.randint(1,100)

        # TODO: document what these are? [command, user]?
        # TODO: move duplication into helper method with intent revealing name
        sys.argv = [random.randint(1,100), random.randint(1,100)]

        fake_main = fudge.Fake('app.App.main', expect_call=True)
        self.patch(app.App, 'main', fake_main)

        # make sure this stays quiet
        fake_good = fudge.Fake('app.logs.ColorLogger.good', expect_call=True)
        self.patch(app.logs.ColorLogger, 'good', fake_good)

        fudge.clear_calls()

        app.App.run()

    def test_run_passed_original_command_and_user_from_argv(self):
        random_ssh_cmd = "rand-%d" % random.randint(1,100)
        random_user = 'user-%d' % random.randint(1,100)

        # TODO: this should be something that can be passed into the app
        #       rather than requiring a patch of the os.environ global
        os.environ['SSH_ORIGINAL_COMMAND'] = random_ssh_cmd
        sys.argv = ['anything', random_user]

        fake_main = fudge.Fake(
            'app.App.main',
            expect_call=True
        ).with_args(
            user=random_user,
            original_command=random_ssh_cmd
        )
        self.patch(app.App, 'main', fake_main)
        fudge.clear_calls()

        original_logger = app.App.logger
        app.App.logger = fudge.Fake().provides('good')
        app.App.run()

        app.App.logger = original_logger

@@ -1589,36 +1589,40 @@
 )%0A%0A        fake_
-good
+instance
  = fudge.Fake('a
@@ -1623,271 +1623,209 @@
 ake(
-'app.logs.ColorLogger.good', expect_call=True).with_args(random_test)%0A        self.patch(app.logs.ColorLogger, 'good', fake_good)%0A        fudge.clear_calls()%0A%0A        class SubApp(app.App):%0A            def main(*args, **kwargs):%0A                return random_test
+)%0A        fake_instance.provides('main').returns(random_test)%0A        fake_instance.logger = fudge.Fake()%0A        fake_instance.logger.expects('good').with_args(random_test)%0A        fudge.clear_calls()
 %0A%0A  
@@ -1942,32 +1942,33 @@
 int(1,100)%5D%0A
+%0A
         
 SubApp.run()
@@ -1951,35 +1951,36 @@
 )%5D%0A%0A        
-Sub
+app.
 App.run(
 )%0A%0A    def t
@@ -1959,32 +1959,54 @@
     app.App.run(
+instance=fake_instance
 )%0A%0A    def test_
@@ -2107,19 +2107,24 @@
    fake_
-bad
+instance
  = fudge
@@ -2133,63 +2133,75 @@
 ake(
-'app.logs.ColorLogger.bad', expect_call=True).with_args
+)%0A        fake_instance.provides('main').raises(NappingCatException
 (ran
@@ -2201,32 +2201,33 @@
 ion(random_test)
+)
 %0A        self.pa
@@ -2223,182 +2223,137 @@
     
-self.patch(app.logs.ColorLogger, 'bad', fake_bad)%0A%0A        class SubApp(app.App):%0A            def main(*args, **kwargs):%0A                raise NappingCatException(random_test
+fake_instance.logger = fudge.Fake()%0A        fake_instance.logger.expects('bad').with_args(random_test)%0A        fudge.clear_calls(
 )%0A%0A 
@@ -2475,24 +2475,25 @@
 1,100)%5D%0A
+%0A
         
 SubApp.r
@@ -2488,19 +2488,20 @@
     
-Sub
+app.
 App.run(
 )%0A%0A 
@@ -2488,32 +2488,54 @@
     app.App.run(
+instance=fake_instance
 )%0A%0A    def test_

refactor out the final SubApps