# Copyright 2016 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Unittests for Project Summary servlet."""
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import

import unittest

from framework import permissions
from project import projectsummary
from mrproto import project_pb2
from mrproto import user_pb2
from services import service_manager
from testing import fake
from testing import testing_helpers


class ProjectSummaryTest(unittest.TestCase):

  def setUp(self):
    services = service_manager.Services(
        project=fake.ProjectService(),
        user=fake.UserService(),
        usergroup=fake.UserGroupService(),
        project_star=fake.ProjectStarService())
    self.project = services.project.TestAddProject(
        'proj', project_id=123, summary='sum',
        description='desc')
    self.servlet = projectsummary.ProjectSummary(services=services)

  def testGatherPageData(self):
    mr = testing_helpers.MakeMonorailRequest(project=self.project)
    page_data = self.servlet.GatherPageData(mr)
    self.assertEqual('desc', page_data['formatted_project_description'])
    self.assertEqual(
        int(project_pb2.ProjectAccess.ANYONE), page_data['access_level'].key)
    self.assertEqual(0, page_data['num_stars'])
    self.assertEqual('s', page_data['plural'])

  def testGatherHelpData(self):
    mr = testing_helpers.MakeMonorailRequest(project=self.project)

    # Non-members cannot edit project, so cue is not relevant.
    mr.perms = permissions.READ_ONLY_PERMISSIONSET
    help_data = self.servlet.GatherHelpData(mr, {})
    self.assertEqual(None, help_data['cue'])

    # Members (not owners) cannot edit project, so cue is not relevant.
    mr.perms = permissions.READ_ONLY_PERMISSIONSET
    help_data = self.servlet.GatherHelpData(mr, {})
    self.assertEqual(None, help_data['cue'])

    # This is a project member who has set up mailing lists and added
    # members, but has not noted any duties.
    mr = testing_helpers.MakeMonorailRequest(project=self.project)
    self.project.issue_notify_address = 'example@domain.com'
    self.project.committer_ids.extend([111, 222])
    help_data = self.servlet.GatherHelpData(mr, {})
    self.assertEqual('document_team_duties', help_data['cue'])

    # Now help set up notes too.
    project_commitments = project_pb2.ProjectCommitments()
    project_commitments.project_id = self.project.project_id
    project_commitments.commitments.append(
        project_pb2.ProjectCommitments.MemberCommitment())
    self.servlet.services.project.TestStoreProjectCommitments(
        project_commitments)
    help_data = self.servlet.GatherHelpData(mr, {})
    self.assertEqual(None, help_data['cue'])

  def testGatherHelpData_Dismissed(self):
    mr = testing_helpers.MakeMonorailRequest(project=self.project)
    mr.auth.user_id = 111
    self.project.committer_ids.extend([111, 222])
    self.servlet.services.user.SetUserPrefs(
        'cnxn', 111,
        [user_pb2.UserPrefValue(name='document_team_duties', value='true')])
    help_data = self.servlet.GatherHelpData(mr, {})
    self.assertEqual(None, help_data['cue'])
