You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AddressBookImplTest.php 17KB

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