mirror of https://github.com/dspinellis/UMLGraph
Initial revision
This commit is contained in:
parent
dac09f0720
commit
5da7e8c305
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* UmlGraph class diagram testing framework
|
||||
*
|
||||
* Contibuted by Andrea Aime
|
||||
* (C) Copyright 2005 Diomidis Spinellis
|
||||
*
|
||||
* Permission to use, copy, and distribute this software and its
|
||||
* documentation for any purpose and without fee is hereby granted,
|
||||
* provided that the above copyright notice appear in all copies and that
|
||||
* both that copyright notice and this permission notice appear in
|
||||
* supporting documentation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
package gr.spinellis.umlgraph.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
|
||||
public class BasicTest {
|
||||
|
||||
static String testSourceFolder = "./test-data/simple/java";
|
||||
|
||||
static String testDestFolder = "./test-data/simple/dot-out";
|
||||
|
||||
static String testRefFolder = "./test-data/simple/dot-ref";
|
||||
|
||||
static PrintWriter pw = new PrintWriter(System.out);
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
String[] javaFiles = new File(testSourceFolder).list(new JavaFilter());
|
||||
// String[] javaFiles = new String[] {"MyVector.java"};
|
||||
|
||||
File outFolder = new File(testDestFolder);
|
||||
if (!outFolder.exists())
|
||||
outFolder.mkdirs();
|
||||
|
||||
boolean equal = true;
|
||||
for (int i = 0; i < javaFiles.length; i++) {
|
||||
String javaFileName = javaFiles[i].substring(0, javaFiles[i].length() - 5);
|
||||
String dotPath = new File(testDestFolder, javaFileName + ".dot").getAbsolutePath();
|
||||
String refPath = new File(testRefFolder, javaFileName + ".dot").getAbsolutePath();
|
||||
String javaPath = new File(testSourceFolder, javaFiles[i]).getAbsolutePath();
|
||||
String[] options = new String[] { "-hide", "Hidden", "-private", "-output", dotPath,
|
||||
javaPath };
|
||||
|
||||
com.sun.tools.javadoc.Main.execute("UMLGraph test", pw, pw, pw, "UmlGraph", options);
|
||||
|
||||
System.out.println("Performing diff:\nout:" + dotPath + "\nref:" + refPath);
|
||||
DotDiff differ = new DotDiff(new File(dotPath), new File(refPath));
|
||||
if (differ.graphEquals()) {
|
||||
System.out.println("File contents are structurally equal");
|
||||
} else {
|
||||
equal = false;
|
||||
System.out.println("File contents are structurally not equal");
|
||||
printList("# Lines in out but not in ref", differ.getExtraLines1());
|
||||
printList("# Lines in ref but not in out", differ.getExtraLines2());
|
||||
printList("# Nodes in out but not in ref", differ.getNodes1());
|
||||
printList("# Nodes in ref but not in out", differ.getNodes2());
|
||||
printList("# Arcs in out but not in ref", differ.getArcs1());
|
||||
printList("# Arcs in ref but not in out", differ.getArcs2());
|
||||
}
|
||||
System.out.println("\n\n");
|
||||
}
|
||||
|
||||
if (!equal)
|
||||
System.out.println("ERROR, some file are not structurally equal");
|
||||
else
|
||||
System.out.println("GOOD, all files are structurally equal");
|
||||
}
|
||||
|
||||
private static void printList(String message, List extraOut) {
|
||||
if (extraOut.size() > 0) {
|
||||
System.out.println(message);
|
||||
for (Object o : extraOut) {
|
||||
System.out.println(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class JavaFilter implements FilenameFilter {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.endsWith(".java");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* UmlGraph class diagram testing framework
|
||||
*
|
||||
* Contibuted by Andrea Aime
|
||||
* (C) Copyright 2005 Diomidis Spinellis
|
||||
*
|
||||
* Permission to use, copy, and distribute this software and its
|
||||
* documentation for any purpose and without fee is hereby granted,
|
||||
* provided that the above copyright notice appear in all copies and that
|
||||
* both that copyright notice and this permission notice appear in
|
||||
* supporting documentation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
package gr.spinellis.umlgraph.test;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StreamTokenizer;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DotDiff {
|
||||
|
||||
private List<DotNode> nodes1 = new ArrayList<DotNode>();
|
||||
|
||||
private List<DotNode> nodes2 = new ArrayList<DotNode>();
|
||||
|
||||
private List<DotArc> arcs1 = new ArrayList<DotArc>();
|
||||
|
||||
private List<DotArc> arcs2 = new ArrayList<DotArc>();
|
||||
|
||||
private List<String> extraLines1 = new ArrayList<String>();
|
||||
|
||||
private List<String> extraLines2 = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Builds a dot differ on the two files
|
||||
*
|
||||
* @param dotFirst
|
||||
* @param dotSecond
|
||||
* @throws IOException
|
||||
*/
|
||||
public DotDiff(File dotFirst, File dotSecond) throws IOException {
|
||||
// gather the lines
|
||||
List<String> lines1 = readGraphLines(dotFirst);
|
||||
List<String> lines2 = readGraphLines(dotSecond);
|
||||
|
||||
// parse the lines
|
||||
extraLines1 = parseLines(lines1, nodes1, arcs1);
|
||||
extraLines2 = parseLines(lines2, nodes2, arcs2);
|
||||
|
||||
// diff extra lines
|
||||
for (Iterator<String> it = extraLines1.iterator(); it.hasNext();) {
|
||||
if (extraLines2.remove(it.next()))
|
||||
it.remove();
|
||||
}
|
||||
|
||||
// diff nodes
|
||||
for (Iterator<DotNode> it = nodes1.iterator(); it.hasNext();) {
|
||||
if (nodes2.remove(it.next()))
|
||||
it.remove();
|
||||
}
|
||||
|
||||
// diff arcs
|
||||
for (Iterator<DotArc> it = arcs1.iterator(); it.hasNext();) {
|
||||
if (arcs2.remove(it.next()))
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the dot files are structurally equal, that is, if every
|
||||
* non comment and non header line of the first file appears in the second,
|
||||
* and otherwise.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean graphEquals() {
|
||||
return (extraLines1.size() + extraLines2.size() + nodes1.size() + nodes2.size()
|
||||
+ arcs1.size() + arcs2.size()) == 0;
|
||||
}
|
||||
|
||||
public List<DotArc> getArcs1() {
|
||||
return arcs1;
|
||||
}
|
||||
|
||||
public List<DotArc> getArcs2() {
|
||||
return arcs2;
|
||||
}
|
||||
|
||||
public List<String> getExtraLines1() {
|
||||
return extraLines1;
|
||||
}
|
||||
|
||||
public List<String> getExtraLines2() {
|
||||
return extraLines2;
|
||||
}
|
||||
|
||||
public List<DotNode> getNodes1() {
|
||||
return nodes1;
|
||||
}
|
||||
|
||||
public List<DotNode> getNodes2() {
|
||||
return nodes2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all relevant lines from the dot file
|
||||
*
|
||||
* @param dotFile
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private List<String> readGraphLines(File dotFile) throws IOException {
|
||||
List<String> lines = new ArrayList<String>();
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
br = new BufferedReader(new FileReader(dotFile));
|
||||
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (graphDefinitionLine(line))
|
||||
lines.add(line);
|
||||
}
|
||||
} finally {
|
||||
if (br != null)
|
||||
br.close();
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if a line is relevant or not (unrelevant lines are headers,
|
||||
* comments, "digraf G {" and the closing "}" (to simplify matters we assume
|
||||
* the file is properly structured).
|
||||
*
|
||||
* @param line
|
||||
* @return
|
||||
*/
|
||||
private boolean graphDefinitionLine(String line) {
|
||||
return !(line.startsWith("#") || line.startsWith("//") || line.equals("digraph G {") || line
|
||||
.equals("}"));
|
||||
}
|
||||
|
||||
private List<String> parseLines(List<String> lines, List<DotNode> nodeList, List<DotArc> arcs)
|
||||
throws IOException {
|
||||
List<String> extraLines = new ArrayList<String>();
|
||||
List<String> arcLines = new ArrayList<String>();
|
||||
Map<String, DotNode> nodes = new HashMap<String, DotNode>();
|
||||
for (String line : lines) {
|
||||
int openBrackedIdx = line.indexOf('[');
|
||||
int closedBracketIdx = line.lastIndexOf(']');
|
||||
int arrowIdx = line.indexOf("->");
|
||||
if (openBrackedIdx < 0 && closedBracketIdx < 0 || line.startsWith("edge")
|
||||
|| line.startsWith("node"))
|
||||
extraLines.add(line);
|
||||
else if (arrowIdx > 0 && arrowIdx < openBrackedIdx) { // that's an
|
||||
arcLines.add(line);
|
||||
} else { // that's a node
|
||||
String attributes = line.substring(openBrackedIdx + 1, closedBracketIdx);
|
||||
Map<String, String> attMap = parseAttributes(attributes);
|
||||
String name = line.substring(0, openBrackedIdx - 1).trim();
|
||||
String label = attMap.get("label");
|
||||
DotNode node = new DotNode(name, label, attMap, line);
|
||||
nodes.put(name, node);
|
||||
nodeList.add(node);
|
||||
}
|
||||
}
|
||||
for (String line : arcLines) {
|
||||
int openBrackedIdx = line.indexOf('[');
|
||||
int closedBracketIdx = line.lastIndexOf(']');
|
||||
String attributes = line.substring(openBrackedIdx + 1, closedBracketIdx);
|
||||
String[] names = line.substring(0, openBrackedIdx).split("->");
|
||||
DotNode from = nodes.get(names[0].trim());
|
||||
DotNode to = nodes.get(names[1].trim());
|
||||
if (from == null) {
|
||||
from = new DotNode(names[0], "", new HashMap<String, String>(), "");
|
||||
}
|
||||
if (to == null) {
|
||||
to = new DotNode(names[1], "", new HashMap<String, String>(), "");
|
||||
}
|
||||
arcs.add(new DotArc(from, to, parseAttributes(attributes), line));
|
||||
}
|
||||
return extraLines;
|
||||
}
|
||||
|
||||
private Map<String, String> parseAttributes(String attributes) throws IOException {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
|
||||
StreamTokenizer st = new StreamTokenizer(new StringReader(attributes));
|
||||
st.wordChars('_', '_');
|
||||
st.wordChars('\\', '\\');
|
||||
st.wordChars('\'', '\'');
|
||||
int tokenType;
|
||||
boolean isValue = false;
|
||||
String attName = null;
|
||||
String token = null;
|
||||
while ((tokenType = st.nextToken()) != StreamTokenizer.TT_EOF) {
|
||||
switch (tokenType) {
|
||||
case StreamTokenizer.TT_NUMBER:
|
||||
token = "" + st.nval;
|
||||
break;
|
||||
case StreamTokenizer.TT_WORD:
|
||||
case '"':
|
||||
case '\'':
|
||||
token = st.sval;
|
||||
break;
|
||||
}
|
||||
tokenType = st.nextToken();
|
||||
|
||||
if (isValue) {
|
||||
map.put(attName, token);
|
||||
isValue = false;
|
||||
} else {
|
||||
attName = token;
|
||||
isValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private static class DotNode {
|
||||
String name;
|
||||
|
||||
String label;
|
||||
|
||||
Map<String, String> attributes;
|
||||
|
||||
String line;
|
||||
|
||||
public DotNode(String name, String label, Map<String, String> attributes, String line) {
|
||||
this.name = name;
|
||||
this.label = label.replace("\n", "\\n");
|
||||
this.attributes = attributes;
|
||||
this.line = line.replace("\n", "\\n");
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof DotNode))
|
||||
return false;
|
||||
|
||||
DotNode on = (DotNode) other;
|
||||
if (label == null) // anonymous node
|
||||
return on.label == null && on.name.equals(name) && on.attributes.equals(attributes);
|
||||
else
|
||||
return on.label.equals(label) && on.attributes.equals(attributes);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return name.hashCode() + 17 * attributes.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Node: " + label + "; " + line;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class DotArc {
|
||||
DotNode from;
|
||||
|
||||
DotNode to;
|
||||
|
||||
Map<String, String> attributes;
|
||||
|
||||
String line;
|
||||
|
||||
public DotArc(DotNode from, DotNode to, Map<String, String> attributes, String line) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.attributes = attributes;
|
||||
this.line = line.replace("\n", "\\n");
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof DotArc))
|
||||
return false;
|
||||
|
||||
DotArc oa = (DotArc) other;
|
||||
return oa.from.equals(from) && oa.to.equals(to) && oa.attributes.equals(attributes);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return from.hashCode() + 17 * (to.hashCode() + 17 * attributes.hashCode());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Arc: " + from.label + " -> " + to.label + "; " + line;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* UmlGraph class diagram testing framework
|
||||
*
|
||||
* Contibuted by Andrea Aime
|
||||
* (C) Copyright 2005 Diomidis Spinellis
|
||||
*
|
||||
* Permission to use, copy, and distribute this software and its
|
||||
* documentation for any purpose and without fee is hereby granted,
|
||||
* provided that the above copyright notice appear in all copies and that
|
||||
* both that copyright notice and this permission notice appear in
|
||||
* supporting documentation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
package gr.spinellis.umlgraph.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
|
||||
public class BasicTest {
|
||||
|
||||
static String testSourceFolder = "./test-data/simple/java";
|
||||
|
||||
static String testDestFolder = "./test-data/simple/dot-out";
|
||||
|
||||
static String testRefFolder = "./test-data/simple/dot-ref";
|
||||
|
||||
static PrintWriter pw = new PrintWriter(System.out);
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
String[] javaFiles = new File(testSourceFolder).list(new JavaFilter());
|
||||
// String[] javaFiles = new String[] {"MyVector.java"};
|
||||
|
||||
File outFolder = new File(testDestFolder);
|
||||
if (!outFolder.exists())
|
||||
outFolder.mkdirs();
|
||||
|
||||
boolean equal = true;
|
||||
for (int i = 0; i < javaFiles.length; i++) {
|
||||
String javaFileName = javaFiles[i].substring(0, javaFiles[i].length() - 5);
|
||||
String dotPath = new File(testDestFolder, javaFileName + ".dot").getAbsolutePath();
|
||||
String refPath = new File(testRefFolder, javaFileName + ".dot").getAbsolutePath();
|
||||
String javaPath = new File(testSourceFolder, javaFiles[i]).getAbsolutePath();
|
||||
String[] options = new String[] { "-hide", "Hidden", "-private", "-output", dotPath,
|
||||
javaPath };
|
||||
|
||||
com.sun.tools.javadoc.Main.execute("UMLGraph test", pw, pw, pw, "UmlGraph", options);
|
||||
|
||||
System.out.println("Performing diff:\nout:" + dotPath + "\nref:" + refPath);
|
||||
DotDiff differ = new DotDiff(new File(dotPath), new File(refPath));
|
||||
if (differ.graphEquals()) {
|
||||
System.out.println("File contents are structurally equal");
|
||||
} else {
|
||||
equal = false;
|
||||
System.out.println("File contents are structurally not equal");
|
||||
printList("# Lines in out but not in ref", differ.getExtraLines1());
|
||||
printList("# Lines in ref but not in out", differ.getExtraLines2());
|
||||
printList("# Nodes in out but not in ref", differ.getNodes1());
|
||||
printList("# Nodes in ref but not in out", differ.getNodes2());
|
||||
printList("# Arcs in out but not in ref", differ.getArcs1());
|
||||
printList("# Arcs in ref but not in out", differ.getArcs2());
|
||||
}
|
||||
System.out.println("\n\n");
|
||||
}
|
||||
|
||||
if (!equal)
|
||||
System.out.println("ERROR, some file are not structurally equal");
|
||||
else
|
||||
System.out.println("GOOD, all files are structurally equal");
|
||||
}
|
||||
|
||||
private static void printList(String message, List extraOut) {
|
||||
if (extraOut.size() > 0) {
|
||||
System.out.println(message);
|
||||
for (Object o : extraOut) {
|
||||
System.out.println(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class JavaFilter implements FilenameFilter {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.endsWith(".java");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* UmlGraph class diagram testing framework
|
||||
*
|
||||
* Contibuted by Andrea Aime
|
||||
* (C) Copyright 2005 Diomidis Spinellis
|
||||
*
|
||||
* Permission to use, copy, and distribute this software and its
|
||||
* documentation for any purpose and without fee is hereby granted,
|
||||
* provided that the above copyright notice appear in all copies and that
|
||||
* both that copyright notice and this permission notice appear in
|
||||
* supporting documentation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
package gr.spinellis.umlgraph.test;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StreamTokenizer;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DotDiff {
|
||||
|
||||
private List<DotNode> nodes1 = new ArrayList<DotNode>();
|
||||
|
||||
private List<DotNode> nodes2 = new ArrayList<DotNode>();
|
||||
|
||||
private List<DotArc> arcs1 = new ArrayList<DotArc>();
|
||||
|
||||
private List<DotArc> arcs2 = new ArrayList<DotArc>();
|
||||
|
||||
private List<String> extraLines1 = new ArrayList<String>();
|
||||
|
||||
private List<String> extraLines2 = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Builds a dot differ on the two files
|
||||
*
|
||||
* @param dotFirst
|
||||
* @param dotSecond
|
||||
* @throws IOException
|
||||
*/
|
||||
public DotDiff(File dotFirst, File dotSecond) throws IOException {
|
||||
// gather the lines
|
||||
List<String> lines1 = readGraphLines(dotFirst);
|
||||
List<String> lines2 = readGraphLines(dotSecond);
|
||||
|
||||
// parse the lines
|
||||
extraLines1 = parseLines(lines1, nodes1, arcs1);
|
||||
extraLines2 = parseLines(lines2, nodes2, arcs2);
|
||||
|
||||
// diff extra lines
|
||||
for (Iterator<String> it = extraLines1.iterator(); it.hasNext();) {
|
||||
if (extraLines2.remove(it.next()))
|
||||
it.remove();
|
||||
}
|
||||
|
||||
// diff nodes
|
||||
for (Iterator<DotNode> it = nodes1.iterator(); it.hasNext();) {
|
||||
if (nodes2.remove(it.next()))
|
||||
it.remove();
|
||||
}
|
||||
|
||||
// diff arcs
|
||||
for (Iterator<DotArc> it = arcs1.iterator(); it.hasNext();) {
|
||||
if (arcs2.remove(it.next()))
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the dot files are structurally equal, that is, if every
|
||||
* non comment and non header line of the first file appears in the second,
|
||||
* and otherwise.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean graphEquals() {
|
||||
return (extraLines1.size() + extraLines2.size() + nodes1.size() + nodes2.size()
|
||||
+ arcs1.size() + arcs2.size()) == 0;
|
||||
}
|
||||
|
||||
public List<DotArc> getArcs1() {
|
||||
return arcs1;
|
||||
}
|
||||
|
||||
public List<DotArc> getArcs2() {
|
||||
return arcs2;
|
||||
}
|
||||
|
||||
public List<String> getExtraLines1() {
|
||||
return extraLines1;
|
||||
}
|
||||
|
||||
public List<String> getExtraLines2() {
|
||||
return extraLines2;
|
||||
}
|
||||
|
||||
public List<DotNode> getNodes1() {
|
||||
return nodes1;
|
||||
}
|
||||
|
||||
public List<DotNode> getNodes2() {
|
||||
return nodes2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all relevant lines from the dot file
|
||||
*
|
||||
* @param dotFile
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private List<String> readGraphLines(File dotFile) throws IOException {
|
||||
List<String> lines = new ArrayList<String>();
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
br = new BufferedReader(new FileReader(dotFile));
|
||||
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (graphDefinitionLine(line))
|
||||
lines.add(line);
|
||||
}
|
||||
} finally {
|
||||
if (br != null)
|
||||
br.close();
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if a line is relevant or not (unrelevant lines are headers,
|
||||
* comments, "digraf G {" and the closing "}" (to simplify matters we assume
|
||||
* the file is properly structured).
|
||||
*
|
||||
* @param line
|
||||
* @return
|
||||
*/
|
||||
private boolean graphDefinitionLine(String line) {
|
||||
return !(line.startsWith("#") || line.startsWith("//") || line.equals("digraph G {") || line
|
||||
.equals("}"));
|
||||
}
|
||||
|
||||
private List<String> parseLines(List<String> lines, List<DotNode> nodeList, List<DotArc> arcs)
|
||||
throws IOException {
|
||||
List<String> extraLines = new ArrayList<String>();
|
||||
List<String> arcLines = new ArrayList<String>();
|
||||
Map<String, DotNode> nodes = new HashMap<String, DotNode>();
|
||||
for (String line : lines) {
|
||||
int openBrackedIdx = line.indexOf('[');
|
||||
int closedBracketIdx = line.lastIndexOf(']');
|
||||
int arrowIdx = line.indexOf("->");
|
||||
if (openBrackedIdx < 0 && closedBracketIdx < 0 || line.startsWith("edge")
|
||||
|| line.startsWith("node"))
|
||||
extraLines.add(line);
|
||||
else if (arrowIdx > 0 && arrowIdx < openBrackedIdx) { // that's an
|
||||
arcLines.add(line);
|
||||
} else { // that's a node
|
||||
String attributes = line.substring(openBrackedIdx + 1, closedBracketIdx);
|
||||
Map<String, String> attMap = parseAttributes(attributes);
|
||||
String name = line.substring(0, openBrackedIdx - 1).trim();
|
||||
String label = attMap.get("label");
|
||||
DotNode node = new DotNode(name, label, attMap, line);
|
||||
nodes.put(name, node);
|
||||
nodeList.add(node);
|
||||
}
|
||||
}
|
||||
for (String line : arcLines) {
|
||||
int openBrackedIdx = line.indexOf('[');
|
||||
int closedBracketIdx = line.lastIndexOf(']');
|
||||
String attributes = line.substring(openBrackedIdx + 1, closedBracketIdx);
|
||||
String[] names = line.substring(0, openBrackedIdx).split("->");
|
||||
DotNode from = nodes.get(names[0].trim());
|
||||
DotNode to = nodes.get(names[1].trim());
|
||||
if (from == null) {
|
||||
from = new DotNode(names[0], "", new HashMap<String, String>(), "");
|
||||
}
|
||||
if (to == null) {
|
||||
to = new DotNode(names[1], "", new HashMap<String, String>(), "");
|
||||
}
|
||||
arcs.add(new DotArc(from, to, parseAttributes(attributes), line));
|
||||
}
|
||||
return extraLines;
|
||||
}
|
||||
|
||||
private Map<String, String> parseAttributes(String attributes) throws IOException {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
|
||||
StreamTokenizer st = new StreamTokenizer(new StringReader(attributes));
|
||||
st.wordChars('_', '_');
|
||||
st.wordChars('\\', '\\');
|
||||
st.wordChars('\'', '\'');
|
||||
int tokenType;
|
||||
boolean isValue = false;
|
||||
String attName = null;
|
||||
String token = null;
|
||||
while ((tokenType = st.nextToken()) != StreamTokenizer.TT_EOF) {
|
||||
switch (tokenType) {
|
||||
case StreamTokenizer.TT_NUMBER:
|
||||
token = "" + st.nval;
|
||||
break;
|
||||
case StreamTokenizer.TT_WORD:
|
||||
case '"':
|
||||
case '\'':
|
||||
token = st.sval;
|
||||
break;
|
||||
}
|
||||
tokenType = st.nextToken();
|
||||
|
||||
if (isValue) {
|
||||
map.put(attName, token);
|
||||
isValue = false;
|
||||
} else {
|
||||
attName = token;
|
||||
isValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private static class DotNode {
|
||||
String name;
|
||||
|
||||
String label;
|
||||
|
||||
Map<String, String> attributes;
|
||||
|
||||
String line;
|
||||
|
||||
public DotNode(String name, String label, Map<String, String> attributes, String line) {
|
||||
this.name = name;
|
||||
this.label = label.replace("\n", "\\n");
|
||||
this.attributes = attributes;
|
||||
this.line = line.replace("\n", "\\n");
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof DotNode))
|
||||
return false;
|
||||
|
||||
DotNode on = (DotNode) other;
|
||||
if (label == null) // anonymous node
|
||||
return on.label == null && on.name.equals(name) && on.attributes.equals(attributes);
|
||||
else
|
||||
return on.label.equals(label) && on.attributes.equals(attributes);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return name.hashCode() + 17 * attributes.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Node: " + label + "; " + line;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class DotArc {
|
||||
DotNode from;
|
||||
|
||||
DotNode to;
|
||||
|
||||
Map<String, String> attributes;
|
||||
|
||||
String line;
|
||||
|
||||
public DotArc(DotNode from, DotNode to, Map<String, String> attributes, String line) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.attributes = attributes;
|
||||
this.line = line.replace("\n", "\\n");
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof DotArc))
|
||||
return false;
|
||||
|
||||
DotArc oa = (DotArc) other;
|
||||
return oa.from.equals(from) && oa.to.equals(to) && oa.attributes.equals(attributes);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return from.hashCode() + 17 * (to.hashCode() + 17 * attributes.hashCode());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Arc: " + from.label + " -> " + to.label + "; " + line;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue