From 290a7c256f2c7d816517268259d34e7fb94e9bf3 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 12 Oct 2021 14:26:44 -0400 Subject: [PATCH] GP-1374 - Update DataTypeWriter enum output to sort by enum value instead of name Closes #1664 --- .../ghidra/app/util/xml/DataTypesXmlMgr.java | 18 +-- .../program/database/data/EnumTest.java | 62 +++++++--- .../ghidra/program/database/data/EnumDB.java | 22 ++-- .../program/model/data/DataTypeWriter.java | 106 +++++++++--------- .../java/ghidra/program/model/data/Enum.java | 4 +- .../program/model/data/EnumDataType.java | 20 ++-- .../model/data/DataTypeWriterTest.java | 96 ++++++++++++++-- .../ghidra/program/model/data/EnumTest.java | 5 +- 8 files changed, 225 insertions(+), 108 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/DataTypesXmlMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/DataTypesXmlMgr.java index 3854dcc187..8878b87ed4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/DataTypesXmlMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/DataTypesXmlMgr.java @@ -30,7 +30,6 @@ import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.exception.DuplicateNameException; import ghidra.util.task.TaskMonitor; -import ghidra.util.task.TaskMonitorAdapter; import ghidra.util.xml.*; import ghidra.xml.*; @@ -245,7 +244,7 @@ public class DataTypesXmlMgr { private boolean processEnum(XmlTreeNode root) { XmlElement element = root.getStartElement(); String name = element.getAttribute("NAME"); - String comment = getRegularComment(root); + String enuumComment = getRegularComment(root); CategoryPath cp = getCategoryPath(element); int size = XmlUtilities.parseInt(element.getAttribute("SIZE"), defaultEnumSize); @@ -257,9 +256,10 @@ public class DataTypesXmlMgr { XmlElement childElement = node.getStartElement(); String entryName = childElement.getAttribute("NAME"); long entryValue = XmlUtilities.parseLong(childElement.getAttribute("VALUE")); - enuum.add(entryName, entryValue); + String comment = childElement.getAttribute("COMMENT"); + enuum.add(entryName, entryValue, comment); } - enuum.setDescription(comment); + enuum.setDescription(enuumComment); dataManager.addDataType(enuum, null); return true; } @@ -288,6 +288,7 @@ public class DataTypesXmlMgr { td.setCategoryPath(cp); } catch (DuplicateNameException e) { + log.appendMsg("Unable to place typedef '" + name + "' in category '" + cp + "'"); } dataManager.addDataType(td, null); @@ -546,11 +547,11 @@ public class DataTypesXmlMgr { writeRegularComment(writer, enuum.getDescription()); String[] names = enuum.getNames(); - Arrays.sort(names); for (String name : names) { attrs = new XmlAttributes(); attrs.addAttribute("NAME", name); attrs.addAttribute("VALUE", enuum.getValue(name), true); + attrs.addAttribute("COMMENT", enuum.getComment(name)); writer.startElement("ENUM_ENTRY", attrs); writer.endElement("ENUM_ENTRY"); } @@ -666,8 +667,8 @@ public class DataTypesXmlMgr { /** * Output data types in XML format for debugging purposes. - * NOTE: There is no support for reading the XML produced by this - * method. + * NOTE: There is no support for reading the XML produced by this method. + * @param dataManager the data type manager * @param outputFilename name of the output file * @throws IOException if there was a problem writing to the file */ @@ -683,9 +684,10 @@ public class DataTypesXmlMgr { MessageLog log = new MessageLog(); DataTypesXmlMgr mgr = new DataTypesXmlMgr(dataManager, log); try { - mgr.write(writer, TaskMonitorAdapter.DUMMY_MONITOR); + mgr.write(writer, TaskMonitor.DUMMY); } catch (CancelledException e) { + // can't happen with dummy monitor } writer.close(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/EnumTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/EnumTest.java index 624867f222..c5f6a87ed6 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/EnumTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/EnumTest.java @@ -29,7 +29,7 @@ import ghidra.program.model.data.Enum; import ghidra.program.model.data.EnumDataType; import ghidra.program.util.ChangeManager; import ghidra.test.AbstractGhidraHeadedIntegrationTest; -import ghidra.util.task.TaskMonitorAdapter; +import ghidra.util.task.TaskMonitor; /** * Tests for Enum data types. @@ -40,10 +40,6 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest { private DataTypeManagerDB dataMgr; private int transactionID; - public EnumTest() { - super(); - } - @Before public void setUp() throws Exception { program = createDefaultProgram("Test", ProgramBuilder._TOY, this); @@ -223,7 +219,7 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest { Enum enummDT = (Enum) dataMgr.resolve(enumm, null); assertNotNull(enummDT); - c.remove(enummDT, TaskMonitorAdapter.DUMMY_MONITOR); + c.remove(enummDT, TaskMonitor.DUMMY); assertNull(c.getDataType("Color")); assertTrue(enummDT.isDeleted()); @@ -294,6 +290,7 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest { Assert.fail("Should have gotten no such element exception!"); } catch (NoSuchElementException e) { + // expected } } @@ -335,27 +332,56 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest { myEnum.add("Green", 15); myEnum.add("Blue", 20); assertTrue(enummDT.isEquivalent(myEnum)); + } + @Test + public void testNameSort() { + + Enum myEnum = new EnumDataType("Color", 1); + myEnum.add("Red", 1); + myEnum.add("Green", 5); + myEnum.add("Blue", 10); + + String[] names = myEnum.getNames(); + assertEquals("Red", names[0]); + assertEquals("Green", names[1]); + assertEquals("Blue", names[2]); + + myEnum = new EnumDataType("Color", 1); + myEnum.add("Red", 20); + myEnum.add("Green", 1); + myEnum.add("Blue", 3); + + names = myEnum.getNames(); + assertEquals("Green", names[0]); + assertEquals("Blue", names[1]); + assertEquals("Red", names[2]); + + // multiple names per value, requires sub-sorting + myEnum = new EnumDataType("Color", 1); + myEnum.add("Red", 20); + myEnum.add("Pink", 20); + myEnum.add("Salmon", 20); + myEnum.add("Green", 1); + myEnum.add("AnotherGreen", 1); + myEnum.add("Blue", 3); + + names = myEnum.getNames(); + assertEquals("AnotherGreen", names[0]); + assertEquals("Green", names[1]); + assertEquals("Blue", names[2]); + assertEquals("Pink", names[3]); + assertEquals("Red", names[4]); + assertEquals("Salmon", names[5]); } private void waitForListenerCount(DomainObjListener listener, int count) { - int cnt = 0; - try { - while (cnt++ < 10 && listener.getCount() != count) { - Thread.sleep(100); - } - Thread.sleep(300); - } - catch (InterruptedException e) { - } + waitForCondition(() -> listener.getCount() == count); } private class DomainObjListener implements DomainObjectListener { private int count; - /* (non-Javadoc) - * @see ghidra.framework.model.DomainObjectListener#domainObjectChanged(ghidra.framework.model.DomainObjectChangedEvent) - */ @Override public void domainObjectChanged(DomainObjectChangedEvent ev) { for (int i = 0; i < ev.numRecords(); i++) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDB.java index fb5402e47f..e8913e6632 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDB.java @@ -45,7 +45,7 @@ class EnumDB extends DataTypeDB implements Enum { private EnumValueDBAdapter valueAdapter; private Map nameMap; // name to value - private Map> valueMap; // value to names + private TreeMap> valueMap; // value to names private Map commentMap; // name to comment private List bitGroups; @@ -86,7 +86,7 @@ class EnumDB extends DataTypeDB implements Enum { private void initialize() throws IOException { bitGroups = null; nameMap = new HashMap<>(); - valueMap = new HashMap<>(); + valueMap = new TreeMap<>(); commentMap = new HashMap<>(); Field[] ids = valueAdapter.getValueIdsInEnum(key); @@ -190,9 +190,7 @@ class EnumDB extends DataTypeDB implements Enum { try { checkIsValid(); initializeIfNeeded(); - long[] values = valueMap.keySet().stream().mapToLong(Long::longValue).toArray(); - Arrays.sort(values); - return values; + return valueMap.keySet().stream().mapToLong(Long::longValue).toArray(); } finally { lock.release(); @@ -205,9 +203,15 @@ class EnumDB extends DataTypeDB implements Enum { try { checkIsValid(); initializeIfNeeded(); - String[] names = nameMap.keySet().toArray(new String[nameMap.size()]); - Arrays.sort(names); - return names; + + // names are first sorted by int value, then sub-sorted by name value + List names = new ArrayList<>(); + Collection> values = valueMap.values(); + for (List list : values) { + Collections.sort(list); + names.addAll(list); + } + return names.toArray(new String[0]); } finally { lock.release(); @@ -319,7 +323,7 @@ class EnumDB extends DataTypeDB implements Enum { bitGroups = null; nameMap = new HashMap<>(); - valueMap = new HashMap<>(); + valueMap = new TreeMap<>(); commentMap = new HashMap<>(); Field[] ids = valueAdapter.getValueIdsInEnum(key); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeWriter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeWriter.java index 385885b56b..005fa309fc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeWriter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeWriter.java @@ -19,14 +19,15 @@ import java.io.IOException; import java.io.Writer; import java.util.*; +import org.apache.commons.lang3.StringUtils; + import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import ghidra.util.task.TaskMonitorAdapter; /** * A class used to convert data types into ANSI-C. - * + * * The ANSI-C code should compile on most platforms. */ public class DataTypeWriter { @@ -53,25 +54,23 @@ public class DataTypeWriter { private boolean cppStyleComments = false; /** - * Constructs a new instance of this class using the - * given writer. The default annotation handler is used. - * @param dtm data-type manager corresponding to target program or null - * for default + * Constructs a new instance of this class using the given writer. The default annotation + * handler is used. + * @param dtm data-type manager corresponding to target program or null for default * @param writer the writer to use when writing data types - * @throws IOException + * @throws IOException if there is an exception writing the output */ public DataTypeWriter(DataTypeManager dtm, Writer writer) throws IOException { this(dtm, writer, new DefaultAnnotationHandler()); } /** - * Constructs a new instance of this class using the - * given writer. The default annotation handler is used. - * @param dtm data-type manager corresponding to target program or null - * for default + * Constructs a new instance of this class using the given writer. The default annotation + * handler is used. + * @param dtm data-type manager corresponding to target program or null for default * @param writer the writer to use when writing data types * @param cppStyleComments whether to use C++ style comments - * @throws IOException + * @throws IOException if there is an exception writing the output */ public DataTypeWriter(DataTypeManager dtm, Writer writer, boolean cppStyleComments) throws IOException { @@ -79,13 +78,11 @@ public class DataTypeWriter { } /** - * Constructs a new instance of this class using the - * given writer and annotation handler - * @param dtm data-type manager corresponding to target program or null - * for default + * Constructs a new instance of this class using the given writer and annotation handler + * @param dtm data-type manager corresponding to target program or null for default * @param writer the writer to use when writing data types * @param annotator the annotation handler to use to annotate the data types - * @throws IOException + * @throws IOException if there is an exception writing the output */ public DataTypeWriter(DataTypeManager dtm, Writer writer, AnnotationHandler annotator) throws IOException { @@ -93,14 +90,12 @@ public class DataTypeWriter { } /** - * Constructs a new instance of this class using the - * given writer and annotation handler - * @param dtm data-type manager corresponding to target program or null - * for default + * Constructs a new instance of this class using the given writer and annotation handler + * @param dtm data-type manager corresponding to target program or null for default * @param writer the writer to use when writing data types * @param annotator the annotation handler to use to annotate the data types * @param cppStyleComments whether to use C++ style comments - * @throws IOException + * @throws IOException if there is an exception writing the output */ public DataTypeWriter(DataTypeManager dtm, Writer writer, AnnotationHandler annotator, boolean cppStyleComments) throws IOException { @@ -130,11 +125,11 @@ public class DataTypeWriter { } /** - * Converts all data types in the data type manager into ANSI-C code. + * Converts all data types in the data type manager into ANSI-C code. * @param dataTypeManager the manager containing the data types to write * @param monitor the task monitor - * @throws IOException if an I/O error occurs when writing the data types to the specified writer - * @throws CancelledException + * @throws IOException if there is an exception writing the output + * @throws CancelledException if the action is cancelled by the user */ public void write(DataTypeManager dataTypeManager, TaskMonitor monitor) throws IOException, CancelledException { @@ -142,11 +137,11 @@ public class DataTypeWriter { } /** - * Converts all data types in the category into ANSI-C code. + * Converts all data types in the category into ANSI-C code. * @param category the category containing the datatypes to write * @param monitor the task monitor - * @throws IOException if an I/O error occurs when writing the data types to the specified writer - * @throws CancelledException + * @throws IOException if there is an exception writing the output + * @throws CancelledException if the action is cancelled by the user */ public void write(Category category, TaskMonitor monitor) throws IOException, CancelledException { @@ -163,11 +158,11 @@ public class DataTypeWriter { } /** - * Converts all data types in the array into ANSI-C code. + * Converts all data types in the array into ANSI-C code. * @param dataTypes the data types to write * @param monitor the task monitor - * @throws IOException if an I/O error occurs when writing the data types to the specified writer - * @throws CancelledException + * @throws IOException if there is an exception writing the output + * @throws CancelledException if the action is cancelled by the user */ public void write(DataType[] dataTypes, TaskMonitor monitor) throws IOException, CancelledException { @@ -181,11 +176,11 @@ public class DataTypeWriter { } /** - * Converts all data types in the list into ANSI-C code. + * Converts all data types in the list into ANSI-C code. * @param dataTypes the data types to write * @param monitor the task monitor - * @throws IOException if an I/O error occurs when writing the data types to the specified writer - * @throws CancelledException + * @throws IOException if there is an exception writing the output + * @throws CancelledException if the action is cancelled by the user */ public void write(List dataTypes, TaskMonitor monitor) throws IOException, CancelledException { @@ -222,8 +217,8 @@ public class DataTypeWriter { /** * Writes the data type as ANSI-C using the underlying writer. * @param dt the data type to write as ANSI-C - * @param monitor - * @throws IOException + * @param monitor the task monitor + * @throws IOException if there is an exception writing the output */ private void doWrite(DataType dt, TaskMonitor monitor, boolean throwExceptionOnInvalidType) throws IOException, CancelledException { @@ -456,7 +451,7 @@ public class DataTypeWriter { String compositeType = composite instanceof Structure ? "struct" : "union"; - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(compositeType + " " + composite.getDisplayName() + " {"); String descrip = composite.getDescription(); @@ -478,7 +473,7 @@ public class DataTypeWriter { writer.write(EOL); } - private void writeComponent(DataTypeComponent component, Composite composite, StringBuffer sb, + private void writeComponent(DataTypeComponent component, Composite composite, StringBuilder sb, TaskMonitor monitor) throws IOException, CancelledException { sb.append(" "); sb.append(annotator.getPrefix(composite, component)); @@ -504,14 +499,13 @@ public class DataTypeWriter { } private String getTypeDeclaration(String name, DataType dataType, int instanceLength, - boolean writeEnabled, TaskMonitor monitor) - throws IOException, CancelledException { + boolean writeEnabled, TaskMonitor monitor) throws IOException, CancelledException { if (name == null) { name = ""; } - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); String componentString = null; if (dataType instanceof Dynamic) { componentString = getDynamicComponentString((Dynamic) dataType, name, instanceLength); @@ -581,11 +575,12 @@ public class DataTypeWriter { } writer.write("typedef enum " + enumName + " " + "{"); - String descrip = enumm.getDescription(); - if (descrip != null && descrip.length() != 0) { - writer.write(" " + comment(descrip)); + String description = enumm.getDescription(); + if (description != null && description.length() != 0) { + writer.write(" " + comment(description)); } writer.write(EOL); + String[] names = enumm.getNames(); for (int j = 0; j < names.length; j++) { writer.write(" "); @@ -593,7 +588,14 @@ public class DataTypeWriter { writer.write(names[j]); writer.write("="); writer.write(Long.toString(enumm.getValue(names[j]))); + + String comment = enumm.getComment(names[j]); + if (!StringUtils.isBlank(comment)) { + writer.write(" " + comment(comment)); + } + writer.write(annotator.getSuffix(enumm, names[j])); + if (j < names.length - 1) { writer.write(","); } @@ -606,7 +608,7 @@ public class DataTypeWriter { /** * Typedef Format: typedef - * @throws CancelledException + * @throws CancelledException if the action is cancelled by the user */ private void writeTypeDef(TypeDef typeDef, TaskMonitor monitor) throws IOException, CancelledException { @@ -704,16 +706,14 @@ public class DataTypeWriter { } /** - * Write all built-in data types declarations into ANSI-C code. - * Those types whose name matches the corresponding primitive C-type. - * are not included. - * @throws IOException if an I/O error occurs when writing the data types to the specified writer - * @throws CancelledException + * Write all built-in data types declarations into ANSI-C code. Those types whose name matches + * the corresponding primitive C-type. are not included. + * @throws IOException if there is an exception writing the output */ private void writeBuiltInDeclarations(DataTypeManager manager) throws IOException { try { - write(DataType.DEFAULT, TaskMonitorAdapter.DUMMY_MONITOR); + write(DataType.DEFAULT, TaskMonitor.DUMMY); SourceArchive builtInArchive = manager.getSourceArchive(DataTypeManager.BUILT_IN_ARCHIVE_UNIVERSAL_ID); @@ -726,7 +726,7 @@ public class DataTypeWriter { (dt instanceof Dynamic)) { continue; } - write(dt, TaskMonitorAdapter.DUMMY_MONITOR); + write(dt, TaskMonitor.DUMMY); } } catch (CancelledException e) { @@ -872,7 +872,7 @@ public class DataTypeWriter { buf.append(ghidra.program.model.listing.FunctionSignature.VAR_ARGS_DISPLAY_STRING); } if ((n == 0) && (!hasVarArgs)) { // If no parameters - buf.append(DataType.VOID.getName()); // Print "void" keyword + buf.append(VoidDataType.dataType.getName()); // Print "void" keyword } buf.append(")"); return buf.toString(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Enum.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Enum.java index bc6cf210fc..76e35a2f72 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Enum.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Enum.java @@ -52,8 +52,8 @@ public interface Enum extends DataType { public long[] getValues(); /** - * Get the names of the enum entries. The returned names are sorted using String's natural - * sort order. + * Get the names of the enum entries. The returned names are first sorted by the enum int + * value, then sub-sorted by name value where there are multiple name values per int value. * @return the names of the enum entries. */ public String[] getNames(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EnumDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EnumDataType.java index eea7eb7346..c28ad61bcc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EnumDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EnumDataType.java @@ -34,7 +34,7 @@ public class EnumDataType extends GenericDataType implements Enum { new SettingsDefinition[] { MutabilitySettingsDefinition.DEF }; private Map nameMap; // name to value - private Map> valueMap; // value to names + private TreeMap> valueMap; // value to names private Map commentMap; // name to comment private int length; private String description; @@ -54,7 +54,7 @@ public class EnumDataType extends GenericDataType implements Enum { throw new IllegalArgumentException("unsupported enum length: " + length); } nameMap = new HashMap<>(); - valueMap = new HashMap<>(); + valueMap = new TreeMap<>(); commentMap = new HashMap<>(); this.length = length; } @@ -68,7 +68,7 @@ public class EnumDataType extends GenericDataType implements Enum { throw new IllegalArgumentException("unsupported enum length: " + length); } nameMap = new HashMap<>(); - valueMap = new HashMap<>(); + valueMap = new TreeMap<>(); commentMap = new HashMap<>(); this.length = length; } @@ -108,15 +108,19 @@ public class EnumDataType extends GenericDataType implements Enum { @Override public long[] getValues() { long[] values = valueMap.keySet().stream().mapToLong(Long::longValue).toArray(); - Arrays.sort(values); return values; } @Override public String[] getNames() { - String[] names = nameMap.keySet().toArray(new String[nameMap.size()]); - Arrays.sort(names); - return names; + // names are first sorted by int value, then sub-sorted by name value + List names = new ArrayList<>(); + Collection> values = valueMap.values(); + for (List list : values) { + Collections.sort(list); + names.addAll(list); + } + return names.toArray(new String[0]); } @Override @@ -417,7 +421,7 @@ public class EnumDataType extends GenericDataType implements Enum { } Enum enumm = (Enum) dataType; nameMap = new HashMap<>(); - valueMap = new HashMap<>(); + valueMap = new TreeMap<>(); commentMap = new HashMap<>(); setLength(enumm.getLength()); String[] names = enumm.getNames(); diff --git a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/DataTypeWriterTest.java b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/DataTypeWriterTest.java index 4ee906eb3f..855abbd8e7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/DataTypeWriterTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/DataTypeWriterTest.java @@ -33,10 +33,6 @@ public class DataTypeWriterTest extends AbstractGTest { private StringWriter writer; private DataTypeWriter dtWriter; - public DataTypeWriterTest() { - super(); - } - @Before public void setUp() throws Exception { @@ -105,8 +101,16 @@ public class DataTypeWriterTest extends AbstractGTest { enumm.add("E", 4); dtWriter.write(enumm, TaskMonitor.DUMMY); String actual = writer.getBuffer().toString(); - String expected = "typedef enum myEnum {" + EOL + " A=0," + EOL + " B=1," + EOL + - " C=2," + EOL + " D=3," + EOL + " E=4" + EOL + "} myEnum;" + EOL + EOL; + + //@formatter:off + String expected = "typedef enum myEnum {" + EOL + + " A=0," + EOL + + " B=1," + EOL + + " C=2," + EOL + + " D=3," + EOL + + " E=4" + EOL + + "} myEnum;" + EOL + EOL; + //@formatter:on assertEquals(expected, actual); } @@ -120,8 +124,84 @@ public class DataTypeWriterTest extends AbstractGTest { enumm.add("E", 254); dtWriter.write(enumm, TaskMonitor.DUMMY); String actual = writer.getBuffer().toString(); - String expected = "typedef enum myEnum {" + EOL + " A=4," + EOL + " B=8," + EOL + - " C=16," + EOL + " D=32," + EOL + " E=254" + EOL + "} myEnum;" + EOL + EOL; + + //@formatter:off + String expected = "typedef enum myEnum {" + EOL + + " A=4," + EOL + + " B=8," + EOL + + " C=16," + EOL + + " D=32," + EOL + + " E=254" + EOL + + "} myEnum;" + EOL + EOL; + //@formatter:on + assertEquals(expected, actual); + } + + @Test + public void testEnum_WithComments() throws IOException, CancelledException { + Enum enumm = new EnumDataType("myEnum", 1); + enumm.add("A", 0); + enumm.add("B", 1, "B Comment"); + enumm.add("C", 2); + enumm.add("D", 3, "D Comment"); + enumm.add("E", 4); + dtWriter.write(enumm, TaskMonitor.DUMMY); + String actual = writer.getBuffer().toString(); + + //@formatter:off + String expected = "typedef enum myEnum {" + EOL + + " A=0," + EOL + + " B=1 /* B Comment */," + EOL + + " C=2," + EOL + + " D=3 /* D Comment */," + EOL + + " E=4" + EOL + + "} myEnum;" + EOL + EOL; + //@formatter:on + assertEquals(expected, actual); + } + + @Test + public void testEnum_MultipleNamesPerValue() throws IOException, CancelledException { + Enum enumm = new EnumDataType("myEnum", 1); + enumm.add("A", 4); + enumm.add("Two", 8); + enumm.add("One", 8); + enumm.add("End", 32); + dtWriter.write(enumm, TaskMonitor.DUMMY); + String actual = writer.getBuffer().toString(); + + //@formatter:off + String expected = "typedef enum myEnum {" + EOL + + " A=4," + EOL + + " One=8," + EOL + + " Two=8," + EOL + + " End=32" + EOL + + "} myEnum;" + EOL + EOL; + //@formatter:on + assertEquals(expected, actual); + } + + @Test + public void testEnum_NamesOrderDifferenentThanValueOrder() + throws IOException, CancelledException { + Enum enumm = new EnumDataType("myEnum", 1); + enumm.add("E", 4); + enumm.add("C", 8); + enumm.add("D", 16); + enumm.add("B", 32); + enumm.add("A", 254); + dtWriter.write(enumm, TaskMonitor.DUMMY); + String actual = writer.getBuffer().toString(); + + //@formatter:off + String expected = "typedef enum myEnum {" + EOL + + " E=4," + EOL + + " C=8," + EOL + + " D=16," + EOL + + " B=32," + EOL + + " A=254" + EOL + + "} myEnum;" + EOL + EOL; + //@formatter:on assertEquals(expected, actual); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/EnumTest.java b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/EnumTest.java index 863daedf9e..4949f7de60 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/EnumTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/EnumTest.java @@ -22,7 +22,7 @@ import java.util.NoSuchElementException; import org.junit.*; import generic.test.AbstractGTest; -import ghidra.util.task.TaskMonitorAdapter; +import ghidra.util.task.TaskMonitor; /** * Tests for Enum data types. @@ -166,7 +166,7 @@ public class EnumTest extends AbstractGTest { Enum enummDT = (Enum) c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER); assertNotNull(enummDT); - c.remove(enummDT, TaskMonitorAdapter.DUMMY_MONITOR); + c.remove(enummDT, TaskMonitor.DUMMY); assertNull(c.getDataType("Color")); assertTrue(enummDT.isDeleted()); @@ -235,6 +235,7 @@ public class EnumTest extends AbstractGTest { Assert.fail("Should have gotten no such element exception!"); } catch (NoSuchElementException e) { + // expected } }