from AccessControl import AuthEncoding
from plone import api as plone_api
from plone.app.testing import IntegrationTesting
from plone.namedfile import NamedBlobImage
from ploneintranet import api as pi_api
from ploneintranet.api.testing import IntegrationTestCase
from ploneintranet.api.testing import PloneintranetApiLayer
from ploneintranet.network.interfaces import INetworkTool
from ploneintranet.userprofile.content.userprofile import UserProfile
from ploneintranet.userprofile.interfaces import IMemberGroup
from ploneintranet.workspace.config import INTRANET_USERS_GROUP_ID
from zope.component import queryUtility
from zope.i18nmessageid import Message
from zope.interface import directlyProvides
from zope.interface import Invalid

import collections
import re


class TestUserProfile(IntegrationTestCase):
    def test_create(self):
        self.login_as_portal_owner()
        profile = pi_api.userprofile.create(
            username="johndoe", email="johndoe@doe.com", approve=True
        )
        self.assertIsInstance(profile, UserProfile)

        # Should have been added to global members group
        # and have Member role
        self.assertIn(
            "johndoe",
            plone_api.group.get(groupname=INTRANET_USERS_GROUP_ID).getMemberIds(),
        )
        self.assertIn("Member", plone_api.user.get_roles(username="johndoe"))

        # We can now login
        self.login("johndoe")

        # Cannot create another with same username
        self.login_as_portal_owner()
        with self.assertRaises(Invalid):
            pi_api.userprofile.create(username="johndoe", email="foobar@doe.com")

    def test_create_fullname_ascii(self):
        self.login_as_portal_owner()
        profile = pi_api.userprofile.create(
            username="johndoe",
            email="johndoe@doe.com",
            approve=True,
            properties=dict(fullname="John Doe"),
        )
        self.assertIsInstance(profile, UserProfile)
        self.assertEqual(profile.fullname, "John Doe")
        self.assertEqual(profile.first_name, "John")
        self.assertEqual(profile.last_name, "Doe")

    def test_create_fullname_unicode(self):
        self.login_as_portal_owner()
        profile = pi_api.userprofile.create(
            username="johndoe",
            email="johndoe@doe.com",
            approve=True,
            properties=dict(fullname="John Doé"),
        )
        self.assertIsInstance(profile, UserProfile)
        self.assertEqual(profile.fullname, "John Doé")
        self.assertEqual(profile.first_name, "John")
        self.assertEqual(profile.last_name, "Doé")

    def test_password_storage(self):
        password_plain = "secret"
        profile = pi_api.userprofile.create(
            username="johndoe",
            email="johndoe@doe.com",
            password=password_plain,
            approve=True,
        )

        self.assertNotEqual(
            profile.password, password_plain, "Password not encrypted correctly"
        )

        self.assertTrue(profile.password.startswith(b"{BCRYPT}"))
        self.assertTrue(AuthEncoding.pw_validate(profile.password, password_plain))

    def test_get(self):
        self.login_as_portal_owner()
        profile = pi_api.userprofile.create(username="janedoe", email="janedoe@doe.com")
        profile2 = pi_api.userprofile.create(username="bobdoe", email="bobdoe@doe.com")

        found = pi_api.userprofile.get("janedoe")
        self.assertEqual(found, profile)
        found = pi_api.userprofile.get("bobdoe")
        self.assertEqual(found, profile2)

        notfound = pi_api.userprofile.get("wigglesdoe")
        self.assertIsNone(notfound)

    def test_get_current(self):
        self.login_as_portal_owner()
        profile = pi_api.userprofile.create(
            username="janedoe", email="janedoe@doe.com", approve=True
        )
        profile2 = pi_api.userprofile.create(
            username="bobdoe", email="bobdoe@doe.com", approve=True
        )

        self.login("janedoe")
        found = pi_api.userprofile.get_current()
        self.assertEqual(found, profile)

        self.login("bobdoe")
        found = pi_api.userprofile.get_current()
        self.assertEqual(found, profile2)

    def test_avatar_url(self):
        self.login_as_portal_owner()
        profile = pi_api.userprofile.create(
            username="janedoe", email="janedoe@doe.com", approve=True
        )

        valid_url = pi_api.userprofile.avatar_url(profile.username)
        self.assertEqual(
            valid_url,
            "{portal_url}/@@avatars/{userid}".format(
                portal_url=self.portal.absolute_url(), userid=profile.username
            ),
        )

    def test_avatar_tag_no_portrait(self):
        self.login_as_portal_owner()
        profile = pi_api.userprofile.create(
            username="janedoe",
            email="janedoe@doe.com",
            approve=True,
            properties={"fullname": "Jane Doe"},
        )

        self.maxDiff = None
        tag_no_link = re.sub(
            "[ \n]+",
            " ",
            pi_api.userprofile.avatar_tag(username="janedoe", link_to=None),
        )
        self.assertEqual(
            tag_no_link,
            ' <span class="pat-avatar avatar" data-initials="{initials}" '
            'title="{fullname}" > '
            "</span>"
            "".format(
                fullname=profile.fullname,
                initials=profile.initials,
            ),
        )

        tag_link_profile = re.sub(
            "[ \n]+",
            " ",
            pi_api.userprofile.avatar_tag(username="janedoe", link_to="profile"),
        )
        self.assertEqual(
            tag_link_profile,
            ' <a href="{portal_url}/profiles/{userid}#app-space" '
            'class="pat-avatar avatar pat-switch pat-inject" '
            'data-initials="{initials}" '
            'title="{fullname}" '
            'data-pat-inject="history: record" '
            'data-pat-switch="#app-space state-off state-on" > '
            "</a>"
            "".format(
                portal_url=self.portal.absolute_url(),
                userid=profile.username,
                fullname=profile.fullname,
                initials=profile.initials,
            ),
        )

        tag_link_image = re.sub(
            "[ \n]+",
            " ",
            pi_api.userprofile.avatar_tag(username="janedoe", link_to="image"),
        )
        self.assertEqual(
            tag_link_image,
            ' <a class="pat-avatar avatar user-info-avatar" '
            'data-initials="{initials}" title="{fullname}" > '
            "</a>"
            "".format(
                fullname=profile.fullname,
                initials=profile.initials,
            ),
        )

    def test_avatar_tag_with_portrait(self):
        self.login_as_portal_owner()
        profile = pi_api.userprofile.create(
            username="janedoe",
            email="janedoe@doe.com",
            approve=True,
            properties={"fullname": "Jane Doe"},
        )
        profile.portrait = NamedBlobImage(data="GIF89a;", filename="avatar.png")
        timestamp = profile.modified().ISO()

        self.maxDiff = None
        tag_no_link = re.sub(
            "[ \n]+",
            " ",
            pi_api.userprofile.avatar_tag(username="janedoe", link_to=None),
        )
        self.assertEqual(
            tag_no_link,
            ' <span class="pat-avatar avatar" data-initials="{initials}" '
            'title="{fullname}" > '
            '<img src="{portal_url}/profiles/{userid}/'
            '@@avatar_profile.jpg?ts={timestamp}" '
            'alt="Image of {fullname}"> '
            "</span>"
            "".format(
                portal_url=self.portal.absolute_url(),
                userid=profile.username,
                fullname=profile.fullname,
                initials=profile.initials,
                timestamp=timestamp,
            ),
        )

        tag_link_profile = re.sub(
            "[ \n]+",
            " ",
            pi_api.userprofile.avatar_tag(username="janedoe", link_to="profile"),
        )
        self.assertEqual(
            tag_link_profile,
            ' <a href="{portal_url}/profiles/{userid}#app-space" '
            'class="pat-avatar avatar pat-switch pat-inject" '
            'data-initials="{initials}" '
            'title="{fullname}" '
            'data-pat-inject="history: record" '
            'data-pat-switch="#app-space state-off state-on" > '
            '<img src="{portal_url}/profiles/{userid}/'
            '@@avatar_profile.jpg?ts={timestamp}" '
            'alt="Image of {fullname}"> '
            "</a>"
            "".format(
                portal_url=self.portal.absolute_url(),
                userid=profile.username,
                fullname=profile.fullname,
                initials=profile.initials,
                timestamp=timestamp,
            ),
        )

        tag_link_image = re.sub(
            "[ \n]+",
            " ",
            pi_api.userprofile.avatar_tag(username="janedoe", link_to="image"),
        )
        self.assertEqual(
            tag_link_image,
            ' <a href="{portal_url}/profiles/{userid}/'
            '@@avatar_profile.jpg?ts={timestamp}#app-space" '
            'class="pat-avatar avatar pat-gallery user-info-avatar" '
            'data-initials="{initials}" title="{fullname}" > '
            '<img src="{portal_url}/profiles/{userid}/'
            '@@avatar_profile.jpg?ts={timestamp}" '
            'alt="Image of {fullname}"> '
            "</a>"
            "".format(
                portal_url=self.portal.absolute_url(),
                userid=profile.username,
                fullname=profile.fullname,
                initials=profile.initials,
                timestamp=timestamp,
            ),
        )

    def test_avatar_tag_disabled_user(self):
        self.login_as_portal_owner()
        profile = pi_api.userprofile.create(
            username="janedoe",
            email="janedoe@doe.com",
            approve=True,
            properties={"fullname": "Jane Doe"},
        )
        profile.portrait = NamedBlobImage(data="GIF89a;", filename="avatar.png")
        plone_api.content.transition(obj=profile, to_state="disabled")

        self.maxDiff = None
        tag_no_link = re.sub(
            "[ \n]+",
            " ",
            pi_api.userprofile.avatar_tag(username="janedoe", link_to=None),
        )
        self.assertEqual(
            tag_no_link,
            ' <span class="pat-avatar avatar inactive" data-initials="{initials}" '
            'title="{fullname}" > '
            "</span>"
            "".format(
                fullname=profile.fullname,
                initials=profile.initials,
            ),
        )

        tag_link_profile = re.sub(
            "[ \n]+",
            " ",
            pi_api.userprofile.avatar_tag(username="janedoe", link_to="profile"),
        )
        self.assertEqual(
            tag_link_profile,
            ' <a class="pat-avatar avatar inactive" data-initials="{initials}" '
            'title="{fullname}" > '
            "</a>"
            "".format(
                fullname=profile.fullname,
                initials=profile.initials,
            ),
        )

        tag_link_image = re.sub(
            "[ \n]+",
            " ",
            pi_api.userprofile.avatar_tag(username="janedoe", link_to="image"),
        )
        self.assertEqual(
            tag_link_image,
            ' <a class="pat-avatar avatar inactive" data-initials="{initials}" '
            'title="{fullname}" > '
            "</a>"
            "".format(
                fullname=profile.fullname,
                initials=profile.initials,
            ),
        )

    def test_get_users_from_userids_and_groupids(self):
        """NB this overlaps with the getters tested below
        but operates on groups that are
        <class 'Products.PlonePAS.tools.groupdata.GroupData'>"""
        self.login_as_portal_owner()
        profile1 = pi_api.userprofile.create(
            username="janedoe", email="janedoe@doe.com"
        )
        profile2 = pi_api.userprofile.create(username="bobdoe", email="bobdoe@doe.com")
        group1 = plone_api.group.create(groupname="group1")
        group1.addMember(profile2.getId())
        users = pi_api.userprofile.get_users_from_userids_and_groupids(
            ids=["janedoe", "group1"]
        )
        self.assertIsInstance(users[0], UserProfile)
        user_ids = [i.getId() for i in users]
        self.assertIn(profile1.getId(), user_ids)
        self.assertIn(profile2.getId(), user_ids)
        self.assertEqual(len(users), 2)


class UserProfileGetUsersLayer(PloneintranetApiLayer):
    def setUpPloneSite(self, portal):
        super().setUpPloneSite(portal)
        pi_api.userprofile.create(username="janedoe", email="janedoe@doe.com")
        pi_api.userprofile.create(username="bobdoe", email="bobdoe@doe.com")
        pi_api.userprofile.create(username="bobschmo", email="bobschmo@schmo.com")
        profile4 = pi_api.userprofile.create(
            username="celinedijon", email="celine@dijon.com"
        )
        group1 = plone_api.group.create(groupname="group1")
        group1.addMember(profile4.getId())
        folder = plone_api.content.create(portal, "Folder", "my-folder", "My Folder")
        folder.members = ["bobdoe", "bobschmo"]
        directlyProvides(folder, IMemberGroup)


USERPROFILE_GET_USERS_FIXTURE = UserProfileGetUsersLayer()
USERPROFILE_GET_USERS_TESTING = IntegrationTesting(
    bases=(USERPROFILE_GET_USERS_FIXTURE,),
    name="PloneintranetUserProfileGetUsersLayer:Integration",
)


class TestUserProfileGetUsers(IntegrationTestCase):
    layer = USERPROFILE_GET_USERS_TESTING

    def setUp(self):
        super().setUp()
        self.portal = self.layer["portal"]
        self.login_as_portal_owner()
        profiles = self.portal.profiles
        self.profile1 = profiles["janedoe"]
        self.profile2 = profiles["bobdoe"]
        self.profile3 = profiles["bobschmo"]
        self.profile4 = profiles["celinedijon"]
        self.group1 = plone_api.group.get(groupname="group1")
        self.folder = self.portal["my-folder"]
        self.folder.members = ["bobdoe", "bobschmo"]
        directlyProvides(self.folder, IMemberGroup)

    def test_get_userids(self):
        """Verify that the method returns a list.
        Verify the list items.
        Do not assert anything, at the moment, about the item order.
        """
        userids = pi_api.userprofile.get_userids()
        self.assertIsInstance(userids, list)
        self.assertSetEqual(
            set(pi_api.userprofile.get_userids()),
            {"bobdoe", "bobschmo", "celinedijon", "janedoe"},
        )

    def test_get_users_rtype_user(self):
        """Verify default rtype for full_objects argument
        - this ought to change from objects to brains soon
        """
        usergen = pi_api.userprofile.get_users()
        retval = [x for x in usergen][0]
        self.assertFalse(hasattr(retval, "getObject"))

    def test_get_users_rtype_iterator_nofullobjects(self):
        """Verify that rtype is iterator"""
        usergen = pi_api.userprofile.get_users()
        self.assertTrue(isinstance(usergen, collections.abc.Iterator))

    def test_get_users_rtype_iterator_fullobjects(self):
        """Verify that rtype is iterator"""
        usergen = pi_api.userprofile.get_users()
        self.assertTrue(isinstance(usergen, collections.abc.Iterator))

    def test_get_users_brains_userid(self):
        usergen = pi_api.userprofile.get_users(full_objects=False)
        self.assertEqual(
            sorted(x.getUserId for x in usergen),
            ["bobdoe", "bobschmo", "celinedijon", "janedoe"],
        )

    def test_get_users_brains_email(self):
        usergen = pi_api.userprofile.get_users(full_objects=False)
        self.assertEqual(
            sorted(x.email for x in usergen),
            [
                "bobdoe@doe.com",
                "bobschmo@schmo.com",
                "celine@dijon.com",
                "janedoe@doe.com",
            ],
        )

    def test_get_users_fullobj(self):
        usergen = pi_api.userprofile.get_users(full_objects=True)
        found = [x for x in usergen]
        self.assertEqual(len(found), 4)
        self.assertIn(self.profile1, found)
        self.assertIn(self.profile2, found)
        self.assertIn(self.profile3, found)
        self.assertIn(self.profile4, found)

    def test_get_users_context_workspace_fullobj(self):
        usergen = pi_api.userprofile.get_users(self.folder, True)
        found = [x for x in usergen]
        self.assertEqual(len(found), 2)
        self.assertNotIn(self.profile1, found)
        self.assertIn(self.profile2, found)
        self.assertIn(self.profile3, found)

    def test_get_users_context_content_fullobj(self):
        page = plone_api.content.create(
            self.folder, "Document", "my-document", "My Document"
        )
        usergen = pi_api.userprofile.get_users(page, True)
        found = [x for x in usergen]
        self.assertEqual(len(found), 2)
        self.assertNotIn(self.profile1, found)
        self.assertIn(self.profile2, found)
        self.assertIn(self.profile3, found)

    def test_get_users_context_workspace_group_lookup(self):
        folder = plone_api.content.create(
            self.portal, "Folder", "my-folder-with-group", "My Folder"
        )
        folder.members = ["bobdoe", "bobschmo", "group1"]
        directlyProvides(folder, IMemberGroup)
        usergen = pi_api.userprofile.get_users(folder, True)
        found = [x for x in usergen]
        self.assertEqual(len(found), 3)
        self.assertNotIn(self.profile1, found)
        self.assertIn(self.profile2, found)
        self.assertIn(self.profile3, found)
        self.assertIn(self.profile4, found)

    def test_get_users_search_fulltext_1(self):
        usergen = pi_api.userprofile.get_users(
            full_objects=False, SearchableText="bob*"
        )
        self.assertEqual(sorted(x.getUserId for x in usergen), ["bobdoe", "bobschmo"])

    def test_get_users_search_fulltext_2(self):
        usergen = pi_api.userprofile.get_users(
            full_objects=False, SearchableText="doe.com"
        )
        self.assertEqual(sorted(x.getUserId for x in usergen), ["bobdoe", "janedoe"])

    def test_get_users_context_search_fulltext(self):
        usergen = pi_api.userprofile.get_users(
            context=self.folder, full_objects=False, SearchableText="doe.com"
        )
        self.assertEqual(sorted(x.getUserId for x in usergen), ["bobdoe"])

    def test_get_users_exactgetuserid(self):
        usergen = pi_api.userprofile.get_users(
            full_objects=True, exact_getUserId=["janedoe", "bobdoe"]
        )
        found = [x for x in usergen]
        self.assertEqual(len(found), 2)
        self.assertIn(self.profile1, found)
        self.assertIn(self.profile2, found)

    def test_get_users_context_exactgetuserid_1(self):
        """Specifiying both a context and exact_getUserId
        returns the intersection of both results
        """
        usergen = pi_api.userprofile.get_users(
            context=self.folder,
            full_objects=True,
            exact_getUserId=["janedoe", "bobdoe"],
        )
        found = [x for x in usergen]
        self.assertEqual(len(found), 1)
        self.assertNotIn(self.profile1, found)
        self.assertIn(self.profile2, found)

    def test_get_users_context_exactgetuserid_2(self):
        """Specifiying both a context and exact_getUserId
        returns the intersection of both results
        """
        usergen = pi_api.userprofile.get_users(
            context=self.folder, full_objects=True, exact_getUserId=["janedoe"]
        )
        found = [x for x in usergen]
        self.assertEqual(len(found), 0)
        self.assertNotIn(self.profile1, found)
        self.assertNotIn(self.profile2, found)

    def test_translate_message_for_user(self):
        """Test that we can translate a message for a user"""
        self.portal.profiles.janedoe.language = "de"
        observed = pi_api.userprofile.translate_message_for_user(
            Message("label_view", domain="plone"), "janedoe"
        )
        self.assertEqual(observed, "Anzeigen")


