AddressBookImplTest.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Björn Schießle <bjoern@schiessle.org>
  7. * @author call-me-matt <nextcloud@matthiasheinisch.de>
  8. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  9. * @author Georg Ehrke <oc.list@georgehrke.com>
  10. * @author Joas Schilling <coding@schilljs.com>
  11. * @author John Molakvoæ <skjnldsv@protonmail.com>
  12. * @author Morris Jobke <hey@morrisjobke.de>
  13. * @author Roeland Jago Douma <roeland@famdouma.nl>
  14. * @author Thomas Müller <thomas.mueller@tmit.eu>
  15. *
  16. * @license AGPL-3.0
  17. *
  18. * This code is free software: you can redistribute it and/or modify
  19. * it under the terms of the GNU Affero General Public License, version 3,
  20. * as published by the Free Software Foundation.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU Affero General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU Affero General Public License, version 3,
  28. * along with this program. If not, see <http://www.gnu.org/licenses/>
  29. *
  30. */
  31. namespace OCA\DAV\Tests\unit\CardDAV;
  32. use OCA\DAV\CardDAV\AddressBook;
  33. use OCA\DAV\CardDAV\AddressBookImpl;
  34. use OCA\DAV\CardDAV\CardDavBackend;
  35. use OCP\IURLGenerator;
  36. use Sabre\VObject\Component\VCard;
  37. use Sabre\VObject\Property\Text;
  38. //use Sabre\VObject\Property\;
  39. use Test\TestCase;
  40. class AddressBookImplTest extends TestCase {
  41. /** @var AddressBookImpl */
  42. private $addressBookImpl;
  43. /** @var array */
  44. private $addressBookInfo;
  45. /** @var AddressBook | \PHPUnit\Framework\MockObject\MockObject */
  46. private $addressBook;
  47. /** @var IURLGenerator | \PHPUnit\Framework\MockObject\MockObject */
  48. private $urlGenerator;
  49. /** @var CardDavBackend | \PHPUnit\Framework\MockObject\MockObject */
  50. private $backend;
  51. /** @var VCard | \PHPUnit\Framework\MockObject\MockObject */
  52. private $vCard;
  53. protected function setUp(): void {
  54. parent::setUp();
  55. $this->addressBookInfo = [
  56. 'id' => 42,
  57. 'uri' => 'system',
  58. 'principaluri' => 'principals/system/system',
  59. '{DAV:}displayname' => 'display name',
  60. ];
  61. $this->addressBook = $this->getMockBuilder(AddressBook::class)
  62. ->disableOriginalConstructor()->getMock();
  63. $this->backend = $this->getMockBuilder(CardDavBackend::class)
  64. ->disableOriginalConstructor()->getMock();
  65. $this->vCard = $this->createMock(VCard::class);
  66. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  67. $this->addressBookImpl = new AddressBookImpl(
  68. $this->addressBook,
  69. $this->addressBookInfo,
  70. $this->backend,
  71. $this->urlGenerator
  72. );
  73. }
  74. public function testGetKey(): void {
  75. $this->assertSame($this->addressBookInfo['id'],
  76. $this->addressBookImpl->getKey());
  77. }
  78. public function testGetDisplayName(): void {
  79. $this->assertSame($this->addressBookInfo['{DAV:}displayname'],
  80. $this->addressBookImpl->getDisplayName());
  81. }
  82. public function testSearch(): void {
  83. /** @var \PHPUnit\Framework\MockObject\MockObject | AddressBookImpl $addressBookImpl */
  84. $addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
  85. ->setConstructorArgs(
  86. [
  87. $this->addressBook,
  88. $this->addressBookInfo,
  89. $this->backend,
  90. $this->urlGenerator,
  91. ]
  92. )
  93. ->setMethods(['vCard2Array', 'readCard'])
  94. ->getMock();
  95. $pattern = 'pattern';
  96. $searchProperties = 'properties';
  97. $this->backend->expects($this->once())->method('search')
  98. ->with($this->addressBookInfo['id'], $pattern, $searchProperties)
  99. ->willReturn(
  100. [
  101. ['uri' => 'foo.vcf', 'carddata' => 'cardData1'],
  102. ['uri' => 'bar.vcf', 'carddata' => 'cardData2']
  103. ]
  104. );
  105. $addressBookImpl->expects($this->exactly(2))->method('readCard')
  106. ->willReturn($this->vCard);
  107. $addressBookImpl->expects($this->exactly(2))->method('vCard2Array')
  108. ->withConsecutive(
  109. ['foo.vcf', $this->vCard],
  110. ['bar.vcf', $this->vCard]
  111. )->willReturn('vCard');
  112. $result = $addressBookImpl->search($pattern, $searchProperties, []);
  113. $this->assertTrue((is_array($result)));
  114. $this->assertSame(2, count($result));
  115. }
  116. /**
  117. * @dataProvider dataTestCreate
  118. *
  119. * @param array $properties
  120. */
  121. public function testCreate($properties): void {
  122. $uid = 'uid';
  123. /** @var \PHPUnit\Framework\MockObject\MockObject | AddressBookImpl $addressBookImpl */
  124. $addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
  125. ->setConstructorArgs(
  126. [
  127. $this->addressBook,
  128. $this->addressBookInfo,
  129. $this->backend,
  130. $this->urlGenerator,
  131. ]
  132. )
  133. ->setMethods(['vCard2Array', 'createUid', 'createEmptyVCard'])
  134. ->getMock();
  135. $expectedProperties = 0;
  136. foreach ($properties as $data) {
  137. if (is_string($data)) {
  138. $expectedProperties++;
  139. } else {
  140. $expectedProperties += count($data);
  141. }
  142. }
  143. $addressBookImpl->expects($this->once())->method('createUid')
  144. ->willReturn($uid);
  145. $addressBookImpl->expects($this->once())->method('createEmptyVCard')
  146. ->with($uid)->willReturn($this->vCard);
  147. $this->vCard->expects($this->exactly($expectedProperties))
  148. ->method('createProperty');
  149. $this->backend->expects($this->once())->method('createCard');
  150. $this->backend->expects($this->never())->method('updateCard');
  151. $this->backend->expects($this->never())->method('getCard');
  152. $addressBookImpl->expects($this->once())->method('vCard2Array')
  153. ->with('uid.vcf', $this->vCard)->willReturn(true);
  154. $this->assertTrue($addressBookImpl->createOrUpdate($properties));
  155. }
  156. public function dataTestCreate() {
  157. return [
  158. [[]],
  159. [['FN' => 'John Doe']],
  160. [['FN' => 'John Doe', 'EMAIL' => ['john@doe.cloud', 'john.doe@example.org']]],
  161. ];
  162. }
  163. public function testUpdate(): void {
  164. $uid = 'uid';
  165. $uri = 'bla.vcf';
  166. $properties = ['URI' => $uri, 'UID' => $uid, 'FN' => 'John Doe'];
  167. /** @var \PHPUnit\Framework\MockObject\MockObject | AddressBookImpl $addressBookImpl */
  168. $addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
  169. ->setConstructorArgs(
  170. [
  171. $this->addressBook,
  172. $this->addressBookInfo,
  173. $this->backend,
  174. $this->urlGenerator,
  175. ]
  176. )
  177. ->setMethods(['vCard2Array', 'createUid', 'createEmptyVCard', 'readCard'])
  178. ->getMock();
  179. $addressBookImpl->expects($this->never())->method('createUid');
  180. $addressBookImpl->expects($this->never())->method('createEmptyVCard');
  181. $this->backend->expects($this->once())->method('getCard')
  182. ->with($this->addressBookInfo['id'], $uri)
  183. ->willReturn(['carddata' => 'data']);
  184. $addressBookImpl->expects($this->once())->method('readCard')
  185. ->with('data')->willReturn($this->vCard);
  186. $this->vCard->expects($this->exactly(count($properties) - 1))
  187. ->method('createProperty');
  188. $this->backend->expects($this->never())->method('createCard');
  189. $this->backend->expects($this->once())->method('updateCard');
  190. $addressBookImpl->expects($this->once())->method('vCard2Array')
  191. ->with($uri, $this->vCard)->willReturn(true);
  192. $this->assertTrue($addressBookImpl->createOrUpdate($properties));
  193. }
  194. public function testUpdateWithTypes(): void {
  195. $uid = 'uid';
  196. $uri = 'bla.vcf';
  197. $properties = ['URI' => $uri, 'UID' => $uid, 'FN' => 'John Doe', 'ADR' => [['type' => 'HOME', 'value' => ';;street;city;;;country']]];
  198. $vCard = new vCard;
  199. $textProperty = $vCard->createProperty('KEY', 'value');
  200. /** @var \PHPUnit\Framework\MockObject\MockObject | AddressBookImpl $addressBookImpl */
  201. $addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
  202. ->setConstructorArgs(
  203. [
  204. $this->addressBook,
  205. $this->addressBookInfo,
  206. $this->backend,
  207. $this->urlGenerator,
  208. ]
  209. )
  210. ->setMethods(['vCard2Array', 'createUid', 'createEmptyVCard', 'readCard'])
  211. ->getMock();
  212. $this->backend->expects($this->once())->method('getCard')
  213. ->with($this->addressBookInfo['id'], $uri)
  214. ->willReturn(['carddata' => 'data']);
  215. $addressBookImpl->expects($this->once())->method('readCard')
  216. ->with('data')->willReturn($this->vCard);
  217. $this->vCard->method('createProperty')->willReturn($textProperty);
  218. $this->vCard->expects($this->exactly(count($properties) - 1))
  219. ->method('createProperty');
  220. $this->vCard->expects($this->once())->method('remove')
  221. ->with('ADR');
  222. $this->vCard->expects($this->once())->method('add');
  223. $addressBookImpl->createOrUpdate($properties);
  224. }
  225. /**
  226. * @dataProvider dataTestGetPermissions
  227. *
  228. * @param array $permissions
  229. * @param int $expected
  230. */
  231. public function testGetPermissions($permissions, $expected): void {
  232. $this->addressBook->expects($this->once())->method('getACL')
  233. ->willReturn($permissions);
  234. $this->assertSame($expected,
  235. $this->addressBookImpl->getPermissions()
  236. );
  237. }
  238. public function dataTestGetPermissions() {
  239. return [
  240. [[], 0],
  241. [[['privilege' => '{DAV:}read']], 1],
  242. [[['privilege' => '{DAV:}write']], 6],
  243. [[['privilege' => '{DAV:}all']], 31],
  244. [[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write']], 7],
  245. [[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}all']], 31],
  246. [[['privilege' => '{DAV:}all'],['privilege' => '{DAV:}write']], 31],
  247. [[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write'],['privilege' => '{DAV:}all']], 31],
  248. [[['privilege' => '{DAV:}all'],['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write']], 31],
  249. ];
  250. }
  251. public function testDelete(): void {
  252. $cardId = 1;
  253. $cardUri = 'cardUri';
  254. $this->backend->expects($this->once())->method('getCardUri')
  255. ->with($cardId)->willReturn($cardUri);
  256. $this->backend->expects($this->once())->method('deleteCard')
  257. ->with($this->addressBookInfo['id'], $cardUri)
  258. ->willReturn(true);
  259. $this->assertTrue($this->addressBookImpl->delete($cardId));
  260. }
  261. public function testReadCard(): void {
  262. $vCard = new VCard();
  263. $vCard->add(new Text($vCard, 'UID', 'uid'));
  264. $vCardSerialized = $vCard->serialize();
  265. $result = $this->invokePrivate($this->addressBookImpl, 'readCard', [$vCardSerialized]);
  266. $resultSerialized = $result->serialize();
  267. $this->assertSame($vCardSerialized, $resultSerialized);
  268. }
  269. public function testCreateUid(): void {
  270. /** @var \PHPUnit\Framework\MockObject\MockObject | AddressBookImpl $addressBookImpl */
  271. $addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
  272. ->setConstructorArgs(
  273. [
  274. $this->addressBook,
  275. $this->addressBookInfo,
  276. $this->backend,
  277. $this->urlGenerator,
  278. ]
  279. )
  280. ->setMethods(['getUid'])
  281. ->getMock();
  282. $addressBookImpl->expects($this->exactly(2))
  283. ->method('getUid')
  284. ->willReturnOnConsecutiveCalls(
  285. 'uid0',
  286. 'uid1',
  287. );
  288. // simulate that 'uid0' already exists, so the second uid will be returned
  289. $this->backend->expects($this->exactly(2))->method('getContact')
  290. ->willReturnCallback(
  291. function ($id, $uid) {
  292. return ($uid === 'uid0.vcf');
  293. }
  294. );
  295. $this->assertSame('uid1',
  296. $this->invokePrivate($addressBookImpl, 'createUid', [])
  297. );
  298. }
  299. public function testCreateEmptyVCard(): void {
  300. $uid = 'uid';
  301. $expectedVCard = new VCard();
  302. $expectedVCard->UID = $uid;
  303. $expectedVCardSerialized = $expectedVCard->serialize();
  304. $result = $this->invokePrivate($this->addressBookImpl, 'createEmptyVCard', [$uid]);
  305. $resultSerialized = $result->serialize();
  306. $this->assertSame($expectedVCardSerialized, $resultSerialized);
  307. }
  308. public function testVCard2Array(): void {
  309. $vCard = new VCard();
  310. $vCard->add($vCard->createProperty('FN', 'Full Name'));
  311. // Multi-value properties
  312. $vCard->add($vCard->createProperty('CLOUD', 'cloud-user1@localhost'));
  313. $vCard->add($vCard->createProperty('CLOUD', 'cloud-user2@example.tld'));
  314. $vCard->add($vCard->createProperty('EMAIL', 'email-user1@localhost'));
  315. $vCard->add($vCard->createProperty('EMAIL', 'email-user2@example.tld'));
  316. $vCard->add($vCard->createProperty('IMPP', 'impp-user1@localhost'));
  317. $vCard->add($vCard->createProperty('IMPP', 'impp-user2@example.tld'));
  318. $vCard->add($vCard->createProperty('TEL', '+49 123456789'));
  319. $vCard->add($vCard->createProperty('TEL', '+1 555 123456789'));
  320. $vCard->add($vCard->createProperty('URL', 'https://localhost'));
  321. $vCard->add($vCard->createProperty('URL', 'https://example.tld'));
  322. // Type depending properties
  323. $property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example');
  324. $property->add('TYPE', 'twitter');
  325. $vCard->add($property);
  326. $property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example-2');
  327. $property->add('TYPE', 'twitter');
  328. $vCard->add($property);
  329. $property = $vCard->createProperty('X-SOCIALPROFILE', 'fb-example');
  330. $property->add('TYPE', 'facebook');
  331. $vCard->add($property);
  332. $array = $this->invokePrivate($this->addressBookImpl, 'vCard2Array', ['uri', $vCard]);
  333. unset($array['PRODID']);
  334. unset($array['UID']);
  335. $this->assertEquals([
  336. 'URI' => 'uri',
  337. 'VERSION' => '4.0',
  338. 'FN' => 'Full Name',
  339. 'CLOUD' => [
  340. 'cloud-user1@localhost',
  341. 'cloud-user2@example.tld',
  342. ],
  343. 'EMAIL' => [
  344. 'email-user1@localhost',
  345. 'email-user2@example.tld',
  346. ],
  347. 'IMPP' => [
  348. 'impp-user1@localhost',
  349. 'impp-user2@example.tld',
  350. ],
  351. 'TEL' => [
  352. '+49 123456789',
  353. '+1 555 123456789',
  354. ],
  355. 'URL' => [
  356. 'https://localhost',
  357. 'https://example.tld',
  358. ],
  359. 'X-SOCIALPROFILE' => [
  360. 'tw-example',
  361. 'tw-example-2',
  362. 'fb-example',
  363. ],
  364. 'isLocalSystemBook' => true,
  365. ], $array);
  366. }
  367. public function testVCard2ArrayWithTypes(): void {
  368. $vCard = new VCard();
  369. $vCard->add($vCard->createProperty('FN', 'Full Name'));
  370. // Multi-value properties
  371. $vCard->add($vCard->createProperty('CLOUD', 'cloud-user1@localhost'));
  372. $vCard->add($vCard->createProperty('CLOUD', 'cloud-user2@example.tld'));
  373. $property = $vCard->createProperty('EMAIL', 'email-user1@localhost');
  374. $property->add('TYPE', 'HOME');
  375. $vCard->add($property);
  376. $property = $vCard->createProperty('EMAIL', 'email-user2@example.tld');
  377. $property->add('TYPE', 'WORK');
  378. $vCard->add($property);
  379. $vCard->add($vCard->createProperty('IMPP', 'impp-user1@localhost'));
  380. $vCard->add($vCard->createProperty('IMPP', 'impp-user2@example.tld'));
  381. $property = $vCard->createProperty('TEL', '+49 123456789');
  382. $property->add('TYPE', 'HOME,VOICE');
  383. $vCard->add($property);
  384. $property = $vCard->createProperty('TEL', '+1 555 123456789');
  385. $property->add('TYPE', 'WORK');
  386. $vCard->add($property);
  387. $vCard->add($vCard->createProperty('URL', 'https://localhost'));
  388. $vCard->add($vCard->createProperty('URL', 'https://example.tld'));
  389. // Type depending properties
  390. $property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example');
  391. $property->add('TYPE', 'twitter');
  392. $vCard->add($property);
  393. $property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example-2');
  394. $property->add('TYPE', 'twitter');
  395. $vCard->add($property);
  396. $property = $vCard->createProperty('X-SOCIALPROFILE', 'fb-example');
  397. $property->add('TYPE', 'facebook');
  398. $vCard->add($property);
  399. $array = $this->invokePrivate($this->addressBookImpl, 'vCard2Array', ['uri', $vCard, true]);
  400. unset($array['PRODID']);
  401. unset($array['UID']);
  402. $this->assertEquals([
  403. 'URI' => 'uri',
  404. 'VERSION' => '4.0',
  405. 'FN' => 'Full Name',
  406. 'CLOUD' => [
  407. ['type' => '', 'value' => 'cloud-user1@localhost'],
  408. ['type' => '', 'value' => 'cloud-user2@example.tld'],
  409. ],
  410. 'EMAIL' => [
  411. ['type' => 'HOME', 'value' => 'email-user1@localhost'],
  412. ['type' => 'WORK', 'value' => 'email-user2@example.tld'],
  413. ],
  414. 'IMPP' => [
  415. ['type' => '', 'value' => 'impp-user1@localhost'],
  416. ['type' => '', 'value' => 'impp-user2@example.tld'],
  417. ],
  418. 'TEL' => [
  419. ['type' => 'HOME,VOICE', 'value' => '+49 123456789'],
  420. ['type' => 'WORK', 'value' => '+1 555 123456789'],
  421. ],
  422. 'URL' => [
  423. ['type' => '', 'value' => 'https://localhost'],
  424. ['type' => '', 'value' => 'https://example.tld'],
  425. ],
  426. 'X-SOCIALPROFILE' => [
  427. ['type' => 'twitter', 'value' => 'tw-example'],
  428. ['type' => 'twitter', 'value' => 'tw-example-2'],
  429. ['type' => 'facebook', 'value' => 'fb-example'],
  430. ],
  431. 'isLocalSystemBook' => true,
  432. ], $array);
  433. }
  434. public function testIsSystemAddressBook(): void {
  435. $addressBookInfo = [
  436. '{http://owncloud.org/ns}owner-principal' => 'principals/system/system',
  437. 'principaluri' => 'principals/system/system',
  438. '{DAV:}displayname' => 'display name',
  439. 'id' => 666,
  440. 'uri' => 'system',
  441. ];
  442. $addressBookImpl = new AddressBookImpl(
  443. $this->addressBook,
  444. $addressBookInfo,
  445. $this->backend,
  446. $this->urlGenerator
  447. );
  448. $this->assertTrue($addressBookImpl->isSystemAddressBook());
  449. }
  450. public function testIsShared(): void {
  451. $addressBookInfo = [
  452. '{http://owncloud.org/ns}owner-principal' => 'user1',
  453. '{DAV:}displayname' => 'Test address book',
  454. 'principaluri' => 'user2',
  455. 'id' => 666,
  456. 'uri' => 'default',
  457. ];
  458. $addressBookImpl = new AddressBookImpl(
  459. $this->addressBook,
  460. $addressBookInfo,
  461. $this->backend,
  462. $this->urlGenerator
  463. );
  464. $this->assertFalse($addressBookImpl->isSystemAddressBook());
  465. $this->assertTrue($addressBookImpl->isShared());
  466. }
  467. public function testIsNotShared(): void {
  468. $addressBookInfo = [
  469. '{http://owncloud.org/ns}owner-principal' => 'user1',
  470. '{DAV:}displayname' => 'Test address book',
  471. 'principaluri' => 'user1',
  472. 'id' => 666,
  473. 'uri' => 'default',
  474. ];
  475. $addressBookImpl = new AddressBookImpl(
  476. $this->addressBook,
  477. $addressBookInfo,
  478. $this->backend,
  479. $this->urlGenerator
  480. );
  481. $this->assertFalse($addressBookImpl->isSystemAddressBook());
  482. $this->assertFalse($addressBookImpl->isShared());
  483. }
  484. }