mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GT-3035 - Restore Integration Tests - restored missing test files; fast
tests
This commit is contained in:
parent
822e5a0610
commit
4dc8e77172
45 changed files with 6609 additions and 0 deletions
196
Ghidra/Framework/Help/src/test/java/help/AbstractHelpTest.java
Normal file
196
Ghidra/Framework/Help/src/test/java/help/AbstractHelpTest.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue