From 4b8cd326b2af13cdb26840791fcf8d570c9bf5bd Mon Sep 17 00:00:00 2001 From: provokateurin Date: Tue, 20 Jan 2026 10:21:07 +0100 Subject: [PATCH] test(UserPlugin): Rewrite unit tests as integration tests Signed-off-by: provokateurin --- .../sharees_features/sharees_user.feature | 415 +++++++++ .../Collaborators/UserPluginTest.php | 815 ------------------ 2 files changed, 415 insertions(+), 815 deletions(-) create mode 100644 build/integration/sharees_features/sharees_user.feature delete mode 100644 tests/lib/Collaboration/Collaborators/UserPluginTest.php diff --git a/build/integration/sharees_features/sharees_user.feature b/build/integration/sharees_features/sharees_user.feature new file mode 100644 index 00000000000..3d8cbbb743a --- /dev/null +++ b/build/integration/sharees_features/sharees_user.feature @@ -0,0 +1,415 @@ +# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later +Feature: sharees_user + + Background: + Given using api version "1" + + Scenario: Search for userid returns exact user + Given user "test" with displayname "Test" exists + And user "user1" exists + And As an "user1" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned are + | Test | 0 | test | test | + And "users" sharees returned is empty + + Scenario: Search for userid returns exact user without sharee enumeration + Given user "test" with displayname "Test" exists + And user "user1" exists + And As an "user1" + And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned are + | Test | 0 | test | test | + And "users" sharees returned is empty + + Scenario: Search for userid without shared group returns nothing with sharing in group only + Given user "test" with displayname "Test" exists + And group "test-group" exists + And user "test" belongs to group "test-group" + And user "user1" exists + And As an "user1" + And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned is empty + And "users" sharees returned is empty + + Scenario: Search for userid without shared group returns nothing with sharing in group only and without sharee enumeration + Given user "test" with displayname "Test" exists + And group "test-group" exists + And user "test" belongs to group "test-group" + And user "user1" exists + And As an "user1" + And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes" + And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned is empty + And "users" sharees returned is empty + + Scenario: Search for userid with shared group returns exact user with sharing in group only + Given user "test" with displayname "Test" exists + And group "test-group" exists + And user "test" belongs to group "test-group" + And user "user1" exists + And user "user1" belongs to group "test-group" + And As an "user1" + And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned are + | Test | 0 | test | test | + And "users" sharees returned is empty + + Scenario: Search for userid with shared group returns exact user with sharing in group only and without sharee enumeration + Given user "test" with displayname "Test" exists + And group "test-group" exists + And user "test" belongs to group "test-group" + And user "user1" exists + And user "user1" belongs to group "test-group" + And As an "user1" + And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes" + And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned are + | Test | 0 | test | test | + And "users" sharees returned is empty + + Scenario: Search for part of userid returns wide user + Given user "test1" with displayname "Test One" exists + And user "user1" exists + And As an "user1" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned is empty + And "users" sharees returned are + | Test One | 0 | test1 | test1 | + + Scenario: Search for part of userid returns nothing without sharee enumeration + Given user "test1" with displayname "Test One" exists + And user "user1" exists + And As an "user1" + And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned is empty + And "users" sharees returned is empty + + Scenario: Search for part of userid returns wide users + Given user "test1" with displayname "Test One" exists + And user "test2" with displayname "Test Two" exists + And user "user1" exists + And As an "user1" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned is empty + And "users" sharees returned are + | Test One | 0 | test1 | test1 | + | Test Two | 0 | test2 | test2 | + + Scenario: Search for part of userid returns nothing without sharee enumeration + Given user "test1" with displayname "Test One" exists + And user "test2" with displayname "Test Two" exists + And user "user1" exists + And As an "user1" + And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned is empty + And "users" sharees returned is empty + + Scenario: Search for part of displayname returns exact user and wide users + Given user "test0" with displayname "Test" exists + And user "test1" with displayname "Test One" exists + And user "test2" with displayname "Test Two" exists + And user "user1" exists + And As an "user1" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned are + | Test | 0 | test0 | test0 | + And "users" sharees returned are + | Test One | 0 | test1 | test1 | + | Test Two | 0 | test2 | test2 | + + Scenario: Search for part of displayname returns exact user without sharee enumeration + Given user "test0" with displayname "Test" exists + And user "test1" with displayname "Test One" exists + And user "test2" with displayname "Test Two" exists + And user "user1" exists + And As an "user1" + And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned are + | Test | 0 | test0 | test0 | + And "users" sharees returned is empty + + Scenario: Search for part of userid with shared group returns wide user with sharing in group only + Given user "test1" with displayname "Test One" exists + And group "abc" exists + And user "test1" belongs to group "abc" + And group "xyz" exists + And user "user1" exists + And user "user1" belongs to group "abc" + And user "user1" belongs to group "xyz" + And As an "user1" + And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned is empty + And "users" sharees returned are + | Test One | 0 | test1 | test1 | + + Scenario: Search for part of userid with shared group returns nothing with sharing in group only and without sharee enumeration + Given user "test1" with displayname "Test One" exists + And group "abc" exists + And user "test1" belongs to group "abc" + And group "xyz" exists + And user "user1" exists + And user "user1" belongs to group "abc" + And user "user1" belongs to group "xyz" + And As an "user1" + And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes" + And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned is empty + And "users" sharees returned is empty + + Scenario: Search for part of userid with shared groups returns wide users with sharing in group only + Given user "test1" with displayname "Test One" exists + And user "test2" with displayname "Test Two" exists + And group "abc" exists + And user "test1" belongs to group "abc" + And user "test2" belongs to group "abc" + And group "xyz" exists + And user "test1" belongs to group "xyz" + And user "test2" belongs to group "xyz" + And user "user1" exists + And user "user1" belongs to group "abc" + And user "user1" belongs to group "xyz" + And As an "user1" + And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned is empty + And "users" sharees returned are + | Test One | 0 | test1 | test1 | + | Test Two | 0 | test2 | test2 | + + Scenario: Search for part of userid with shared groups returns nothing with sharing in group only and without sharee enumeration + Given user "test1" with displayname "Test One" exists + And user "test2" with displayname "Test Two" exists + And group "abc" exists + And user "test1" belongs to group "abc" + And user "test2" belongs to group "abc" + And group "xyz" exists + And user "test1" belongs to group "xyz" + And user "test2" belongs to group "xyz" + And user "user1" exists + And user "user1" belongs to group "abc" + And user "user1" belongs to group "xyz" + And As an "user1" + And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes" + And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned is empty + And "users" sharees returned is empty + + Scenario: Search for part of userid with shared groups returns exact user and wide user with sharing in group only + Given user "test" with displayname "Test One" exists + And user "test2" with displayname "Test Two" exists + And group "abc" exists + And user "test" belongs to group "abc" + And group "xyz" exists + And user "test2" belongs to group "xyz" + And user "user1" exists + And user "user1" belongs to group "abc" + And user "user1" belongs to group "xyz" + And As an "user1" + And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned are + | Test One | 0 | test | test | + And "users" sharees returned are + | Test Two | 0 | test2 | test2 | + + Scenario: Search for part of userid with shared groups returns exact user with sharing in group only and without sharee enumeration + Given user "test" with displayname "Test One" exists + And user "test2" with displayname "Test Two" exists + And group "abc" exists + And user "test" belongs to group "abc" + And group "xyz" exists + And user "test2" belongs to group "xyz" + And user "user1" exists + And user "user1" belongs to group "abc" + And user "user1" belongs to group "xyz" + And As an "user1" + And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes" + And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned are + | Test One | 0 | test | test | + And "users" sharees returned is empty + + Scenario: Search for part of userid with shared group returns wide user with sharee enumeration limited to group + Given user "test" with displayname "foo" exists + And user "test1" exists + And user "test2" exists + And group "groupA" exists + And group "groupB" exists + And user "test" belongs to group "groupA" + And user "test1" belongs to group "groupA" + And user "test2" belongs to group "groupB" + And As an "test" + And parameter "shareapi_restrict_user_enumeration_to_group" of app "core" is set to "yes" + When getting sharees for + | search | test | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned is empty + And "users" sharees returned are + | test1 | 0 | test1 | test1 | + + Scenario: Search for exact userid with shared group returns nothing without sharee enumeration and without full match userid enumeration + Given user "test" with displayname "foo" exists + And user "test1" with displayname "Test One" exists + And user "test2" with displayname "Test Two" exists + And group "groupA" exists + And user "test" belongs to group "groupA" + And user "test1" belongs to group "groupA" + And user "test2" belongs to group "groupA" + And As an "test" + And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no" + And parameter "shareapi_restrict_user_enumeration_full_match_userid" of app "core" is set to "no" + When getting sharees for + | search | test1 | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned is empty + And "users" sharees returned is empty + + Scenario: Search for displayname returns exact user without sharee enumeration and without full match userid enumeration + Given user "test" with displayname "foo" exists + And user "test1" with displayname "Test One" exists + And user "test2" with displayname "Test Two" exists + And group "groupA" exists + And user "test" belongs to group "groupA" + And user "test1" belongs to group "groupA" + And user "test2" belongs to group "groupA" + And As an "test" + And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no" + And parameter "shareapi_restrict_user_enumeration_full_match_user_id" of app "core" is set to "no" + When getting sharees for + | search | Test One | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned are + | Test One | 0 | test1 | test1 | + And "users" sharees returned is empty + + Scenario: Search for part of displayname returns exact user without sharee enumeration and with ignoring full match of second displayname + Given user "test" with displayname "foo" exists + And user "test1" with displayname "Test One (Second displayname for user 1)" exists + And user "test2" with displayname "Test Two (Second displayname for user 2)" exists + And group "groupA" exists + And user "test" belongs to group "groupA" + And user "test1" belongs to group "groupA" + And user "test2" belongs to group "groupA" + And As an "test" + And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no" + And parameter "shareapi_restrict_user_enumeration_full_match_ignore_second_dn" of app "core" is set to "yes" + When getting sharees for + | search | Test One | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned are + | Test One (Second displayname for user 1) | 0 | test1 | test1 | + And "users" sharees returned is empty + + Scenario: Search for exact userid with shared group returns exact user with sharee enumeration limited to group + Given user "test" with displayname "foo" exists + And user "test1" exists + And user "test2" exists + And group "groupA" exists + And group "groupB" exists + And user "test" belongs to group "groupA" + And user "test1" belongs to group "groupA" + And user "test2" belongs to group "groupB" + And As an "test" + And parameter "shareapi_restrict_user_enumeration_to_group" of app "core" is set to "yes" + When getting sharees for + | search | test1 | + | itemType | file | + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And "exact users" sharees returned are + | test1 | 0 | test1 | test1 | + And "users" sharees returned is empty diff --git a/tests/lib/Collaboration/Collaborators/UserPluginTest.php b/tests/lib/Collaboration/Collaborators/UserPluginTest.php deleted file mode 100644 index 35071ca96f9..00000000000 --- a/tests/lib/Collaboration/Collaborators/UserPluginTest.php +++ /dev/null @@ -1,815 +0,0 @@ -config = $this->createMock(IConfig::class); - - $this->userManager = $this->createMock(IUserManager::class); - - $this->groupManager = $this->createMock(IGroupManager::class); - - $this->session = $this->createMock(IUserSession::class); - - $this->knownUserService = $this->createMock(KnownUserService::class); - - $this->userStatusManager = $this->createMock(IUserStatusManager::class); - - $this->searchResult = new SearchResult(); - - $this->user = $this->getUserMock('admin', 'Administrator'); - } - - public function instantiatePlugin() { - // cannot be done within setUp, because dependent mocks needs to be set - // up with configuration etc. first - $this->plugin = new UserPlugin( - $this->config, - $this->userManager, - $this->groupManager, - $this->session, - $this->knownUserService, - $this->userStatusManager - ); - } - - public function mockConfig($mockedSettings) { - $this->config->expects($this->any()) - ->method('getAppValue') - ->willReturnCallback( - function ($appName, $key, $default) use ($mockedSettings) { - return $mockedSettings[$appName][$key] ?? $default; - } - ); - } - - public function getUserMock($uid, $displayName, $enabled = true, $groups = []) { - $user = $this->createMock(IUser::class); - - $user->expects($this->any()) - ->method('getUID') - ->willReturn($uid); - - $user->expects($this->any()) - ->method('getDisplayName') - ->willReturn($displayName); - - $user->expects($this->any()) - ->method('isEnabled') - ->willReturn($enabled); - - return $user; - } - - public function getGroupMock($gid) { - $group = $this->createMock(IGroup::class); - - $group->expects($this->any()) - ->method('getGID') - ->willReturn($gid); - - return $group; - } - - public function dataGetUsers() { - return [ - ['test', false, true, [], [], [], [], true, false], - ['test', false, false, [], [], [], [], true, false], - ['test', true, true, [], [], [], [], true, false], - ['test', true, false, [], [], [], [], true, false], - [ - 'test', false, true, [], [], - [ - ['label' => 'Test', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test'], - ], [], true, $this->getUserMock('test', 'Test'), - ], - [ - 'test', false, false, [], [], - [ - ['label' => 'Test', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test'], - ], [], true, $this->getUserMock('test', 'Test'), - ], - [ - 'test', true, true, [], [], - [], [], true, $this->getUserMock('test', 'Test'), - ], - [ - 'test', true, false, [], [], - [], [], true, $this->getUserMock('test', 'Test'), - ], - [ - 'test', true, true, ['test-group'], [['test-group', 'test', 2, 0, []]], - [ - ['label' => 'Test', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test'], - ], [], true, $this->getUserMock('test', 'Test'), - ], - [ - 'test', true, false, ['test-group'], [['test-group', 'test', 2, 0, []]], - [ - ['label' => 'Test', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test'], - ], [], true, $this->getUserMock('test', 'Test'), - ], - [ - 'test', - false, - true, - [], - [ - $this->getUserMock('test1', 'Test One'), - ], - [], - [ - ['label' => 'Test One', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test1'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test1'], - ], - true, - false, - ], - [ - 'test', - false, - false, - [], - [ - $this->getUserMock('test1', 'Test One'), - ], - [], - [], - true, - false, - ], - [ - 'test', - false, - true, - [], - [ - $this->getUserMock('test1', 'Test One'), - $this->getUserMock('test2', 'Test Two'), - ], - [], - [ - ['label' => 'Test One', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test1'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test1'], - ['label' => 'Test Two', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test2'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test2'], - ], - false, - false, - ], - [ - 'test', - false, - false, - [], - [ - $this->getUserMock('test1', 'Test One'), - $this->getUserMock('test2', 'Test Two'), - ], - [], - [], - true, - false, - ], - [ - 'test', - false, - true, - [], - [ - $this->getUserMock('test0', 'Test'), - $this->getUserMock('test1', 'Test One'), - $this->getUserMock('test2', 'Test Two'), - ], - [ - ['label' => 'Test', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test0'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test0'], - ], - [ - ['label' => 'Test One', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test1'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test1'], - ['label' => 'Test Two', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test2'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test2'], - ], - false, - false, - ], - [ - 'test', - false, - true, - [], - [ - $this->getUserMock('test0', 'Test'), - $this->getUserMock('test1', 'Test One'), - $this->getUserMock('test2', 'Test Two'), - ], - [ - ['label' => 'Test', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test0'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test0'], - ], - [ - ['label' => 'Test One', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test1'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test1'], - ['label' => 'Test Two', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test2'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test2'], - ], - false, - false, - [], - true, - ], - [ - 'test', - false, - false, - [], - [ - $this->getUserMock('test0', 'Test'), - $this->getUserMock('test1', 'Test One'), - $this->getUserMock('test2', 'Test Two'), - ], - [ - ['label' => 'Test', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test0'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test0'], - ], - [], - true, - false, - ], - [ - 'test', - true, - true, - ['abc', 'xyz'], - [ - ['abc', 'test', 2, 0, ['test1' => 'Test One']], - ['xyz', 'test', 2, 0, []], - ], - [], - [ - ['label' => 'Test One', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test1'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test1'], - ], - true, - false, - [['test1', $this->getUserMock('test1', 'Test One')]], - ], - [ - 'test', - true, - false, - ['abc', 'xyz'], - [ - ['abc', 'test', 2, 0, ['test1' => 'Test One']], - ['xyz', 'test', 2, 0, []], - ], - [], - [], - true, - false, - [['test1', $this->getUserMock('test1', 'Test One')]], - ], - [ - 'test', - true, - true, - ['abc', 'xyz'], - [ - ['abc', 'test', 2, 0, [ - 'test1' => 'Test One', - 'test2' => 'Test Two', - ]], - ['xyz', 'test', 2, 0, [ - 'test1' => 'Test One', - 'test2' => 'Test Two', - ]], - ], - [], - [ - ['label' => 'Test One', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test1'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test1'], - ['label' => 'Test Two', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test2'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test2'], - ], - true, - false, - [ - ['test1', $this->getUserMock('test1', 'Test One')], - ['test2', $this->getUserMock('test2', 'Test Two')], - ], - ], - [ - 'test', - true, - false, - ['abc', 'xyz'], - [ - ['abc', 'test', 2, 0, [ - 'test1' => 'Test One', - 'test2' => 'Test Two', - ]], - ['xyz', 'test', 2, 0, [ - 'test1' => 'Test One', - 'test2' => 'Test Two', - ]], - ], - [], - [], - true, - false, - [ - ['test1', $this->getUserMock('test1', 'Test One')], - ['test2', $this->getUserMock('test2', 'Test Two')], - ], - ], - [ - 'test', - true, - true, - ['abc', 'xyz'], - [ - ['abc', 'test', 2, 0, [ - 'test' => 'Test One', - ]], - ['xyz', 'test', 2, 0, [ - 'test2' => 'Test Two', - ]], - ], - [ - ['label' => 'Test One', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test'], - ], - [ - ['label' => 'Test Two', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test2'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test2'], - ], - false, - false, - [ - ['test', $this->getUserMock('test', 'Test One')], - ['test2', $this->getUserMock('test2', 'Test Two')], - ], - ], - [ - 'test', - true, - false, - ['abc', 'xyz'], - [ - ['abc', 'test', 2, 0, [ - 'test' => 'Test One', - ]], - ['xyz', 'test', 2, 0, [ - 'test2' => 'Test Two', - ]], - ], - [ - ['label' => 'Test One', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'icon' => 'icon-user', 'subline' => null, 'status' => [], 'shareWithDisplayNameUnique' => 'test'], - ], - [], - true, - false, - [ - ['test', $this->getUserMock('test', 'Test One')], - ['test2', $this->getUserMock('test2', 'Test Two')], - ], - ], - ]; - } - - /** - * @dataProvider dataGetUsers - * - * @param string $searchTerm - * @param bool $shareWithGroupOnly - * @param bool $shareeEnumeration - * @param array $groupResponse - * @param array $userResponse - * @param array $exactExpected - * @param array $expected - * @param bool $reachedEnd - * @param bool|IUser $singleUser - * @param array $users - */ - public function testSearch( - $searchTerm, - $shareWithGroupOnly, - $shareeEnumeration, - array $groupResponse, - array $userResponse, - array $exactExpected, - array $expected, - $reachedEnd, - $singleUser, - array $users = [], - $shareeEnumerationPhone = false, - ): void { - $this->mockConfig(['core' => [ - 'shareapi_only_share_with_group_members' => $shareWithGroupOnly ? 'yes' : 'no', - 'shareapi_allow_share_dialog_user_enumeration' => $shareeEnumeration? 'yes' : 'no', - 'shareapi_restrict_user_enumeration_to_group' => false ? 'yes' : 'no', - 'shareapi_restrict_user_enumeration_to_phone' => $shareeEnumerationPhone ? 'yes' : 'no', - ]]); - - $this->instantiatePlugin(); - - $this->session->expects($this->any()) - ->method('getUser') - ->willReturn($this->user); - - $this->userManager->expects($this->any()) - ->method('searchDisplayName') - ->willReturn($userResponse); - - if (!$shareWithGroupOnly) { - if ($shareeEnumerationPhone) { - $this->userManager->expects($this->once()) - ->method('searchKnownUsersByDisplayName') - ->with($this->user->getUID(), $searchTerm, $this->limit, $this->offset) - ->willReturn($userResponse); - - $this->knownUserService->method('isKnownToUser') - ->willReturnMap([ - [$this->user->getUID(), 'test0', true], - [$this->user->getUID(), 'test1', true], - [$this->user->getUID(), 'test2', true], - ]); - } else { - $this->userManager->expects($this->once()) - ->method('searchDisplayName') - ->with($searchTerm, $this->limit, $this->offset) - ->willReturn($userResponse); - } - } else { - $this->groupManager->method('getUserGroupIds') - ->with($this->user) - ->willReturn($groupResponse); - - if ($singleUser !== false) { - $this->groupManager->method('getUserGroupIds') - ->with($singleUser) - ->willReturn($groupResponse); - } - - $this->groupManager->method('displayNamesInGroup') - ->willReturnMap($userResponse); - } - - if ($singleUser !== false) { - $users[] = [$searchTerm, $singleUser]; - } - - if (!empty($users)) { - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturnMap($users); - } - - $moreResults = $this->plugin->search($searchTerm, $this->limit, $this->offset, $this->searchResult); - $result = $this->searchResult->asArray(); - - $this->assertEquals($exactExpected, $result['exact']['users']); - $this->assertEquals($expected, $result['users']); - $this->assertSame($reachedEnd, $moreResults); - } - - public function takeOutCurrentUserProvider() { - $inputUsers = [ - 'alice' => 'Alice', - 'bob' => 'Bob', - 'carol' => 'Carol', - ]; - return [ - [ - $inputUsers, - ['alice', 'carol'], - 'bob', - ], - [ - $inputUsers, - ['alice', 'bob', 'carol'], - 'dave', - ], - [ - $inputUsers, - ['alice', 'bob', 'carol'], - null, - ], - ]; - } - - /** - * @dataProvider takeOutCurrentUserProvider - * @param array $users - * @param array $expectedUIDs - * @param $currentUserId - */ - public function testTakeOutCurrentUser(array $users, array $expectedUIDs, $currentUserId): void { - $this->instantiatePlugin(); - - $this->session->expects($this->once()) - ->method('getUser') - ->willReturnCallback(function () use ($currentUserId) { - if ($currentUserId !== null) { - return $this->getUserMock($currentUserId, $currentUserId); - } - return null; - }); - - $this->plugin->takeOutCurrentUser($users); - $this->assertSame($expectedUIDs, array_keys($users)); - } - - public function dataSearchEnumeration() { - return [ - [ - 'test', - ['groupA'], - [ - ['uid' => 'test1', 'groups' => ['groupA']], - ['uid' => 'test2', 'groups' => ['groupB']], - ], - ['exact' => [], 'wide' => ['test1']], - ['core' => ['shareapi_restrict_user_enumeration_to_group' => 'yes']], - ], - [ - 'test', - ['groupA'], - [ - ['uid' => 'test1', 'displayName' => 'Test user 1', 'groups' => ['groupA']], - ['uid' => 'test2', 'displayName' => 'Test user 2', 'groups' => ['groupA']], - ], - ['exact' => [], 'wide' => []], - ['core' => ['shareapi_allow_share_dialog_user_enumeration' => 'no']], - ], - [ - 'test1', - ['groupA'], - [ - ['uid' => 'test1', 'displayName' => 'Test user 1', 'groups' => ['groupA']], - ['uid' => 'test2', 'displayName' => 'Test user 2', 'groups' => ['groupA']], - ], - ['exact' => ['test1'], 'wide' => []], - ['core' => ['shareapi_allow_share_dialog_user_enumeration' => 'no']], - ], - [ - 'test1', - ['groupA'], - [ - ['uid' => 'test1', 'displayName' => 'Test user 1', 'groups' => ['groupA']], - ['uid' => 'test2', 'displayName' => 'Test user 2', 'groups' => ['groupA']], - ], - ['exact' => [], 'wide' => []], - [ - 'core' => [ - 'shareapi_allow_share_dialog_user_enumeration' => 'no', - 'shareapi_restrict_user_enumeration_full_match_userid' => 'no', - ], - ] - ], - [ - 'Test user 1', - ['groupA'], - [ - ['uid' => 'test1', 'displayName' => 'Test user 1', 'groups' => ['groupA']], - ['uid' => 'test2', 'displayName' => 'Test user 2', 'groups' => ['groupA']], - ], - ['exact' => ['test1'], 'wide' => []], - [ - 'core' => [ - 'shareapi_allow_share_dialog_user_enumeration' => 'no', - 'shareapi_restrict_user_enumeration_full_match_userid' => 'no', - ], - ] - ], - [ - 'Test user 1', - ['groupA'], - [ - ['uid' => 'test1', 'displayName' => 'Test user 1 (Second displayName for user 1)', 'groups' => ['groupA']], - ['uid' => 'test2', 'displayName' => 'Test user 2 (Second displayName for user 2)', 'groups' => ['groupA']], - ], - ['exact' => [], 'wide' => []], - ['core' => ['shareapi_allow_share_dialog_user_enumeration' => 'no'], - ] - ], - [ - 'Test user 1', - ['groupA'], - [ - ['uid' => 'test1', 'displayName' => 'Test user 1 (Second displayName for user 1)', 'groups' => ['groupA']], - ['uid' => 'test2', 'displayName' => 'Test user 2 (Second displayName for user 2)', 'groups' => ['groupA']], - ], - ['exact' => ['test1'], 'wide' => []], - [ - 'core' => [ - 'shareapi_allow_share_dialog_user_enumeration' => 'no', - 'shareapi_restrict_user_enumeration_full_match_ignore_second_dn' => 'yes', - ], - ] - ], - [ - 'test1', - ['groupA'], - [ - ['uid' => 'test1', 'groups' => ['groupA']], - ['uid' => 'test2', 'groups' => ['groupB']], - ], - ['exact' => ['test1'], 'wide' => []], - ['core' => ['shareapi_restrict_user_enumeration_to_group' => 'yes']], - ], - [ - 'test', - ['groupA'], - [ - ['uid' => 'test1', 'groups' => ['groupA']], - ['uid' => 'test2', 'groups' => ['groupB', 'groupA']], - ], - ['exact' => [], 'wide' => ['test1', 'test2']], - ['core' => ['shareapi_restrict_user_enumeration_to_group' => 'yes']], - ], - [ - 'test', - ['groupA'], - [ - ['uid' => 'test1', 'groups' => ['groupA', 'groupC']], - ['uid' => 'test2', 'groups' => ['groupB', 'groupA']], - ], - ['exact' => [], 'wide' => ['test1', 'test2']], - ['core' => ['shareapi_restrict_user_enumeration_to_group' => 'yes']], - ], - [ - 'test', - ['groupC', 'groupB'], - [ - ['uid' => 'test1', 'groups' => ['groupA', 'groupC']], - ['uid' => 'test2', 'groups' => ['groupB', 'groupA']], - ], - ['exact' => [], 'wide' => ['test1', 'test2']], - ['core' => ['shareapi_restrict_user_enumeration_to_group' => 'yes']], - ], - [ - 'test', - [], - [ - ['uid' => 'test1', 'groups' => ['groupA']], - ['uid' => 'test2', 'groups' => ['groupB', 'groupA']], - ], - ['exact' => [], 'wide' => []], - ['core' => ['shareapi_restrict_user_enumeration_to_group' => 'yes']], - ], - [ - 'test', - ['groupC', 'groupB'], - [ - ['uid' => 'test1', 'groups' => []], - ['uid' => 'test2', 'groups' => []], - ], - ['exact' => [], 'wide' => []], - ['core' => ['shareapi_restrict_user_enumeration_to_group' => 'yes']], - ], - [ - 'test', - ['groupC', 'groupB'], - [ - ['uid' => 'test1', 'groups' => []], - ['uid' => 'test2', 'groups' => []], - ], - ['exact' => [], 'wide' => []], - ['core' => ['shareapi_restrict_user_enumeration_to_group' => 'yes']], - ], - ]; - } - - /** - * @dataProvider dataSearchEnumeration - */ - public function testSearchEnumerationLimit($search, $userGroups, $matchingUsers, $result, $mockedSettings): void { - $this->mockConfig($mockedSettings); - - $userResults = []; - foreach ($matchingUsers as $user) { - $userResults[$user['uid']] = $user['uid']; - } - - $usersById = []; - foreach ($matchingUsers as $user) { - $usersById[$user['uid']] = $user; - } - - $mappedResultExact = array_map(function ($user) use ($usersById, $search) { - return [ - 'label' => $search === $user ? $user : $usersById[$user]['displayName'], - 'value' => ['shareType' => 0, 'shareWith' => $user], - 'icon' => 'icon-user', - 'subline' => null, - 'status' => [], - 'shareWithDisplayNameUnique' => $user, - ]; - }, $result['exact']); - $mappedResultWide = array_map(function ($user) { - return [ - 'label' => $user, - 'value' => ['shareType' => 0, 'shareWith' => $user], - 'icon' => 'icon-user', - 'subline' => null, - 'status' => [], - 'shareWithDisplayNameUnique' => $user, - ]; - }, $result['wide']); - - $this->userManager - ->method('get') - ->willReturnCallback(function ($userId) use ($userResults) { - if (isset($userResults[$userId])) { - return $this->getUserMock($userId, $userId); - } - return null; - }); - $this->userManager - ->method('searchDisplayName') - ->willReturnCallback(function ($search) use ($matchingUsers) { - $users = array_filter( - $matchingUsers, - fn ($user) => str_contains(strtolower($user['displayName'] ?? $user['uid']), strtolower($search)) - ); - return array_map( - fn ($user) => $this->getUserMock($user['uid'], $user['displayName'] ?? $user['uid']), - $users); - }); - - $this->groupManager->method('displayNamesInGroup') - ->willReturn($userResults); - - - $this->session->expects($this->any()) - ->method('getUser') - ->willReturn($this->getUserMock('test', 'foo')); - $this->groupManager->expects($this->any()) - ->method('getUserGroupIds') - ->willReturnCallback(function ($user) use ($matchingUsers, $userGroups) { - static $firstCall = true; - if ($firstCall) { - $firstCall = false; - // current user - return $userGroups; - } - $neededObject = array_filter( - $matchingUsers, - function ($e) use ($user) { - return $user->getUID() === $e['uid']; - } - ); - if (count($neededObject) > 0) { - return array_shift($neededObject)['groups']; - } - return []; - }); - - $this->instantiatePlugin(); - $this->plugin->search($search, $this->limit, $this->offset, $this->searchResult); - $result = $this->searchResult->asArray(); - - $this->assertEquals($mappedResultExact, $result['exact']['users']); - $this->assertEquals($mappedResultWide, $result['users']); - } -}