package com.google.jstestdriver.coverage;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* Deserializes a file coverage prototbuffer. Not the prettiest solution
* but workable.
* @author corysmith@google.com (Cory Smith)
*/
public class FileCoverageDeserializer {
// TODO(corysmith): clean this up into a good oo structure...
public FileCoverage deserializeCoverage(InputStream in) throws IOException {
int fileId = parseToIntEndingWith(in, ',');
verifyAndConsumeToken(in, '[');
List<CoveredLine> lines = deserializeLines(in);
return new FileCoverage(fileId, lines);
}
public List<FileCoverage> deserializeCoverages(InputStream in) throws IOException {
verifyAndConsumeToken(in, '[');
List<FileCoverage> coverages = Lists.newLinkedList();
char next = consumeToken(in);
while(next == '[') {
coverages.add(deserializeCoverage(in));
next = conditionalConsumeToken(in, ',');
}
verifyToken(next, ']');
return coverages;
}
public List<CoveredLine> deserializeLines(InputStream in) throws IOException {
List<CoveredLine> lines = Lists.newLinkedList();
char next = consumeToken(in);
while(next == '[') {
lines.add(deserializeLine(in));
next = consumeToken(in);
next = conditionalConsumeToken(in, ',');
}
verifyToken(next, ']');
return lines;
}
public CoveredLine deserializeLine(InputStream in) throws IOException {
int lineNumber = parseToIntEndingWith(in, ',');
int executedNumber = parseToIntEndingWith(in, ']');
return new CoveredLine(lineNumber, executedNumber);
}
// TODO(corysmith): replce this with a utility class?
private char conditionalConsumeToken(InputStream in, char consumable) throws IOException {
char next = consumeToken(in);
if (next == consumable) {
next = consumeToken(in);
}
return next;
}
private void verifyToken(char next, char expected) {
if (next != expected) {
throw new RuntimeException(
String.format("unrecognized format, expected %s was %s",
expected, next));
}
}
private int parseToIntEndingWith(InputStream in, char delim) throws IOException {
StringBuilder intBuilder = new StringBuilder();
char token = consumeToken(in);
while (token != delim) {
intBuilder.append(token);
token = consumeToken(in);
}
return Integer.parseInt(intBuilder.toString());
}
private void verifyAndConsumeToken(InputStream in, char expected) throws IOException {
char token = consumeToken(in);
if (token != expected) {
throw new RuntimeException(
String.format("unrecognized format, expected %s was %s",
expected, token));
}
}
private char consumeToken(InputStream in) throws IOException {
char token = (char) in.read();
while (token == ' ') {
token = (char) in.read();
}
return token;
}
}