mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
GP-155 - Help - fixed intermittent build failure due to different nodes
with shared 'text' attribute values
This commit is contained in:
parent
798c3abf42
commit
68ef3a22c5
4 changed files with 252 additions and 145 deletions
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,16 +15,16 @@
|
|||
*/
|
||||
package help;
|
||||
|
||||
import help.validator.LinkDatabase;
|
||||
import help.validator.model.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
import help.validator.LinkDatabase;
|
||||
import help.validator.model.*;
|
||||
|
||||
/**
|
||||
* A class that will take in a group of help directories and create a tree of
|
||||
* A class that will take in a group of help directories and create a tree of
|
||||
* help Table of Contents (TOC) items. Ideally, this tree can be used to create a single
|
||||
* TOC document, or individual TOC documents, one for each help directory (this allows
|
||||
* for better modularity).
|
||||
|
@ -33,7 +32,6 @@ import java.util.*;
|
|||
* We call this class an <b>overlay</b> tree to drive home the idea that each
|
||||
* help directory's TOC data is put into the tree, with any duplicate paths overlayed
|
||||
* on top of those from other help directories.
|
||||
*
|
||||
*/
|
||||
public class OverlayHelpTree {
|
||||
|
||||
|
@ -44,10 +42,13 @@ public class OverlayHelpTree {
|
|||
|
||||
public OverlayHelpTree(TOCItemProvider tocItemProvider, LinkDatabase linkDatabase) {
|
||||
this.linkDatabase = linkDatabase;
|
||||
for (TOCItemExternal external : tocItemProvider.getTOCItemExternalsByDisplayMapping().values()) {
|
||||
for (TOCItemExternal external : tocItemProvider.getTOCItemExternalsByDisplayMapping()
|
||||
.values()) {
|
||||
addExternalTOCItem(external);
|
||||
}
|
||||
for (TOCItemDefinition definition : tocItemProvider.getTOCItemDefinitionsByIDMapping().values()) {
|
||||
|
||||
for (TOCItemDefinition definition : tocItemProvider.getTOCItemDefinitionsByIDMapping()
|
||||
.values()) {
|
||||
addSourceTOCItem(definition);
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +62,7 @@ public class OverlayHelpTree {
|
|||
|
||||
//
|
||||
// We will have equivalent items in the generated TOC files, as that is how we
|
||||
// enable merging of TOC files in the JavaHelp system. So, multiple roots are
|
||||
// enable merging of TOC files in the JavaHelp system. So, multiple roots are
|
||||
// OK.
|
||||
//
|
||||
|
||||
|
@ -86,7 +87,7 @@ public class OverlayHelpTree {
|
|||
if (parentID == null) {
|
||||
// must be the root, since the root has no parent
|
||||
if (rootItem != null) {
|
||||
// when loading source items, it is only an error when there is more than one
|
||||
// when loading source items, it is only an error when there is more than one
|
||||
// root item defined *in the same file*
|
||||
if (rootItem.getSourceFile().equals(item.getSourceFile())) {
|
||||
throw new IllegalArgumentException(
|
||||
|
@ -125,7 +126,7 @@ public class OverlayHelpTree {
|
|||
PrintWriter writer = new PrintWriter(new BufferedWriter(osw));
|
||||
printTreeForID(writer, sourceFileID);
|
||||
|
||||
// debug
|
||||
// debug
|
||||
// writer = new PrintWriter(System.err);
|
||||
// printTreeForID(writer, sourceFileID);
|
||||
}
|
||||
|
@ -167,12 +168,6 @@ public class OverlayHelpTree {
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO delete this debug
|
||||
// Set<Entry<String, Set<TOCItem>>> entrySet = parentToChildrenMap.entrySet();
|
||||
// for (Entry<String, Set<TOCItem>> entry : entrySet) {
|
||||
// System.out.println(entry.getKey() + " -> " + entry.getValue());
|
||||
// }
|
||||
|
||||
OverlayNode newRootNode = new OverlayNode(null, rootItem);
|
||||
buildChildren(newRootNode);
|
||||
|
||||
|
@ -255,6 +250,7 @@ public class OverlayHelpTree {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO LOOKIE
|
||||
private static final Comparator<OverlayNode> CHILD_SORT_COMPARATOR =
|
||||
new Comparator<OverlayNode>() {
|
||||
@Override
|
||||
|
@ -266,7 +262,7 @@ public class OverlayHelpTree {
|
|||
return o1.getSortPreference().compareTo(o2.getSortPreference());
|
||||
}
|
||||
|
||||
// if sort preference is the same, then sort alphabetically by display name
|
||||
// if sort preference is the same, then sort alphabetically by display name
|
||||
String text1 = o1.getTextAttribute();
|
||||
String text2 = o2.getTextAttribute();
|
||||
|
||||
|
@ -283,7 +279,16 @@ public class OverlayHelpTree {
|
|||
return -1;
|
||||
}
|
||||
|
||||
return text1.compareTo(text2);
|
||||
int result = text1.compareTo(text2);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// At this point we have 2 nodes that have the same text attribute as children of
|
||||
// a <TOCDEF> tag. This is OK, as we use text only for sorting, but not for the
|
||||
// display text. Use the ID as a tie-breaker for sorting, which should provide
|
||||
// sorting consistency.
|
||||
return o1.getIDAttribute().compareTo(o2.getIDAttribute()); // ID should not be null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,27 +15,27 @@
|
|||
*/
|
||||
package help.validator.model;
|
||||
|
||||
import help.validator.LinkDatabase;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
import help.validator.LinkDatabase;
|
||||
|
||||
/**
|
||||
* A Table of Contents entry, which is represented in the help output as an xml tag.
|
||||
*/
|
||||
public abstract class TOCItem {
|
||||
|
||||
//@formatter:off
|
||||
protected static final String[] INDENTS = {
|
||||
"",
|
||||
"\t",
|
||||
"\t\t",
|
||||
"\t\t\t",
|
||||
protected static final String[] INDENTS = {
|
||||
"",
|
||||
"\t",
|
||||
"\t\t",
|
||||
"\t\t\t",
|
||||
"\t\t\t\t",
|
||||
"\t\t\t\t\t",
|
||||
"\t\t\t\t\t\t",
|
||||
"\t\t\t\t\t\t\t",
|
||||
"\t\t\t\t\t",
|
||||
"\t\t\t\t\t\t",
|
||||
"\t\t\t\t\t\t\t",
|
||||
"\t\t\t\t\t\t\t\t"
|
||||
};
|
||||
//@formatter:on
|
||||
|
@ -63,7 +63,8 @@ public abstract class TOCItem {
|
|||
String sortPreference, int lineNumber) {
|
||||
this.parentItem = parentItem;
|
||||
this.sourceFile = sourceFile;
|
||||
this.IDAttribute = ID;
|
||||
this.IDAttribute = Objects.requireNonNull(ID,
|
||||
"TOC Tag missing 'id' attribute: " + sourceFile + ":" + lineNumber);
|
||||
this.textAttribute = text;
|
||||
|
||||
this.targetAttribute = target;
|
||||
|
@ -157,82 +158,108 @@ public abstract class TOCItem {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
if (this == obj) {
|
||||
return true;
|
||||
if (obj == null)
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TOCItem other = (TOCItem) obj;
|
||||
if (IDAttribute == null) {
|
||||
if (other.IDAttribute != null)
|
||||
if (other.IDAttribute != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!IDAttribute.equals(other.IDAttribute))
|
||||
else if (!IDAttribute.equals(other.IDAttribute)) {
|
||||
return false;
|
||||
}
|
||||
if (sortPreference == null) {
|
||||
if (other.sortPreference != null)
|
||||
if (other.sortPreference != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!sortPreference.equals(other.sortPreference))
|
||||
else if (!sortPreference.equals(other.sortPreference)) {
|
||||
return false;
|
||||
}
|
||||
if (sourceFile == null) {
|
||||
if (other.sourceFile != null)
|
||||
if (other.sourceFile != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!sourceFile.equals(other.sourceFile))
|
||||
else if (!sourceFile.equals(other.sourceFile)) {
|
||||
return false;
|
||||
}
|
||||
if (targetAttribute == null) {
|
||||
if (other.targetAttribute != null)
|
||||
if (other.targetAttribute != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!targetAttribute.equals(other.targetAttribute))
|
||||
else if (!targetAttribute.equals(other.targetAttribute)) {
|
||||
return false;
|
||||
}
|
||||
if (textAttribute == null) {
|
||||
if (other.textAttribute != null)
|
||||
if (other.textAttribute != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!textAttribute.equals(other.textAttribute))
|
||||
else if (!textAttribute.equals(other.textAttribute)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the two items are the same, except that they come from a different source file.
|
||||
* @param other the other item
|
||||
* @return true if equivalent
|
||||
*/
|
||||
public boolean isEquivalent(TOCItem other) {
|
||||
if (this == other)
|
||||
if (this == other) {
|
||||
return true;
|
||||
if (other == null)
|
||||
}
|
||||
if (other == null) {
|
||||
return false;
|
||||
if (getClass() != other.getClass())
|
||||
}
|
||||
if (getClass() != other.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IDAttribute == null) {
|
||||
if (other.IDAttribute != null)
|
||||
if (other.IDAttribute != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!IDAttribute.equals(other.IDAttribute))
|
||||
else if (!IDAttribute.equals(other.IDAttribute)) {
|
||||
return false;
|
||||
}
|
||||
if (sortPreference == null) {
|
||||
if (other.sortPreference != null)
|
||||
if (other.sortPreference != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!sortPreference.equals(other.sortPreference))
|
||||
else if (!sortPreference.equals(other.sortPreference)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (targetAttribute == null) {
|
||||
if (other.targetAttribute != null)
|
||||
if (other.targetAttribute != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!targetAttribute.equals(other.targetAttribute))
|
||||
else if (!targetAttribute.equals(other.targetAttribute)) {
|
||||
return false;
|
||||
}
|
||||
if (textAttribute == null) {
|
||||
if (other.textAttribute != null)
|
||||
if (other.textAttribute != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!textAttribute.equals(other.textAttribute))
|
||||
else if (!textAttribute.equals(other.textAttribute)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -253,14 +280,15 @@ public abstract class TOCItem {
|
|||
}
|
||||
}
|
||||
|
||||
public String generateTOCItemTag(LinkDatabase linkDatabase, boolean isInlineTag, int indentLevel) {
|
||||
public String generateTOCItemTag(LinkDatabase linkDatabase, boolean isInlineTag,
|
||||
int indentLevel) {
|
||||
StringBuilder buildy = new StringBuilder();
|
||||
buildy.append(INDENTS[indentLevel]);
|
||||
buildy.append('<').append(TOC_TAG_NAME).append(' ');
|
||||
|
||||
// text attribute
|
||||
// NOTE: we do not put our display text in this attribute. This is because JavaHelp uses
|
||||
// this attribute for sorting. We want to separate sorting from display, so we
|
||||
// this attribute for sorting. We want to separate sorting from display, so we
|
||||
// manipulate the JavaHelp software by setting this attribute the desired sort value.
|
||||
// We have overridden JavaHelp to use a custom renderer that will paint the display
|
||||
// text with the attribute we set below.
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package help;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
@ -36,31 +36,31 @@ import help.validator.model.*;
|
|||
public class OverlayHelpTreeTest {
|
||||
|
||||
@Test
|
||||
public void testSourceTOCFileThatDependsUponPreBuiltHelp() {
|
||||
public void testSourceTOCFileThatDependsUponPreBuiltHelp() {
|
||||
//
|
||||
// We want to make sure the overlay tree will properly resolve help TOC items being
|
||||
// We want to make sure the overlay tree will properly resolve help TOC items being
|
||||
// built from TOC_Source.xml files when that file uses <TOCREF> items that are defined
|
||||
// in a help <TOCITEM> that lives inside of a pre-built jar file.
|
||||
//
|
||||
/*
|
||||
|
||||
|
||||
Example makeup we will create:
|
||||
|
||||
|
||||
PreBuild_TOC.xml
|
||||
|
||||
|
||||
<tocitem id="root" target="fake">
|
||||
<tocitem id="child_1" target="fake" />
|
||||
</tocitem>
|
||||
|
||||
|
||||
TOC_Source.xml
|
||||
|
||||
|
||||
|
||||
TOC_Source.xml
|
||||
|
||||
<tocref id="root">
|
||||
<tocref="child_1">
|
||||
<tocdef id="child_2" target="fake" />
|
||||
</tocref>
|
||||
</tocref>
|
||||
|
||||
|
||||
*/
|
||||
|
||||
TOCItemExternal root = externalItem("root");
|
||||
|
@ -68,12 +68,12 @@ public class OverlayHelpTreeTest {
|
|||
|
||||
Path tocSourceFile = Paths.get("/fake/path_2/TOC_Source.xml");
|
||||
String root_ID = root.getIDAttribute();
|
||||
TOCItemReference root_ref = referenceItem(root_ID, tocSourceFile);
|
||||
TOCItemReference root_ref = tocref(root_ID, tocSourceFile);
|
||||
|
||||
String child_1_ID = child_1.getIDAttribute();
|
||||
TOCItemReference child_1_ref = referenceItem(root_ref, child_1_ID, tocSourceFile);
|
||||
TOCItemReference child_1_ref = tocref(root_ref, child_1_ID, tocSourceFile);
|
||||
|
||||
TOCItemDefinition child_2 = definitionItem(child_1_ref, "child_2", tocSourceFile);
|
||||
TOCItemDefinition child_2 = tocdef(child_1_ref, "child_2", tocSourceFile);
|
||||
|
||||
TOCItemProviderTestStub tocProvider = new TOCItemProviderTestStub();
|
||||
tocProvider.addExternal(root);
|
||||
|
@ -89,41 +89,92 @@ public class OverlayHelpTreeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSourceTOCFileThatDependsUponPreBuiltHelp_MultiplePreBuiltInputs() {
|
||||
public void testSourceTOCFileThatDependsAnotherTOCSourceFile() {
|
||||
|
||||
/*
|
||||
|
||||
The first source file defines attributes that the second file references.
|
||||
|
||||
Example makeup we will create:
|
||||
|
||||
TOC_Source.xml
|
||||
|
||||
<tocdef id="root" target="fake">
|
||||
<tocdef id="child_1" target="fake" />
|
||||
</tocdef>
|
||||
|
||||
|
||||
Another TOC_Source.xml
|
||||
|
||||
<tocref id="root">
|
||||
<tocref="child_1">
|
||||
<tocdef id="child_2" target="fake" />
|
||||
</tocref>
|
||||
</tocref>
|
||||
|
||||
*/
|
||||
|
||||
Path toc_1 = Paths.get("/fake/path_1/TOC_Source.xml");
|
||||
TOCItemDefinition root = tocdef("root", toc_1);
|
||||
TOCItemDefinition child_1 = tocdef(root, "child_1", toc_1);
|
||||
|
||||
Path toc_2 = Paths.get("/fake/path_2/TOC_Source.xml");
|
||||
String root_ID = root.getIDAttribute();
|
||||
String child_1_ID = child_1.getIDAttribute();
|
||||
|
||||
TOCItemReference root_ref = tocref(root_ID, toc_2);
|
||||
TOCItemReference child_1_ref = tocref(root_ref, child_1_ID, toc_2);
|
||||
TOCItemDefinition child_2 = tocdef(child_1_ref, "child_2", toc_2);
|
||||
|
||||
TOCItemProviderTestStub tocProvider = new TOCItemProviderTestStub();
|
||||
tocProvider.addDefinition(root);
|
||||
tocProvider.addDefinition(child_1);
|
||||
tocProvider.addDefinition(child_2);// in the second TOC file
|
||||
|
||||
TOCSpyWriter spy = printOverlayTree(tocProvider, toc_2);
|
||||
|
||||
assertNodeCount(spy, 3);
|
||||
assertOrder(spy, 1, root);
|
||||
assertOrder(spy, 2, child_1);
|
||||
assertOrder(spy, 3, child_2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSourceTOCFileThatDependsUponPreBuiltHelp_MultiplePreBuiltInputs() {
|
||||
//
|
||||
// We want to make sure the overlay tree will properly resolve help TOC items being
|
||||
// We want to make sure the overlay tree will properly resolve help TOC items being
|
||||
// built from TOC_Source.xml files when that file uses <TOCREF> items that are defined
|
||||
// in a help <TOCITEM> that lives inside of multiple pre-built jar files.
|
||||
//
|
||||
/*
|
||||
|
||||
|
||||
Example makeup we will create:
|
||||
|
||||
|
||||
PreBuild_TOC.xml
|
||||
|
||||
|
||||
<tocitem id="root" target="fake">
|
||||
<tocitem id="child_1" target="fake">
|
||||
<tocitem="prebuilt_a_child" target="fake" />
|
||||
</tocitem>
|
||||
</tocitem>
|
||||
|
||||
|
||||
Another PreBuild_TOC.xml
|
||||
|
||||
|
||||
<tocitem id="root" target="fake">
|
||||
<tocitem id="child_1" target="fake">
|
||||
<tocitem="prebuilt_b_child" target="fake" />
|
||||
</tocitem>
|
||||
</tocitem>
|
||||
|
||||
|
||||
TOC_Source.xml
|
||||
|
||||
|
||||
|
||||
TOC_Source.xml
|
||||
|
||||
<tocref id="root">
|
||||
<tocref="child_1">
|
||||
<tocdef id="child_2" target="fake" />
|
||||
</tocref>
|
||||
</tocref>
|
||||
|
||||
|
||||
*/
|
||||
|
||||
TOCItemExternal root_a = externalItem("root");
|
||||
|
@ -131,18 +182,17 @@ public class OverlayHelpTreeTest {
|
|||
TOCItemExternal prebuilt_a_child = externalItem(child_1_a, "prebuilt_a_child");
|
||||
|
||||
// note: same ID values, since they represent the same nodes, but from different TOC files
|
||||
TOCItemExternal root_b = externalItemAlt(null, "root");
|
||||
TOCItemExternal child_1_b = externalItemAlt(root_b, "child_1");
|
||||
TOCItemExternal prebuilt_b_child = externalItemAlt(child_1_b, "prebuilt_b_child");
|
||||
TOCItemExternal root_b = externalItem(null, "root");
|
||||
TOCItemExternal child_1_b = externalItem(root_b, "child_1");
|
||||
TOCItemExternal prebuilt_b_child = externalItem(child_1_b, "prebuilt_b_child");
|
||||
|
||||
Path tocSourceFile = Paths.get("/fake/path_2/TOC_Source.xml");
|
||||
String root_ID = root_a.getIDAttribute();
|
||||
TOCItemReference root_ref = referenceItem(root_ID, tocSourceFile);
|
||||
TOCItemReference root_ref = tocref(root_ID, tocSourceFile);
|
||||
|
||||
String child_1_ID = child_1_a.getIDAttribute();
|
||||
TOCItemReference child_1_ref = referenceItem(root_ref, child_1_ID, tocSourceFile);
|
||||
|
||||
TOCItemDefinition child_2 = definitionItem(child_1_ref, "child_2", tocSourceFile);
|
||||
TOCItemReference child_1_ref = tocref(root_ref, child_1_ID, tocSourceFile);
|
||||
TOCItemDefinition child_2 = tocdef(child_1_ref, "child_2", tocSourceFile);
|
||||
|
||||
TOCItemProviderTestStub tocProvider = new TOCItemProviderTestStub();
|
||||
tocProvider.addExternal(root_a);
|
||||
|
@ -160,60 +210,85 @@ public class OverlayHelpTreeTest {
|
|||
assertOrder(spy, 2, child_1_a);// could also be child_1_b, same ID
|
||||
assertOrder(spy, 3, child_2);
|
||||
|
||||
// note: prebuilt_a_child and prebuilt_b_child don't get output, since they do not have
|
||||
// note: prebuilt_a_child and prebuilt_b_child don't get output, since they do not have
|
||||
// the same TOC file ID as the help file being processed (in other words, they don't
|
||||
// live in the TOC_Source.xml being processes, so they are not part of the output).
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSourceTOCFileThatDependsAnotherTOCSourceFile() {
|
||||
public void testSourceTOCFileThatHasNodeWithSameTextAttributeAsOneOfItsExternalModluleDependencies() {
|
||||
|
||||
/*
|
||||
|
||||
The first source file defines attributes that the second file references.
|
||||
|
||||
|
||||
The first source file defines attributes that the second file references. Both files
|
||||
will have multiple nodes that coincidentally share 'text' attribute values.
|
||||
|
||||
Note: the 'id' attributes have to be unique; the 'text' attributes do not have to be unique
|
||||
|
||||
Example makeup we will create:
|
||||
|
||||
TOC_Source.xml
|
||||
|
||||
<tocdef id="root" target="fake">
|
||||
<tocdef id="child_1" target="fake" />
|
||||
</tocdef>
|
||||
|
||||
|
||||
Another TOC_Source.xml
|
||||
|
||||
PreBuild_TOC.xml
|
||||
|
||||
<tocitem id="root" target="fake">
|
||||
<tocitem id="child_1_1" text="Child 1" target="fake" />
|
||||
</tocitem>
|
||||
|
||||
Another PreBuild_TOC.xml
|
||||
|
||||
<tocitem id="root" target="fake">
|
||||
<tocitem id="child_2_1" text=Child 1" target="fake" />
|
||||
<tocitem id="child_2_2" text=Child 2" target="fake" />
|
||||
</tocitem>
|
||||
|
||||
|
||||
Another TOC_Source.xml
|
||||
|
||||
<tocref id="root">
|
||||
<tocref="child_1">
|
||||
<tocdef id="child_2" target="fake" />
|
||||
<tocref="child_1_1">
|
||||
<tocdef id="child_2_1a" text="Child 1a" target="fake" />
|
||||
</tocref>
|
||||
<tocdef id="child_3_2" text="Child 2" target="fake" />
|
||||
</tocref>
|
||||
|
||||
*/
|
||||
|
||||
Path toc_1 = Paths.get("/fake/path_1/TOC_Source.xml");
|
||||
TOCItemDefinition root = definitionItem("root", toc_1);
|
||||
TOCItemDefinition child_1 = definitionItem(root, "child_1", toc_1);
|
||||
TOCItemExternal root_a = externalItem("root");
|
||||
TOCItemExternal child_1_1 = externalItem(root_a, "child_1_1", "Child 1");
|
||||
|
||||
Path toc_2 = Paths.get("/fake/path_2/TOC_Source.xml");
|
||||
String root_ID = root.getIDAttribute();
|
||||
String child_1_ID = child_1.getIDAttribute();
|
||||
// note: same ID values, since they represent the same nodes, but from different TOC files
|
||||
TOCItemExternal root_b = externalItem(null, "root");
|
||||
TOCItemExternal child_2_1 = externalItem(root_b, "child_2_1", "Child 1");
|
||||
TOCItemExternal child_2_2 = externalItem(root_b, "child_2_2", "Child 2");
|
||||
|
||||
TOCItemReference root_ref = referenceItem(root_ID, toc_2);
|
||||
TOCItemReference child_1_ref = referenceItem(root_ref, child_1_ID, toc_2);
|
||||
TOCItemDefinition child_2 = definitionItem(child_1_ref, "child_2", toc_2);
|
||||
Path toc = Paths.get("/fake/path_2/TOC_Source.xml");
|
||||
String root_ID = root_a.getIDAttribute();
|
||||
String child_1_ID = child_1_1.getIDAttribute();
|
||||
|
||||
TOCItemReference root_ref = tocref(root_ID, toc);
|
||||
TOCItemReference child_1_ref = tocref(root_ref, child_1_ID, toc);
|
||||
TOCItemDefinition child_2_1a = tocdef(child_1_ref, "child_2_1a", "Child 1a", toc);
|
||||
TOCItemDefinition child_3_2 = tocdef(root_ref, "child_3_2", "Child 2", toc);
|
||||
|
||||
TOCItemProviderTestStub tocProvider = new TOCItemProviderTestStub();
|
||||
tocProvider.addDefinition(root);
|
||||
tocProvider.addDefinition(child_1);
|
||||
tocProvider.addDefinition(child_2);// in the second TOC file
|
||||
tocProvider.addExternal(root_a);
|
||||
tocProvider.addExternal(child_1_1);
|
||||
tocProvider.addExternal(root_b);
|
||||
tocProvider.addExternal(child_2_1);
|
||||
tocProvider.addExternal(child_2_2);
|
||||
tocProvider.addDefinition(child_2_1a); // in the first external TOC file
|
||||
tocProvider.addDefinition(child_3_2);
|
||||
|
||||
TOCSpyWriter spy = printOverlayTree(tocProvider, toc_2);
|
||||
TOCSpyWriter spy = printOverlayTree(tocProvider, toc);
|
||||
|
||||
assertNodeCount(spy, 3);
|
||||
assertOrder(spy, 1, root);
|
||||
assertOrder(spy, 2, child_1);
|
||||
assertOrder(spy, 3, child_2);
|
||||
assertNodeCount(spy, 4);
|
||||
assertOrder(spy, 1, root_a);
|
||||
assertOrder(spy, 2, child_1_1);
|
||||
assertOrder(spy, 3, child_2_1a);
|
||||
assertOrder(spy, 4, child_3_2);
|
||||
|
||||
// note: prebuilt_a_child and prebuilt_b_child don't get output, since they do not have
|
||||
// the same TOC file ID as the help file being processed (in other words, they don't
|
||||
// live in the TOC_Source.xml being processes, so they are not part of the output).
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
@ -225,7 +300,7 @@ public class OverlayHelpTreeTest {
|
|||
//
|
||||
// Create a test version of the LinkDatabase for the overlay tree, with test versions of
|
||||
// it's required TOC input file and HelpModuleLocation
|
||||
//
|
||||
//
|
||||
GhidraTOCFileDummy toc = new GhidraTOCFileDummy(tocFile);
|
||||
OverlayHelpModuleLocationTestStub location = new OverlayHelpModuleLocationTestStub(toc);
|
||||
LinkDatabaseTestStub db = new LinkDatabaseTestStub(location);
|
||||
|
@ -242,22 +317,26 @@ public class OverlayHelpTreeTest {
|
|||
return spy;
|
||||
}
|
||||
|
||||
private TOCItemDefinition definitionItem(String ID, Path tocSourceFile) {
|
||||
return definitionItem(null, ID, tocSourceFile);
|
||||
private TOCItemDefinition tocdef(String ID, Path tocSourceFile) {
|
||||
return tocdef(null, ID, tocSourceFile);
|
||||
}
|
||||
|
||||
private TOCItemDefinition definitionItem(TOCItem parent, String ID, Path tocSourceFile) {
|
||||
private TOCItemDefinition tocdef(TOCItem parent, String ID, Path tocSourceFile) {
|
||||
return tocdef(parent, ID, ID, tocSourceFile);
|
||||
}
|
||||
|
||||
private TOCItemDefinition tocdef(TOCItem parent, String ID, String text, Path tocSourceFile) {
|
||||
String target = "fake";
|
||||
String sort = "";
|
||||
int line = 1;
|
||||
return new TOCItemDefinition(parent, tocSourceFile, ID, ID, target, sort, line);
|
||||
return new TOCItemDefinition(parent, tocSourceFile, ID, text, target, sort, line);
|
||||
}
|
||||
|
||||
private TOCItemReference referenceItem(String referenceID, Path tocSourceFile) {
|
||||
return referenceItem(null, referenceID, tocSourceFile);
|
||||
private TOCItemReference tocref(String referenceID, Path tocSourceFile) {
|
||||
return tocref(null, referenceID, tocSourceFile);
|
||||
}
|
||||
|
||||
private TOCItemReference referenceItem(TOCItem parent, String referenceID, Path tocSourceFile) {
|
||||
private TOCItemReference tocref(TOCItem parent, String referenceID, Path tocSourceFile) {
|
||||
return new TOCItemReference(parent, tocSourceFile, referenceID, 1);
|
||||
}
|
||||
|
||||
|
@ -266,24 +345,20 @@ public class OverlayHelpTreeTest {
|
|||
}
|
||||
|
||||
private TOCItemExternal externalItem(TOCItem parent, String ID) {
|
||||
Path tocFile = Paths.get("/fake/path_1/PreBuild_TOC.xml");
|
||||
String target = "fake";
|
||||
String sort = "";
|
||||
int line = 1;
|
||||
return new TOCItemExternal(parent, tocFile, ID, ID, target, sort, line);
|
||||
return externalItem(parent, ID, ID);
|
||||
}
|
||||
|
||||
private TOCItemExternal externalItemAlt(TOCItem parent, String ID) {
|
||||
private TOCItemExternal externalItem(TOCItem parent, String ID, String text) {
|
||||
Path tocFile = Paths.get("/fake/path_1/PreBuild_TOC.xml");
|
||||
String target = "fake";
|
||||
String sort = "";
|
||||
int line = 1;
|
||||
return new TOCItemExternal(parent, tocFile, ID, ID, target, sort, line);
|
||||
return new TOCItemExternal(parent, tocFile, ID, text, target, sort, line);
|
||||
}
|
||||
|
||||
private void assertOrder(TOCSpyWriter spy, int ordinal, TOCItem item) {
|
||||
String ID = spy.getItem(ordinal - 1 /* make an index */);
|
||||
assertEquals("Did not find TOC item at expected index: " + ordinal, item.getIDAttribute(),
|
||||
assertEquals("Did not find TOC item at expected ordinal: " + ordinal, item.getIDAttribute(),
|
||||
ID);
|
||||
}
|
||||
|
||||
|
@ -324,7 +399,7 @@ public class OverlayHelpTreeTest {
|
|||
|
||||
private void storeDisplayAttribute(String s) {
|
||||
// create a pattern to pull out the display string
|
||||
Pattern p = Pattern.compile(".*display=\"(.*)\" toc_id.*");
|
||||
Pattern p = Pattern.compile(".*toc_id=\"(.*)\".*");
|
||||
Matcher matcher = p.matcher(s.trim());
|
||||
|
||||
if (!matcher.matches()) {
|
||||
|
@ -347,8 +422,8 @@ public class OverlayHelpTreeTest {
|
|||
Map<String, TOCItemDefinition> definitions = new HashMap<>();
|
||||
|
||||
void addExternal(TOCItemExternal item) {
|
||||
String displayText = item.getIDAttribute();
|
||||
externals.put(displayText, item);
|
||||
String ID = item.getIDAttribute();
|
||||
externals.put(ID, item);
|
||||
}
|
||||
|
||||
void addDefinition(TOCItemDefinition item) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue