<commit_before>import uuid
import mock
import os
from xml.etree import ElementTree

from corehq.util.test_utils import flag_enabled

from datetime import datetime, timedelta
from django.test import TestCase
from casexml.apps.phone.models import SyncLog
from casexml.apps.phone.tests.utils import create_restore_user
from corehq.apps.domain.shortcuts import create_domain
from corehq.apps.domain.models import Domain
from corehq.apps.commtrack.tests.util import bootstrap_domain
from corehq.apps.users.models import CommCareUser

from corehq.apps.app_manager.tests.util import TestXmlMixin
from casexml.apps.case.xml import V2
from corehq.apps.users.dbaccessors.all_commcare_users import delete_all_users

from .util import (
    LocationHierarchyPerTest,
    setup_location_types_with_structure,
    setup_locations_with_structure,
    LocationStructure,
    LocationTypeStructure,
)
from ..fixtures import _location_to_fixture, LocationSet, should_sync_locations, location_fixture_generator, \
    flat_location_fixture_generator, should_sync_flat_fixture, should_sync_hierarchical_fixture
from ..models import SQLLocation, LocationType, Location, LocationFixtureConfiguration


class FixtureHasLocationsMixin(TestXmlMixin):
    root = os.path.dirname(__file__)
    file_path = ['data']

    # Adding this feature flag allows rendering of hierarchical fixture where requested
    # and wont interfere with flat fixture generation
    @flag_enabled('HIERARCHICAL_LOCATION_FIXTURE')
    def _assert_fixture_has_locations(self, xml_name, desired_locations, flat=False):
        ids = {
            "{}_id".format(desired_location.lower().replace(" ", "_")): (
                self.locations[desired_location].location_id
            )
            for desired_location in desired_locations
        }  # eg: {"massachusetts_id" = self.locations["Massachusetts"].location_id}

        generator = flat_location_fixture_generator if flat else location_fixture_generator
        fixture = ElementTree.tostring(generator(self.user, V2)[0])
        desired_fixture = self.get_xml(xml_name).format(
            user_id=self.user.user_id,
            **ids
        )
        self.assertXmlEqual(desired_fixture, fixture)


@mock.patch.object(Domain, 'uses_locations', return_value=True)  # removes dependency on accounting
class LocationFixturesTest(LocationHierarchyPerTest, FixtureHasLocationsMixin):
    location_type_names = ['state', 'county', 'city']
    location_structure = [
        ('Massachusetts', [
            ('Middlesex', [
                ('Cambridge', []),
                ('Somerville', []),
            ]),
            ('Suffolk', [
                ('Boston', []),
                ('Revere', []),
            ])
        ]),
        ('New York', [
            ('New York City', [
                ('Manhattan', []),
                ('Brooklyn', []),
                ('Queens', []),
            ]),
        ]),
    ]

    def setUp(self):
        super(LocationFixturesTest, self).setUp()
        self.user = create_restore_user(self.domain, 'user', '123')

    @flag_enabled('HIERARCHICAL_LOCATION_FIXTURE')
    def test_no_user_locations_returns_empty(self, uses_locations):
        empty_fixture = "<fixture id='commtrack:locations' user_id='{}' />".format(self.user.user_id)
        fixture = ElementTree.tostring(location_fixture_generator(self.user, V2)[0])
        self.assertXmlEqual(empty_fixture, fixture)

    def test_simple_location_fixture(self, uses_locations):
        self.user._couch_user.set_location(self.locations['Suffolk'].couch_location)

        self._assert_fixture_has_locations(
            'simple_fixture',
            ['Massachusetts', 'Suffolk', 'Boston', 'Revere']
        )

    def test_multiple_locations(self, uses_locations):
        self.user._couch_user.add_to_assigned_locations(self.locations['Suffolk'].couch_location)
        self.user._couch_user.add_to_assigned_locations(self.locations['New York City'].couch_location)

        self._assert_fixture_has_locations(
            'multiple_locations',
            ['Massachusetts', 'Suffolk', 'Boston', 'Revere', 'New York',
             'New York City', 'Manhattan', 'Queens', 'Brooklyn']
        )

    def test_all_locations_flag_returns_all_locations(self, uses_locations):
        with flag_enabled('SYNC_ALL_LOCATIONS'):
            self._assert_fixture_has_locations(
                'expand_from_root',
                ['Massachusetts', 'Suffolk', 'Middlesex', 'Boston', 'Revere', 'Cambridge',
                 'Somerville', 'New York', 'New York City', 'Manhattan', 'Queens', 'Brooklyn']
            )

    @mock.patch.object(CommCareUser, 'locations')
    @mock.patch.object(Domain, 'supports_multiple_locations_per_user')
    def test_multiple_locations_returns_multiple_trees(
            self,
            supports_multiple_locations,
            user_locations,
            uses_locations
    ):
        multiple_locations_different_states = [
            self.locations['Suffolk'].couch_location,
            self.locations['New York City'].couch_location
        ]
        supports_multiple_locations.__get__ = mock.Mock(return_value=True)
        user_locations.__get__ = mock.Mock(return_value=multiple_locations_different_states)

        self._assert_fixture_has_locations(
            'multiple_locations',
            ['Massachusetts', 'Suffolk', 'Boston', 'Revere', 'New York',
             'New York City', 'Manhattan', 'Queens', 'Brooklyn']
        )

    def test_expand_to_county(self, uses_locations):
        """
        expand to "county"
        should return:
            Mass
            - Suffolk
        """
        self.user._couch_user.set_location(self.locations['Suffolk'].couch_location)
        location_type = self.locations['Suffolk'].location_type
        location_type.expand_to = location_type
        location_type.save()

        self._assert_fixture_has_locations(
            'expand_to_county',
            ['Massachusetts', 'Suffolk']
        )

    def test_expand_to_county_from_state(self, uses_locations):
        self.user._couch_user.set_location(self.locations['Massachusetts'].couch_location)
        location_type = self.locations['Massachusetts'].location_type
        location_type.expand_to = self.locations['Suffolk'].location_type
        location_type.save()

        self._assert_fixture_has_locations(
            'expand_to_county_from_state',
            ['Massachusetts', 'Suffolk', 'Middlesex']
        )

    def test_expand_from_county_at_city(self, uses_locations):
        self.user._couch_user.set_location(self.locations['Boston'].couch_location)
        location_type = self.locations['Boston'].location_type
        location_type.expand_from = self.locations['Suffolk'].location_type
        location_type.save()

        self._assert_fixture_has_locations(
            'expand_from_county_at_city',
            ['Massachusetts', 'Suffolk', 'Middlesex', 'Boston', 'Revere']
        )

    def test_expand_from_root_at_city(self, uses_locations):
        self.user._couch_user.set_location(self.locations['Boston'].couch_location)
        location_type = self.locations['Boston'].location_type
        location_type.expand_from_root = True
        location_type.save()

        self._assert_fixture_has_locations(
            'expand_from_root',
            ['Massachusetts', 'Suffolk', 'Middlesex', 'Boston', 'Revere', 'Cambridge',
             'Somerville', 'New York', 'New York City', 'Manhattan', 'Queens', 'Brooklyn']
        )

    def test_expand_from_root_to_county(self, uses_locations):
        self.user._couch_user.set_location(self.locations['Massachusetts'].couch_location)
        location_type = self.locations['Massachusetts'].location_type
        location_type.expand_from_root = True
        location_type.expand_to = self.locations['Suffolk'].location_type
        location_type.save()
        self._assert_fixture_has_locations(
            'expand_from_root_to_county',
            ['Massachusetts', 'Suffolk', 'Middlesex', 'New York', 'New York City']
        )

    def test_flat_sync_format(self, uses_locations):
        with flag_enabled('SYNC_ALL_LOCATIONS'):
            with flag_enabled('FLAT_LOCATION_FIXTURE'):
                self._assert_fixture_has_locations(
                    'expand_from_root_flat',
                    ['Massachusetts', 'Suffolk', 'Middlesex', 'Boston', 'Revere', 'Cambridge',
                     'Somerville', 'New York', 'New York City', 'Manhattan', 'Queens', 'Brooklyn'],
                    flat=True,
                )

    def test_include_without_expanding(self, uses_locations):
        self.user._couch_user.set_location(self.locations['Boston'].couch_location)
        location_type = self.locations['Boston'].location_type
        location_type.expand_from = self.locations['Suffolk'].location_type
        location_type.include_without_expanding = self.locations['Massachusetts'].location_type
        location_type.save()

        self._assert_fixture_has_locations(
            'include_without_expanding',
            ['Massachusetts', 'Suffolk', 'Boston', 'Revere', 'New York']
        )


@mock.patch.object(Domain, 'uses_locations', return_value=True)  # removes dependency on accounting
class WebUserLocationFixturesTest(LocationHierarchyPerTest, FixtureHasLocationsMixin):

    location_type_names = ['state', 'county', 'city']
    location_structure = [
        ('Massachusetts', [
            ('Middlesex', [
                ('Cambridge', []),
                ('Somerville', []),
            ]),
            ('Suffolk', [
                ('Boston', []),
                ('Revere', []),
            ])
        ]),
        ('New York', [
            ('New York City', [
                ('Manhattan', []),
                ('Brooklyn', []),
                ('Queens', []),
            ]),
        ]),
    ]

    def setUp(self):
        super(WebUserLocationFixturesTest, self).setUp()
        delete_all_users()
        self.user = create_restore_user(self.domain, 'web_user', '123', is_mobile_user=False)

    @flag_enabled('HIERARCHICAL_LOCATION_FIXTURE')
    def test_no_user_locations_returns_empty(self, uses_locations):
        empty_fixture = "<fixture id='commtrack:locations' user_id='{}' />".format(self.user.user_id)
        fixture = ElementTree.tostring(location_fixture_generator(self.user, V2)[0])
        self.assertXmlEqual(empty_fixture, fixture)

    def test_simple_location_fixture(self, uses_locations):
        self.user._couch_user.set_location(self.domain, self.locations['Suffolk'].couch_location)

        self._assert_fixture_has_locations(
            'simple_fixture',
            ['Massachusetts', 'Suffolk', 'Boston', 'Revere']
        )

    def test_multiple_locations(self, uses_locations):
        self.user._couch_user.add_to_assigned_locations(self.domain, self.locations['Suffolk'].couch_location)
        self.user._couch_user.add_to_assigned_locations(
            self.domain,
            self.locations['New York City'].couch_location
        )

        self._assert_fixture_has_locations(
            'multiple_locations',
            ['Massachusetts', 'Suffolk', 'Boston', 'Revere', 'New York',
             'New York City', 'Manhattan', 'Queens', 'Brooklyn']
        )


