Project import generated by Copybara.

GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/project/test/project_helpers_test.py b/project/test/project_helpers_test.py
new file mode 100644
index 0000000..4732895
--- /dev/null
+++ b/project/test/project_helpers_test.py
@@ -0,0 +1,179 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file or at
+# https://developers.google.com/open-source/licenses/bsd
+
+"""Unit tests for helpers module."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+from mock import patch
+
+from framework import framework_views
+from framework import permissions
+from project import project_constants
+from project import project_helpers
+from proto import project_pb2
+from services import service_manager
+from testing import fake
+
+
+class HelpersUnitTest(unittest.TestCase):
+
+  def setUp(self):
+    self.cnxn = 'fake sql connection'
+    self.services = service_manager.Services(
+        project=fake.ProjectService(),
+        user=fake.UserService())
+    self.services.user.TestAddUser('a@example.com', 111)
+    self.services.user.TestAddUser('b@example.com', 222)
+    self.services.user.TestAddUser('c@example.com', 333)
+    self.users_by_id = framework_views.MakeAllUserViews(
+        'cnxn', self.services.user, [111, 222, 333])
+    self.effective_ids_by_user = {user: set() for user in {111, 222, 333}}
+
+  def testBuildProjectMembers(self):
+    project = project_pb2.MakeProject(
+        'proj', owner_ids=[111], committer_ids=[222],
+        contributor_ids=[333])
+    page_data = project_helpers.BuildProjectMembers(
+        self.cnxn, project, self.services.user)
+    self.assertEqual(111, page_data['owners'][0].user_id)
+    self.assertEqual(222, page_data['committers'][0].user_id)
+    self.assertEqual(333, page_data['contributors'][0].user_id)
+    self.assertEqual(3, len(page_data['all_members']))
+
+  def testParseUsernames(self):
+    # Form field was not present in post data.
+    id_set = project_helpers.ParseUsernames(
+        self.cnxn, self.services.user, None)
+    self.assertEqual(set(), id_set)
+
+    # Form field was present, but empty.
+    id_set = project_helpers.ParseUsernames(
+        self.cnxn, self.services.user, '')
+    self.assertEqual(set(), id_set)
+
+    # Parsing valid user names.
+    id_set = project_helpers.ParseUsernames(
+        self.cnxn, self.services.user, 'a@example.com, c@example.com')
+    self.assertEqual({111, 333}, id_set)
+
+  def testParseProjectAccess_NotOffered(self):
+    project = project_pb2.MakeProject('proj')
+    access = project_helpers.ParseProjectAccess(project, None)
+    self.assertEqual(None, access)
+
+  def testParseProjectAccess_AllowedChoice(self):
+    project = project_pb2.MakeProject('proj')
+    access = project_helpers.ParseProjectAccess(project, '1')
+    self.assertEqual(project_pb2.ProjectAccess.ANYONE, access)
+
+    access = project_helpers.ParseProjectAccess(project, '3')
+    self.assertEqual(project_pb2.ProjectAccess.MEMBERS_ONLY, access)
+
+  def testParseProjectAccess_BogusChoice(self):
+    project = project_pb2.MakeProject('proj')
+    access = project_helpers.ParseProjectAccess(project, '9')
+    self.assertEqual(None, access)
+
+  def testUsersWithPermsInProject_StandardPermission(self):
+    project = project_pb2.MakeProject('proj', committer_ids=[111])
+    perms_needed = {permissions.VIEW, permissions.EDIT_ISSUE}
+    actual = project_helpers.UsersWithPermsInProject(
+        project, perms_needed, self.users_by_id, self.effective_ids_by_user)
+    self.assertEqual(
+        {permissions.VIEW: {111, 222, 333},
+         permissions.EDIT_ISSUE: {111}},
+        actual)
+
+  def testUsersWithPermsInProject_IndirectPermission(self):
+    perms_needed = {permissions.EDIT_ISSUE}
+    # User 111 has the EDIT_ISSUE permission.
+    project = project_pb2.MakeProject('proj', committer_ids=[111])
+    # User 222 has the EDIT_ISSUE permission, because 111 is included in its
+    # effective IDs.
+    self.effective_ids_by_user[222] = {111}
+    # User 333 doesn't have the EDIT_ISSUE permission, since only direct
+    # effective IDs are taken into account.
+    self.effective_ids_by_user[333] = {222}
+    actual = project_helpers.UsersWithPermsInProject(
+        project, perms_needed, self.users_by_id, self.effective_ids_by_user)
+    self.assertEqual(
+        {permissions.EDIT_ISSUE: {111, 222}},
+        actual)
+
+  def testUsersWithPermsInProject_CustomPermission(self):
+    project = project_pb2.MakeProject('proj')
+    project.extra_perms = [
+        project_pb2.Project.ExtraPerms(
+            member_id=111,
+            perms=['FooPerm', 'BarPerm']),
+        project_pb2.Project.ExtraPerms(
+            member_id=222,
+            perms=['BarPerm'])]
+    perms_needed = {'FooPerm', 'BarPerm'}
+    actual = project_helpers.UsersWithPermsInProject(
+        project, perms_needed, self.users_by_id, self.effective_ids_by_user)
+    self.assertEqual(
+        {'FooPerm': {111},
+         'BarPerm': {111, 222}},
+        actual)
+
+  @patch('google.appengine.api.app_identity.get_default_gcs_bucket_name')
+  @patch('framework.gcs_helpers.SignUrl')
+  def testGetThumbnailUrl(self, mock_SignUrl, mock_get_default_gcs_bucket_name):
+    bucket_name = 'testbucket'
+    expected_url = 'signed/url'
+
+    mock_get_default_gcs_bucket_name.return_value = bucket_name
+    mock_SignUrl.return_value = expected_url
+
+    self.assertEqual(expected_url, project_helpers.GetThumbnailUrl('xyz'))
+    mock_get_default_gcs_bucket_name.assert_called_once()
+    mock_SignUrl.assert_called_once_with(bucket_name, 'xyz' + '-thumbnail')
+
+  def testIsValidProjectName_BadChars(self):
+    self.assertFalse(project_helpers.IsValidProjectName('spa ce'))
+    self.assertFalse(project_helpers.IsValidProjectName('under_score'))
+    self.assertFalse(project_helpers.IsValidProjectName('name.dot'))
+    self.assertFalse(project_helpers.IsValidProjectName('pie#sign$'))
+    self.assertFalse(project_helpers.IsValidProjectName('(who?)'))
+
+  def testIsValidProjectName_BadHyphen(self):
+    self.assertFalse(project_helpers.IsValidProjectName('name-'))
+    self.assertFalse(project_helpers.IsValidProjectName('-name'))
+    self.assertTrue(project_helpers.IsValidProjectName('project-name'))
+
+  def testIsValidProjectName_MinimumLength(self):
+    self.assertFalse(project_helpers.IsValidProjectName('x'))
+    self.assertTrue(project_helpers.IsValidProjectName('xy'))
+
+  def testIsValidProjectName_MaximumLength(self):
+    self.assertFalse(
+        project_helpers.IsValidProjectName(
+            'x' * (project_constants.MAX_PROJECT_NAME_LENGTH + 1)))
+    self.assertTrue(
+        project_helpers.IsValidProjectName(
+            'x' * (project_constants.MAX_PROJECT_NAME_LENGTH)))
+
+  def testIsValidProjectName_InvalidName(self):
+    self.assertFalse(project_helpers.IsValidProjectName(''))
+    self.assertFalse(project_helpers.IsValidProjectName('000'))
+
+  def testIsValidProjectName_ValidName(self):
+    self.assertTrue(project_helpers.IsValidProjectName('098asd'))
+    self.assertTrue(project_helpers.IsValidProjectName('one-two-three'))
+
+  def testAllProjectMembers(self):
+    p = project_pb2.Project()
+    self.assertEqual(project_helpers.AllProjectMembers(p), [])
+
+    p.owner_ids.extend([1, 2, 3])
+    p.committer_ids.extend([4, 5, 6])
+    p.contributor_ids.extend([7, 8, 9])
+    self.assertEqual(
+        project_helpers.AllProjectMembers(p), [1, 2, 3, 4, 5, 6, 7, 8, 9])