class UserProfileGetUserSuggestionsLayer(PloneintranetApiLayer):
    def setUpPloneSite(self, portal):
        super().setUpPloneSite(portal)
        [
            pi_api.userprofile.create(
                username="bobschmo-%s" % x,
                email="bobschmo-%s@schmo.com" % x,
                approve=True,
            )
            for x in range(8)
        ]
        [
            pi_api.userprofile.create(
                username="bobdoe-%s" % x, email="bobdoe-%s@doe.com" % x, approve=True
            )
            for x in range(8)
        ]
        [
            pi_api.userprofile.create(
                username="maryjane-%s" % x,
                email="maryjane-%s@doe.com" % x,
                approve=True,
            )
            for x in range(8)
        ]
        pi_api.userprofile.create(
            username="bobnot_enabled", email="bobnot_enabled@doe.com"
        )
        plone_api.content.create(portal, "Folder", "my-folder", "My Folder")


USERPROFILE_GET_USER_SUGGESTION_FIXTURE = UserProfileGetUserSuggestionsLayer()
USERPROFILE_GET_USER_SUGGESTION_TESTING = IntegrationTesting(
    bases=(USERPROFILE_GET_USER_SUGGESTION_FIXTURE,),
    name="PloneintranetUserProfileGetUserSuggestionsLayer:Integration",
)


