1<?php 2 3namespace Sabre\VObject\Component; 4 5use Sabre\VObject; 6 7class VCardTest extends \PHPUnit_Framework_TestCase { 8 9 /** 10 * @dataProvider validateData 11 */ 12 function testValidate($input, $expectedWarnings, $expectedRepairedOutput) { 13 14 $vcard = VObject\Reader::read($input); 15 16 $warnings = $vcard->validate(); 17 18 $warnMsg = []; 19 foreach ($warnings as $warning) { 20 $warnMsg[] = $warning['message']; 21 } 22 23 $this->assertEquals($expectedWarnings, $warnMsg); 24 25 $vcard->validate(VObject\Component::REPAIR); 26 27 $this->assertEquals( 28 $expectedRepairedOutput, 29 $vcard->serialize() 30 ); 31 32 } 33 34 function validateData() { 35 36 $tests = []; 37 38 // Correct 39 $tests[] = [ 40 "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nUID:foo\r\nEND:VCARD\r\n", 41 [], 42 "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nUID:foo\r\nEND:VCARD\r\n", 43 ]; 44 45 // No VERSION 46 $tests[] = [ 47 "BEGIN:VCARD\r\nFN:John Doe\r\nUID:foo\r\nEND:VCARD\r\n", 48 [ 49 'VERSION MUST appear exactly once in a VCARD component', 50 ], 51 "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nUID:foo\r\nEND:VCARD\r\n", 52 ]; 53 54 // Unknown version 55 $tests[] = [ 56 "BEGIN:VCARD\r\nVERSION:2.2\r\nFN:John Doe\r\nUID:foo\r\nEND:VCARD\r\n", 57 [ 58 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.', 59 ], 60 "BEGIN:VCARD\r\nVERSION:2.1\r\nFN:John Doe\r\nUID:foo\r\nEND:VCARD\r\n", 61 ]; 62 63 // No FN 64 $tests[] = [ 65 "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nEND:VCARD\r\n", 66 [ 67 'The FN property must appear in the VCARD component exactly 1 time', 68 ], 69 "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nEND:VCARD\r\n", 70 ]; 71 // No FN, N fallback 72 $tests[] = [ 73 "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nN:Doe;John;;;;;\r\nEND:VCARD\r\n", 74 [ 75 'The FN property must appear in the VCARD component exactly 1 time', 76 ], 77 "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nN:Doe;John;;;;;\r\nFN:John Doe\r\nEND:VCARD\r\n", 78 ]; 79 // No FN, N fallback, no first name 80 $tests[] = [ 81 "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nN:Doe;;;;;;\r\nEND:VCARD\r\n", 82 [ 83 'The FN property must appear in the VCARD component exactly 1 time', 84 ], 85 "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nN:Doe;;;;;;\r\nFN:Doe\r\nEND:VCARD\r\n", 86 ]; 87 88 // No FN, ORG fallback 89 $tests[] = [ 90 "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nORG:Acme Co.\r\nEND:VCARD\r\n", 91 [ 92 'The FN property must appear in the VCARD component exactly 1 time', 93 ], 94 "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nORG:Acme Co.\r\nFN:Acme Co.\r\nEND:VCARD\r\n", 95 ]; 96 return $tests; 97 98 } 99 100 function testGetDocumentType() { 101 102 $vcard = new VCard([], false); 103 $vcard->VERSION = '2.1'; 104 $this->assertEquals(VCard::VCARD21, $vcard->getDocumentType()); 105 106 $vcard = new VCard([], false); 107 $vcard->VERSION = '3.0'; 108 $this->assertEquals(VCard::VCARD30, $vcard->getDocumentType()); 109 110 $vcard = new VCard([], false); 111 $vcard->VERSION = '4.0'; 112 $this->assertEquals(VCard::VCARD40, $vcard->getDocumentType()); 113 114 $vcard = new VCard([], false); 115 $this->assertEquals(VCard::UNKNOWN, $vcard->getDocumentType()); 116 } 117 118 function testGetByType() { 119 $vcard = <<<VCF 120BEGIN:VCARD 121VERSION:3.0 122EMAIL;TYPE=home:1@example.org 123EMAIL;TYPE=work:2@example.org 124END:VCARD 125VCF; 126 127 $vcard = VObject\Reader::read($vcard); 128 $this->assertEquals('1@example.org', $vcard->getByType('EMAIL', 'home')->getValue()); 129 $this->assertEquals('2@example.org', $vcard->getByType('EMAIL', 'work')->getValue()); 130 $this->assertNull($vcard->getByType('EMAIL', 'non-existant')); 131 $this->assertNull($vcard->getByType('ADR', 'non-existant')); 132 } 133 134 function testPreferredNoPref() { 135 136 $vcard = <<<VCF 137BEGIN:VCARD 138VERSION:3.0 139EMAIL:1@example.org 140EMAIL:2@example.org 141END:VCARD 142VCF; 143 144 $vcard = VObject\Reader::read($vcard); 145 $this->assertEquals('1@example.org', $vcard->preferred('EMAIL')->getValue()); 146 147 } 148 149 function testPreferredWithPref() { 150 151 $vcard = <<<VCF 152BEGIN:VCARD 153VERSION:3.0 154EMAIL:1@example.org 155EMAIL;TYPE=PREF:2@example.org 156END:VCARD 157VCF; 158 159 $vcard = VObject\Reader::read($vcard); 160 $this->assertEquals('2@example.org', $vcard->preferred('EMAIL')->getValue()); 161 162 } 163 164 function testPreferredWith40Pref() { 165 166 $vcard = <<<VCF 167BEGIN:VCARD 168VERSION:4.0 169EMAIL:1@example.org 170EMAIL;PREF=3:2@example.org 171EMAIL;PREF=2:3@example.org 172END:VCARD 173VCF; 174 175 $vcard = VObject\Reader::read($vcard); 176 $this->assertEquals('3@example.org', $vcard->preferred('EMAIL')->getValue()); 177 178 } 179 180 function testPreferredNotFound() { 181 182 $vcard = <<<VCF 183BEGIN:VCARD 184VERSION:4.0 185END:VCARD 186VCF; 187 188 $vcard = VObject\Reader::read($vcard); 189 $this->assertNull($vcard->preferred('EMAIL')); 190 191 } 192 193 function testNoUIDCardDAV() { 194 195 $vcard = <<<VCF 196BEGIN:VCARD 197VERSION:4.0 198FN:John Doe 199END:VCARD 200VCF; 201 $this->assertValidate( 202 $vcard, 203 VCARD::PROFILE_CARDDAV, 204 3, 205 'vCards on CardDAV servers MUST have a UID property.' 206 ); 207 208 } 209 210 function testNoUIDNoCardDAV() { 211 212 $vcard = <<<VCF 213BEGIN:VCARD 214VERSION:4.0 215FN:John Doe 216END:VCARD 217VCF; 218 $this->assertValidate( 219 $vcard, 220 0, 221 2, 222 'Adding a UID to a vCard property is recommended.' 223 ); 224 225 } 226 function testNoUIDNoCardDAVRepair() { 227 228 $vcard = <<<VCF 229BEGIN:VCARD 230VERSION:4.0 231FN:John Doe 232END:VCARD 233VCF; 234 $this->assertValidate( 235 $vcard, 236 VCARD::REPAIR, 237 1, 238 'Adding a UID to a vCard property is recommended.' 239 ); 240 241 } 242 243 function testVCard21CardDAV() { 244 245 $vcard = <<<VCF 246BEGIN:VCARD 247VERSION:2.1 248FN:John Doe 249UID:foo 250END:VCARD 251VCF; 252 $this->assertValidate( 253 $vcard, 254 VCARD::PROFILE_CARDDAV, 255 3, 256 'CardDAV servers are not allowed to accept vCard 2.1.' 257 ); 258 259 } 260 261 function testVCard21NoCardDAV() { 262 263 $vcard = <<<VCF 264BEGIN:VCARD 265VERSION:2.1 266FN:John Doe 267UID:foo 268END:VCARD 269VCF; 270 $this->assertValidate( 271 $vcard, 272 0, 273 0 274 ); 275 276 } 277 278 function assertValidate($vcf, $options, $expectedLevel, $expectedMessage = null) { 279 280 $vcal = VObject\Reader::read($vcf); 281 $result = $vcal->validate($options); 282 283 $this->assertValidateResult($result, $expectedLevel, $expectedMessage); 284 285 } 286 287 function assertValidateResult($input, $expectedLevel, $expectedMessage = null) { 288 289 $messages = []; 290 foreach ($input as $warning) { 291 $messages[] = $warning['message']; 292 } 293 294 if ($expectedLevel === 0) { 295 $this->assertEquals(0, count($input), 'No validation messages were expected. We got: ' . implode(', ', $messages)); 296 } else { 297 $this->assertEquals(1, count($input), 'We expected exactly 1 validation message, We got: ' . implode(', ', $messages)); 298 299 $this->assertEquals($expectedMessage, $input[0]['message']); 300 $this->assertEquals($expectedLevel, $input[0]['level']); 301 } 302 303 } 304} 305