AddressBookImplTest.php 14 KB

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