package se.dolkow.tangiblexml;
import android.util.Xml;
import junit.framework.TestCase;
import org.xmlpull.v1.XmlPullParser;
import java.io.StringReader;
import java.util.ArrayList;
import se.dolkow.tangiblexml.testobj.Student;
import se.dolkow.tangiblexml.testobj.StudentResults;
public class ParserTests extends TestCase {
private <E> E parse(Class<E> clazz, String data) throws Exception {
XmlPullParser xml = Xml.newPullParser();
xml.setInput(new StringReader(data));
Parser<E> parser = new Parser<>(clazz);
return parser.parse(xml);
}
private static final String fullXml = "<?xml version='1.0' encoding='utf-8'?>"
+ "<StudentRegistry>"
+ " <StudentList>"
+ " <Student>"
+ " <CourseGrade>"
+ " <Name>C Programming</Name>"
+ " <Grade>Pretty okay, I guess</Grade>"
+ " <StuffThatWeDontCareAbout />"
+ " </CourseGrade>"
+ " <Name>Snild</Name>"
+ " <CourseGrade>"
+ " <Name>Calculus</Name>"
+ " <Grade>Not that great</Grade>"
+ " </CourseGrade>"
+ " <Id>73</Id>"
+ " <CourseGrade>"
+ " <Name>Some other stuff</Name>"
+ " <!-- this is a comment -->"
+ " </CourseGrade>"
+ " </Student>"
+ " <NotAStudent>"
+ " <Junk />"
+ " </NotAStudent>"
+ " <Student>"
+ " <Name>Someone Else</Name>"
+ " <CourseGrade>"
+ " <Name>Some other stuff</Name>"
+ " </CourseGrade>"
+ " <CourseGrade>"
+ " <Name />"
+ " </CourseGrade>"
+ " </Student>"
+ " </StudentList>"
+ "</StudentRegistry>";
/**
* Checks the result of the "fullXml" string.
*/
private void checkFullResult(StudentResults res) {
assertNotNull(res);
assertNotNull(res.students);
assertEquals(2, res.students.size());
final Student snild = res.students.get(0);
assertEquals("Snild", snild.name);
assertNotNull(snild.id);
assertEquals(73, (int)snild.id);
assertNotNull(snild.courses);
assertNotNull(snild.grades);
assertEquals(3, snild.courses.size());
assertEquals(2, snild.grades.size());
assertEquals("C Programming", snild.courses.get(0));
assertEquals("Calculus", snild.courses.get(1));
assertEquals("Some other stuff", snild.courses.get(2));
assertEquals("Pretty okay, I guess", snild.grades.get(0));
assertEquals("Not that great", snild.grades.get(1));
final Student other = res.students.get(1);
assertEquals("Someone Else", other.name);
assertNull(other.id);
assertNotNull(other.courses);
assertNotNull(other.grades);
assertEquals(2, other.courses.size());
assertEquals(0, other.grades.size());
}
public void testParseRegistry() throws Exception {
StudentResults res = parse(StudentResults.class, fullXml);
checkFullResult(res);
}
private static final class ConcurrentParser extends Thread {
private static final int REPEATS = 100;
public final ArrayList<StudentResults> results = new ArrayList<>();
public final Parser<StudentResults> parser;
public Throwable err = null;
private ConcurrentParser(Parser<StudentResults> parser) {
this.parser = parser;
}
@Override
public void run() {
try {
for (int j=0; j<REPEATS; ++j) {
XmlPullParser xml = Xml.newPullParser();
xml.setInput(new StringReader(fullXml));
results.add(parser.parse(xml));
}
} catch (Throwable t) {
err = t;
}
}
}
public void testParseConcurrent() throws Exception {
final int N = 5;
final Parser<StudentResults> parser = new Parser<>(StudentResults.class);
final ConcurrentParser[] threads = new ConcurrentParser[N];
for (int i=0; i<N; ++i) {
threads[i] = new ConcurrentParser(parser);
}
for (ConcurrentParser t : threads) {
t.start();
}
for (ConcurrentParser t : threads) {
t.join();
assertNull(t.err);
assertEquals(ConcurrentParser.REPEATS, t.results.size());
}
for (int i=0; i<N; ++i) {
for (int j=i+1; j<N; ++j) {
for (StudentResults r1 : threads[i].results) {
checkFullResult(r1);
for (StudentResults r2 : threads[j].results) {
assertNotSame(r1, r2);
}
}
}
}
}
public void testOnlyRoot() throws Exception {
final String xml = "<?xml version='1.0' encoding='utf-8'?>"
+ "<StudentRegistry>"
+ "</StudentRegistry>";
try {
parse(StudentResults.class, xml);
fail("Expected an exception");
} catch (ValueCountException e) {
// ok! We never found a /StudentRegistry/StudentList node!
}
}
public void testEmptyList() throws Exception {
final String xml = "<?xml version='1.0' encoding='utf-8'?>"
+ "<StudentRegistry>"
+ " <StudentList>"
+ " </StudentList>"
+ "</StudentRegistry>";
StudentResults res = parse(StudentResults.class, xml);
assertNotNull(res);
assertNotNull(res.students);
assertEquals(0, res.students.size());
}
public void testMultipleLists() throws Exception {
final String xml = "<?xml version='1.0' encoding='utf-8'?>"
+ "<StudentRegistry>"
+ " <StudentList>"
+ " </StudentList>"
+ "</StudentRegistry>";
parse(StudentResults.class, xml);
}
public void testMissingRequiredField() throws Exception {
final String xml = "<?xml version='1.0' encoding='utf-8'?>"
+ "<StudentRegistry>"
+ " <StudentList>"
+ " <Student>"
+ " <CourseGrade>"
+ " <Name>C Programming</Name>"
+ " <Grade>Pretty okay, I guess</Grade>"
+ " <StuffThatWeDontCareAbout />"
+ " </CourseGrade>"
+ " </Student>"
+ " </StudentList>"
+ "</StudentRegistry>";
try {
parse(StudentResults.class, xml);
fail("Expected an exception");
} catch (ValueCountException e) {
// ok!
}
}
public void testMissingRequiredListElem() throws Exception {
final String xml = "<?xml version='1.0' encoding='utf-8'?>"
+ "<StudentRegistry>"
+ " <StudentList>"
+ " <Student>"
+ " <Name>Snild</Name>"
+ " </Student>"
+ " </StudentList>"
+ "</StudentRegistry>";
try {
parse(StudentResults.class, xml);
fail("Expected an exception");
} catch (ValueCountException e) {
// ok!
}
}
public void testDoubleField() throws Exception {
final String xml = "<?xml version='1.0' encoding='utf-8'?>"
+ "<StudentRegistry>"
+ " <StudentList>"
+ " <Student>"
+ " <Name>Snild</Name>"
+ " <Name>Someone Else</Name>"
+ " </Student>"
+ " </StudentList>"
+ "</StudentRegistry>";
try {
parse(StudentResults.class, xml);
fail("Expected an exception");
} catch (ValueCountException e) {
// ok!
}
}
}