<commit_before># -*- coding: utf-8 -*-
from datetime import date, timedelta
from mock import patch
import reversion
from urlparse import urlparse

from django import forms
from django.contrib.auth.models import User, AnonymousUser
from django.core.urlresolvers import reverse
from django.db import models
from django.test import TestCase, Client, RequestFactory

from TWLight.resources.models import Partner, Stream
from TWLight.resources.factories import PartnerFactory
from TWLight.users.factories import EditorFactory, UserFactory
from TWLight.users.groups import get_coordinators
from TWLight.users.models import Editor

from . import views
from .helpers import USER_FORM_FIELDS, PARTNER_FORM_OPTIONAL_FIELDS, FIELD_TYPES
from .factories import ApplicationFactory
from .forms import BaseApplicationForm
from .models import Application


class SynchronizeFieldsTest(TestCase):
    """
    There are four distinct places we record facts about what types of extra
    information Partners might request in Applications:
    * resources.models.Partner (checks which information this Partner requires)
    * applications.models.Application (records the actual information supplied
      by the user, specific to an application for a given partner resource)
    * users.models.Editor (records the actual information supplied by the user,
      specific to that user but not to any one partner application)
    * applications.helpers (the list of information partners might require,
      plus a mapping from each type of information to the type of form field
      suitable for containing it)

    Ideally we would have a single source of truth (in applications.helpers),
    but we have to actually define the database schemata for Partner and
    Application in a fixed way. Alas!

    In lieu of a single source of truth, we have a test case here which checks
    the following:

    * does every optional partner and optional user data field correspond to an
      attribute of Partner? (That is, does Partner actually let us record
      whether a given partner wishes us to harvest that optional datum or not.)
    * are all the optional partner fields reflected in Application? (That is,
      can we actually record them?)
    * are all the optional user data fields reflected in User? (Again, can we
      record them?)
    * for each data field, do we have a form field type (allowing us to
      generate forms for harvesting the data)?
    * does that form field type match the corresponding field on Editor or
      Application?

    The purpose of this test is to save us from ourselves. To wit:

    If future Partners require types of information not reflected in our
    current code, we need to add that information to several places. This test
    ensures that all of those places are kept in sync - that is, that we update
    all the things we need to update, if we update any of them.

    Note: the Django _meta API changes in 1.8 and this code will need
    to be updated accordingly if TWLight is upgraded to 1.8.
    """

    def test_user_form_fields_reflected_in_partner(self):
        """
        The Partner model should let each instance indicate whether it requires
        the optional user data.
        """
        for field in USER_FORM_FIELDS:
            self.assertTrue(field in Partner._meta.get_all_field_names())


    def test_optional_partner_form_fields_reflected_in_partner(self):
        """
        The Partner model should let each instance indicate whether it requires
        the optional partner data.
        """
        for field in PARTNER_FORM_OPTIONAL_FIELDS:
            self.assertTrue(field in Partner._meta.get_all_field_names())


    def test_partner_optional_fields_are_boolean(self):
        """
        The optional user and partner data fields on Partner should be
        booleans, allowing each instance to indicate whether (True/False) it
        requires that data.
        """
        optional_fields = USER_FORM_FIELDS + PARTNER_FORM_OPTIONAL_FIELDS
        for field in optional_fields:
            self.assertTrue(
                isinstance(Partner._meta.get_field(field),
                    models.BooleanField))


    def test_optional_partner_form_fields_reflected_in_application(self):
        """
        The Application model should let each instance record the optional
        partner data, as needed.
        """
        for field in PARTNER_FORM_OPTIONAL_FIELDS:
            self.assertTrue(field in Application._meta.get_all_field_names())


    def test_application_optional_fields_match_field_type(self):
        """
        The optional partner-specific data fields on Application should
        correspond to the FIELD_TYPES used on the form. Additionally, each
        should allow blank=True (since not all instances require all data),
        except for BooleanFields, which should default False (i.e. they should
        default to not requiring the data).
        """
        for field in PARTNER_FORM_OPTIONAL_FIELDS:
            # Ensure Application fields allow for empty data.
            if not isinstance(Application._meta.get_field(field),
                    models.BooleanField):
                self.assertTrue(Application._meta.get_field(field).blank)
            else:
                self.assertFalse(Application._meta.get_field(field).default)

            # Make sure the form fields we're using match what the model fields
            # can record.
            modelfield = Application._meta.get_field(field)
            formfield = modelfield.formfield()

            self.assertEqual(type(formfield), type(FIELD_TYPES[field]))


    def test_user_form_fields_reflected_in_editor(self):
        """
        The Editor model should let each instance record the user data, as
        needed.
        """
        for field in USER_FORM_FIELDS:
            self.assertTrue(field in Editor._meta.get_all_field_names())


    def test_editor_optional_fields_match_field_type(self):
        """
        The optional user data fields on Editor should correspond to the
        FIELD_TYPES used on the application form. Additionally, each should
        allow blank=True (since not all instances require all data), except for
        BooleanFields, which should default False (i.e. they should default to
        not requiring the data).
        """
        for field in USER_FORM_FIELDS:
            # Ensure Editor fields allow for empty data.
            if not isinstance(Editor._meta.get_field(field),
                    models.BooleanField):
                self.assertTrue(Editor._meta.get_field(field).blank)
            else:
                self.assertFalse(Editor._meta.get_field(field).default)

            # Make sure the form fields we're using match what the model fields
            # can record.
            modelfield = Editor._meta.get_field(field)
            formfield = modelfield.formfield()

            self.assertEqual(type(formfield), type(FIELD_TYPES[field]))
