diff options
Diffstat (limited to 'tests/Core/Command/Config')
-rw-r--r-- | tests/Core/Command/Config/App/DeleteConfigTest.php | 99 | ||||
-rw-r--r-- | tests/Core/Command/Config/App/GetConfigTest.php | 138 | ||||
-rw-r--r-- | tests/Core/Command/Config/App/SetConfigTest.php | 107 | ||||
-rw-r--r-- | tests/Core/Command/Config/ImportTest.php | 169 | ||||
-rw-r--r-- | tests/Core/Command/Config/ListConfigsTest.php | 328 | ||||
-rw-r--r-- | tests/Core/Command/Config/System/CastHelperTest.php | 66 | ||||
-rw-r--r-- | tests/Core/Command/Config/System/DeleteConfigTest.php | 207 | ||||
-rw-r--r-- | tests/Core/Command/Config/System/GetConfigTest.php | 161 | ||||
-rw-r--r-- | tests/Core/Command/Config/System/SetConfigTest.php | 115 |
9 files changed, 1390 insertions, 0 deletions
diff --git a/tests/Core/Command/Config/App/DeleteConfigTest.php b/tests/Core/Command/Config/App/DeleteConfigTest.php new file mode 100644 index 00000000000..9e43f389214 --- /dev/null +++ b/tests/Core/Command/Config/App/DeleteConfigTest.php @@ -0,0 +1,99 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Tests\Core\Command\Config\App; + +use OC\Config\ConfigManager; +use OC\Core\Command\Config\App\DeleteConfig; +use OCP\IAppConfig; +use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Test\TestCase; + +class DeleteConfigTest extends TestCase { + protected IAppConfig&MockObject $appConfig; + protected ConfigManager&MockObject $configManager; + protected InputInterface&MockObject $consoleInput; + protected OutputInterface&MockObject $consoleOutput; + protected Command $command; + + protected function setUp(): void { + parent::setUp(); + + $this->appConfig = $this->createMock(IAppConfig::class); + $this->configManager = $this->createMock(ConfigManager::class); + $this->consoleInput = $this->createMock(InputInterface::class); + $this->consoleOutput = $this->createMock(OutputInterface::class); + + $this->command = new DeleteConfig($this->appConfig, $this->configManager); + } + + + public static function dataDelete(): array { + return [ + [ + 'name', + true, + true, + 0, + 'info', + ], + [ + 'name', + true, + false, + 0, + 'info', + ], + [ + 'name', + false, + false, + 0, + 'info', + ], + [ + 'name', + false, + true, + 1, + 'error', + ], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataDelete')] + public function testDelete(string $configName, bool $configExists, bool $checkIfExists, int $expectedReturn, string $expectedMessage): void { + $this->appConfig->expects(($checkIfExists) ? $this->once() : $this->never()) + ->method('getKeys') + ->with('app-name') + ->willReturn($configExists ? [$configName] : []); + + $this->appConfig->expects(($expectedReturn === 0) ? $this->once() : $this->never()) + ->method('deleteKey') + ->with('app-name', $configName); + + $this->consoleInput->expects($this->exactly(2)) + ->method('getArgument') + ->willReturnMap([ + ['app', 'app-name'], + ['name', $configName], + ]); + $this->consoleInput->method('hasParameterOption') + ->with('--error-if-not-exists') + ->willReturn($checkIfExists); + + $this->consoleOutput->method('writeln') + ->with($this->stringContains($expectedMessage)); + + $this->assertSame($expectedReturn, self::invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput])); + } +} diff --git a/tests/Core/Command/Config/App/GetConfigTest.php b/tests/Core/Command/Config/App/GetConfigTest.php new file mode 100644 index 00000000000..13392cddf55 --- /dev/null +++ b/tests/Core/Command/Config/App/GetConfigTest.php @@ -0,0 +1,138 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Tests\Core\Command\Config\App; + +use OC\Config\ConfigManager; +use OC\Core\Command\Config\App\GetConfig; +use OCP\Exceptions\AppConfigUnknownKeyException; +use OCP\IAppConfig; +use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Test\TestCase; + +class GetConfigTest extends TestCase { + protected IAppConfig&MockObject $appConfig; + protected ConfigManager&MockObject $configManager; + protected InputInterface&MockObject $consoleInput; + protected OutputInterface&MockObject $consoleOutput; + protected Command $command; + + protected function setUp(): void { + parent::setUp(); + + $this->appConfig = $this->createMock(IAppConfig::class); + $this->configManager = $this->createMock(ConfigManager::class); + $this->consoleInput = $this->createMock(InputInterface::class); + $this->consoleOutput = $this->createMock(OutputInterface::class); + + $this->command = new GetConfig($this->appConfig, $this->configManager); + } + + + public static function dataGet(): array { + return [ + // String output as json + ['name', 'newvalue', true, null, false, 'json', 0, json_encode('newvalue')], + // String output as plain text + ['name', 'newvalue', true, null, false, 'plain', 0, 'newvalue'], + // String falling back to default output as json + ['name', null, false, 'newvalue', true, 'json', 0, json_encode('newvalue')], + // String falling back without default: error + ['name', null, false, null, false, 'json', 1, null], + + // Int "0" output as json/plain + ['name', 0, true, null, false, 'json', 0, json_encode(0)], + ['name', 0, true, null, false, 'plain', 0, '0'], + // Int "1" output as json/plain + ['name', 1, true, null, false, 'json', 0, json_encode(1)], + ['name', 1, true, null, false, 'plain', 0, '1'], + + // Bool "true" output as json/plain + ['name', true, true, null, false, 'json', 0, json_encode(true)], + ['name', true, true, null, false, 'plain', 0, 'true'], + // Bool "false" output as json/plain + ['name', false, true, null, false, 'json', 0, json_encode(false)], + ['name', false, true, null, false, 'plain', 0, 'false'], + + // Null output as json/plain + ['name', null, true, null, false, 'json', 0, json_encode(null)], + ['name', null, true, null, false, 'plain', 0, 'null'], + + // Array output as json/plain + ['name', ['a', 'b'], true, null, false, 'json', 0, json_encode(['a', 'b'])], + ['name', ['a', 'b'], true, null, false, 'plain', 0, "a\nb"], + // Key array output as json/plain + ['name', [0 => 'a', 1 => 'b'], true, null, false, 'json', 0, json_encode(['a', 'b'])], + ['name', [0 => 'a', 1 => 'b'], true, null, false, 'plain', 0, "a\nb"], + // Associative array output as json/plain + ['name', ['a' => 1, 'b' => 2], true, null, false, 'json', 0, json_encode(['a' => 1, 'b' => 2])], + ['name', ['a' => 1, 'b' => 2], true, null, false, 'plain', 0, "a: 1\nb: 2"], + + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataGet')] + public function testGet(string $configName, mixed $value, bool $configExists, mixed $defaultValue, bool $hasDefault, string $outputFormat, int $expectedReturn, ?string $expectedMessage): void { + if (!$expectedReturn) { + if ($configExists) { + $this->appConfig->expects($this->once()) + ->method('getDetails') + ->with('app-name', $configName) + ->willReturn(['value' => $value]); + } + } + + if (!$configExists) { + $this->appConfig->expects($this->once()) + ->method('getDetails') + ->with('app-name', $configName) + ->willThrowException(new AppConfigUnknownKeyException()); + } + + $this->consoleInput->expects($this->exactly(2)) + ->method('getArgument') + ->willReturnMap([ + ['app', 'app-name'], + ['name', $configName], + ]); + $this->consoleInput->method('getOption') + ->willReturnMap([ + ['default-value', $defaultValue], + ['output', $outputFormat], + ]); + $this->consoleInput->method('hasParameterOption') + ->willReturnMap([ + ['--output', false, true], + ['--default-value', false, $hasDefault], + ]); + + if ($expectedMessage !== null) { + global $output; + + $output = ''; + $this->consoleOutput->method('writeln') + ->willReturnCallback(function ($value) { + global $output; + $output .= $value . "\n"; + return $output; + }); + } + + $this->assertSame($expectedReturn, self::invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput])); + + if ($expectedMessage !== null) { + global $output; + // Remove the trailing newline + $this->assertSame($expectedMessage, substr($output, 0, -1)); + } + } +} diff --git a/tests/Core/Command/Config/App/SetConfigTest.php b/tests/Core/Command/Config/App/SetConfigTest.php new file mode 100644 index 00000000000..a5c62368163 --- /dev/null +++ b/tests/Core/Command/Config/App/SetConfigTest.php @@ -0,0 +1,107 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Tests\Core\Command\Config\App; + +use OC\AppConfig; +use OC\Config\ConfigManager; +use OC\Core\Command\Config\App\SetConfig; +use OCP\Exceptions\AppConfigUnknownKeyException; +use OCP\IAppConfig; +use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Test\TestCase; + +class SetConfigTest extends TestCase { + protected IAppConfig&MockObject $appConfig; + protected ConfigManager&MockObject $configManager; + protected InputInterface&MockObject $consoleInput; + protected OutputInterface&MockObject $consoleOutput; + protected Command $command; + + protected function setUp(): void { + parent::setUp(); + + $this->appConfig = $this->createMock(AppConfig::class); + $this->configManager = $this->createMock(ConfigManager::class); + $this->consoleInput = $this->createMock(InputInterface::class); + $this->consoleOutput = $this->createMock(OutputInterface::class); + + $this->command = new SetConfig($this->appConfig, $this->configManager); + } + + + public static function dataSet(): array { + return [ + [ + 'name', + 'newvalue', + true, + true, + true, + 'info', + ], + [ + 'name', + 'newvalue', + false, + true, + false, + 'comment', + ], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataSet')] + public function testSet(string $configName, mixed $newValue, bool $configExists, bool $updateOnly, bool $updated, string $expectedMessage): void { + $this->appConfig->method('hasKey') + ->with('app-name', $configName) + ->willReturn($configExists); + + if (!$configExists) { + $this->appConfig->method('getValueType') + ->willThrowException(new AppConfigUnknownKeyException()); + } else { + $this->appConfig->method('getValueType') + ->willReturn(IAppConfig::VALUE_MIXED); + } + + if ($updated) { + $this->appConfig->expects($this->once()) + ->method('setValueMixed') + ->with('app-name', $configName, $newValue); + } + + $this->consoleInput->expects($this->exactly(2)) + ->method('getArgument') + ->willReturnMap([ + ['app', 'app-name'], + ['name', $configName], + ]); + $this->consoleInput->method('getOption') + ->willReturnMap([ + ['value', $newValue], + ['lazy', null], + ['sensitive', null], + ['no-interaction', true], + ]); + $this->consoleInput->method('hasParameterOption') + ->willReturnMap([ + ['--type', false, false], + ['--value', false, true], + ['--update-only', false, $updateOnly] + ]); + $this->consoleOutput->method('writeln') + ->with($this->stringContains($expectedMessage)); + + self::invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]); + } +} diff --git a/tests/Core/Command/Config/ImportTest.php b/tests/Core/Command/Config/ImportTest.php new file mode 100644 index 00000000000..14cdd714d12 --- /dev/null +++ b/tests/Core/Command/Config/ImportTest.php @@ -0,0 +1,169 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Tests\Core\Command\Config; + +use OC\Core\Command\Config\Import; +use OCP\IConfig; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Test\TestCase; + +class ImportTest extends TestCase { + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $config; + + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $consoleInput; + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $consoleOutput; + + /** @var \Symfony\Component\Console\Command\Command */ + protected $command; + + protected function setUp(): void { + parent::setUp(); + + $config = $this->config = $this->getMockBuilder(IConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock(); + $this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock(); + + /** @var IConfig $config */ + $this->command = new Import($config); + } + + public static function validateAppsArrayData(): array { + return [ + [0], + [1], + [null], + ['new \Exception()'], + [json_encode([])], + ]; + } + + /** + * @param mixed $configValue + */ + #[\PHPUnit\Framework\Attributes\DataProvider('validateAppsArrayData')] + public function testValidateAppsArray($configValue): void { + $this->invokePrivate($this->command, 'validateAppsArray', [['app' => ['name' => $configValue]]]); + $this->assertTrue(true, 'Asserting that no exception is thrown'); + } + + public static function validateAppsArrayThrowsData(): array { + return [ + [false], + [true], + [[]], + [new \Exception()], + ]; + } + + /** + * @param mixed $configValue + */ + #[\PHPUnit\Framework\Attributes\DataProvider('validateAppsArrayThrowsData')] + public function testValidateAppsArrayThrows($configValue): void { + try { + $this->invokePrivate($this->command, 'validateAppsArray', [['app' => ['name' => $configValue]]]); + $this->fail('Did not throw expected UnexpectedValueException'); + } catch (\UnexpectedValueException $e) { + $this->assertStringStartsWith('Invalid app config value for "app":"name".', $e->getMessage()); + } + } + + public static function checkTypeRecursivelyData(): array { + return [ + [0], + [1], + [null], + ['new \Exception()'], + [json_encode([])], + [false], + [true], + [[]], + [['string']], + [['test' => 'string']], + [['test' => ['sub' => 'string']]], + ]; + } + + /** + * @param mixed $configValue + */ + #[\PHPUnit\Framework\Attributes\DataProvider('checkTypeRecursivelyData')] + public function testCheckTypeRecursively($configValue): void { + $this->invokePrivate($this->command, 'checkTypeRecursively', [$configValue, 'name']); + $this->assertTrue(true, 'Asserting that no exception is thrown'); + } + + public static function checkTypeRecursivelyThrowsData(): array { + return [ + [new \Exception()], + [[new \Exception()]], + [['test' => new \Exception()]], + [['test' => ['sub' => new \Exception()]]], + ]; + } + + /** + * @param mixed $configValue + */ + #[\PHPUnit\Framework\Attributes\DataProvider('checkTypeRecursivelyThrowsData')] + public function testCheckTypeRecursivelyThrows($configValue): void { + try { + $this->invokePrivate($this->command, 'checkTypeRecursively', [$configValue, 'name']); + $this->fail('Did not throw expected UnexpectedValueException'); + } catch (\UnexpectedValueException $e) { + $this->assertStringStartsWith('Invalid system config value for "name"', $e->getMessage()); + } + } + + public static function validateArrayData(): array { + return [ + [['system' => []]], + [['apps' => []]], + [['system' => [], 'apps' => []]], + ]; + } + + /** + * @param array $configArray + */ + #[\PHPUnit\Framework\Attributes\DataProvider('validateArrayData')] + public function testValidateArray($configArray): void { + $this->invokePrivate($this->command, 'validateArray', [$configArray]); + $this->assertTrue(true, 'Asserting that no exception is thrown'); + } + + public static function validateArrayThrowsData(): array { + return [ + [[], 'At least one key of the following is expected:'], + [[0 => []], 'Found invalid entries in root'], + [['string' => []], 'Found invalid entries in root'], + ]; + } + + /** + * + * @param mixed $configArray + * @param string $expectedException + */ + #[\PHPUnit\Framework\Attributes\DataProvider('validateArrayThrowsData')] + public function testValidateArrayThrows($configArray, $expectedException): void { + try { + $this->invokePrivate($this->command, 'validateArray', [$configArray]); + $this->fail('Did not throw expected UnexpectedValueException'); + } catch (\UnexpectedValueException $e) { + $this->assertStringStartsWith($expectedException, $e->getMessage()); + } + } +} diff --git a/tests/Core/Command/Config/ListConfigsTest.php b/tests/Core/Command/Config/ListConfigsTest.php new file mode 100644 index 00000000000..e4af55116c0 --- /dev/null +++ b/tests/Core/Command/Config/ListConfigsTest.php @@ -0,0 +1,328 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Tests\Core\Command\Config; + +use OC\Config\ConfigManager; +use OC\Core\Command\Config\ListConfigs; +use OC\SystemConfig; +use OCP\IAppConfig; +use OCP\IConfig; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Test\TestCase; + +class ListConfigsTest extends TestCase { + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $appConfig; + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $systemConfig; + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $configManager; + + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $consoleInput; + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $consoleOutput; + + /** @var \Symfony\Component\Console\Command\Command */ + protected $command; + + protected function setUp(): void { + parent::setUp(); + + $systemConfig = $this->systemConfig = $this->getMockBuilder(SystemConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $appConfig = $this->appConfig = $this->getMockBuilder(IAppConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $configManager = $this->configManager = $this->getMockBuilder(ConfigManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock(); + $this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock(); + + /** @var \OC\SystemConfig $systemConfig */ + /** @var \OCP\IAppConfig $appConfig */ + /** @var ConfigManager $configManager */ + $this->command = new ListConfigs($systemConfig, $appConfig, $configManager); + } + + public static function listData(): array { + return [ + [ + 'all', + // config.php + [ + 'secret', + 'overwrite.cli.url', + ], + [ + ['secret', 'N;', IConfig::SENSITIVE_VALUE], + ['overwrite.cli.url', 'N;', 'http://localhost'], + ], + // app config + [ + ['files', [ + 'enabled' => 'yes', + ]], + ['core', [ + 'global_cache_gc_lastrun' => '1430388388', + ]], + ], + false, + json_encode([ + 'system' => [ + 'secret' => IConfig::SENSITIVE_VALUE, + 'overwrite.cli.url' => 'http://localhost', + ], + 'apps' => [ + 'core' => [ + 'global_cache_gc_lastrun' => '1430388388', + ], + 'files' => [ + 'enabled' => 'yes', + ], + ], + ]), + ], + [ + 'all', + // config.php + [ + 'secret', + 'overwrite.cli.url', + ], + [ + ['secret', 'N;', 'my secret'], + ['overwrite.cli.url', 'N;', 'http://localhost'], + ], + // app config + [ + ['files', false, [ + 'enabled' => 'yes', + ]], + ['core', false, [ + 'global_cache_gc_lastrun' => '1430388388', + ]], + ], + true, + json_encode([ + 'system' => [ + 'secret' => 'my secret', + 'overwrite.cli.url' => 'http://localhost', + ], + 'apps' => [ + 'core' => [ + 'global_cache_gc_lastrun' => '1430388388', + ], + 'files' => [ + 'enabled' => 'yes', + ], + ], + ]), + ], + [ + 'system', + // config.php + [ + 'secret', + 'objectstore', + 'overwrite.cli.url', + ], + [ + ['secret', 'N;', IConfig::SENSITIVE_VALUE], + ['objectstore', 'N;', [ + 'class' => 'OC\\Files\\ObjectStore\\Swift', + 'arguments' => [ + 'username' => 'facebook100000123456789', + 'password' => IConfig::SENSITIVE_VALUE, + ], + ]], + ['overwrite.cli.url', 'N;', 'http://localhost'], + ], + // app config + [ + ['files', [ + 'enabled' => 'yes', + ]], + ['core', [ + 'global_cache_gc_lastrun' => '1430388388', + ]], + ], + false, + json_encode([ + 'system' => [ + 'secret' => IConfig::SENSITIVE_VALUE, + 'objectstore' => [ + 'class' => 'OC\\Files\\ObjectStore\\Swift', + 'arguments' => [ + 'username' => 'facebook100000123456789', + 'password' => IConfig::SENSITIVE_VALUE, + ], + ], + 'overwrite.cli.url' => 'http://localhost', + ], + ]), + ], + [ + 'system', + // config.php + [ + 'secret', + 'overwrite.cli.url', + ], + [ + ['secret', 'N;', 'my secret'], + ['overwrite.cli.url', 'N;', 'http://localhost'], + ], + // app config + [ + ['files', [ + 'enabled' => 'yes', + ]], + ['core', [ + 'global_cache_gc_lastrun' => '1430388388', + ]], + ], + true, + json_encode([ + 'system' => [ + 'secret' => 'my secret', + 'overwrite.cli.url' => 'http://localhost', + ], + ]), + ], + [ + 'files', + // config.php + [ + 'secret', + 'overwrite.cli.url', + ], + [ + ['secret', 'N;', 'my secret'], + ['overwrite.cli.url', 'N;', 'http://localhost'], + ], + // app config + [ + ['files', [ + 'enabled' => 'yes', + ]], + ['core', [ + 'global_cache_gc_lastrun' => '1430388388', + ]], + ], + false, + json_encode([ + 'apps' => [ + 'files' => [ + 'enabled' => 'yes', + ], + ], + ]), + ], + [ + 'files', + // config.php + [ + 'secret', + 'overwrite.cli.url', + ], + [ + ['secret', 'N;', 'my secret'], + ['overwrite.cli.url', 'N;', 'http://localhost'], + ], + // app config + [ + ['files', false, [ + 'enabled' => 'yes', + ]], + ['core', false, [ + 'global_cache_gc_lastrun' => '1430388388', + ]], + ], + true, + json_encode([ + 'apps' => [ + 'files' => [ + 'enabled' => 'yes', + ], + ], + ]), + ], + ]; + } + + /** + * + * @param string $app + * @param array $systemConfigs + * @param array $systemConfigMap + * @param array $appConfig + * @param bool $private + * @param string $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('listData')] + public function testList($app, $systemConfigs, $systemConfigMap, $appConfig, $private, $expected): void { + $this->systemConfig->expects($this->any()) + ->method('getKeys') + ->willReturn($systemConfigs); + if ($private) { + $this->systemConfig->expects($this->any()) + ->method('getValue') + ->willReturnMap($systemConfigMap); + $this->appConfig->expects($this->any()) + ->method('getValues') + ->willReturnMap($appConfig); + } else { + $this->systemConfig->expects($this->any()) + ->method('getFilteredValue') + ->willReturnMap($systemConfigMap); + $this->appConfig->expects($this->any()) + ->method('getFilteredValues') + ->willReturnMap($appConfig); + } + + $this->appConfig->expects($this->any()) + ->method('getApps') + ->willReturn(['core', 'files']); + $this->appConfig->expects($this->any()) + ->method('getValues') + ->willReturnMap($appConfig); + + $this->consoleInput->expects($this->once()) + ->method('getArgument') + ->with('app') + ->willReturn($app); + + $this->consoleInput->expects($this->any()) + ->method('getOption') + ->willReturnMap([ + ['output', 'json'], + ['private', $private], + ]); + + global $output; + + $output = ''; + $this->consoleOutput->expects($this->any()) + ->method('writeln') + ->willReturnCallback(function ($value) { + global $output; + $output .= $value . "\n"; + return $output; + }); + + $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]); + + $this->assertEquals($expected, trim($output, "\n")); + } +} diff --git a/tests/Core/Command/Config/System/CastHelperTest.php b/tests/Core/Command/Config/System/CastHelperTest.php new file mode 100644 index 00000000000..924887daaf7 --- /dev/null +++ b/tests/Core/Command/Config/System/CastHelperTest.php @@ -0,0 +1,66 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Core\Command\Config\System; + +use OC\Core\Command\Config\System\CastHelper; +use Test\TestCase; + +class CastHelperTest extends TestCase { + private CastHelper $castHelper; + + protected function setUp(): void { + parent::setUp(); + $this->castHelper = new CastHelper(); + } + + public static function castValueProvider(): array { + return [ + [null, 'string', ['value' => '', 'readable-value' => 'empty string']], + + ['abc', 'string', ['value' => 'abc', 'readable-value' => 'string abc']], + + ['123', 'integer', ['value' => 123, 'readable-value' => 'integer 123']], + ['456', 'int', ['value' => 456, 'readable-value' => 'integer 456']], + + ['2.25', 'double', ['value' => 2.25, 'readable-value' => 'double 2.25']], + ['0.5', 'float', ['value' => 0.5, 'readable-value' => 'double 0.5']], + + ['', 'null', ['value' => null, 'readable-value' => 'null']], + + ['true', 'boolean', ['value' => true, 'readable-value' => 'boolean true']], + ['false', 'bool', ['value' => false, 'readable-value' => 'boolean false']], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('castValueProvider')] + public function testCastValue($value, $type, $expectedValue): void { + $this->assertSame( + $expectedValue, + $this->castHelper->castValue($value, $type) + ); + } + + public static function castValueInvalidProvider(): array { + return [ + ['123', 'foobar'], + + [null, 'integer'], + ['abc', 'integer'], + ['76ggg', 'double'], + ['true', 'float'], + ['foobar', 'boolean'], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('castValueInvalidProvider')] + public function testCastValueInvalid($value, $type): void { + $this->expectException(\InvalidArgumentException::class); + + $this->castHelper->castValue($value, $type); + } +} diff --git a/tests/Core/Command/Config/System/DeleteConfigTest.php b/tests/Core/Command/Config/System/DeleteConfigTest.php new file mode 100644 index 00000000000..b0a3580e1cd --- /dev/null +++ b/tests/Core/Command/Config/System/DeleteConfigTest.php @@ -0,0 +1,207 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Tests\Core\Command\Config\System; + +use OC\Core\Command\Config\System\DeleteConfig; +use OC\SystemConfig; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Test\TestCase; + +class DeleteConfigTest extends TestCase { + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $systemConfig; + + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $consoleInput; + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $consoleOutput; + + /** @var \Symfony\Component\Console\Command\Command */ + protected $command; + + protected function setUp(): void { + parent::setUp(); + + $systemConfig = $this->systemConfig = $this->getMockBuilder(SystemConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock(); + $this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock(); + + /** @var SystemConfig $systemConfig */ + $this->command = new DeleteConfig($systemConfig); + } + + public static function deleteData(): array { + return [ + [ + 'name1', + true, + true, + 0, + 'info', + ], + [ + 'name2', + true, + false, + 0, + 'info', + ], + [ + 'name3', + false, + false, + 0, + 'info', + ], + [ + 'name4', + false, + true, + 1, + 'error', + ], + ]; + } + + /** + * + * @param string $configName + * @param bool $configExists + * @param bool $checkIfExists + * @param int $expectedReturn + * @param string $expectedMessage + */ + #[\PHPUnit\Framework\Attributes\DataProvider('deleteData')] + public function testDelete($configName, $configExists, $checkIfExists, $expectedReturn, $expectedMessage): void { + $this->systemConfig->expects(($checkIfExists) ? $this->once() : $this->never()) + ->method('getKeys') + ->willReturn($configExists ? [$configName] : []); + + $this->systemConfig->expects(($expectedReturn === 0) ? $this->once() : $this->never()) + ->method('deleteValue') + ->with($configName); + + $this->consoleInput->expects($this->once()) + ->method('getArgument') + ->with('name') + ->willReturn([$configName]); + $this->consoleInput->expects($this->any()) + ->method('hasParameterOption') + ->with('--error-if-not-exists') + ->willReturn($checkIfExists); + + $this->consoleOutput->expects($this->any()) + ->method('writeln') + ->with($this->stringContains($expectedMessage)); + + $this->assertSame($expectedReturn, $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput])); + } + + public static function deleteArrayData(): array { + return [ + [ + ['name', 'sub'], + true, + false, + true, + true, + 0, + 'info', + ], + [ + ['name', 'sub', '2sub'], + true, + false, + ['sub' => ['2sub' => 1], 'sub2' => false], + ['sub' => [], 'sub2' => false], + 0, + 'info', + ], + [ + ['name', 'sub3'], + true, + false, + ['sub' => ['2sub' => 1], 'sub2' => false], + ['sub' => ['2sub' => 1], 'sub2' => false], + 0, + 'info', + ], + [ + ['name', 'sub'], + false, + true, + true, + true, + 1, + 'error', + ], + [ + ['name', 'sub'], + true, + true, + true, + true, + 1, + 'error', + ], + [ + ['name', 'sub3'], + true, + true, + ['sub' => ['2sub' => 1], 'sub2' => false], + ['sub' => ['2sub' => 1], 'sub2' => false], + 1, + 'error', + ], + ]; + } + + /** + * + * @param string[] $configNames + * @param bool $configKeyExists + * @param bool $checkIfKeyExists + * @param mixed $configValue + * @param mixed $updateValue + * @param int $expectedReturn + * @param string $expectedMessage + */ + #[\PHPUnit\Framework\Attributes\DataProvider('deleteArrayData')] + public function testArrayDelete(array $configNames, $configKeyExists, $checkIfKeyExists, $configValue, $updateValue, $expectedReturn, $expectedMessage): void { + $this->systemConfig->expects(($checkIfKeyExists) ? $this->once() : $this->never()) + ->method('getKeys') + ->willReturn($configKeyExists ? [$configNames[0]] : []); + + $this->systemConfig->expects(($configKeyExists) ? $this->once() : $this->never()) + ->method('getValue') + ->willReturn($configValue); + + $this->systemConfig->expects(($expectedReturn === 0) ? $this->once() : $this->never()) + ->method('setValue') + ->with($configNames[0], $updateValue); + + $this->consoleInput->expects($this->once()) + ->method('getArgument') + ->with('name') + ->willReturn($configNames); + $this->consoleInput->expects($this->any()) + ->method('hasParameterOption') + ->with('--error-if-not-exists') + ->willReturn($checkIfKeyExists); + + $this->consoleOutput->expects($this->any()) + ->method('writeln') + ->with($this->stringContains($expectedMessage)); + + $this->assertSame($expectedReturn, $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput])); + } +} diff --git a/tests/Core/Command/Config/System/GetConfigTest.php b/tests/Core/Command/Config/System/GetConfigTest.php new file mode 100644 index 00000000000..8b84fd14198 --- /dev/null +++ b/tests/Core/Command/Config/System/GetConfigTest.php @@ -0,0 +1,161 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Tests\Core\Command\Config\System; + +use OC\Core\Command\Config\System\GetConfig; +use OC\SystemConfig; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Test\TestCase; + +class GetConfigTest extends TestCase { + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $systemConfig; + + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $consoleInput; + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $consoleOutput; + + /** @var \Symfony\Component\Console\Command\Command */ + protected $command; + + protected function setUp(): void { + parent::setUp(); + + $systemConfig = $this->systemConfig = $this->getMockBuilder(SystemConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock(); + $this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock(); + + /** @var SystemConfig $systemConfig */ + $this->command = new GetConfig($systemConfig); + } + + + public static function getData(): array { + return [ + // String output as json + ['name', 'newvalue', true, null, false, 'json', 0, json_encode('newvalue')], + // String output as plain text + ['name', 'newvalue', true, null, false, 'plain', 0, 'newvalue'], + // String falling back to default output as json + ['name', null, false, 'newvalue', true, 'json', 0, json_encode('newvalue')], + // String falling back without default: error + ['name', null, false, null, false, 'json', 1, null], + + // Int "0" output as json/plain + ['name', 0, true, null, false, 'json', 0, json_encode(0)], + ['name', 0, true, null, false, 'plain', 0, '0'], + // Int "1" output as json/plain + ['name', 1, true, null, false, 'json', 0, json_encode(1)], + ['name', 1, true, null, false, 'plain', 0, '1'], + + // Bool "true" output as json/plain + ['name', true, true, null, false, 'json', 0, json_encode(true)], + ['name', true, true, null, false, 'plain', 0, 'true'], + // Bool "false" output as json/plain + ['name', false, true, null, false, 'json', 0, json_encode(false)], + ['name', false, true, null, false, 'plain', 0, 'false'], + + // Null output as json/plain + ['name', null, true, null, false, 'json', 0, json_encode(null)], + ['name', null, true, null, false, 'plain', 0, 'null'], + + // Array output as json/plain + ['name', ['a', 'b'], true, null, false, 'json', 0, json_encode(['a', 'b'])], + ['name', ['a', 'b'], true, null, false, 'plain', 0, "a\nb"], + // Key array output as json/plain + ['name', [0 => 'a', 1 => 'b'], true, null, false, 'json', 0, json_encode(['a', 'b'])], + ['name', [0 => 'a', 1 => 'b'], true, null, false, 'plain', 0, "a\nb"], + // Associative array output as json/plain + ['name', ['a' => 1, 'b' => 2], true, null, false, 'json', 0, json_encode(['a' => 1, 'b' => 2])], + ['name', ['a' => 1, 'b' => 2], true, null, false, 'plain', 0, "a: 1\nb: 2"], + + // Nested depth + [['name', 'a'], ['a' => 1, 'b' => 2], true, null, false, 'json', 0, json_encode(1)], + [['name', 'a'], ['a' => 1, 'b' => 2], true, null, false, 'plain', 0, '1'], + [['name', 'c'], ['a' => 1, 'b' => 2], true, true, true, 'json', 0, json_encode(true)], + [['name', 'c'], ['a' => 1, 'b' => 2], true, true, false, 'json', 1, null], + + ]; + } + + /** + * + * @param string[] $configNames + * @param mixed $value + * @param bool $configExists + * @param mixed $defaultValue + * @param bool $hasDefault + * @param string $outputFormat + * @param int $expectedReturn + * @param string $expectedMessage + */ + #[\PHPUnit\Framework\Attributes\DataProvider('getData')] + public function testGet($configNames, $value, $configExists, $defaultValue, $hasDefault, $outputFormat, $expectedReturn, $expectedMessage): void { + if (is_array($configNames)) { + $configName = $configNames[0]; + } else { + $configName = $configNames; + $configNames = [$configName]; + } + $this->systemConfig->expects($this->atLeastOnce()) + ->method('getKeys') + ->willReturn($configExists ? [$configName] : []); + + if (!$expectedReturn) { + if ($configExists) { + $this->systemConfig->expects($this->once()) + ->method('getValue') + ->with($configName) + ->willReturn($value); + } + } + + $this->consoleInput->expects($this->once()) + ->method('getArgument') + ->with('name') + ->willReturn($configNames); + $this->consoleInput->expects($this->any()) + ->method('getOption') + ->willReturnMap([ + ['default-value', $defaultValue], + ['output', $outputFormat], + ]); + $this->consoleInput->expects($this->any()) + ->method('hasParameterOption') + ->willReturnMap([ + ['--output', false, true], + ['--default-value', false,$hasDefault], + ]); + + if ($expectedMessage !== null) { + global $output; + + $output = ''; + $this->consoleOutput->expects($this->any()) + ->method('writeln') + ->willReturnCallback(function ($value) { + global $output; + $output .= $value . "\n"; + return $output; + }); + } + + $this->assertSame($expectedReturn, $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput])); + + if ($expectedMessage !== null) { + global $output; + // Remove the trailing newline + $this->assertSame($expectedMessage, substr($output, 0, -1)); + } + } +} diff --git a/tests/Core/Command/Config/System/SetConfigTest.php b/tests/Core/Command/Config/System/SetConfigTest.php new file mode 100644 index 00000000000..a99b832c160 --- /dev/null +++ b/tests/Core/Command/Config/System/SetConfigTest.php @@ -0,0 +1,115 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Tests\Core\Command\Config\System; + +use OC\Core\Command\Config\System\CastHelper; +use OC\Core\Command\Config\System\SetConfig; +use OC\SystemConfig; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Test\TestCase; + +class SetConfigTest extends TestCase { + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $systemConfig; + + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $consoleInput; + /** @var \PHPUnit\Framework\MockObject\MockObject */ + protected $consoleOutput; + + /** @var \Symfony\Component\Console\Command\Command */ + protected $command; + + protected function setUp(): void { + parent::setUp(); + + $systemConfig = $this->systemConfig = $this->getMockBuilder(SystemConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock(); + $this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock(); + + /** @var SystemConfig $systemConfig */ + $this->command = new SetConfig($systemConfig, new CastHelper()); + } + + + public static function dataTest() { + return [ + [['name'], 'newvalue', null, 'newvalue'], + [['a', 'b', 'c'], 'foobar', null, ['b' => ['c' => 'foobar']]], + [['a', 'b', 'c'], 'foobar', ['b' => ['d' => 'barfoo']], ['b' => ['d' => 'barfoo', 'c' => 'foobar']]], + ]; + } + + /** + * + * @param array $configNames + * @param string $newValue + * @param mixed $existingData + * @param mixed $expectedValue + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataTest')] + public function testSet($configNames, $newValue, $existingData, $expectedValue): void { + $this->systemConfig->expects($this->once()) + ->method('setValue') + ->with($configNames[0], $expectedValue); + $this->systemConfig->method('getValue') + ->with($configNames[0]) + ->willReturn($existingData); + + $this->consoleInput->expects($this->once()) + ->method('getArgument') + ->with('name') + ->willReturn($configNames); + $this->consoleInput->method('getOption') + ->willReturnMap([ + ['value', $newValue], + ['type', 'string'], + ]); + + $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]); + } + + public static function setUpdateOnlyProvider(): array { + return [ + [['name'], null], + [['a', 'b', 'c'], null], + [['a', 'b', 'c'], ['b' => 'foobar']], + [['a', 'b', 'c'], ['b' => ['d' => 'foobar']]], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('setUpdateOnlyProvider')] + public function testSetUpdateOnly($configNames, $existingData): void { + $this->expectException(\UnexpectedValueException::class); + + $this->systemConfig->expects($this->never()) + ->method('setValue'); + $this->systemConfig->method('getValue') + ->with($configNames[0]) + ->willReturn($existingData); + $this->systemConfig->method('getKeys') + ->willReturn($existingData ? $configNames[0] : []); + + $this->consoleInput->expects($this->once()) + ->method('getArgument') + ->with('name') + ->willReturn($configNames); + $this->consoleInput->method('getOption') + ->willReturnMap([ + ['value', 'foobar'], + ['type', 'string'], + ['update-only', true], + ]); + + $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]); + } +} |