class TestUserProfileGetUserSuggestions(IntegrationTestCase):
    layer = USERPROFILE_GET_USER_SUGGESTION_TESTING

    def setUp(self):
        super().setUp()
        self.login_as_portal_owner()
        profiles = self.portal.profiles
        self.profiles_1 = [profiles["bobschmo-%s" % x] for x in range(8)]
        self.profiles_2 = [profiles["bobdoe-%s" % x] for x in range(8)]
        self.profiles_3 = [profiles["maryjane-%s" % x] for x in range(8)]
        self.profile_4 = profiles["bobnot_enabled"]
        self.folder = self.portal["my-folder"]

    def test_suggestions_all(self):
        """Default unfiltered"""
        usergen = pi_api.userprofile.get_user_suggestions(full_objects=True)
        found = {x for x in usergen}
        self.assertEqual(
            found, set(self.profiles_1 + self.profiles_2 + self.profiles_3)
        )

    def test_suggestions_context_overlimit(self):
        """Context provides enough"""
        self.folder.members = ["maryjane-%x" % x for x in range(8)]
        directlyProvides(self.folder, IMemberGroup)
        usergen = pi_api.userprofile.get_user_suggestions(
            self.folder, full_objects=True
        )
        found = {x for x in usergen}
        self.assertEqual(found, set(self.profiles_3))

    def test_suggestions_context_underlimit(self):
        """Context too small, fallback to all users"""
        self.folder.members = ["maryjane-%x" % x for x in range(8)]
        directlyProvides(self.folder, IMemberGroup)
        usergen = pi_api.userprofile.get_user_suggestions(
            self.folder, full_objects=True, min_matches=10
        )
        found = {x for x in usergen}
        self.assertEqual(
            found, set(self.profiles_1 + self.profiles_2 + self.profiles_3)
        )

    def test_suggestions_context_search_overlimit(self):
        """Context provides enough"""
        self.folder.members = ["bobschmo-%x" % x for x in range(8)]
        directlyProvides(self.folder, IMemberGroup)
        q = {"SearchableText": "bob*"}
        usergen = pi_api.userprofile.get_user_suggestions(
            self.folder, full_objects=True, **q
        )
        found = {x for x in usergen}
        self.assertEqual(found, set(self.profiles_1))

    def test_suggestions_only_include_enabled_users(self):
        """Context provides enough"""
        self.folder.members = ["bobschmo-%x" % x for x in range(8)] + [
            self.profile_4.username
        ]
        directlyProvides(self.folder, IMemberGroup)
        q = {"SearchableText": "bob*"}
        usergen = pi_api.userprofile.get_user_suggestions(
            self.folder, full_objects=True, **q
        )
        found = {x for x in usergen}
        # bobnot is not found
        self.assertEqual(found, set(self.profiles_1))
        # Now enable bobnot
        plone_api.content.transition(self.profile_4, to_state="enabled")
        usergen = pi_api.userprofile.get_user_suggestions(
            self.folder, full_objects=True, **q
        )
        found = {x for x in usergen}
        self.assertEqual(found, set(self.profiles_1 + [self.profile_4]))

    def test_suggestions_context_search_underlimit(self):
        """Context provides enough"""
        self.folder.members = ["bobschmo-%x" % x for x in range(8)]
        directlyProvides(self.folder, IMemberGroup)
        q = {"SearchableText": "bob*"}
        usergen = pi_api.userprofile.get_user_suggestions(
            self.folder, full_objects=True, min_matches=10, **q
        )
        found = {x for x in usergen}
        self.assertEqual(found, set(self.profiles_1 + self.profiles_2))

    def test_suggestions_network_overlimit(self):
        """Network provides enough"""
        graph = queryUtility(INetworkTool)
        # current user is 'admin'
        for x in range(8):
            graph.follow("user", "bobdoe-%s" % x, "admin")
        usergen = pi_api.userprofile.get_user_suggestions(None, full_objects=True)
        found = {x for x in usergen}
        self.assertEqual(found, set(self.profiles_2))

    def test_suggestions_network_underlimit(self):
        """Network too small, fall back to all users"""
        graph = queryUtility(INetworkTool)
        # current user is 'admin'
        for x in range(8):
            graph.follow("user", "bobdoe-%s" % x, "admin")
        usergen = pi_api.userprofile.get_user_suggestions(
            None, full_objects=True, min_matches=10
        )
        found = {x for x in usergen}
        self.assertEqual(
            found, set(self.profiles_1 + self.profiles_2 + self.profiles_3)
        )

    def test_suggestions_context_network_overlimit(self):
        """Context and network combined provide enough"""
        self.folder.members = ["maryjane-%x" % x for x in range(8)]
        directlyProvides(self.folder, IMemberGroup)
        graph = queryUtility(INetworkTool)
        # current user is 'admin'
        for x in range(8):
            graph.follow("user", "bobdoe-%s" % x, "admin")
        usergen = pi_api.userprofile.get_user_suggestions(
            self.folder, full_objects=True, min_matches=10
        )
        found = {x for x in usergen}
        self.assertEqual(found, set(self.profiles_2 + self.profiles_3))

    def test_suggestions_context_network_overlap(self):
        """Context and network combined provide enough.
        Users matching both sets are listed only once.
        """
        self.folder.members = ["maryjane-%x" % x for x in range(8)]
        directlyProvides(self.folder, IMemberGroup)
        graph = queryUtility(INetworkTool)
        # current user is 'admin'
        for x in range(8):
            graph.follow("user", "bobdoe-%s" % x, "admin")
        for x in range(4):
            graph.follow("user", "maryjane-%s" % x, "admin")
        usergen = pi_api.userprofile.get_user_suggestions(
            self.folder, full_objects=True, min_matches=10
        )
        found = {x for x in usergen}
        self.assertEqual(len(found), 16)
        self.assertEqual(found, set(self.profiles_2 + self.profiles_3))

    def test_suggestions_context_network_underlimit(self):
        """The combination of context and network is not enough"""
        self.folder.members = ["maryjane-%x" % x for x in range(8)]
        directlyProvides(self.folder, IMemberGroup)
        graph = queryUtility(INetworkTool)
        # current user is 'admin'
        for x in range(8):
            graph.follow("user", "bobdoe-%s" % x, "admin")
        usergen = pi_api.userprofile.get_user_suggestions(
            self.folder, full_objects=True, min_matches=20
        )
        found = {x for x in usergen}
        self.assertEqual(
            found, set(self.profiles_1 + self.profiles_2 + self.profiles_3)
        )

    def test_suggestions_context_network_underlimit_waybeyond(self):
        """The threshold is bigger than all users, check optimization."""
        self.folder.members = ["maryjane-%x" % x for x in range(8)]
        directlyProvides(self.folder, IMemberGroup)
        graph = queryUtility(INetworkTool)
        # current user is 'admin'
        for x in range(8):
            graph.follow("user", "bobdoe-%s" % x, "admin")
        usergen = pi_api.userprofile.get_user_suggestions(
            self.folder, full_objects=True, min_matches=30
        )
        found = {x for x in usergen}
        self.assertEqual(
            found, set(self.profiles_1 + self.profiles_2 + self.profiles_3)
        )
