package ezvcard.io.text;
import static ezvcard.VCardDataType.INTEGER;
import static ezvcard.VCardDataType.TEXT;
import static ezvcard.VCardVersion.V2_1;
import static ezvcard.VCardVersion.V3_0;
import static ezvcard.VCardVersion.V4_0;
import static ezvcard.util.StringUtils.NEWLINE;
import static ezvcard.util.TestUtils.assertNoMoreVCards;
import static ezvcard.util.TestUtils.assertPropertyCount;
import static ezvcard.util.TestUtils.assertVersion;
import static ezvcard.util.TestUtils.assertWarnings;
import static ezvcard.util.TestUtils.each;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.junit.Test;
import com.github.mangstadt.vinnie.codec.QuotedPrintableCodec;
import ezvcard.VCard;
import ezvcard.VCardDataType;
import ezvcard.VCardVersion;
import ezvcard.io.EmbeddedVCardException;
import ezvcard.io.LuckyNumProperty;
import ezvcard.io.LuckyNumProperty.LuckyNumScribe;
import ezvcard.io.MyFormattedNameProperty;
import ezvcard.io.MyFormattedNameProperty.MyFormattedNameScribe;
import ezvcard.io.scribe.CannotParseScribe;
import ezvcard.io.scribe.SkipMeScribe;
import ezvcard.io.scribe.VCardPropertyScribe;
import ezvcard.parameter.AddressType;
import ezvcard.parameter.VCardParameters;
import ezvcard.property.Address;
import ezvcard.property.FormattedName;
import ezvcard.property.Label;
import ezvcard.property.RawProperty;
import ezvcard.property.VCardProperty;
import ezvcard.property.asserter.VCardAsserter;
/*
Copyright (c) 2012-2016, Michael Angstadt
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
/**
* @author Michael Angstadt
*/
public class VCardReaderTest {
/**
* Account for an error in the 4.0 specification, which places multi-valued
* TYPE parameters in double quotes.
*/
@Test
public void type_parameter_enclosed_in_double_quotes() throws Exception {
VCardVersion version = V2_1;
{
//@formatter:off
VCardAsserter asserter = read(
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"PROP;TYPE=\"one,two,,three\";FOO=\"four,five,,six\":\r\n" +
"END:VCARD\r\n"
);
asserter.next(version);
asserter.rawProperty("PROP")
.param("TYPE", "\"one,two,,three\"")
.param("FOO", "\"four,five,,six\"")
.value("")
.noMore();
asserter.done();
//@formatter:on
}
for (VCardVersion v : each(V3_0, V4_0)) {
//@formatter:off
VCardAsserter asserter = read(
"BEGIN:VCARD\r\n" +
"VERSION:" + v + "\r\n" +
"PROP;TYPE=\"one,two,,three\";FOO=\"four,five,,six\":\r\n" +
"END:VCARD\r\n"
);
asserter.next(v);
asserter.rawProperty("PROP")
.param("TYPE", "one", "two", "", "three")
.param("FOO", "four,five,,six")
.value("")
.noMore();
asserter.done();
//@formatter:on
}
}
/**
* All nameless parameters should be assigned a name.
*/
@Test
public void nameless_parameters() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
VCardAsserter asserter = read(
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"PROP;TEXT;QUOTED-PRINTABLE;HOME;FOO:\r\n" +
"END:VCARD\r\n"
);
asserter.next(version);
asserter.rawProperty("PROP")
.param("ENCODING", "QUOTED-PRINTABLE")
.param("TYPE", "HOME", "FOO")
.dataType(VCardDataType.TEXT)
.value("")
.noMore();
asserter.done();
//@formatter:on
}
}
@Test
public void quoted_printable_encoding_invalid_value() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
VCardAsserter asserter = read(
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"PROP;ENCODING=QUOTED-PRINTABLE:=nnnn\r\n" +
"END:VCARD\r\n"
);
asserter.next(version);
asserter.rawProperty("PROP")
.param("ENCODING", "QUOTED-PRINTABLE")
.value("=nnnn")
.noMore();
asserter.warnings(1);
asserter.done();
//@formatter:on
}
}
@Test
public void quoted_printable_invalid_charset() throws Exception {
String decoded = "one=two";
for (VCardVersion version : VCardVersion.values()) {
//without default charset defined
{
Charset charset = Charset.defaultCharset();
QuotedPrintableCodec codec = new QuotedPrintableCodec(charset.name());
String encoded = codec.encode(decoded);
//@formatter:off
VCardAsserter asserter = read(
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"PROP;ENCODING=QUOTED-PRINTABLE;CHARSET=invalid:" + encoded + "\r\n" +
"END:VCARD\r\n"
);
asserter.next(version);
asserter.rawProperty("PROP")
.param("ENCODING", "QUOTED-PRINTABLE")
.param("CHARSET", "invalid")
.value(decoded)
.noMore();
asserter.warnings(1);
asserter.done();
//@formatter:on
}
//with default charset defined
{
Charset charset = Charset.forName("UTF-16");
QuotedPrintableCodec codec = new QuotedPrintableCodec(charset.name());
String encoded = codec.encode(decoded);
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"PROP;ENCODING=QUOTED-PRINTABLE;CHARSET=invalid:" + encoded + "\r\n" +
"END:VCARD\r\n";
VCardReader reader = new VCardReader(str);
reader.setDefaultQuotedPrintableCharset(charset);
VCardAsserter asserter = new VCardAsserter(reader);
asserter.next(version);
asserter.rawProperty("PROP")
.param("ENCODING", "QUOTED-PRINTABLE")
.param("CHARSET", "invalid")
.value(decoded)
.noMore();
asserter.warnings(1);
asserter.done();
//@formatter:on
}
}
}
@Test
public void extended_properties() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"X-LUCKY-NUM:24\r\n" +
"X-GENDER:ma\\,le\r\n" +
"X-LUCKY-NUM:22\r\n" +
"END:VCARD\r\n";
//@formatter:on
VCardReader reader = new VCardReader(str);
reader.registerScribe(new LuckyNumScribe());
VCard vcard = reader.readNext();
assertVersion(version, vcard);
assertPropertyCount(3, vcard);
//read a type that has a type class
List<LuckyNumProperty> luckyNumTypes = vcard.getProperties(LuckyNumProperty.class);
assertEquals(2, luckyNumTypes.size());
assertEquals(24, luckyNumTypes.get(0).luckyNum);
assertEquals(22, luckyNumTypes.get(1).luckyNum);
assertTrue(vcard.getExtendedProperties("X-LUCKY-NUM").isEmpty());
//read a type without a type class
List<RawProperty> genderTypes = vcard.getExtendedProperties("X-GENDER");
assertEquals(1, genderTypes.size());
assertEquals("ma\\,le", genderTypes.get(0).getValue()); //raw type values are not unescaped
assertWarnings(0, reader);
assertNoMoreVCards(reader);
}
}
@Test
public void extended_properties_override_standard_property_scribes() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"FN:John Doe\r\n" +
"END:VCARD\r\n";
//@formatter:on
VCardReader reader = new VCardReader(str);
reader.registerScribe(new MyFormattedNameScribe());
VCard vcard = reader.readNext();
assertVersion(version, vcard);
assertPropertyCount(1, vcard);
//read a type that has a type class
MyFormattedNameProperty fn = vcard.getProperty(MyFormattedNameProperty.class);
assertEquals("JOHN DOE", fn.value);
assertWarnings(0, reader);
assertNoMoreVCards(reader);
}
}
@Test
public void read_multiple() throws Exception {
//@formatter:off
VCardAsserter asserter = read(
"BEGIN:VCARD\r\n" +
"VERSION:2.1\r\n" +
"FN:John Doe\r\n" +
"END:VCARD\r\n" +
"BEGIN:VCARD\r\n" +
"VERSION:3.0\r\n" +
"FN:Jane Doe\r\n" +
"END:VCARD\r\n"
);
asserter.next(V2_1);
asserter.simpleProperty(FormattedName.class)
.value("John Doe")
.noMore();
asserter.next(V3_0);
asserter.simpleProperty(FormattedName.class)
.value("Jane Doe")
.noMore();
asserter.done();
//@formatter:on
}
@Test
public void nested_vcard() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
/*
* Test against all versions, even though nested vCards are only
* supported by 2.1.
*/
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"AGENT:\r\n" +
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"FN:Agent 007\r\n" +
"AGENT:\r\n" +
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"FN:Agent 009\r\n" +
"END:VCARD\r\n" +
"END:VCARD\r\n" +
"FN:John Doe\r\n" +
"END:VCARD\r\n";
//@formatter:on
VCardReader reader = new VCardReader(str);
VCard vcard = reader.readNext();
assertVersion(version, vcard);
assertPropertyCount(2, vcard);
assertEquals("John Doe", vcard.getFormattedName().getValue());
{
VCard agent1 = vcard.getAgent().getVCard();
assertVersion(version, agent1);
assertPropertyCount(2, agent1);
assertEquals("Agent 007", agent1.getFormattedName().getValue());
{
VCard agent2 = agent1.getAgent().getVCard();
assertVersion(version, agent2);
assertPropertyCount(1, agent2);
assertEquals("Agent 009", agent2.getFormattedName().getValue());
}
}
assertWarnings(0, reader);
assertNoMoreVCards(reader);
}
}
@Test
public void nested_vcard_missing_vcard() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
/*
* Test against all versions, even though nested vCards are only
* supported by 2.1.
*/
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"NESTED:\r\n" +
"FN:John Doe\r\n" +
"END:VCARD\r\n";
//@formatter:on
VCardReader reader = new VCardReader(str);
reader.registerScribe(new NestedScribe());
VCard vcard = reader.readNext();
assertVersion(version, vcard);
assertPropertyCount(2, vcard);
assertEquals("John Doe", vcard.getFormattedName().getValue());
assertNull(vcard.getProperty(Nested.class).vcard);
assertWarnings(0, reader);
assertNoMoreVCards(reader);
}
}
@Test
public void nested_vcard_with_labels() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
/*
* Test against all versions, even though nested vCards are only
* supported by 2.1.
*/
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"ADR;TYPE=home:;;;;;\r\n" +
"ADR;TYPE=work:;;;;;\r\n" +
"AGENT:\r\n" +
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"LABEL;TYPE=home:home label\r\n" +
"AGENT:\r\n" +
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"ADR;TYPE=dom:;;;;;\r\n" +
"LABEL;TYPE=dom:dom label\r\n" +
"END:VCARD\r\n" +
"ADR;TYPE=dom:;;;;;\r\n" +
"END:VCARD\r\n" +
"LABEL;TYPE=work:work label\r\n" +
"END:VCARD\r\n";
//@formatter:on
VCardReader reader = new VCardReader(str);
VCard vcard = reader.readNext();
assertVersion(version, vcard);
assertPropertyCount(3, vcard);
Iterator<Address> adrs = vcard.getAddresses().iterator();
Address adr = adrs.next();
assertEquals(Arrays.asList(AddressType.HOME), adr.getTypes());
assertNull(adr.getLabel());
adr = adrs.next();
assertEquals(Arrays.asList(AddressType.WORK), adr.getTypes());
assertEquals("work label", adr.getLabel());
{
VCard agentVCard = vcard.getAgent().getVCard();
assertVersion(version, agentVCard);
assertPropertyCount(3, agentVCard);
adr = agentVCard.getAddresses().get(0);
assertEquals(Arrays.asList(AddressType.DOM), adr.getTypes());
assertNull(adr.getLabel());
Label label = agentVCard.getOrphanedLabels().get(0);
assertEquals(Arrays.asList(AddressType.HOME), label.getTypes());
{
VCard agentAgentVCard = agentVCard.getAgent().getVCard();
assertVersion(version, agentAgentVCard);
assertPropertyCount(1, agentAgentVCard);
adr = agentAgentVCard.getAddresses().get(0);
assertEquals(Arrays.asList(AddressType.DOM), adr.getTypes());
assertEquals("dom label", adr.getLabel());
}
}
assertWarnings(0, reader);
assertNoMoreVCards(reader);
}
}
@Test
public void embedded_vcard() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
/*
* Test against all versions, even though embedded vCards are only
* supported by 3.0.
*/
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"AGENT:" +
"BEGIN:VCARD\\n" +
"VERSION:" + version + "\\n" +
"FN:Agent 007\\n" +
"AGENT:" +
"BEGIN:VCARD\\\\n" +
"VERSION:" + version + "\\\\n" +
"FN:Agent 009\\\\n" +
"END:VCARD\\\\n" +
"END:VCARD\r\n" +
"FN:John Doe\r\n" +
"END:VCARD\r\n";
//@formatter:on
VCardReader reader = new VCardReader(str);
VCard vcard = reader.readNext();
assertVersion(version, vcard);
assertPropertyCount(2, vcard);
assertEquals("John Doe", vcard.getFormattedName().getValue());
{
VCard agentVCard = vcard.getAgent().getVCard();
assertVersion(version, agentVCard);
assertPropertyCount(2, agentVCard);
assertEquals("Agent 007", agentVCard.getFormattedName().getValue());
{
VCard agentAgentVCard = agentVCard.getAgent().getVCard();
assertVersion(version, agentAgentVCard);
assertPropertyCount(1, agentAgentVCard);
assertEquals("Agent 009", agentAgentVCard.getFormattedName().getValue());
}
}
assertWarnings(0, reader);
assertNoMoreVCards(reader);
}
}
/**
* LABEL properties should be assigned to an ADR and stored in the
* "Address.getLabel()" field. LABELs that could not be assigned to an ADR
* should go in "VCard.getOrphanedLabels()".
*/
@Test
public void label_properties() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
VCardAsserter asserter = read(
"BEGIN:VCARD\r\n" +
"VERSION:" + version.getVersion() + "\r\n" +
"ADR;TYPE=home;TYPE=parcel:;;123 Main St.;Austin;TX;91827;USA\r\n" +
"LABEL;TYPE=parcel;TYPE=home:123 Main St.\\nAustin\\, TX 91827\\nUSA\r\n" +
"ADR;TYPE=work:;;200 Broadway;New York;NY;12345;USA\r\n" +
"LABEL;TYPE=parcel:200 Broadway\\nNew York\\, NY 12345\\nUSA\r\n" +
"END:VCARD\r\n"
);
asserter.next(version);
asserter.address()
.streetAddress("123 Main St.")
.locality("Austin")
.region("TX")
.postalCode("91827")
.country("USA")
.label("123 Main St." + NEWLINE + "Austin, TX 91827" + NEWLINE + "USA")
.types(AddressType.HOME, AddressType.PARCEL)
.next()
.streetAddress("200 Broadway")
.locality("New York")
.region("NY")
.postalCode("12345")
.country("USA")
.types(AddressType.WORK)
.noMore();
asserter.simpleProperty(Label.class)
.value("200 Broadway" + NEWLINE + "New York, NY 12345" + NEWLINE + "USA")
.param("TYPE", "parcel")
.noMore();
asserter.done();
//@formatter:on
}
}
/**
* Escaped newlines should ONLY be unescaped in LABEL parameters of ADR
* properties.
*/
@Test
public void label_parameters() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
VCardAsserter asserter = read(
"BEGIN:VCARD\r\n" +
"VERSION:" + version.getVersion() + "\r\n" +
"ADR;LABEL=one\\ntwo;PARAM=one\\ntwo:\r\n" +
"PROP;LABEL=one\\ntwo;PARAM=one\\ntwo:\r\n" +
"END:VCARD\r\n"
);
asserter.next(version);
asserter.address()
.label("one" + NEWLINE + "two")
.param("PARAM", "one\\ntwo")
.noMore();
asserter.rawProperty("PROP")
.param("LABEL", "one\\ntwo")
.param("PARAM", "one\\ntwo")
.value("")
.noMore();
asserter.done();
//@formatter:on
}
}
@Test
public void skipMeException() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"SKIPME:value\r\n" +
"X-FOO:value\r\n" +
"END:VCARD\r\n";
VCardReader reader = new VCardReader(str);
reader.registerScribe(new SkipMeScribe());
VCardAsserter asserter = new VCardAsserter(reader);
asserter.next(version);
asserter.rawProperty("X-FOO")
.value("value")
.noMore();
asserter.warnings(1);
asserter.done();
//@formatter:on
}
}
@Test
public void cannotParseException() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"group.CANNOTPARSE;PARAM=value;VALUE=text:value\r\n" +
"X-FOO:value\r\n" +
"END:VCARD\r\n";
VCardReader reader = new VCardReader(str);
reader.registerScribe(new CannotParseScribe());
VCardAsserter asserter = new VCardAsserter(reader);
asserter.next(version);
asserter.rawProperty("X-FOO")
.value("value")
.noMore();
asserter.rawProperty("CANNOTPARSE")
.group("group")
.param("PARAM", "value")
.dataType(VCardDataType.TEXT)
.value("value")
.noMore();
asserter.warnings(1);
asserter.done();
//@formatter:on
}
}
@Test
public void invalid_line() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
VCardAsserter asserter = read(
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"bad-line\r\n" +
"END:VCARD\r\n"
);
//@formatter:on
asserter.next(version);
asserter.warnings(1);
asserter.done();
}
}
@Test
public void property_warning() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"WARNINGS:foo\r\n" +
"END:VCARD\r\n";
//@formatter:on
VCardReader reader = new VCardReader(str);
reader.registerScribe(new WarningsScribe());
VCard vcard = reader.readNext();
assertVersion(version, vcard);
assertPropertyCount(1, vcard);
assertEquals(Arrays.asList("Line 3 (WARNINGS property): one"), reader.getWarnings());
assertNoMoreVCards(reader);
}
}
@Test
public void warnings_list_cleared() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
VCardAsserter asserter = read(
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"bad-line\r\n" +
"END:VCARD\r\n" +
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"END:VCARD\r\n"
);
//@formatter:on
asserter.next(version);
asserter.warnings(1);
asserter.next(version);
asserter.done();
}
}
@Test
public void warnings_in_nested_vcard() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"AGENT:\r\n" +
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"WARNINGS:value\r\n" +
"END:VCARD\r\n" +
"END:VCARD\r\n";
//@formatter:on
VCardReader reader = new VCardReader(str);
reader.registerScribe(new WarningsScribe());
reader.readNext();
assertEquals(Arrays.asList("Line 6 (WARNINGS property): one"), reader.getWarnings());
assertNoMoreVCards(reader);
}
}
@Test
public void warnings_in_embedded_vcard() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"AGENT:BEGIN:VCARD\\nVERSION:" + version + "\\nWARNINGS:value\\nEND:VCARD\r\n" +
"END:VCARD\r\n";
//@formatter:on
VCardReader reader = new VCardReader(str);
reader.registerScribe(new WarningsScribe());
reader.readNext();
assertEquals(Arrays.asList("Line 3 (AGENT property): Problem parsing property in nested vCard: Line 3 (WARNINGS property): one"), reader.getWarnings());
assertNoMoreVCards(reader);
}
}
@Test
public void value_parameter() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
String str =
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"VAL;VALUE=text;LANGUAGE=en:value\r\n" +
"VAL;LANGUAGE=en:value\r\n" +
"VAL;VALUE=text:value\r\n" +
"VAL:value\r\n" +
"END:VCARD\r\n";
//@formatter:on
VCardReader reader = new VCardReader(str);
reader.registerScribe(new ValueScribe());
VCard vcard = reader.readNext();
assertVersion(version, vcard);
assertPropertyCount(4, vcard);
Iterator<ValueProp> it = vcard.getProperties(ValueProp.class).iterator();
ValueProp prop = it.next();
assertEquals(TEXT, prop.dataType);
assertEquals(1, prop.getParameters().size());
assertNull(prop.getParameters().getValue());
assertEquals("en", prop.getParameters().getLanguage());
prop = it.next();
assertEquals(INTEGER, prop.dataType);
assertEquals(1, prop.getParameters().size());
assertNull(prop.getParameters().getValue());
assertEquals("en", prop.getParameters().getLanguage());
prop = it.next();
assertEquals(TEXT, prop.dataType);
assertEquals(0, prop.getParameters().size());
assertNull(prop.getParameters().getValue());
assertNull(prop.getParameters().getLanguage());
prop = it.next();
assertEquals(INTEGER, prop.dataType);
assertEquals(0, prop.getParameters().size());
assertNull(prop.getParameters().getValue());
assertNull(prop.getParameters().getLanguage());
assertWarnings(0, reader);
assertNoMoreVCards(reader);
}
}
@Test
public void invalid_version() throws Exception {
//@formatter:off
VCardAsserter asserter = read(
"BEGIN:VCARD\r\n" +
"VERSION:invalid\r\n" +
"END:VCARD\r\n"
);
asserter.next(V2_1); //default to 2.1
asserter.rawProperty("VERSION")
.value("invalid")
.noMore();
asserter.warnings(1);
asserter.done();
//@formatter:on
}
@Test
public void skip_non_vcard_components() throws Exception {
for (VCardVersion version : VCardVersion.values()) {
//@formatter:off
VCardAsserter asserter = read(
"BEGIN:VCALENDAR\r\n" +
"VERSION:2.0\r\n" +
"invalid line--warning should not be logged\r\n" +
"PRODID:-//Company//Application//EN\r\n" +
"END:VCALENDAR\r\n" +
"invalid line--warning should not be logged\r\n" +
"BEGIN:VCARD\r\n" +
"VERSION:" + version + "\r\n" +
"FN:John Doe\r\n" +
"END:VCARD\r\n"
);
asserter.next(version);
asserter.simpleProperty(FormattedName.class)
.value("John Doe")
.noMore();
asserter.done();
//@formatter:on
}
}
private static class ValueProp extends VCardProperty {
private final VCardDataType dataType;
public ValueProp(VCardDataType dataType) {
this.dataType = dataType;
}
}
private static class ValueScribe extends VCardPropertyScribe<ValueProp> {
public ValueScribe() {
super(ValueProp.class, "VAL");
}
@Override
protected VCardDataType _defaultDataType(VCardVersion version) {
return INTEGER;
}
@Override
protected String _writeText(ValueProp property, WriteContext context) {
return null;
}
@Override
protected ValueProp _parseText(String value, VCardDataType dataType, VCardVersion version, VCardParameters parameters, List<String> warnings) {
return new ValueProp(dataType);
}
}
private static class WarningsProperty extends VCardProperty {
//empty
}
private static class WarningsScribe extends VCardPropertyScribe<WarningsProperty> {
public WarningsScribe() {
super(WarningsProperty.class, "WARNINGS");
}
@Override
protected VCardDataType _defaultDataType(VCardVersion version) {
return null;
}
@Override
protected String _writeText(WarningsProperty property, WriteContext context) {
return null;
}
@Override
protected WarningsProperty _parseText(String value, VCardDataType dataType, VCardVersion version, VCardParameters parameters, List<String> warnings) {
warnings.add("one");
return new WarningsProperty();
}
}
private static class Nested extends VCardProperty {
/*
* Initialize this to a new VCard instance to test for the fact that
* this should be set to null.
*/
private VCard vcard = new VCard();
}
private static class NestedScribe extends VCardPropertyScribe<Nested> {
public NestedScribe() {
super(Nested.class, "NESTED");
}
@Override
protected VCardDataType _defaultDataType(VCardVersion version) {
return null;
}
@Override
protected String _writeText(Nested property, WriteContext context) {
return "";
}
@Override
protected Nested _parseText(String value, VCardDataType dataType, VCardVersion version, VCardParameters parameters, List<String> warnings) {
throw new EmbeddedVCardException(new EmbeddedVCardException.InjectionCallback() {
private final Nested property = new Nested();
public void injectVCard(VCard vcard) {
property.vcard = vcard;
}
public VCardProperty getProperty() {
return property;
}
});
}
}
private static VCardAsserter read(String str) {
VCardReader reader = new VCardReader(str);
return new VCardAsserter(reader);
}
}