Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added round-trip tests #49

Closed
wants to merge 11 commits into from
81 changes: 81 additions & 0 deletions src/test/java/ezvcard/io/roundtrip/JCardRoundTripTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package ezvcard.io.roundtrip;

import java.io.*;

import org.junit.Test;

import ezvcard.VCardVersion;
import ezvcard.io.StreamReader;
import ezvcard.io.StreamWriter;
import ezvcard.io.json.JCardReader;
import ezvcard.io.json.JCardWriter;

/*
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 Buddy Gorven
*/
public class JCardRoundTripTest extends RoundTripTestBase {

public JCardRoundTripTest() throws Throwable {
updateSamples(VCardVersion.V4_0);
}

@Test
public void convert_to_jcard() throws Throwable {
convertAllFromVCard(VCardVersion.V4_0, true, true,
"outlook" // newline conversion on linux
);
}

@Test
public void convert_from_jcard() throws Throwable {
convertAllToVCard(VCardVersion.V4_0, true, true,
"outlook" // newline conversion on linux
);
}

@Override
protected StreamWriter getTargetWriter(Writer sw) {
JCardWriter writer = new JCardWriter(sw);
writer.setPrettyPrint(true);
return writer;
}

@Override
protected StreamReader getTargetReader(File file) throws FileNotFoundException {
return new JCardReader(file);
}

@Override
protected String getTargetExtension() {
return "json";
}
}
217 changes: 217 additions & 0 deletions src/test/java/ezvcard/io/roundtrip/RoundTripTestBase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
package ezvcard.io.roundtrip;

import static org.junit.Assert.*;

import java.io.*;
import java.util.List;

import ezvcard.VCard;
import ezvcard.VCardVersion;
import ezvcard.io.StreamReader;
import ezvcard.io.StreamWriter;
import ezvcard.io.text.VCardReader;
import ezvcard.io.text.VCardWriter;
import ezvcard.property.VCardProperty;
import ezvcard.util.IOUtils;

public abstract class RoundTripTestBase {

static final class Filter implements FilenameFilter {
private final String extension;
private final String[] excludes;

private Filter(String extension, String... excludes) {
this.extension = "." + extension;
for (int i = 0; i < excludes.length; i++) {
excludes[i] = excludes[i].toLowerCase();
}
this.excludes = excludes;
}

public boolean accept(File dir, String name) {
name = name.toLowerCase();
if (!name.endsWith(extension)) {
return false;
} else {
for (String exclude : excludes) {
if (name.contains(exclude)) {
return false;
}
}
}
return true;
}
}

private static final String VCF_EXTENSION = "vcf";

protected RoundTripTestBase() {
getSampleDir().mkdirs();
for (File existing : getSampleDir().listFiles()) {
existing.delete();
}
}

/**
* Run this if there are new vcard samples added to
* src/test/resources/ezvcard/io/text/, or if the output format changes.
*
* @param version the version of VCard to roundtrip to
* @param excludes files to exclude (i.e. files that are known to fail
* roundtrip testing). Files will be excluded if the exclude string is found
* anywhere in the file name (case-insensitive)
*/
public void updateSamples(VCardVersion version, String... excludes) throws Exception {
// Convert source files to target type
File[] sourceFiles = listFiles(new File("src/test/resources/ezvcard/io/text"), VCF_EXTENSION, excludes);
for (File sourceFile : sourceFiles) {
String file = sourceFile.getName().toString();
StringWriter sw = new StringWriter();
try {
convert(getVCardReader(sourceFile), getTargetWriter(sw), version);
} catch (Exception e) {
throw new Exception("Error converting " + file, e);
}
write(file.replaceAll("vcf$", "v" + version.getVersion() + "." + getTargetExtension()), sw.toString());
}

// Convert files from target type back to vcard
for (File targetFile : listFiles(version, getTargetExtension())) {
String file = targetFile.getName().toString();
StringWriter sw = new StringWriter();
try {
convert(getTargetReader(targetFile), getVCardWriter(sw, version), version);
} catch (Exception e) {
throw new Exception("Error converting " + file, e);
}
write(file.replace(getTargetExtension(), VCF_EXTENSION), sw.toString());
}
}

/**
* Converts all files in {@link #getSampleDir()} with names ending in
* {@link #VCF_EXTENSION} using {@link #getTargetWriter(StringWriter)} , and
* asserts that the content matches the file with the corresponding target
* extension.
*
* @param excludes source files to exclude from this test
* @throws IOException
*/
public void convertAllFromVCard(VCardVersion version, boolean equals, boolean content, String... excludes) throws Exception {
for (File vcf : listFiles(version, VCF_EXTENSION, excludes)) {
String vcardFile = vcf.getName().toString();
String targetFile = vcardFile.replace(VCF_EXTENSION, getTargetExtension());
StringWriter vcardSW = new StringWriter();
try {
List<VCard> vcard = convert(getVCardReader(vcf), getTargetWriter(vcardSW), version);
List<VCard> card = convert(getTargetReader(new File(getSampleDir(), targetFile)), null, version);
if (equals) {
assertEquals(vcardFile, card, vcard);
}
} catch (Exception e) {
throw new Exception("Error converting " + vcardFile, e);
}
if (content) {
assertEquals(vcardFile, read(targetFile), vcardSW.toString());
}
}
}

/**
* Converts all files in {@link #getSampleDir()} with names ending in
* {@link #getTargetExtension()} using
* {@link #getVCardWriter(StringWriter, VCardVersion)}, and asserts that the
* content matches the file with the corresponding vcard extension.
*/
public void convertAllToVCard(VCardVersion version, boolean equals, boolean content, String... excludes) throws Exception {
for (File target : listFiles(version, getTargetExtension(), excludes)) {
String targetFile = target.getName().toString();
String vcardFile = targetFile.replace(getTargetExtension(), VCF_EXTENSION);
StringWriter targetSW = new StringWriter();
try {
List<VCard> card = convert(getTargetReader(target), getVCardWriter(targetSW, version), version);
List<VCard> vcard = convert(getVCardReader(new File(getSampleDir(), vcardFile)), null, version);
if (equals) {
assertEquals(vcardFile, vcard, card);
}
} catch (Exception e) {
throw new Exception("Error converting " + targetFile, e);
}
if (content) {
assertEquals(targetFile, read(vcardFile), targetSW.toString());
}
}
}

/**
* @return The extension of the file type under test, not including the "."
*/
protected abstract String getTargetExtension();

/**
* @return A writer for the file type under test
*/
protected abstract StreamWriter getTargetWriter(Writer sw);

/**
* @return A reader for the file type under test
*/
protected abstract StreamReader getTargetReader(File file) throws FileNotFoundException;

protected File getSampleDir() {
return new File("src/test/resources/ezvcard/io/" + getTargetExtension() + "/roundtrip/");
}

protected StreamWriter getVCardWriter(Writer sw, VCardVersion version) {
return new VCardWriter(sw, version);
}

protected StreamReader getVCardReader(File file) throws FileNotFoundException {
return new VCardReader(file);
}

public File[] listFiles(VCardVersion version, String extension, String... excludes) {
return listFiles(getSampleDir(), "v" + version + "." + extension, excludes);
}

public static File[] listFiles(File dir, String extension, String... excludes) {
return dir.listFiles(new Filter(extension, excludes));
}

private static List<VCard> convert(StreamReader reader, StreamWriter writer, VCardVersion version) throws IOException {
try {
List<VCard> result = reader.readAll();
for (VCard vcard : result) {
// Remove any property that is not supported by the version of VCard to be round-tripped to
for (VCardProperty prop : vcard.getProperties()) {
if (!prop.isSupportedBy(version)) {
vcard.removeProperty(prop);
}
}
vcard.setVersion(version);
if (writer != null) {
writer.write(vcard);
}
}
return result;
} finally {
if (writer != null) {
writer.close();
}
reader.close();
}
}

private String read(String fileName) throws IOException {
return IOUtils.getFileContents(new File(getSampleDir(), fileName));
}

private void write(String fileName, String converted) throws IOException {
Writer writer = IOUtils.utf8Writer(new File(getSampleDir(), fileName));
try {
writer.write(converted);
} finally {
writer.close();
}
}
}
75 changes: 75 additions & 0 deletions src/test/java/ezvcard/io/roundtrip/XCardRoundTripTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package ezvcard.io.roundtrip;

import java.io.*;

import org.junit.Test;

import ezvcard.VCardVersion;
import ezvcard.io.StreamReader;
import ezvcard.io.StreamWriter;
import ezvcard.io.xml.XCardReader;
import ezvcard.io.xml.XCardWriter;

public class XCardRoundTripTest extends RoundTripTestBase {

public XCardRoundTripTest() throws Exception {
updateSamples(VCardVersion.V4_0,
"outlook-2003" // &#12; in fburl is not valid xml
);
updateSamples(VCardVersion.V3_0);
}

@Test
public void equals_compare_vcard_4_to_xcard() throws Exception {
convertAllFromVCard(VCardVersion.V4_0, true, false,
"outlook" // newlines not preserved on linux
);
}

@Test
public void content_compare_vcard_4_to_xcard() throws Exception {
convertAllFromVCard(VCardVersion.V4_0, false, true,
"outlook", // newlines not preserved on linux
"iphone", "lotus_notes" // groups are reordered
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

groups are reordered

This has do to with the fact that ez-vcard does not preserve property order in all cases when parsing vCards.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might just need to leave this exclude in then; there's still the equals_compare test to verify that the data from these vcards makes it through the round-trip correctly.

);
}

@Test
public void compare_xcard_to_vcard_4() throws Exception {
convertAllToVCard(VCardVersion.V4_0, true, true,
"outlook" // newline conversion on linux
);
}

@Test
public void compare_vcard_3_to_xcard() throws Exception {
convertAllFromVCard(VCardVersion.V3_0, false, true,
"android", // <pref><integer>1</integer></pref> removed from the ÑÑÑÑÑÑÑÑÑÑÑÑ email
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<pref><integer>1</integer></pref> removed from the ÑÑÑÑÑÑÑÑÑÑÑÑ email

vCard versions 2.1 and 3.0 do not have a PREF parameter. Instead, they have a TYPE=PREF parameter. ez-vcard converts between the two.

"ms_outlook", // newlines not preserved on linux
"iphone", "lotus_notes", // groups are reordered
"outlook-2007", "rfc6350", // tel uri cannot round trip through VCard V3 (is converted to text type)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tel uri cannot round trip through VCard V3 (is converted to text type)

Yep.

"outlook-2003", "thunderbird" // TYPE parameters converted to lowercase
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TYPE parameters converted to lowercase

I've only observed this on TYPE parameters that belong to properties that hold binary data (PHOTO and KEY). This is due to the way ez-vcard parses these properties. All other TYPE parameters keep their case. TYPE properties are case-insensitive, so no data is lost.

);
}

@Test
public void content_compare_xcard_to_vcard_3() throws Exception {
convertAllToVCard(VCardVersion.V3_0, false, true);
}

@Override
protected String getTargetExtension() {
return "xml";
}

@Override
protected StreamWriter getTargetWriter(Writer sw) {
return new XCardWriter(sw);
}

@Override
protected StreamReader getTargetReader(File file) throws FileNotFoundException {
return new XCardReader(file);
}

}
Loading