diff --git a/core/Command/User/Profile.php b/core/Command/User/Profile.php new file mode 100644 index 0000000000000..fd5fbed08cd48 --- /dev/null +++ b/core/Command/User/Profile.php @@ -0,0 +1,234 @@ +setName('user:profile') + ->setDescription('Read and modify user profile properties') + ->addArgument( + 'uid', + InputArgument::REQUIRED, + 'Account ID used to login' + ) + ->addArgument( + 'key', + InputArgument::OPTIONAL, + 'Profile property to set, get or delete', + '' + ) + + // Get + ->addOption( + 'default-value', + null, + InputOption::VALUE_REQUIRED, + '(Only applicable on get) If no default value is set and the property does not exist, the command will exit with 1' + ) + + // Set + ->addArgument( + 'value', + InputArgument::OPTIONAL, + 'The new value of the property', + null + ) + ->addOption( + 'update-only', + null, + InputOption::VALUE_NONE, + 'Only updates the value, if it is not set before, it is not being added' + ) + + // Delete + ->addOption( + 'delete', + null, + InputOption::VALUE_NONE, + 'Specify this option to delete the property value' + ) + ->addOption( + 'error-if-not-exists', + null, + InputOption::VALUE_NONE, + 'Checks whether the property exists before deleting it' + ) + ; + } + + protected function checkInput(InputInterface $input): IUser { + $uid = $input->getArgument('uid'); + $user = $this->userManager->get($uid); + if (!$user) { + throw new \InvalidArgumentException('The user "' . $uid . '" does not exist.'); + } + // normalize uid + $input->setArgument('uid', $user->getUID()); + + $key = $input->getArgument('key'); + if ($key === '') { + if ($input->hasParameterOption('--default-value')) { + throw new \InvalidArgumentException('The "default-value" option can only be used when specifying a key.'); + } + if ($input->getArgument('value') !== null) { + throw new \InvalidArgumentException('The value argument can only be used when specifying a key.'); + } + if ($input->getOption('delete')) { + throw new \InvalidArgumentException('The "delete" option can only be used when specifying a key.'); + } + } + + if ($input->getArgument('value') !== null && $input->hasParameterOption('--default-value')) { + throw new \InvalidArgumentException('The value argument can not be used together with "default-value".'); + } + if ($input->getOption('update-only') && $input->getArgument('value') === null) { + throw new \InvalidArgumentException('The "update-only" option can only be used together with "value".'); + } + + if ($input->getOption('delete') && $input->hasParameterOption('--default-value')) { + throw new \InvalidArgumentException('The "delete" option can not be used together with "default-value".'); + } + if ($input->getOption('delete') && $input->getArgument('value') !== null) { + throw new \InvalidArgumentException('The "delete" option can not be used together with "value".'); + } + if ($input->getOption('error-if-not-exists') && !$input->getOption('delete')) { + throw new \InvalidArgumentException('The "error-if-not-exists" option can only be used together with "delete".'); + } + + return $user; + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + try { + $user = $this->checkInput($input); + } catch (\InvalidArgumentException $e) { + $output->writeln('' . $e->getMessage() . ''); + return self::FAILURE; + } + + $uid = $input->getArgument('uid'); + $key = $input->getArgument('key'); + $userAccount = $this->accountManager->getAccount($user); + + if ($key === '') { + $settings = $this->getAllProfileProperties($userAccount); + $this->writeArrayInOutputFormat($input, $output, $settings); + return self::SUCCESS; + } + + $value = $this->getStoredValue($userAccount, $key); + $inputValue = $input->getArgument('value'); + if ($inputValue !== null) { + if ($input->hasParameterOption('--update-only') && $value === null) { + $output->writeln('The property does not exist for user "' . $uid . '".'); + return self::FAILURE; + } + + return $this->editProfileProperty($output, $userAccount, $key, $inputValue); + } elseif ($input->hasParameterOption('--delete')) { + if ($input->hasParameterOption('--error-if-not-exists') && $value === null) { + $output->writeln('The property does not exist for user "' . $uid . '".'); + return self::FAILURE; + } + + return $this->deleteProfileProperty($output, $userAccount, $key); + } elseif ($value !== null) { + $output->writeln($value); + } elseif ($input->hasParameterOption('--default-value')) { + $output->writeln($input->getOption('default-value')); + } else { + $output->writeln('The property does not exist for user "' . $uid . '".'); + return self::FAILURE; + } + + return self::SUCCESS; + } + + private function deleteProfileProperty(OutputInterface $output, IAccount $userAccount, string $key): int { + return $this->editProfileProperty($output, $userAccount, $key, ''); + } + + private function editProfileProperty(OutputInterface $output, IAccount $userAccount, string $key, string $value): int { + try { + $userAccount->getProperty($key)->setValue($value); + } catch (PropertyDoesNotExistException $exception) { + $output->writeln('' . $exception->getMessage() . ''); + return self::FAILURE; + } + + $this->accountManager->updateAccount($userAccount); + return self::SUCCESS; + } + + private function getStoredValue(IAccount $userAccount, string $key): ?string { + try { + $property = $userAccount->getProperty($key); + } catch (PropertyDoesNotExistException) { + return null; + } + return $property->getValue() === '' ? null : $property->getValue(); + } + + private function getAllProfileProperties(IAccount $userAccount): array { + $properties = []; + + foreach ($userAccount->getAllProperties() as $property) { + if ($property->getValue() !== '') { + $properties[$property->getName()] = $property->getValue(); + } + } + + return $properties; + } + + /** + * @param string $argumentName + * @param CompletionContext $context + * @return string[] + */ + public function completeArgumentValues($argumentName, CompletionContext $context): array { + if ($argumentName === 'uid') { + return array_map(static fn (IUser $user) => $user->getUID(), $this->userManager->search($context->getCurrentWord())); + } + if ($argumentName === 'key') { + $userId = $context->getWordAtIndex($context->getWordIndex() - 1); + $user = $this->userManager->get($userId); + if (!($user instanceof IUser)) { + return []; + } + + $account = $this->accountManager->getAccount($user); + + $properties = $this->getAllProfileProperties($account); + return array_keys($properties); + } + return []; + } +} diff --git a/core/register_command.php b/core/register_command.php index 72a4b70f059ca..488317d2f5ddd 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -92,6 +92,7 @@ use OC\Core\Command\User\Info; use OC\Core\Command\User\Keys\Verify; use OC\Core\Command\User\LastSeen; +use OC\Core\Command\User\Profile; use OC\Core\Command\User\Report; use OC\Core\Command\User\ResetPassword; use OC\Core\Command\User\Setting; @@ -206,6 +207,7 @@ $application->add(Server::get(Report::class)); $application->add(Server::get(ResetPassword::class)); $application->add(Server::get(Setting::class)); + $application->add(Server::get(Profile::class)); $application->add(Server::get(Command\User\ListCommand::class)); $application->add(Server::get(ClearGeneratedAvatarCacheCommand::class)); $application->add(Server::get(Info::class)); diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index e0d86d084dd0e..3bf63efce0ffb 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -1331,6 +1331,7 @@ 'OC\\Core\\Command\\User\\Keys\\Verify' => $baseDir . '/core/Command/User/Keys/Verify.php', 'OC\\Core\\Command\\User\\LastSeen' => $baseDir . '/core/Command/User/LastSeen.php', 'OC\\Core\\Command\\User\\ListCommand' => $baseDir . '/core/Command/User/ListCommand.php', + 'OC\\Core\\Command\\User\\Profile' => $baseDir . '/core/Command/User/Profile.php', 'OC\\Core\\Command\\User\\Report' => $baseDir . '/core/Command/User/Report.php', 'OC\\Core\\Command\\User\\ResetPassword' => $baseDir . '/core/Command/User/ResetPassword.php', 'OC\\Core\\Command\\User\\Setting' => $baseDir . '/core/Command/User/Setting.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 0bf675a77be8b..f076aaca78302 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -1372,6 +1372,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Command\\User\\Keys\\Verify' => __DIR__ . '/../../..' . '/core/Command/User/Keys/Verify.php', 'OC\\Core\\Command\\User\\LastSeen' => __DIR__ . '/../../..' . '/core/Command/User/LastSeen.php', 'OC\\Core\\Command\\User\\ListCommand' => __DIR__ . '/../../..' . '/core/Command/User/ListCommand.php', + 'OC\\Core\\Command\\User\\Profile' => __DIR__ . '/../../..' . '/core/Command/User/Profile.php', 'OC\\Core\\Command\\User\\Report' => __DIR__ . '/../../..' . '/core/Command/User/Report.php', 'OC\\Core\\Command\\User\\ResetPassword' => __DIR__ . '/../../..' . '/core/Command/User/ResetPassword.php', 'OC\\Core\\Command\\User\\Setting' => __DIR__ . '/../../..' . '/core/Command/User/Setting.php', diff --git a/tests/Core/Command/User/ProfileTest.php b/tests/Core/Command/User/ProfileTest.php new file mode 100644 index 0000000000000..2e3227ab56b1a --- /dev/null +++ b/tests/Core/Command/User/ProfileTest.php @@ -0,0 +1,470 @@ +accountManager = $this->createMock(IAccountManager::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->connection = $this->createMock(IDBConnection::class); + $this->consoleInput = $this->createMock(InputInterface::class); + $this->consoleOutput = $this->createMock(OutputInterface::class); + } + + public function getCommand(array $methods = []): Profile|MockObject { + if (empty($methods)) { + return new Profile($this->userManager, $this->accountManager); + } else { + return $this->getMockBuilder(Profile::class) + ->setConstructorArgs([ + $this->userManager, + $this->accountManager, + ]) + ->onlyMethods($methods) + ->getMock(); + } + } + + public static function dataCheckInput(): array { + return [ + 'Call with existing user should pass check' => [ + [['uid', 'username']], + [], + [], + true, + null, + ], + 'Call with non-existing user should fail check' => [ + [['uid', 'username']], + [], + [], + false, + 'The user "username" does not exist.', + ], + + 'Call with uid, key and --default value should pass check' => [ + [['uid', 'username'], ['key', 'configkey']], + [], + [['--default-value', false, true]], + true, + null, + ], + 'Call with uid and empty key with default-value option should fail check' => [ + [['uid', 'username'], ['key', '']], + [], + [['--default-value', false, true]], + true, + 'The "default-value" option can only be used when specifying a key.', + ], + + 'Call with uid, key, value should pass check' => [ + [['uid', 'username'], ['key', 'configkey'], ['value', '']], + [], + [], + true, + null, + ], + 'Call with uid, empty key and empty value should fail check' => [ + [['uid', 'username'], ['key', ''], ['value', '']], + [], + [], + true, + 'The value argument can only be used when specifying a key.', + ], + 'Call with uid, key, empty value and default-value option should fail check' => [ + [['uid', 'username'], ['key', 'configkey'], ['value', '']], + [], + [['--default-value', false, true]], + true, + 'The value argument can not be used together with "default-value".', + ], + 'Call with uid, key, empty value and update-only option should pass check' => [ + [['uid', 'username'], ['key', 'configkey'], ['value', '']], + [['update-only', true]], + [], + true, + null, + ], + 'Call with uid, key, null value and update-only option should fail check' => [ + [['uid', 'username'], ['key', 'configkey'], ['value', null]], + [['update-only', true]], + [], + true, + 'The "update-only" option can only be used together with "value".', + ], + + 'Call with uid, key and delete option should pass check' => [ + [['uid', 'username'], ['key', 'configkey']], + [['delete', true]], + [], + true, + null, + ], + 'Call with uid, empty key and delete option should fail check' => [ + [['uid', 'username'], ['key', '']], + [['delete', true]], + [], + true, + 'The "delete" option can only be used when specifying a key.', + ], + 'Call with uid, key, delete option and default-value should fail check' => [ + [['uid', 'username'], ['key', 'configkey']], + [['delete', true]], + [['--default-value', false, true]], + true, + 'The "delete" option can not be used together with "default-value".', + ], + 'Call with uid, key, empty value and delete option should fail check' => [ + [['uid', 'username'], ['key', 'configkey'], ['value', '']], + [['delete', true]], + [], + true, + 'The "delete" option can not be used together with "value".', + ], + 'Call with uid, key, delete and error-if-not-exists should pass check' => [ + [['uid', 'username'], ['key', 'configkey']], + [['delete', true], ['error-if-not-exists', true]], + [], + true, + null, + ], + 'Call with uid, key and error-if-not-exists should fail check' => [ + [['uid', 'username'], ['key', 'configkey']], + [['delete', false], ['error-if-not-exists', true]], + [], + true, + 'The "error-if-not-exists" option can only be used together with "delete".', + ], + ]; + } + + /** + * @dataProvider dataCheckInput + */ + public function testCheckInput(array $arguments, array $options, array $parameterOptions, bool $existingUser, ?string $expectedException): void { + $this->consoleInput->expects($this->any()) + ->method('getArgument') + ->willReturnMap($arguments); + $this->consoleInput->expects($this->any()) + ->method('getOption') + ->willReturnMap($options); + $this->consoleInput->expects($this->any()) + ->method('hasParameterOption') + ->willReturnCallback(function (string|array $values, bool $onlyParams = false) use ($parameterOptions): bool { + $arguments = func_get_args(); + foreach ($parameterOptions as $parameterOption) { + // check the arguments of the function, if they are the same, return the mocked value + if (array_diff($arguments, $parameterOption) === []) { + return end($parameterOption); + } + } + + return false; + }); + + $returnedUser = null; + if ($existingUser) { + $mockUser = $this->createMock(IUser::class); + $mockUser->expects($this->once())->method('getUID')->willReturn('user'); + $returnedUser = $mockUser; + } + $this->userManager->expects($this->once()) + ->method('get') + ->willReturn($returnedUser); + + $command = $this->getCommand(); + try { + $this->invokePrivate($command, 'checkInput', [$this->consoleInput]); + $this->assertNull($expectedException); + } catch (\InvalidArgumentException $e) { + $this->assertEquals($expectedException, $e->getMessage()); + } + } + + public function testCheckInputExceptionCatch(): void { + $command = $this->getCommand(['checkInput']); + $command->expects($this->once()) + ->method('checkInput') + ->willThrowException(new \InvalidArgumentException('test')); + + $this->consoleOutput->expects($this->once()) + ->method('writeln') + ->with('test'); + + $this->assertEquals(1, $this->invokePrivate($command, 'execute', [$this->consoleInput, $this->consoleOutput])); + } + + public static function dataExecuteDeleteProfileProperty(): array { + return [ + 'Deleting existing property should succeed' => ['address', 'Berlin', false, null, Command::SUCCESS], + 'Deleting existing property with error-if-not-exists should succeed' => ['address', 'Berlin', true, null, Command::SUCCESS], + 'Deleting non-existing property should succeed' => ['address', '', false, null, Command::SUCCESS], + 'Deleting non-existing property with error-if-not-exists should fail' => ['address', '', true, 'The property does not exist for user "username".', Command::FAILURE], + ]; + } + + /** + * Tests the deletion mechanism on profile settings. + * + * @dataProvider dataExecuteDeleteProfileProperty + */ + public function testExecuteDeleteProfileProperty(string $configKey, string $value, bool $errorIfNotExists, ?string $expectedLine, int $expectedReturn): void { + $uid = 'username'; + $appName = 'profile'; + $command = $this->getCommand([ + 'writeArrayInOutputFormat', + 'checkInput', + ]); + + $this->consoleInput->expects($this->any()) + ->method('getArgument') + ->willReturnMap([ + ['uid', $uid], + ['app', $appName], + ['key', $configKey], + ]); + + $mocks = $this->setupProfilePropertiesMock([$configKey => $value]); + + $command->expects($this->once()) + ->method('checkInput') + ->willReturn($mocks['userMock']); + + $this->consoleInput->expects($this->atLeastOnce()) + ->method('hasParameterOption') + ->willReturnMap([ + ['--delete', false, true], + ['--error-if-not-exists', false, $errorIfNotExists], + ]); + + if ($expectedLine === null) { + $this->consoleOutput->expects($this->never()) + ->method('writeln'); + $mocks['profilePropertiesMocks'][0]->expects($this->once()) + ->method('setValue') + ->with(''); + $this->accountManager->expects($this->once()) + ->method('updateAccount') + ->with($mocks['accountMock']); + } else { + $this->consoleOutput->expects($this->once()) + ->method('writeln') + ->with($expectedLine); + $this->accountManager->expects($this->never()) + ->method('updateAccount'); + } + + $this->assertEquals($expectedReturn, $this->invokePrivate($command, 'execute', [$this->consoleInput, $this->consoleOutput])); + } + + public function testExecuteSetProfileProperty(): void { + $command = $this->getCommand([ + 'writeArrayInOutputFormat', + 'checkInput', + ]); + + $uid = 'username'; + $propertyKey = 'address'; + $propertyValue = 'Barcelona'; + + $this->consoleInput->expects($this->atLeast(3)) + ->method('getArgument') + ->willReturnMap([ + ['uid', $uid], + ['key', $propertyKey], + ['value', $propertyValue], + ]); + + $mocks = $this->setupProfilePropertiesMock([$propertyKey => $propertyValue]); + + $command->expects($this->once()) + ->method('checkInput') + ->willReturn($mocks['userMock']); + + $mocks['profilePropertiesMocks'][0]->expects($this->once()) + ->method('setValue') + ->with($propertyValue); + $this->accountManager->expects($this->once()) + ->method('updateAccount') + ->with($mocks['accountMock']); + + $this->assertEquals(0, $this->invokePrivate($command, 'execute', [$this->consoleInput, $this->consoleOutput])); + } + + public static function dataExecuteGet(): array { + return [ + 'Get property with set value should pass' => ['configkey', 'value', null, 'value', Command::SUCCESS], + 'Get property with empty value and default-value option should pass' => ['configkey', '', 'default-value', 'default-value', Command::SUCCESS], + 'Get property with empty value should fail' => ['configkey', '', null, 'The property does not exist for user "username".', Command::FAILURE], + ]; + } + + /** + * @dataProvider dataExecuteGet + */ + public function testExecuteGet(string $key, string $value, ?string $defaultValue, string $expectedLine, int $expectedReturn): void { + $command = $this->getCommand([ + 'writeArrayInOutputFormat', + 'checkInput', + ]); + + $uid = 'username'; + + $this->consoleInput->expects($this->any()) + ->method('getArgument') + ->willReturnMap([ + ['uid', $uid], + ['key', $key], + ]); + + $mocks = $this->setupProfilePropertiesMock([$key => $value]); + + $command->expects($this->once()) + ->method('checkInput') + ->willReturn($mocks['userMock']); + + if ($value === '') { + if ($defaultValue === null) { + $this->consoleInput->expects($this->atLeastOnce()) + ->method('hasParameterOption') + ->willReturn(false); + } else { + $this->consoleInput->expects($this->atLeastOnce()) + ->method('hasParameterOption') + ->willReturnCallback(fn (string|array $values): bool => $values === '--default-value'); + $this->consoleInput->expects($this->once()) + ->method('getOption') + ->with('default-value') + ->willReturn($defaultValue); + } + } + + $this->consoleOutput->expects($this->once()) + ->method('writeln') + ->with($expectedLine); + + $this->assertEquals($expectedReturn, $this->invokePrivate($command, 'execute', [$this->consoleInput, $this->consoleOutput])); + } + + public function testExecuteList(): void { + $uid = 'username'; + $profileData = [ + 'pronouns' => 'they/them', + 'address' => 'Berlin', + ]; + + $command = $this->getCommand([ + 'writeArrayInOutputFormat', + 'checkInput', + ]); + + $this->consoleInput->expects($this->any()) + ->method('getArgument') + ->willReturnMap([ + ['uid', $uid], + ['key', ''], + ]); + + $mocks = $this->setupProfilePropertiesMock(['address' => $profileData['address'], 'pronouns' => $profileData['pronouns']]); + + $command->expects($this->once()) + ->method('checkInput') + ->willReturn($mocks['userMock']); + + $command->expects($this->once()) + ->method('writeArrayInOutputFormat') + ->with($this->consoleInput, $this->consoleOutput, $profileData); + + + $this->assertEquals(0, $this->invokePrivate($command, 'execute', [$this->consoleInput, $this->consoleOutput])); + } + + /** + * Helper to avoid boilerplate in tests in this file when mocking objects + * of IAccountProperty type. + * + * @param array $properties the properties to be set up as key => value + * @return array{ + * userMock: IUser&MockObject, + * accountMock: IAccount&MockObject, + * profilePropertiesMocks: IAccountProperty&MockObject[] + * } + */ + private function setupProfilePropertiesMock(array $properties): array { + $userMock = $this->createMock(IUser::class); + $accountMock = $this->createMock(IAccount::class); + $this->accountManager->expects($this->atLeastOnce()) + ->method('getAccount') + ->with($userMock) + ->willReturn($accountMock); + + /** @var IAccountProperty&MockObject[] $propertiesMocks */ + $propertiesMocks = []; + foreach ($properties as $key => $value) { + $propertiesMocks[] = $this->getAccountPropertyMock($key, $value); + } + + if (count($properties) === 1) { + $accountMock->expects($this->atLeastOnce()) + ->method('getProperty') + ->with(array_keys($properties)[0]) + ->willReturn($propertiesMocks[array_key_first($propertiesMocks)]); + } else { + $accountMock->expects($this->atLeastOnce()) + ->method('getAllProperties') + ->willReturnCallback(function () use ($propertiesMocks) { + foreach ($propertiesMocks as $property) { + yield $property; + } + }); + } + + return [ + 'userMock' => $userMock, + 'accountMock' => $accountMock, + 'profilePropertiesMocks' => $propertiesMocks, + ]; + } + + private function getAccountPropertyMock(string $name, string $value): IAccountProperty&MockObject { + $propertyMock = $this->getMockBuilder(IAccountProperty::class) + ->disableOriginalConstructor() + ->getMock(); + $propertyMock->expects($this->any()) + ->method('getName') + ->willReturn($name); + $propertyMock->expects($this->any()) + ->method('getValue') + ->willReturn($value); + + return $propertyMock; + } +} diff --git a/tests/Core/Command/User/SettingTest.php b/tests/Core/Command/User/SettingTest.php index e9e150b78de7e..dbe81c5af7890 100644 --- a/tests/Core/Command/User/SettingTest.php +++ b/tests/Core/Command/User/SettingTest.php @@ -7,44 +7,31 @@ namespace Tests\Core\Command\User; +use InvalidArgumentException; use OC\Core\Command\User\Setting; use OCP\IConfig; use OCP\IDBConnection; use OCP\IUserManager; +use PHPUnit\Framework\MockObject\MockObject; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Test\TestCase; class SettingTest extends TestCase { - /** @var \OCP\IUserManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $userManager; - /** @var \OCP\IConfig|\PHPUnit\Framework\MockObject\MockObject */ - protected $config; - /** @var \OCP\IDBConnection|\PHPUnit\Framework\MockObject\MockObject */ - protected $connection; - /** @var \Symfony\Component\Console\Input\InputInterface|\PHPUnit\Framework\MockObject\MockObject */ - protected $consoleInput; - /** @var \Symfony\Component\Console\Output\OutputInterface|\PHPUnit\Framework\MockObject\MockObject */ - protected $consoleOutput; + protected IUserManager&MockObject $userManager; + protected IConfig&MockObject $config; + protected IDBConnection&MockObject $connection; + protected InputInterface&MockObject $consoleInput; + protected MockObject&OutputInterface $consoleOutput; protected function setUp(): void { parent::setUp(); - $this->userManager = $this->getMockBuilder(IUserManager::class) - ->disableOriginalConstructor() - ->getMock(); - $this->config = $this->getMockBuilder(IConfig::class) - ->disableOriginalConstructor() - ->getMock(); - $this->connection = $this->getMockBuilder(IDBConnection::class) - ->disableOriginalConstructor() - ->getMock(); - $this->consoleInput = $this->getMockBuilder(InputInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->consoleOutput = $this->getMockBuilder(OutputInterface::class) - ->disableOriginalConstructor() - ->getMock(); + $this->userManager = $this->createMock(IUserManager::class); + $this->config = $this->createMock(IConfig::class); + $this->connection = $this->createMock(IDBConnection::class); + $this->consoleInput = $this->createMock(InputInterface::class); + $this->consoleOutput = $this->createMock(OutputInterface::class); } public function getCommand(array $methods = []) { @@ -217,7 +204,7 @@ public function testCheckInput($arguments, $options, $parameterOptions, $user, $ try { $this->invokePrivate($command, 'checkInput', [$this->consoleInput]); $this->assertFalse($expectedException); - } catch (\InvalidArgumentException $e) { + } catch (InvalidArgumentException $e) { $this->assertEquals($expectedException, $e->getMessage()); } } @@ -226,7 +213,7 @@ public function testCheckInputExceptionCatch(): void { $command = $this->getCommand(['checkInput']); $command->expects($this->once()) ->method('checkInput') - ->willThrowException(new \InvalidArgumentException('test')); + ->willThrowException(new InvalidArgumentException('test')); $this->consoleOutput->expects($this->once()) ->method('writeln')