<commit_msg>Test coverage for new feature<commit_after># -*- coding: utf-8 -*-
from datetime import date, timedelta
from mock import patch
import reversion
from urlparse import urlparse

from django import forms
from django.contrib.auth.models import User, AnonymousUser
from django.core.urlresolvers import reverse
from django.db import models
from django.test import TestCase, Client, RequestFactory

from TWLight.resources.models import Partner, Stream
from TWLight.resources.factories import PartnerFactory
from TWLight.users.factories import EditorFactory, UserFactory
from TWLight.users.groups import get_coordinators
from TWLight.users.models import Editor

from . import views
from .helpers import (USER_FORM_FIELDS,
                      PARTNER_FORM_OPTIONAL_FIELDS,
                      FIELD_TYPES,
                      get_output_for_application)
from .factories import ApplicationFactory
from .forms import BaseApplicationForm
from .models import Application


class SynchronizeFieldsTest(TestCase):
    """
    There are four distinct places we record facts about what types of extra
    information Partners might request in Applications:
    * resources.models.Partner (checks which information this Partner requires)
    * applications.models.Application (records the actual information supplied
      by the user, specific to an application for a given partner resource)
    * users.models.Editor (records the actual information supplied by the user,
      specific to that user but not to any one partner application)
    * applications.helpers (the list of information partners might require,
      plus a mapping from each type of information to the type of form field
      suitable for containing it)

    Ideally we would have a single source of truth (in applications.helpers),
    but we have to actually define the database schemata for Partner and
    Application in a fixed way. Alas!

    In lieu of a single source of truth, we have a test case here which checks
    the following:

    * does every optional partner and optional user data field correspond to an
      attribute of Partner? (That is, does Partner actually let us record
      whether a given partner wishes us to harvest that optional datum or not.)
    * are all the optional partner fields reflected in Application? (That is,
      can we actually record them?)
    * are all the optional user data fields reflected in User? (Again, can we
      record them?)
    * for each data field, do we have a form field type (allowing us to
      generate forms for harvesting the data)?
    * does that form field type match the corresponding field on Editor or
      Application?

    The purpose of this test is to save us from ourselves. To wit:

    If future Partners require types of information not reflected in our
    current code, we need to add that information to several places. This test
    ensures that all of those places are kept in sync - that is, that we update
    all the things we need to update, if we update any of them.

    Note: the Django _meta API changes in 1.8 and this code will need
    to be updated accordingly if TWLight is upgraded to 1.8.
    """

    def test_user_form_fields_reflected_in_partner(self):
        """
        The Partner model should let each instance indicate whether it requires
        the optional user data.
        """
        for field in USER_FORM_FIELDS:
            self.assertTrue(field in Partner._meta.get_all_field_names())


    def test_optional_partner_form_fields_reflected_in_partner(self):
        """
        The Partner model should let each instance indicate whether it requires
        the optional partner data.
        """
        for field in PARTNER_FORM_OPTIONAL_FIELDS:
            self.assertTrue(field in Partner._meta.get_all_field_names())


    def test_partner_optional_fields_are_boolean(self):
        """
        The optional user and partner data fields on Partner should be
        booleans, allowing each instance to indicate whether (True/False) it
        requires that data.
        """
        optional_fields = USER_FORM_FIELDS + PARTNER_FORM_OPTIONAL_FIELDS
        for field in optional_fields:
            self.assertTrue(
                isinstance(Partner._meta.get_field(field),
                    models.BooleanField))


    def test_optional_partner_form_fields_reflected_in_application(self):
        """
        The Application model should let each instance record the optional
        partner data, as needed.
        """
        for field in PARTNER_FORM_OPTIONAL_FIELDS:
            self.assertTrue(field in Application._meta.get_all_field_names())


    def test_application_optional_fields_match_field_type(self):
        """
        The optional partner-specific data fields on Application should
        correspond to the FIELD_TYPES used on the form. Additionally, each
        should allow blank=True (since not all instances require all data),
        except for BooleanFields, which should default False (i.e. they should
        default to not requiring the data).
        """
        for field in PARTNER_FORM_OPTIONAL_FIELDS:
            # Ensure Application fields allow for empty data.
            if not isinstance(Application._meta.get_field(field),
                    models.BooleanField):
                self.assertTrue(Application._meta.get_field(field).blank)
            else:
                self.assertFalse(Application._meta.get_field(field).default)

            # Make sure the form fields we're using match what the model fields
            # can record.
            modelfield = Application._meta.get_field(field)
            formfield = modelfield.formfield()

            self.assertEqual(type(formfield), type(FIELD_TYPES[field]))


    def test_user_form_fields_reflected_in_editor(self):
        """
        The Editor model should let each instance record the user data, as
        needed.
        """
        for field in USER_FORM_FIELDS:
            self.assertTrue(field in Editor._meta.get_all_field_names())


    def test_editor_optional_fields_match_field_type(self):
        """
        The optional user data fields on Editor should correspond to the
        FIELD_TYPES used on the application form. Additionally, each should
        allow blank=True (since not all instances require all data), except for
        BooleanFields, which should default False (i.e. they should default to
        not requiring the data).
        """
        for field in USER_FORM_FIELDS:
            # Ensure Editor fields allow for empty data.
            if not isinstance(Editor._meta.get_field(field),
                    models.BooleanField):
                self.assertTrue(Editor._meta.get_field(field).blank)
            else:
                self.assertFalse(Editor._meta.get_field(field).default)

            # Make sure the form fields we're using match what the model fields
            # can record.
            modelfield = Editor._meta.get_field(field)
            formfield = modelfield.formfield()

            self.assertEqual(type(formfield), type(FIELD_TYPES[field]))


    def test_application_output_1(self):
        """
        We also rely on our field names to generate data to send to partners,
        and need to ensure that get_output_for_application provides all needed
        data (but no unneeded data).

        Case 1, we'll test an application where a partner requires all of the
        optional fields.
        """
        editor = EditorFactory()

        partner = Partner()
        for field in USER_FORM_FIELDS + PARTNER_FORM_OPTIONAL_FIELDS:
            setattr(partner, field, True)
        partner.save()

        app = ApplicationFactory(status=Application.APPROVED,
            partner=partner,
            editor=editor,
            rationale='just because',
            comments='nope')
        app.agreement_with_terms_of_use = True
        for field in USER_FORM_FIELDS + PARTNER_FORM_OPTIONAL_FIELDS:
            if field != 'agreement_with_terms_of_use':
                setattr(app, field, 'blah blah')
        app.save()

        # Force reload (in 1.8 we can replace this with refresh_from_db)
        app = Application.objects.get(pk=app.pk)

        output = get_output_for_application(app)
        self.assertEqual(output['rationale'], 'just because')
        self.assertEqual(output['comments'], 'nope')
        for field in USER_FORM_FIELDS + PARTNER_FORM_OPTIONAL_FIELDS:
            self.assertEqual(output[field], 'blah blah')


    def test_application_output_2(self):
        """
        Case 2, we'll test an application where a partner requires none of the
        optional fields.
        """
        editor = EditorFactory()

        partner = Partner()
        for field in USER_FORM_FIELDS + PARTNER_FORM_OPTIONAL_FIELDS:
            setattr(partner, field, False)
        partner.save()

        app = ApplicationFactory(status=Application.APPROVED,
            partner=partner,
            editor=editor,
            rationale='just because',
            comments='nope')
        app.agreement_with_terms_of_use = False
        for field in USER_FORM_FIELDS + PARTNER_FORM_OPTIONAL_FIELDS:
            if field != 'agreement_with_terms_of_use':
                setattr(app, field, '')
        app.save()

        # Force reload (in 1.8 we can replace this with refresh_from_db)
        app = Application.objects.get(pk=app.pk)

        output = get_output_for_application(app)
        self.assertEqual(output['rationale'], 'just because')
        self.assertEqual(output['comments'], 'nope')
        for field in USER_FORM_FIELDS + PARTNER_FORM_OPTIONAL_FIELDS:
            self.assertFalse(output[field])


    def test_application_output_3(self):
        """
        Case 2, we'll test an application where a partner requires some but not
        all of the optional fields.
        """
        editor = EditorFactory()

        partner = Partner()
        for field in USER_FORM_FIELDS + PARTNER_FORM_OPTIONAL_FIELDS:
            setattr(partner, field, False)
        partner.save()

        app = ApplicationFactory(status=Application.APPROVED,
            partner=partner,
            editor=editor,
            rationale='just because',
            comments='nope')
        app.agreement_with_terms_of_use = False
        for field in PARTNER_FORM_OPTIONAL_FIELDS:
            if field != 'agreement_with_terms_of_use':
                setattr(app, field, '')
        for field in USER_FORM_FIELDS:
            setattr(app, field, 'blah blah')
        app.save()

        # Force reload (in 1.8 we can replace this with refresh_from_db)
        app = Application.objects.get(pk=app.pk)

        output = get_output_for_application(app)
        self.assertEqual(output['rationale'], 'just because')
        self.assertEqual(output['comments'], 'nope')
        for field in PARTNER_FORM_OPTIONAL_FIELDS:
            self.assertFalse(output[field])
        for field in PARTNER_FORM_OPTIONAL_FIELDS:
            self.assertEqual(output[field], 'blah blah')

{'fraction_non_alphanumeric': 0.059162100835685426, 'fraction_numerical': 0.0012175549283302894, 'mean_word_length': 2.7112343397001437, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2948209', 'n_tokens_mistral': 4628, 'n_tokens_neox': 4538, 'n_words': 1694}