@mock.patch.object(Domain, 'uses_locations', return_value=True)  # removes dependency on accounting
class ForkedHierarchyLocationFixturesTest(LocationHierarchyPerTest, FixtureHasLocationsMixin):
    """
    - State
        - County
            - City
        - Region
            - Town
    """
    location_type_structure = [
        LocationTypeStructure('state', [
            LocationTypeStructure('county', [
                LocationTypeStructure('city', [])
            ]),
            LocationTypeStructure('region', [
                LocationTypeStructure('town', [])
            ])
        ])
    ]

    location_structure = [
        LocationStructure('Massachusetts', 'state', [
            LocationStructure('Middlesex', 'county', [
                LocationStructure('Cambridge', 'city', []),
                LocationStructure('Somerville', 'city', [])
            ]),
            LocationStructure('Suffolk', 'county', [
                LocationStructure('Boston', 'city', []),<commit_msg>Avoid passing unneeded parameter from mock<commit_after>import uuid
import mock
import os
from xml.etree import ElementTree

from corehq.util.test_utils import flag_enabled

from datetime import datetime, timedelta
from django.test import TestCase
from casexml.apps.phone.models import SyncLog
from casexml.apps.phone.tests.utils import create_restore_user
from corehq.apps.domain.shortcuts import create_domain
from corehq.apps.domain.models import Domain
from corehq.apps.commtrack.tests.util import bootstrap_domain
from corehq.apps.users.models import CommCareUser

from corehq.apps.app_manager.tests.util import TestXmlMixin
from casexml.apps.case.xml import V2
from corehq.apps.users.dbaccessors.all_commcare_users import delete_all_users

from .util import (
    LocationHierarchyPerTest,
    setup_location_types_with_structure,
    setup_locations_with_structure,
    LocationStructure,
    LocationTypeStructure,
)
from ..fixtures import _location_to_fixture, LocationSet, should_sync_locations, location_fixture_generator, \
    flat_location_fixture_generator, should_sync_flat_fixture, should_sync_hierarchical_fixture
from ..models import SQLLocation, LocationType, Location, LocationFixtureConfiguration


class FixtureHasLocationsMixin(TestXmlMixin):
    root = os.path.dirname(__file__)
    file_path = ['data']

    # Adding this feature flag allows rendering of hierarchical fixture where requested
    # and wont interfere with flat fixture generation
    @flag_enabled('HIERARCHICAL_LOCATION_FIXTURE')
    def _assert_fixture_has_locations(self, xml_name, desired_locations, flat=False):
        ids = {
            "{}_id".format(desired_location.lower().replace(" ", "_")): (
                self.locations[desired_location].location_id
            )
            for desired_location in desired_locations
        }  # eg: {"massachusetts_id" = self.locations["Massachusetts"].location_id}

        generator = flat_location_fixture_generator if flat else location_fixture_generator
        fixture = ElementTree.tostring(generator(self.user, V2)[0])
        desired_fixture = self.get_xml(xml_name).format(
            user_id=self.user.user_id,
            **ids
        )
        self.assertXmlEqual(desired_fixture, fixture)


@mock.patch.object(Domain, 'uses_locations', lambda: True)  # removes dependency on accounting
class LocationFixturesTest(LocationHierarchyPerTest, FixtureHasLocationsMixin):
    location_type_names = ['state', 'county', 'city']
    location_structure = [
        ('Massachusetts', [
            ('Middlesex', [
                ('Cambridge', []),
                ('Somerville', []),
            ]),
            ('Suffolk', [
                ('Boston', []),
                ('Revere', []),
            ])
        ]),
        ('New York', [
            ('New York City', [
                ('Manhattan', []),
                ('Brooklyn', []),
                ('Queens', []),
            ]),
        ]),
    ]

    def setUp(self):
        super(LocationFixturesTest, self).setUp()
        self.user = create_restore_user(self.domain, 'user', '123')

    @flag_enabled('HIERARCHICAL_LOCATION_FIXTURE')
    def test_no_user_locations_returns_empty(self):
        empty_fixture = "<fixture id='commtrack:locations' user_id='{}' />".format(self.user.user_id)
        fixture = ElementTree.tostring(location_fixture_generator(self.user, V2)[0])
        self.assertXmlEqual(empty_fixture, fixture)

    def test_simple_location_fixture(self):
        self.user._couch_user.set_location(self.locations['Suffolk'].couch_location)

        self._assert_fixture_has_locations(
            'simple_fixture',
            ['Massachusetts', 'Suffolk', 'Boston', 'Revere']
        )

    def test_multiple_locations(self):
        self.user._couch_user.add_to_assigned_locations(self.locations['Suffolk'].couch_location)
        self.user._couch_user.add_to_assigned_locations(self.locations['New York City'].couch_location)

        self._assert_fixture_has_locations(
            'multiple_locations',
            ['Massachusetts', 'Suffolk', 'Boston', 'Revere', 'New York',
             'New York City', 'Manhattan', 'Queens', 'Brooklyn']
        )

    def test_all_locations_flag_returns_all_locations(self):
        with flag_enabled('SYNC_ALL_LOCATIONS'):
            self._assert_fixture_has_locations(
                'expand_from_root',
                ['Massachusetts', 'Suffolk', 'Middlesex', 'Boston', 'Revere', 'Cambridge',
                 'Somerville', 'New York', 'New York City', 'Manhattan', 'Queens', 'Brooklyn']
            )

    @mock.patch.object(CommCareUser, 'locations')
    @mock.patch.object(Domain, 'supports_multiple_locations_per_user')
    def test_multiple_locations_returns_multiple_trees(
            self,
            supports_multiple_locations,
            user_locations,
    ):
        multiple_locations_different_states = [
            self.locations['Suffolk'].couch_location,
            self.locations['New York City'].couch_location
        ]
        supports_multiple_locations.__get__ = mock.Mock(return_value=True)
        user_locations.__get__ = mock.Mock(return_value=multiple_locations_different_states)

        self._assert_fixture_has_locations(
            'multiple_locations',
            ['Massachusetts', 'Suffolk', 'Boston', 'Revere', 'New York',
             'New York City', 'Manhattan', 'Queens', 'Brooklyn']
        )

    def test_expand_to_county(self):
        """
        expand to "county"
        should return:
            Mass
            - Suffolk
        """
        self.user._couch_user.set_location(self.locations['Suffolk'].couch_location)
        location_type = self.locations['Suffolk'].location_type
        location_type.expand_to = location_type
        location_type.save()

        self._assert_fixture_has_locations(
            'expand_to_county',
            ['Massachusetts', 'Suffolk']
        )

    def test_expand_to_county_from_state(self):
        self.user._couch_user.set_location(self.locations['Massachusetts'].couch_location)
        location_type = self.locations['Massachusetts'].location_type
        location_type.expand_to = self.locations['Suffolk'].location_type
        location_type.save()

        self._assert_fixture_has_locations(
            'expand_to_county_from_state',
            ['Massachusetts', 'Suffolk', 'Middlesex']
        )

    def test_expand_from_county_at_city(self):
        self.user._couch_user.set_location(self.locations['Boston'].couch_location)
        location_type = self.locations['Boston'].location_type
        location_type.expand_from = self.locations['Suffolk'].location_type
        location_type.save()

        self._assert_fixture_has_locations(
            'expand_from_county_at_city',
            ['Massachusetts', 'Suffolk', 'Middlesex', 'Boston', 'Revere']
        )

    def test_expand_from_root_at_city(self):
        self.user._couch_user.set_location(self.locations['Boston'].couch_location)
        location_type = self.locations['Boston'].location_type
        location_type.expand_from_root = True
        location_type.save()

        self._assert_fixture_has_locations(
            'expand_from_root',
            ['Massachusetts', 'Suffolk', 'Middlesex', 'Boston', 'Revere', 'Cambridge',
             'Somerville', 'New York', 'New York City', 'Manhattan', 'Queens', 'Brooklyn']
        )

    def test_expand_from_root_to_county(self):
        self.user._couch_user.set_location(self.locations['Massachusetts'].couch_location)
        location_type = self.locations['Massachusetts'].location_type
        location_type.expand_from_root = True
        location_type.expand_to = self.locations['Suffolk'].location_type
        location_type.save()
        self._assert_fixture_has_locations(
            'expand_from_root_to_county',
            ['Massachusetts', 'Suffolk', 'Middlesex', 'New York', 'New York City']
        )

    def test_flat_sync_format(self):
        with flag_enabled('SYNC_ALL_LOCATIONS'):
            with flag_enabled('FLAT_LOCATION_FIXTURE'):
                self._assert_fixture_has_locations(
                    'expand_from_root_flat',
                    ['Massachusetts', 'Suffolk', 'Middlesex', 'Boston', 'Revere', 'Cambridge',
                     'Somerville', 'New York', 'New York City', 'Manhattan', 'Queens', 'Brooklyn'],
                    flat=True,
                )

    def test_include_without_expanding(self):
        self.user._couch_user.set_location(self.locations['Boston'].couch_location)
        location_type = self.locations['Boston'].location_type
        location_type.expand_from = self.locations['Suffolk'].location_type
        location_type.include_without_expanding = self.locations['Massachusetts'].location_type
        location_type.save()

        self._assert_fixture_has_locations(
            'include_without_expanding',
            ['Massachusetts', 'Suffolk', 'Boston', 'Revere', 'New York']
        )


@mock.patch.object(Domain, 'uses_locations', lambda: True)  # removes dependency on accounting
class WebUserLocationFixturesTest(LocationHierarchyPerTest, FixtureHasLocationsMixin):

    location_type_names = ['state', 'county', 'city']
    location_structure = [
        ('Massachusetts', [
            ('Middlesex', [
                ('Cambridge', []),
                ('Somerville', []),
            ]),
            ('Suffolk', [
                ('Boston', []),
                ('Revere', []),
            ])
        ]),
        ('New York', [
            ('New York City', [
                ('Manhattan', []),
                ('Brooklyn', []),
                ('Queens', []),
            ]),
        ]),
    ]

    def setUp(self):
        super(WebUserLocationFixturesTest, self).setUp()
        delete_all_users()
        self.user = create_restore_user(self.domain, 'web_user', '123', is_mobile_user=False)

    @flag_enabled('HIERARCHICAL_LOCATION_FIXTURE')
    def test_no_user_locations_returns_empty(self):
        empty_fixture = "<fixture id='commtrack:locations' user_id='{}' />".format(self.user.user_id)
        fixture = ElementTree.tostring(location_fixture_generator(self.user, V2)[0])
        self.assertXmlEqual(empty_fixture, fixture)

    def test_simple_location_fixture(self):
        self.user._couch_user.set_location(self.domain, self.locations['Suffolk'].couch_location)

        self._assert_fixture_has_locations(
            'simple_fixture',
            ['Massachusetts', 'Suffolk', 'Boston', 'Revere']
        )

    def test_multiple_locations(self):
        self.user._couch_user.add_to_assigned_locations(self.domain, self.locations['Suffolk'].couch_location)
        self.user._couch_user.add_to_assigned_locations(
            self.domain,
            self.locations['New York City'].couch_location
        )

        self._assert_fixture_has_locations(
            'multiple_locations',
            ['Massachusetts', 'Suffolk', 'Boston', 'Revere', 'New York',
             'New York City', 'Manhattan', 'Queens', 'Brooklyn']
        )


@mock.patch.object(Domain, 'uses_locations', lambda: True)  # removes dependency on accounting
class ForkedHierarchyLocationFixturesTest(LocationHierarchyPerTest, FixtureHasLocationsMixin):
    """
    - State
        - County
            - City
        - Region
            - Town
    """
    location_type_structure = [
        LocationTypeStructure('state', [
            LocationTypeStructure('county', [
                LocationTypeStructure('city', [])
            ]),
            LocationTypeStructure('region', [
                LocationTypeStructure('town', [])
            ])
        ])
    ]

    location_structure = [
        LocationStructure('Massachusetts', 'state', [
            LocationStructure('Middlesex', 'county', [
                LocationStructure('Cambridge', 'city', []),
                LocationStructure('Somerville', 'city', [])
            ]),
            LocationStructure('Suffolk', 'county', [
                LocationStructure('Boston', 'city', []),
{'fraction_non_alphanumeric': 0.11413065822472557, 'fraction_numerical': 0.0010689470871191875, 'mean_word_length': 2.868320610687023, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 16}, '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': '3950643', 'n_tokens_mistral': 7349, 'n_tokens_neox': 6936, 'n_words': 1075}