AddressBookImplTest.php 15 KB

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