GT-3035 - Restore Integration Tests - restored missing test files; fast

tests
This commit is contained in:
dragonmacher 2019-08-14 15:08:37 -04:00
parent 822e5a0610
commit 4dc8e77172
45 changed files with 6609 additions and 0 deletions

View file

@ -0,0 +1,196 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package help;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import java.nio.file.*;
import org.junit.After;
import org.junit.Before;
import generic.test.AbstractGenericTest;
import utilities.util.FileUtilities;
public abstract class AbstractHelpTest extends AbstractGenericTest {
protected static final String HELP_FILENAME_PREFIX = "Fake";
protected static final String HELP_FILENAME = HELP_FILENAME_PREFIX + ".html";
private Path testTempDir;
public AbstractHelpTest() {
super();
}
@Before
public void setUp() throws Exception {
testTempDir = Files.createTempDirectory(testName.getMethodName());
}
@After
public void tearDown() throws Exception {
FileUtilities.deleteDir(testTempDir.toFile());
}
protected Path createHelpBuildOutputDir() throws IOException {
Path out = testTempDir.resolve("build/help/main/help");
Files.createDirectories(out);
return out;
}
protected Path createFakeHelpTopic(Path helpDir) throws IOException {
return createFakeHelpTopic("FakeTopic", helpDir);
}
protected Path createFakeHelpTopic(String topicName, Path helpDir) throws IOException {
Path topicsDir = helpDir.resolve("topics");
Path fakeTopicDir = topicsDir.resolve(topicName);
Files.createDirectories(fakeTopicDir);
return fakeTopicDir;
}
protected Path createTempHelpDir() throws IOException {
Path helpDir = testTempDir.resolve("help");
Files.createDirectory(helpDir);
return helpDir;
}
protected void addRequiredHelpDirStructure(Path helpDir) throws IOException {
// HelpFile wants to read one of these, so put one there
createEmpty_TOC_Source_File(helpDir);
createSharedDir(helpDir);
}
protected Path createSharedDir(Path helpDir) throws IOException {
Path sharedDir = helpDir.resolve("shared");
Files.createDirectory(sharedDir);
Path css = sharedDir.resolve("Frontpage.css");
Files.createFile(css);
Path png = sharedDir.resolve("test.png");
Files.createFile(png);
return sharedDir;
}
protected Path createEmpty_TOC_Source_File(Path dir) throws IOException {
Path fullTOCPath = dir.resolve("TOC_Source.xml");
Path file = Files.createFile(fullTOCPath);
//@formatter:off
String TOCXML = "<?xml version='1.0' encoding='ISO-8859-1' ?>\n" +
"<!-- Auto-generated on Fri Apr 03 09:37:08 EDT 2015 -->\n\n" +
"<tocroot>\n" +
"</tocroot>\n";
//@formatter:on
Files.write(file, TOCXML.getBytes(), StandardOpenOption.CREATE);
return file;
}
protected Path createHelpContent(Path topic, String anchor) throws IOException {
Path htmlPath = topic.resolve(HELP_FILENAME);
Path file = Files.createFile(htmlPath);
if (anchor == null) {
anchor = "Default_Anchor";
}
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
" <H1><A name=\""+anchor+"\"></A>Configure Tool</H1>\n" +
" Some text with reference to shared image <IMG src=\"../../shared/test.png\">\n" +
" \n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
protected Path createHelpContent_WithReferenceHREF(Path topic, String HREF) throws IOException {
Path htmlPath = topic.resolve(HELP_FILENAME);
Path file = Files.createFile(htmlPath);
assertNotNull("Must specify the A tag HREF attribute", HREF);
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
" <H1><A name=\"Fake_Anchor\"></A>Configure Tool</H1>\n" +
" And this is a link <A HREF=\""+HREF+"\">Click Me</A>" +
" \n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
protected Path createHelpContent_WithReferenceIMG_SRC(Path topic, String SRC)
throws IOException {
Path htmlPath = topic.resolve(HELP_FILENAME);
Path file = Files.createFile(htmlPath);
assertNotNull("Must specify the A tag SRC attribute", SRC);
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
" <H1><A name=\"Fake_Anchor\"></A>Configure Tool</H1>\n" +
" Some text with reference to shared image <IMG src=\""+SRC+"\">\n" +
" \n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
protected void copy(Path from, Path to) throws Exception {
FileUtilities.copyDir(from.toFile(), to.toFile(), null);
}
}

View file

@ -0,0 +1,99 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package help;
import static org.junit.Assert.*;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.Test;
public class HelpBuildUtilsTest extends AbstractHelpTest {
private static final String HELP_TOPIC_PATH = "/some/fake/path/to/help/topics";
private static final String TOPIC_AND_FILENAME = "FooTopic/FooFile.html";
private static final String HTML_FILE_PATH = HELP_TOPIC_PATH + '/' + TOPIC_AND_FILENAME;
public HelpBuildUtilsTest() {
super();
}
@Test
public void testGetRelativeHelpPath() {
String relativeString = "help/topics/FooTopic/FooFile.html";
Path path = Paths.get("/some/fake/path/to/" + relativeString);
Path relative = HelpBuildUtils.relativizeWithHelpTopics(path);
assertEquals(relativeString, relative.toString());
}
@Test
public void testGetRelativeHelpPath_NoHelpTopicInPath() {
String invalidRelativeString = "help/topicz/" + TOPIC_AND_FILENAME;
Path path = Paths.get("/some/fake/path/to/" + invalidRelativeString);
Path relative = HelpBuildUtils.relativizeWithHelpTopics(path);
assertNull(relative);
}
@Test
public void testLocateReference_Local_HelpSystemSyntax() throws URISyntaxException {
Path sourceFile = Paths.get(HTML_FILE_PATH);
String reference = "help/topics/shared/foo.png";
Path resolved = HelpBuildUtils.locateReference(sourceFile, reference);
assertEquals("Help System syntax was not preserved", Paths.get(reference), resolved);
}
@Test
public void testLocateReference_Local_RelativeSyntax() throws URISyntaxException {
Path sourceFile = Paths.get(HTML_FILE_PATH);
String reference = "../shared/foo.png";// go up one to the help dir
Path resolved = HelpBuildUtils.locateReference(sourceFile, reference);
assertEquals("Relative syntax did not locate file",
Paths.get(HELP_TOPIC_PATH + "/shared/foo.png"), resolved);
}
@Test
public void testLocateReference_Remote() throws URISyntaxException {
Path sourceFile = Paths.get(HTML_FILE_PATH);
String reference = "http://some.fake.server/foo.png";
Path resolved = HelpBuildUtils.locateReference(sourceFile, reference);
assertNull(resolved);
boolean isRemote = HelpBuildUtils.isRemote(reference);
assertTrue(isRemote);
}
@Test
public void testLocateReferences_Icons() throws URISyntaxException {
Path sourceFile = Paths.get(HTML_FILE_PATH);
String reference = "Icons.REFRESH_ICON"; // see Icons class
ImageLocation location = HelpBuildUtils.locateImageReference(sourceFile, reference);
Path resolved = location.getResolvedPath();
String name = resolved.getFileName().toString();
assertEquals("Help System syntax was not preserved", "reload3.png", name);
assertTrue(location.isRuntime());
assertFalse(location.isRemote());
}
@Test
public void testLocateReferences_Icons_BadName() throws URISyntaxException {
Path sourceFile = Paths.get(HTML_FILE_PATH);
String reference = "Icons.REFRESH_ICON_BAD"; // non-existent
ImageLocation location = HelpBuildUtils.locateImageReference(sourceFile, reference);
Path resolved = location.getResolvedPath();
assertNull(resolved);
}
}

View file

@ -0,0 +1,418 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package help;
import static org.junit.Assert.assertEquals;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.help.HelpSet;
import org.junit.Test;
import help.validator.LinkDatabase;
import help.validator.location.*;
import help.validator.model.*;
public class OverlayHelpTreeTest {
@Test
public void testSourceTOCFileThatDependsUponPreBuiltHelp() {
//
// 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
<tocref id="root">
<tocref="child_1">
<tocdef id="child_2" target="fake" />
</tocref>
</tocref>
*/
TOCItemExternal root = externalItem("root");
TOCItemExternal child_1 = externalItem(root, "child_1");
Path tocSourceFile = Paths.get("/fake/path_2/TOC_Source.xml");
String root_ID = root.getIDAttribute();
TOCItemReference root_ref = referenceItem(root_ID, tocSourceFile);
String child_1_ID = child_1.getIDAttribute();
TOCItemReference child_1_ref = referenceItem(root_ref, child_1_ID, tocSourceFile);
TOCItemDefinition child_2 = definitionItem(child_1_ref, "child_2", tocSourceFile);
TOCItemProviderTestStub tocProvider = new TOCItemProviderTestStub();
tocProvider.addExternal(root);
tocProvider.addExternal(child_1);
tocProvider.addDefinition(child_2);
TOCSpyWriter spy = printOverlayTree(tocProvider, tocSourceFile);
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
// 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
<tocref id="root">
<tocref="child_1">
<tocdef id="child_2" target="fake" />
</tocref>
</tocref>
*/
TOCItemExternal root_a = externalItem("root");
TOCItemExternal child_1_a = externalItem(root_a, "child_1");
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");
Path tocSourceFile = Paths.get("/fake/path_2/TOC_Source.xml");
String root_ID = root_a.getIDAttribute();
TOCItemReference root_ref = referenceItem(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);
TOCItemProviderTestStub tocProvider = new TOCItemProviderTestStub();
tocProvider.addExternal(root_a);
tocProvider.addExternal(root_b);
tocProvider.addExternal(child_1_a);
tocProvider.addExternal(child_1_b);
tocProvider.addExternal(prebuilt_a_child);
tocProvider.addExternal(prebuilt_b_child);
tocProvider.addDefinition(child_2);
TOCSpyWriter spy = printOverlayTree(tocProvider, tocSourceFile);
assertNodeCount(spy, 3);
assertOrder(spy, 1, root_a);// could also be root_b, same ID
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
// 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() {
/*
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 = definitionItem("root", toc_1);
TOCItemDefinition child_1 = definitionItem(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 = 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);
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);
}
//==================================================================================================
// Inner Classes
//==================================================================================================
private TOCSpyWriter printOverlayTree(TOCItemProviderTestStub tocItemProvider, Path tocFile) {
//
// 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);
// This is the class we are testing!!
OverlayHelpTree overlayHelpTree = new OverlayHelpTree(tocItemProvider, db);
TOCSpyWriter spy = new TOCSpyWriter();
String TOCID = tocFile.toUri().toString();
overlayHelpTree.printTreeForID(spy, TOCID);
System.out.println(spy.toString());
return spy;
}
private TOCItemDefinition definitionItem(String ID, Path tocSourceFile) {
return definitionItem(null, ID, tocSourceFile);
}
private TOCItemDefinition definitionItem(TOCItem parent, String ID, Path tocSourceFile) {
String target = "fake";
String sort = "";
int line = 1;
return new TOCItemDefinition(parent, tocSourceFile, ID, ID, target, sort, line);
}
private TOCItemReference referenceItem(String referenceID, Path tocSourceFile) {
return referenceItem(null, referenceID, tocSourceFile);
}
private TOCItemReference referenceItem(TOCItem parent, String referenceID, Path tocSourceFile) {
return new TOCItemReference(parent, tocSourceFile, referenceID, 1);
}
private TOCItemExternal externalItem(String ID) {
return externalItem(null, ID);
}
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);
}
private TOCItemExternal externalItemAlt(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);
}
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(),
ID);
}
private void assertNodeCount(TOCSpyWriter spy, int count) {
assertEquals("Did not get exactly one node per TOC item input", count, spy.getItemCount());
}
private class TOCSpyWriter extends PrintWriter {
private StringWriter stringWriter;
private List<String> tocItems = new ArrayList<>();
public TOCSpyWriter() {
super(new StringWriter(), true);
stringWriter = ((StringWriter) out);
}
String getItem(int position) {
return tocItems.get(position);
}
int getItemCount() {
return tocItems.size();
}
@Override
public void println(String s) {
super.println(s);
s = s.trim();
if (!s.startsWith("<tocitem")) {
return;
}
storeDisplayAttribute(s);
}
private void storeDisplayAttribute(String s) {
// create a pattern to pull out the display string
Pattern p = Pattern.compile(".*display=\"(.*)\" toc_id.*");
Matcher matcher = p.matcher(s.trim());
if (!matcher.matches()) {
return;// not a TOC item
}
String value = matcher.group(1);
tocItems.add(value);
}
@Override
public String toString() {
return stringWriter.getBuffer().toString();
}
}
private class TOCItemProviderTestStub implements TOCItemProvider {
Map<String, TOCItemExternal> externals = new HashMap<>();
Map<String, TOCItemDefinition> definitions = new HashMap<>();
void addExternal(TOCItemExternal item) {
String displayText = item.getIDAttribute();
externals.put(displayText, item);
}
void addDefinition(TOCItemDefinition item) {
String ID = item.getIDAttribute();
definitions.put(ID, item);
}
@Override
public Map<String, TOCItemExternal> getTOCItemExternalsByDisplayMapping() {
return externals;
}
@Override
public Map<String, TOCItemDefinition> getTOCItemDefinitionsByIDMapping() {
return definitions;
}
}
private class LinkDatabaseTestStub extends LinkDatabase {
public LinkDatabaseTestStub(HelpModuleLocation loc) {
super(HelpModuleCollection.fromHelpLocations(Collections.singleton(loc)));
}
@Override
public String getIDForLink(String target) {
return "test_ID_" + target;
}
}
private class OverlayHelpModuleLocationTestStub extends HelpModuleLocationTestDouble {
OverlayHelpModuleLocationTestStub(GhidraTOCFileDummy toc) {
super(Paths.get("/fake/help"));
this.sourceTOCFile = toc;
}
@Override
protected void loadHelpTopics() {
// no! ...don't really go to the filesystem
}
@Override
public GhidraTOCFile loadSourceTOCFile() {
return null;// we set this in the constructor
}
@Override
public HelpSet loadHelpSet() {
return null;
}
@Override
public boolean isHelpInputSource() {
return true;
}
}
private class GhidraTOCFileDummy extends GhidraTOCFileTestDouble {
public GhidraTOCFileDummy(Path path) {
super(path);
}
}
}

View file

@ -0,0 +1,28 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package help.validator.location;
import java.nio.file.Path;
import help.validator.location.HelpModuleLocation;
public abstract class HelpModuleLocationTestDouble extends HelpModuleLocation {
// this class exists to open up the package-level constructor
public HelpModuleLocationTestDouble(Path source) {
super(source);
}
}

View file

@ -0,0 +1,70 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package help.validator.model;
import static org.junit.Assert.assertEquals;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.Assert;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.util.exception.AssertException;
public class AnchorDefinitionTest extends AbstractGenericTest {
public AnchorDefinitionTest() {
super();
}
@Test
public void testFileWithoutAnchor() {
// this should generate and ID that is the filename only
Path fullPath = Paths.get("/fake/full/path/help/topics/TopicName/HelpFilename.html"); // dir case
AnchorDefinition def = new AnchorDefinition(fullPath, null, 1);
assertEquals("TopicName_HelpFilename", def.getId());
}
@Test
public void testFileInHelpTopicDir() {
Path fullPath = Paths.get("/fake/full/path/help/topics/TopicName/HelpFilename.html"); // dir case
AnchorDefinition def = new AnchorDefinition(fullPath, "anchor_1", 1);
assertEquals("TopicName_anchor_1", def.getId());
}
@Test
public void testFileInHelpTopicJar() {
Path fullPath = Paths.get("/help/topics/TopicName/HelpFilename.html"); // jar case
AnchorDefinition def = new AnchorDefinition(fullPath, "anchor_1", 1);
assertEquals("TopicName_anchor_1", def.getId());
}
@Test
public void testFileInHelpDir_NotUnderHelpTopic() {
Path fullPath = Paths.get("/fake/full/path/help/HelpFilename.html"); // dir case
try {
new AnchorDefinition(fullPath, "anchor_1", 1);
Assert.fail("Did not fail with file not living under a help topic directory");
}
catch (AssertException e) {
// good
}
}
}

View file

@ -0,0 +1,28 @@
/* ###
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package help.validator.model;
import java.nio.file.Path;
public class GhidraTOCFileTestDouble extends GhidraTOCFile {
// this class exists to open up constructor access
public GhidraTOCFileTestDouble(Path sourceFile) {
super(sourceFile);
}
}

View file

@ -0,0 +1,307 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package help.validator.model;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.nio.file.*;
import java.util.Collection;
import org.junit.Test;
import help.AbstractHelpTest;
import help.validator.*;
import help.validator.location.DirectoryHelpModuleLocation;
public class HelpFileTest extends AbstractHelpTest {
@Test
public void testGoodHTML() throws IOException {
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
Path topic = createFakeHelpTopic(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
Path html = createGoodHTMLFile(topic);
new HelpFile(helpLocation, html);
// if we get here, then no exceptions happened
}
@Test
public void testBadHTML_InvalidStyleSheet() throws Exception {
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
Path topic = createFakeHelpTopic(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
Path html = createBadHTMLFile_InvalidStyleSheet(topic);
try {
new HelpFile(helpLocation, html);
fail("Parsing did not fail for invalid stylesheet");
}
catch (Exception e) {
// good
}
}
@Test
public void testBadHTML_InvalidAnchorRef_BadURI() throws Exception {
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
Path topic = createFakeHelpTopic(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
Path html = createBadHTMLFile_InvalidAnchor_BadURI(topic);
try {
new HelpFile(helpLocation, html);
fail("Parsing did not fail for invalid stylesheet");
}
catch (Exception e) {
// good
}
}
@Test
public void testBadHTML_InvalidAnchorRef_WrongAttribtues() throws Exception {
// no 'name' or 'href' attribute
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
Path topic = createFakeHelpTopic(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
Path html = createBadHTMLFile_InvalidAnchor_WrongAttributes(topic);
try {
new HelpFile(helpLocation, html);
fail("Parsing did not fail for invalid stylesheet");
}
catch (Exception e) {
// good
}
}
@Test
public void testBadHTML_InvalidIMG_WrongAttribtues() throws Exception {
// no 'src'
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
Path topic = createFakeHelpTopic(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
Path html = createBadHTMLFile_InvalidIMG_WrongAttributes(topic);
try {
new HelpFile(helpLocation, html);
fail("Parsing did not fail for invalid stylesheet");
}
catch (Exception e) {
// good
}
}
@Test
public void testCommentGetsIgnored() throws Exception {
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
Path topic = createFakeHelpTopic(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
Path html = createGoodHTMLFile_InvalidAnchor_CommentedOut_MultiLineComment(topic);
HelpFile helpFile = new HelpFile(helpLocation, html);
Collection<HREF> hrefs = helpFile.getAllHREFs();
assertTrue(hrefs.isEmpty());
}
// @Test
// for debugging a real help file
public void test() throws Exception {
Path path = Paths.get("<home dir>/<git>/ghidra/Ghidra/Features/" +
"Base/src/main/help/help/topics/Annotations/Annotations.html");
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
AnchorManager anchorManager = new AnchorManager();
ReferenceTagProcessor tagProcessor = new ReferenceTagProcessor(helpLocation, anchorManager);
HTMLFileParser.scanHtmlFile(path, tagProcessor);
}
//==================================================================================================
// Private Methods
//==================================================================================================
/** Has valid links */
private Path createGoodHTMLFile(Path topic) throws IOException {
String anchor = "ManagePluginsDialog";
return createHelpContent(topic, anchor);
}
private Path createBadHTMLFile_InvalidAnchor_WrongAttributes(Path topic) throws IOException {
Path htmlPath = topic.resolve("FakeHTML_WrongAttributes.html");
Path file = Files.createFile(htmlPath);
String badAttr = "bob=1";
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
"<H1><A name=\"ManagePluginsDialog\"></A>Configure Tool</H1>\n" +
"Some text with reference to shared image <a "+badAttr+">Click me</a>\n" +
"\n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
private Path createBadHTMLFile_InvalidIMG_WrongAttributes(Path topic) throws IOException {
Path htmlPath = topic.resolve("FakeHTML_WrongAttributes.html");
Path file = Files.createFile(htmlPath);
String badAttr = "bob=1";
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
"<H1><A name=\"ManagePluginsDialog\"></A>Configure Tool</H1>\n" +
"Some text with reference to shared image <IMG "+badAttr+"s>\n" +
"\n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
private Path createBadHTMLFile_InvalidAnchor_BadURI(Path topic) throws IOException {
Path htmlPath = topic.resolve("FakeHTML_BadURI.html");
Path file = Files.createFile(htmlPath);
String badURI = ":baduri"; // no scheme name on this URI
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
"<H1><A name=\"ManagePluginsDialog\"></A>Configure Tool</H1>\n" +
"Some text with reference to shared image <a href=\""+badURI+"\">Click me</a>\n" +
"\n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
private Path createBadHTMLFile_InvalidStyleSheet(Path topic) throws IOException {
Path htmlPath = topic.resolve("FakeHTML_InvalidStyleSheet.html");
Path file = Files.createFile(htmlPath);
String badName = "bad_name";
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/"+badName+".css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
"<H1><A name=\"ManagePluginsDialog\"></A>Configure Tool</H1>\n" +
"Some text with reference to shared image <IMG src=\"../../shared/test.png\">\n" +
"\n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
private Path createGoodHTMLFile_InvalidAnchor_CommentedOut_MultiLineComment(Path topic)
throws IOException {
Path htmlPath = topic.resolve("HTMLWithComment.html");
Path file = Files.createFile(htmlPath);
String badURI = ":baduri"; // no scheme name on this URI
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
"<H1><A name=\"ManagePluginsDialog\"></A>Configure Tool</H1>\n" +
" <!--" +
" Some text with reference to shared image <a href=\""+badURI+"\">Click me</a>\n" +
" -->" +
"\n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
}