1
0

DeclarativeManagerTest.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace Test\Settings;
  8. use OC\AppFramework\Bootstrap\Coordinator;
  9. use OC\AppFramework\Bootstrap\RegistrationContext;
  10. use OC\AppFramework\Bootstrap\ServiceRegistration;
  11. use OC\Settings\DeclarativeManager;
  12. use OCP\EventDispatcher\IEventDispatcher;
  13. use OCP\IAppConfig;
  14. use OCP\IConfig;
  15. use OCP\IGroupManager;
  16. use OCP\IUser;
  17. use OCP\Settings\DeclarativeSettingsTypes;
  18. use OCP\Settings\Events\DeclarativeSettingsSetValueEvent;
  19. use OCP\Settings\IDeclarativeManager;
  20. use OCP\Settings\IDeclarativeSettingsForm;
  21. use OCP\Settings\IDeclarativeSettingsFormWithHandlers;
  22. use PHPUnit\Framework\MockObject\MockObject;
  23. use Psr\Log\LoggerInterface;
  24. use Test\TestCase;
  25. class DeclarativeManagerTest extends TestCase {
  26. /** @var IDeclarativeManager|MockObject */
  27. private $declarativeManager;
  28. /** @var IEventDispatcher|MockObject */
  29. private $eventDispatcher;
  30. /** @var IGroupManager|MockObject */
  31. private $groupManager;
  32. /** @var Coordinator|MockObject */
  33. private $coordinator;
  34. /** @var IConfig|MockObject */
  35. private $config;
  36. /** @var IAppConfig|MockObject */
  37. private $appConfig;
  38. /** @var LoggerInterface|MockObject */
  39. private $logger;
  40. /** @var IUser|MockObject */
  41. private $user;
  42. /** @var IUser|MockObject */
  43. private $adminUser;
  44. private IDeclarativeSettingsForm&MockObject $closureForm;
  45. public const validSchemaAllFields = [
  46. 'id' => 'test_form_1',
  47. 'priority' => 10,
  48. 'section_type' => DeclarativeSettingsTypes::SECTION_TYPE_ADMIN, // admin, personal
  49. 'section_id' => 'additional',
  50. 'storage_type' => DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL, // external, internal (handled by core to store in appconfig and preferences)
  51. 'title' => 'Test declarative settings', // NcSettingsSection name
  52. 'description' => 'These fields are rendered dynamically from declarative schema', // NcSettingsSection description
  53. 'doc_url' => '', // NcSettingsSection doc_url for documentation or help page, empty string if not needed
  54. 'fields' => [
  55. [
  56. 'id' => 'test_field_7', // configkey
  57. 'title' => 'Multi-selection', // name or label
  58. 'description' => 'Select some option setting', // hint
  59. 'type' => DeclarativeSettingsTypes::MULTI_SELECT,
  60. 'options' => ['foo', 'bar', 'baz'], // simple options for select, radio, multi-select
  61. 'placeholder' => 'Select some multiple options', // input placeholder
  62. 'default' => ['foo', 'bar'],
  63. ],
  64. [
  65. 'id' => 'some_real_setting',
  66. 'title' => 'Select single option',
  67. 'description' => 'Single option radio buttons',
  68. 'type' => DeclarativeSettingsTypes::RADIO, // radio (NcCheckboxRadioSwitch type radio)
  69. 'placeholder' => 'Select single option, test interval',
  70. 'default' => '40m',
  71. 'options' => [
  72. [
  73. 'name' => 'Each 40 minutes', // NcCheckboxRadioSwitch display name
  74. 'value' => '40m' // NcCheckboxRadioSwitch value
  75. ],
  76. [
  77. 'name' => 'Each 60 minutes',
  78. 'value' => '60m'
  79. ],
  80. [
  81. 'name' => 'Each 120 minutes',
  82. 'value' => '120m'
  83. ],
  84. [
  85. 'name' => 'Each day',
  86. 'value' => 60 * 24 . 'm'
  87. ],
  88. ],
  89. ],
  90. [
  91. 'id' => 'test_field_1', // configkey
  92. 'title' => 'Default text field', // label
  93. 'description' => 'Set some simple text setting', // hint
  94. 'type' => DeclarativeSettingsTypes::TEXT,
  95. 'placeholder' => 'Enter text setting', // placeholder
  96. 'default' => 'foo',
  97. ],
  98. [
  99. 'id' => 'test_field_1_1',
  100. 'title' => 'Email field',
  101. 'description' => 'Set email config',
  102. 'type' => DeclarativeSettingsTypes::EMAIL,
  103. 'placeholder' => 'Enter email',
  104. 'default' => '',
  105. ],
  106. [
  107. 'id' => 'test_field_1_2',
  108. 'title' => 'Tel field',
  109. 'description' => 'Set tel config',
  110. 'type' => DeclarativeSettingsTypes::TEL,
  111. 'placeholder' => 'Enter your tel',
  112. 'default' => '',
  113. ],
  114. [
  115. 'id' => 'test_field_1_3',
  116. 'title' => 'Url (website) field',
  117. 'description' => 'Set url config',
  118. 'type' => 'url',
  119. 'placeholder' => 'Enter url',
  120. 'default' => '',
  121. ],
  122. [
  123. 'id' => 'test_field_1_4',
  124. 'title' => 'Number field',
  125. 'description' => 'Set number config',
  126. 'type' => DeclarativeSettingsTypes::NUMBER,
  127. 'placeholder' => 'Enter number value',
  128. 'default' => 0,
  129. ],
  130. [
  131. 'id' => 'test_field_2',
  132. 'title' => 'Password',
  133. 'description' => 'Set some secure value setting',
  134. 'type' => 'password',
  135. 'placeholder' => 'Set secure value',
  136. 'default' => '',
  137. ],
  138. [
  139. 'id' => 'test_field_3',
  140. 'title' => 'Selection',
  141. 'description' => 'Select some option setting',
  142. 'type' => DeclarativeSettingsTypes::SELECT,
  143. 'options' => ['foo', 'bar', 'baz'],
  144. 'placeholder' => 'Select some option setting',
  145. 'default' => 'foo',
  146. ],
  147. [
  148. 'id' => 'test_field_4',
  149. 'title' => 'Toggle something',
  150. 'description' => 'Select checkbox option setting',
  151. 'type' => DeclarativeSettingsTypes::CHECKBOX,
  152. 'label' => 'Verify something if enabled',
  153. 'default' => false,
  154. ],
  155. [
  156. 'id' => 'test_field_5',
  157. 'title' => 'Multiple checkbox toggles, describing one setting, checked options are saved as an JSON object {foo: true, bar: false}',
  158. 'description' => 'Select checkbox option setting',
  159. 'type' => DeclarativeSettingsTypes::MULTI_CHECKBOX,
  160. 'default' => ['foo' => true, 'bar' => true],
  161. 'options' => [
  162. [
  163. 'name' => 'Foo',
  164. 'value' => 'foo', // multiple-checkbox configkey
  165. ],
  166. [
  167. 'name' => 'Bar',
  168. 'value' => 'bar',
  169. ],
  170. [
  171. 'name' => 'Baz',
  172. 'value' => 'baz',
  173. ],
  174. [
  175. 'name' => 'Qux',
  176. 'value' => 'qux',
  177. ],
  178. ],
  179. ],
  180. [
  181. 'id' => 'test_field_6',
  182. 'title' => 'Radio toggles, describing one setting like single select',
  183. 'description' => 'Select radio option setting',
  184. 'type' => DeclarativeSettingsTypes::RADIO, // radio (NcCheckboxRadioSwitch type radio)
  185. 'label' => 'Select single toggle',
  186. 'default' => 'foo',
  187. 'options' => [
  188. [
  189. 'name' => 'First radio', // NcCheckboxRadioSwitch display name
  190. 'value' => 'foo' // NcCheckboxRadioSwitch value
  191. ],
  192. [
  193. 'name' => 'Second radio',
  194. 'value' => 'bar'
  195. ],
  196. [
  197. 'name' => 'Second radio',
  198. 'value' => 'baz'
  199. ],
  200. ],
  201. ],
  202. ],
  203. ];
  204. public static bool $testSetInternalValueAfterChange = false;
  205. protected function setUp(): void {
  206. parent::setUp();
  207. $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
  208. $this->groupManager = $this->createMock(IGroupManager::class);
  209. $this->coordinator = $this->createMock(Coordinator::class);
  210. $this->config = $this->createMock(IConfig::class);
  211. $this->appConfig = $this->createMock(IAppConfig::class);
  212. $this->logger = $this->createMock(LoggerInterface::class);
  213. $this->declarativeManager = new DeclarativeManager(
  214. $this->eventDispatcher,
  215. $this->groupManager,
  216. $this->coordinator,
  217. $this->config,
  218. $this->appConfig,
  219. $this->logger
  220. );
  221. $this->user = $this->createMock(IUser::class);
  222. $this->user->expects($this->any())
  223. ->method('getUID')
  224. ->willReturn('test_user');
  225. $this->adminUser = $this->createMock(IUser::class);
  226. $this->adminUser->expects($this->any())
  227. ->method('getUID')
  228. ->willReturn('admin_test_user');
  229. $this->groupManager->expects($this->any())
  230. ->method('isAdmin')
  231. ->willReturnCallback(function ($userId) {
  232. return $userId === 'admin_test_user';
  233. });
  234. }
  235. public function testRegisterSchema(): void {
  236. $app = 'testing';
  237. $schema = self::validSchemaAllFields;
  238. $this->declarativeManager->registerSchema($app, $schema);
  239. $formIds = $this->declarativeManager->getFormIDs($this->adminUser, $schema['section_type'], $schema['section_id']);
  240. $this->assertTrue(isset($formIds[$app]) && in_array($schema['id'], $formIds[$app]));
  241. }
  242. /**
  243. * Simple test to verify that exception is thrown when trying to register schema with duplicate id
  244. */
  245. public function testRegisterDuplicateSchema(): void {
  246. $this->declarativeManager->registerSchema('testing', self::validSchemaAllFields);
  247. $this->expectException(\Exception::class);
  248. $this->declarativeManager->registerSchema('testing', self::validSchemaAllFields);
  249. }
  250. /**
  251. * It's not allowed to register schema with duplicate fields ids for the same app
  252. */
  253. public function testRegisterSchemaWithDuplicateFields(): void {
  254. // Register first valid schema
  255. $this->declarativeManager->registerSchema('testing', self::validSchemaAllFields);
  256. // Register second schema with duplicate fields, but different schema id
  257. $this->expectException(\Exception::class);
  258. $schema = self::validSchemaAllFields;
  259. $schema['id'] = 'test_form_2';
  260. $this->declarativeManager->registerSchema('testing', $schema);
  261. }
  262. public function testRegisterMultipleSchemasAndDuplicate(): void {
  263. $app = 'testing';
  264. $schema = self::validSchemaAllFields;
  265. $this->declarativeManager->registerSchema($app, $schema);
  266. $formIds = $this->declarativeManager->getFormIDs($this->adminUser, $schema['section_type'], $schema['section_id']);
  267. // 1. Check that form is registered for the app
  268. $this->assertTrue(isset($formIds[$app]) && in_array($schema['id'], $formIds[$app]));
  269. $app = 'testing2';
  270. $this->declarativeManager->registerSchema($app, $schema);
  271. $formIds = $this->declarativeManager->getFormIDs($this->adminUser, $schema['section_type'], $schema['section_id']);
  272. // 2. Check that form is registered for the second app
  273. $this->assertTrue(isset($formIds[$app]) && in_array($schema['id'], $formIds[$app]));
  274. $app = 'testing';
  275. $this->expectException(\Exception::class); // expecting duplicate form id and duplicate fields ids exception
  276. $this->declarativeManager->registerSchema($app, $schema);
  277. $schemaDuplicateFields = self::validSchemaAllFields;
  278. $schemaDuplicateFields['id'] = 'test_form_2'; // change form id to test duplicate fields
  279. $this->declarativeManager->registerSchema($app, $schemaDuplicateFields);
  280. // 3. Check that not valid form with duplicate fields is not registered
  281. $formIds = $this->declarativeManager->getFormIDs($this->adminUser, $schemaDuplicateFields['section_type'], $schemaDuplicateFields['section_id']);
  282. $this->assertFalse(isset($formIds[$app]) && in_array($schemaDuplicateFields['id'], $formIds[$app]));
  283. }
  284. /**
  285. * @dataProvider dataValidateSchema
  286. */
  287. public function testValidateSchema(bool $expected, bool $expectException, string $app, array $schema): void {
  288. if ($expectException) {
  289. $this->expectException(\Exception::class);
  290. }
  291. $this->declarativeManager->registerSchema($app, $schema);
  292. $formIds = $this->declarativeManager->getFormIDs($this->adminUser, $schema['section_type'], $schema['section_id']);
  293. $this->assertEquals($expected, isset($formIds[$app]) && in_array($schema['id'], $formIds[$app]));
  294. }
  295. public static function dataValidateSchema(): array {
  296. return [
  297. 'valid schema with all supported fields' => [
  298. true,
  299. false,
  300. 'testing',
  301. self::validSchemaAllFields,
  302. ],
  303. 'invalid schema with missing id' => [
  304. false,
  305. true,
  306. 'testing',
  307. [
  308. 'priority' => 10,
  309. 'section_type' => DeclarativeSettingsTypes::SECTION_TYPE_ADMIN,
  310. 'section_id' => 'additional',
  311. 'storage_type' => DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL,
  312. 'title' => 'Test declarative settings',
  313. 'description' => 'These fields are rendered dynamically from declarative schema',
  314. 'doc_url' => '',
  315. 'fields' => [
  316. [
  317. 'id' => 'test_field_7',
  318. 'title' => 'Multi-selection',
  319. 'description' => 'Select some option setting',
  320. 'type' => DeclarativeSettingsTypes::MULTI_SELECT,
  321. 'options' => ['foo', 'bar', 'baz'],
  322. 'placeholder' => 'Select some multiple options',
  323. 'default' => ['foo', 'bar'],
  324. ],
  325. ],
  326. ],
  327. ],
  328. 'invalid schema with invalid field' => [
  329. false,
  330. true,
  331. 'testing',
  332. [
  333. 'id' => 'test_form_1',
  334. 'priority' => 10,
  335. 'section_type' => DeclarativeSettingsTypes::SECTION_TYPE_ADMIN,
  336. 'section_id' => 'additional',
  337. 'storage_type' => DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL,
  338. 'title' => 'Test declarative settings',
  339. 'description' => 'These fields are rendered dynamically from declarative schema',
  340. 'doc_url' => '',
  341. 'fields' => [
  342. [
  343. 'id' => 'test_invalid_field',
  344. 'title' => 'Invalid field',
  345. 'description' => 'Some invalid setting description',
  346. 'type' => 'some_invalid_type',
  347. 'placeholder' => 'Some invalid field placeholder',
  348. 'default' => null,
  349. ],
  350. ],
  351. ],
  352. ],
  353. ];
  354. }
  355. public function testGetFormIDs(): void {
  356. $app = 'testing';
  357. $schema = self::validSchemaAllFields;
  358. $this->declarativeManager->registerSchema($app, $schema);
  359. $formIds = $this->declarativeManager->getFormIDs($this->adminUser, $schema['section_type'], $schema['section_id']);
  360. $this->assertTrue(isset($formIds[$app]) && in_array($schema['id'], $formIds[$app]));
  361. $app = 'testing2';
  362. $this->declarativeManager->registerSchema($app, $schema);
  363. $formIds = $this->declarativeManager->getFormIDs($this->adminUser, $schema['section_type'], $schema['section_id']);
  364. $this->assertTrue(isset($formIds[$app]) && in_array($schema['id'], $formIds[$app]));
  365. }
  366. /**
  367. * Check that form with default values is returned with internal storage_type
  368. */
  369. public function testGetFormsWithDefaultValues(): void {
  370. $app = 'testing';
  371. $schema = self::validSchemaAllFields;
  372. $this->declarativeManager->registerSchema($app, $schema);
  373. $this->config->expects($this->any())
  374. ->method('getAppValue')
  375. ->willReturnCallback(fn ($app, $configkey, $default) => $default);
  376. $forms = $this->declarativeManager->getFormsWithValues($this->adminUser, $schema['section_type'], $schema['section_id']);
  377. $this->assertNotEmpty($forms);
  378. $this->assertTrue(array_search($schema['id'], array_column($forms, 'id')) !== false);
  379. // Check some_real_setting field default value
  380. $someRealSettingField = array_values(array_filter(array_filter($forms, fn ($form) => $form['id'] === $schema['id'])[0]['fields'], fn ($field) => $field['id'] === 'some_real_setting'))[0];
  381. $schemaSomeRealSettingField = array_values(array_filter($schema['fields'], fn ($field) => $field['id'] === 'some_real_setting'))[0];
  382. $this->assertEquals($schemaSomeRealSettingField['default'], $someRealSettingField['default']);
  383. }
  384. /**
  385. * Check values in json format to ensure that they are properly encoded
  386. */
  387. public function testGetFormsWithDefaultValuesJson(): void {
  388. $app = 'testing';
  389. $schema = [
  390. 'id' => 'test_form_1',
  391. 'priority' => 10,
  392. 'section_type' => DeclarativeSettingsTypes::SECTION_TYPE_PERSONAL,
  393. 'section_id' => 'additional',
  394. 'storage_type' => DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL,
  395. 'title' => 'Test declarative settings',
  396. 'description' => 'These fields are rendered dynamically from declarative schema',
  397. 'doc_url' => '',
  398. 'fields' => [
  399. [
  400. 'id' => 'test_field_json',
  401. 'title' => 'Multi-selection',
  402. 'description' => 'Select some option setting',
  403. 'type' => DeclarativeSettingsTypes::MULTI_SELECT,
  404. 'options' => ['foo', 'bar', 'baz'],
  405. 'placeholder' => 'Select some multiple options',
  406. 'default' => ['foo', 'bar'],
  407. ],
  408. ],
  409. ];
  410. $this->declarativeManager->registerSchema($app, $schema);
  411. // config->getUserValue() should be called with json encoded default value
  412. $this->config->expects($this->once())
  413. ->method('getUserValue')
  414. ->with($this->adminUser->getUID(), $app, 'test_field_json', json_encode($schema['fields'][0]['default']))
  415. ->willReturn(json_encode($schema['fields'][0]['default']));
  416. $forms = $this->declarativeManager->getFormsWithValues($this->adminUser, $schema['section_type'], $schema['section_id']);
  417. $this->assertNotEmpty($forms);
  418. $this->assertTrue(array_search($schema['id'], array_column($forms, 'id')) !== false);
  419. $testFieldJson = array_values(array_filter(array_filter($forms, fn ($form) => $form['id'] === $schema['id'])[0]['fields'], fn ($field) => $field['id'] === 'test_field_json'))[0];
  420. $this->assertEquals(json_encode($schema['fields'][0]['default']), $testFieldJson['value']);
  421. }
  422. /**
  423. * Check that saving value for field with internal storage_type is handled by core
  424. */
  425. public function testSetInternalValue(): void {
  426. $app = 'testing';
  427. $schema = self::validSchemaAllFields;
  428. $this->declarativeManager->registerSchema($app, $schema);
  429. self::$testSetInternalValueAfterChange = false;
  430. $this->config->expects($this->any())
  431. ->method('getAppValue')
  432. ->willReturnCallback(function ($app, $configkey, $default) {
  433. if ($configkey === 'some_real_setting' && self::$testSetInternalValueAfterChange) {
  434. return '120m';
  435. }
  436. return $default;
  437. });
  438. $this->appConfig->expects($this->once())
  439. ->method('setValueString')
  440. ->with($app, 'some_real_setting', '120m');
  441. $forms = $this->declarativeManager->getFormsWithValues($this->adminUser, $schema['section_type'], $schema['section_id']);
  442. $someRealSettingField = array_values(array_filter(array_filter($forms, fn ($form) => $form['id'] === $schema['id'])[0]['fields'], fn ($field) => $field['id'] === 'some_real_setting'))[0];
  443. $this->assertEquals('40m', $someRealSettingField['value']); // first check that default value (40m) is returned
  444. // Set new value for some_real_setting field
  445. $this->declarativeManager->setValue($this->adminUser, $app, $schema['id'], 'some_real_setting', '120m');
  446. self::$testSetInternalValueAfterChange = true;
  447. $forms = $this->declarativeManager->getFormsWithValues($this->adminUser, $schema['section_type'], $schema['section_id']);
  448. $this->assertNotEmpty($forms);
  449. $this->assertTrue(array_search($schema['id'], array_column($forms, 'id')) !== false);
  450. // Check some_real_setting field default value
  451. $someRealSettingField = array_values(array_filter(array_filter($forms, fn ($form) => $form['id'] === $schema['id'])[0]['fields'], fn ($field) => $field['id'] === 'some_real_setting'))[0];
  452. $this->assertEquals('120m', $someRealSettingField['value']);
  453. }
  454. public function testSetExternalValue(): void {
  455. $app = 'testing';
  456. $schema = self::validSchemaAllFields;
  457. // Change storage_type to external and section_type to personal
  458. $schema['storage_type'] = DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL;
  459. $schema['section_type'] = DeclarativeSettingsTypes::SECTION_TYPE_PERSONAL;
  460. $this->declarativeManager->registerSchema($app, $schema);
  461. $setDeclarativeSettingsValueEvent = new DeclarativeSettingsSetValueEvent(
  462. $this->adminUser,
  463. $app,
  464. $schema['id'],
  465. 'some_real_setting',
  466. '120m'
  467. );
  468. $this->eventDispatcher->expects($this->once())
  469. ->method('dispatchTyped')
  470. ->with($setDeclarativeSettingsValueEvent);
  471. $this->declarativeManager->setValue($this->adminUser, $app, $schema['id'], 'some_real_setting', '120m');
  472. }
  473. public function testAdminFormUserUnauthorized(): void {
  474. $app = 'testing';
  475. $schema = self::validSchemaAllFields;
  476. $this->declarativeManager->registerSchema($app, $schema);
  477. $this->expectException(\Exception::class);
  478. $this->declarativeManager->getFormsWithValues($this->user, $schema['section_type'], $schema['section_id']);
  479. }
  480. /**
  481. * Ensure that the `setValue` method is called if the form implements the handler interface.
  482. */
  483. public function testSetValueWithHandler(): void {
  484. $schema = self::validSchemaAllFields;
  485. $schema['storage_type'] = DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL;
  486. $form = $this->createMock(IDeclarativeSettingsFormWithHandlers::class);
  487. $form->expects(self::atLeastOnce())
  488. ->method('getSchema')
  489. ->willReturn($schema);
  490. // The setter should be called once!
  491. $form->expects(self::once())
  492. ->method('setValue')
  493. ->with('test_field_2', 'some password', $this->adminUser);
  494. \OC::$server->registerService('OCA\\Testing\\Settings\\DeclarativeForm', fn () => $form, false);
  495. $context = $this->createMock(RegistrationContext::class);
  496. $context->expects(self::atLeastOnce())
  497. ->method('getDeclarativeSettings')
  498. ->willReturn([new ServiceRegistration('testing', 'OCA\\Testing\\Settings\\DeclarativeForm')]);
  499. $this->coordinator->expects(self::atLeastOnce())
  500. ->method('getRegistrationContext')
  501. ->willReturn($context);
  502. $this->declarativeManager->loadSchemas();
  503. $this->eventDispatcher->expects(self::never())
  504. ->method('dispatchTyped');
  505. $this->declarativeManager->setValue($this->adminUser, 'testing', 'test_form_1', 'test_field_2', 'some password');
  506. }
  507. public function testGetValueWithHandler(): void {
  508. $schema = self::validSchemaAllFields;
  509. $schema['storage_type'] = DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL;
  510. $form = $this->createMock(IDeclarativeSettingsFormWithHandlers::class);
  511. $form->expects(self::atLeastOnce())
  512. ->method('getSchema')
  513. ->willReturn($schema);
  514. // The setter should be called once!
  515. $form->expects(self::once())
  516. ->method('getValue')
  517. ->with('test_field_2', $this->adminUser)
  518. ->willReturn('very secret password');
  519. \OC::$server->registerService('OCA\\Testing\\Settings\\DeclarativeForm', fn () => $form, false);
  520. $context = $this->createMock(RegistrationContext::class);
  521. $context->expects(self::atLeastOnce())
  522. ->method('getDeclarativeSettings')
  523. ->willReturn([new ServiceRegistration('testing', 'OCA\\Testing\\Settings\\DeclarativeForm')]);
  524. $this->coordinator->expects(self::atLeastOnce())
  525. ->method('getRegistrationContext')
  526. ->willReturn($context);
  527. $this->declarativeManager->loadSchemas();
  528. $this->eventDispatcher->expects(self::never())
  529. ->method('dispatchTyped');
  530. $password = $this->invokePrivate($this->declarativeManager, 'getValue', [$this->adminUser, 'testing', 'test_form_1', 'test_field_2']);
  531. self::assertEquals('very secret password', $password);
  532. }
  533. }