from django.test import TestCase

from extras.api.routers import ScriptRouter
from extras.api.views import CustomFieldChoiceSetViewSet, ScriptViewSet, WebhookViewSet


class ScriptRouterTestCase(TestCase):
    """
    Verify the routes generated by ScriptRouter.
    """
    @staticmethod
    def get_actions(viewset):
        """
        Return a mapping of route name to the HTTP methods bound on it for the given ViewSet.
        """
        router = ScriptRouter()
        router.register('dummy', viewset, basename='dummy')

        return {
            url.name: url.callback.actions
            for url in router.urls if hasattr(url.callback, 'actions')
        }

    def test_script_routes(self):
        actions = self.get_actions(ScriptViewSet)

        # POST on the detail route runs the script; the list route accepts only GET
        self.assertEqual(actions['dummy-detail'], {'get': 'retrieve', 'post': 'run'})
        self.assertEqual(actions['dummy-list'], {'get': 'list'})

    def test_script_viewset_subclass(self):
        # A subclass of ScriptViewSet (e.g. as registered by a plugin) gets the same route mapping
        class MyScriptViewSet(ScriptViewSet):
            pass

        actions = self.get_actions(MyScriptViewSet)

        self.assertEqual(actions['dummy-detail'], {'get': 'retrieve', 'post': 'run'})
        self.assertEqual(actions['dummy-list'], {'get': 'list'})

    def test_other_viewsets_unaffected(self):
        # Standard ViewSets keep the stock detail route mapping
        self.assertNotIn('post', self.get_actions(WebhookViewSet)['dummy-detail'])

        # Routes generated for @action methods are untouched
        self.assertEqual(self.get_actions(CustomFieldChoiceSetViewSet)['dummy-choices'], {'get': 'choices'})

    def test_route_templates_not_mutated(self):
        router = ScriptRouter()
        router.get_routes(ScriptViewSet)

        self.assertNotIn('post', router.routes[2].mapping)
