/* ### * 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 ghidra.program.database.data; import static org.junit.Assert.*; import java.awt.Color; import org.junit.*; import ghidra.docking.settings.*; import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramDB; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSpace; import ghidra.program.model.data.*; import ghidra.program.model.listing.Data; import ghidra.program.model.listing.Listing; import ghidra.program.model.mem.Memory; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitorAdapter; /** * * Test setting default and instance settings on Data. * * */ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest { private ProgramDB program; private DataTypeManagerDB dataMgr; private Listing listing; private AddressSpace space; private int transactionID; public SettingsTest() { super(); } @Before public void setUp() throws Exception { program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this); space = program.getAddressFactory().getDefaultAddressSpace(); dataMgr = program.getDataTypeManager(); listing = program.getListing(); transactionID = program.startTransaction("Test"); addBlock(); } @After public void tearDown() throws Exception { if (program.getCurrentTransaction() != null) { program.endTransaction(transactionID, true); } program.release(this); } @Test public void testSetDefaultSettings() throws Exception { listing.createData(addr(10), new ByteDataType(), 1); Data data = listing.getDataAt(addr(10)); ByteDataType dt = (ByteDataType) data.getDataType(); Settings defaultSettings = dt.getDefaultSettings(); defaultSettings.setString("color", "red"); defaultSettings.setLong("someLongValue", 10); defaultSettings.setByteArray("bytes", new byte[] { 0, 1, 2 }); assertEquals("red", defaultSettings.getString("color")); Long lv = defaultSettings.getLong("someLongValue"); assertNotNull(lv); assertEquals(10, lv.longValue()); byte[] b = defaultSettings.getByteArray("bytes"); assertNotNull(b); assertEquals(3, b.length); defaultSettings.setValue("long", new Long(10)); Object obj = defaultSettings.getValue("long"); assertNotNull(obj); assertEquals(10, ((Long) obj).longValue()); } @Test public void testSetDefaultSettings2() throws Exception { TypedefDataType td = new TypedefDataType("ByteTypedef", new ByteDataType()); listing.createData(addr(10), td, td.getLength()); Data data = listing.getDataAt(addr(10)); TypeDef typeDef = (TypeDef) data.getDataType(); Settings defaultSettings = typeDef.getDefaultSettings(); defaultSettings.setString("color", "red"); defaultSettings.setLong("someLongValue", 10); defaultSettings.setByteArray("bytes", new byte[] { 0, 1, 2 }); assertEquals("red", defaultSettings.getString("color")); Long lv = defaultSettings.getLong("someLongValue"); assertNotNull(lv); assertEquals(10, lv.longValue()); byte[] b = defaultSettings.getByteArray("bytes"); assertNotNull(b); assertEquals(3, b.length); defaultSettings.setValue("long", new Long(10)); Object obj = defaultSettings.getValue("long"); assertNotNull(obj); assertEquals(10, ((Long) obj).longValue()); try { defaultSettings.setValue("color", Color.RED); Assert.fail("Should not be able to set arbitrary objects"); } catch (IllegalArgumentException e) { // expected } } @Test public void testIsEmpty() throws Exception { listing.createData(addr(10), new ByteDataType(), 1); Data data = listing.getDataAt(addr(10)); ByteDataType dt = (ByteDataType) data.getDataType(); Settings defaultSettings = dt.getDefaultSettings(); defaultSettings.setString("color", "red"); defaultSettings.setLong("someLongValue", 10); defaultSettings.setByteArray("bytes", new byte[] { 0, 1, 2 }); assertTrue(!defaultSettings.isEmpty()); defaultSettings.clearAllSettings(); assertTrue(defaultSettings.isEmpty()); } @Test public void testGetNames() throws Exception { listing.createData(addr(10), new ByteDataType(), 1); Data data = listing.getDataAt(addr(10)); ByteDataType dt = (ByteDataType) data.getDataType(); Settings defaultSettings = dt.getDefaultSettings(); defaultSettings.setString("color", "red"); defaultSettings.setLong("someLongValue", 10); defaultSettings.setByteArray("bytes", new byte[] { 0, 1, 2 }); defaultSettings.setString("endian", "big Endian"); String[] names = defaultSettings.getNames(); assertEquals(4, names.length); } @Test public void testClearSetting() throws Exception { listing.createData(addr(10), new ByteDataType(), 1); Data data = listing.getDataAt(addr(10)); ByteDataType dt = (ByteDataType) data.getDataType(); Settings defaultSettings = dt.getDefaultSettings(); defaultSettings.setString("color", "red"); defaultSettings.setLong("someLongValue", 10); defaultSettings.setByteArray("bytes", new byte[] { 0, 1, 2 }); defaultSettings.clearSetting("color"); assertNull(defaultSettings.getString("color")); } @Test public void testInstanceSettings() throws Exception { listing.createData(addr(10), new ByteDataType(), 1); Data data = listing.getDataAt(addr(10)); ByteDataType dt = (ByteDataType) data.getDataType(); Settings defaultSettings = dt.getDefaultSettings(); defaultSettings.setLong("format", FormatSettingsDefinition.CHAR); defaultSettings.setLong("signed", 0); defaultSettings.setLong("padded", 1); SettingsDefinition[] defs = dt.getSettingsDefinitions(); for (int i = 0; i < defs.length; i++) { if (defs[i] instanceof EnumSettingsDefinition) { EnumSettingsDefinition enumDef = (EnumSettingsDefinition) defs[i]; int value = enumDef.getChoice(data); enumDef.setChoice(data, value); if (i == 0) { assertEquals(FormatSettingsDefinition.CHAR, data.getLong("format").longValue()); } else if (i == 1) { assertEquals(0, data.getLong("signed").longValue()); } else if (i == 2) { assertEquals(1, data.getLong("padded").longValue()); } } } } @Test public void testGetInstanceNames() throws Exception { listing.createData(addr(10), new ByteDataType(), 1); Data data = listing.getDataAt(addr(10)); data.setString("color", "red"); data.setLong("someLongValue", 10); data.setByteArray("bytes", new byte[] { 0, 1, 2 }); data.setString("endian", "big Endian"); String[] names = data.getNames(); assertEquals(4, names.length); } @Test public void testClearInstanceSettings() throws Exception { listing.createData(addr(10), new ByteDataType(), 1); Data data = listing.getDataAt(addr(10)); data.setString("color", "red"); data.setLong("someLongValue", 10); data.setByteArray("bytes", new byte[] { 0, 1, 2 }); data.clearSetting("color"); assertNull(data.getString("color")); } @Test public void testClearAllInstanceSettings() throws Exception { listing.createData(addr(10), new ByteDataType(), 1); Data data = listing.getDataAt(addr(10)); data.setString("color", "red"); data.setLong("someLongValue", 10); data.setByteArray("bytes", new byte[] { 0, 1, 2 }); data.setString("endian", "big Endian"); data.clearAllSettings(); assertNull(data.getString("color")); assertNull(data.getLong("someLongValue")); assertNull(data.getByteArray("bytes")); assertNull(data.getString("endian")); } @Test public void testIsEmptyInstanceSettings() throws Exception { listing.createData(addr(10), new ByteDataType(), 1); Data data = listing.getDataAt(addr(10)); data.setString("color", "red"); data.setLong("someLongValue", 10); data.setByteArray("bytes", new byte[] { 0, 1, 2 }); data.setString("endian", "big Endian"); assertTrue(!data.isEmpty()); data.clearAllSettings(); assertTrue(data.isEmpty()); } @Test public void testMoveSettings() throws Exception { for (int i = 0; i < 10; i++) { Address a = addr(i); dataMgr.setStringSettingsValue(a, "color", "red" + i); dataMgr.setLongSettingsValue(a, "someLongValue", i); dataMgr.setByteSettingsValue(a, "bytes", new byte[] { 0, 1, 2 }); } dataMgr.moveAddressRange(addr(0), addr(20), 10, TaskMonitorAdapter.DUMMY_MONITOR); int j = 0; for (int i = 20; i < 30; i++, j++) { Address a = addr(i); String s = dataMgr.getStringSettingsValue(a, "color"); assertEquals("red" + j, s); Long lvalue = dataMgr.getLongSettingsValue(a, "someLongValue"); assertEquals(j, lvalue.longValue()); assertNotNull(dataMgr.getByteSettingsValue(a, "bytes")); } } @Test public void testMoveSettings2() { for (int i = 0; i < 10; i++) { Address a = addr(i); dataMgr.setStringSettingsValue(a, "color", "red" + i); dataMgr.setLongSettingsValue(a, "someLongValue", i); dataMgr.setByteSettingsValue(a, "bytes", new byte[] { 0, 1, 2 }); } try { dataMgr.moveAddressRange(addr(0), addr(5), 10, TaskMonitorAdapter.DUMMY_MONITOR); } catch (CancelledException e) { Assert.fail("Unexpected cancelled exception"); } int j = 0; for (int i = 5; i < 15; i++, j++) { Address a = addr(i); String s = dataMgr.getStringSettingsValue(a, "color"); assertEquals("red" + j, s); Long lvalue = dataMgr.getLongSettingsValue(a, "someLongValue"); assertEquals(j, lvalue.longValue()); assertNotNull(dataMgr.getByteSettingsValue(a, "bytes")); } } @Test public void testMoveSettings3() { int j = 20; for (int i = 20; i < 30; i++, j++) { Address a = addr(i); dataMgr.setStringSettingsValue(a, "color", "red" + i); dataMgr.setLongSettingsValue(a, "someLongValue", i); dataMgr.setByteSettingsValue(a, "bytes", new byte[] { 0, 1, 2 }); } j = 20; try { dataMgr.moveAddressRange(addr(20), addr(5), 10, TaskMonitorAdapter.DUMMY_MONITOR); } catch (CancelledException e) { Assert.fail("Unexpected cancelled exception"); } for (int i = 5; i < 15; i++, j++) { Address a = addr(i); String s = dataMgr.getStringSettingsValue(a, "color"); assertEquals("red" + j, s); Long lvalue = dataMgr.getLongSettingsValue(a, "someLongValue"); assertEquals(j, lvalue.longValue()); assertNotNull(dataMgr.getByteSettingsValue(a, "bytes")); } } @Test public void testDefaultSettingsOnCharArray() throws Exception { DataType charDT = dataMgr.resolve(new CharDataType(), null); SettingsDefinition[] settingsDefinitions = charDT.getSettingsDefinitions(); assertTrue("Expect multiple settings on char type", settingsDefinitions.length > 2); // make sure we get more than two settings Array array = new ArrayDataType(charDT, 5, -1); assertArrayEquals(settingsDefinitions, array.getSettingsDefinitions()); array = (Array) dataMgr.resolve(array, null); assertArrayEquals(settingsDefinitions, array.getSettingsDefinitions()); Settings defaultSettings = array.getDefaultSettings(); assertEquals(FormatSettingsDefinition.CHAR, FormatSettingsDefinition.DEF_CHAR.getChoice(defaultSettings)); assertEquals(MutabilitySettingsDefinition.NORMAL, MutabilitySettingsDefinition.DEF.getChoice(defaultSettings)); assertEquals(String.class, array.getValueClass(defaultSettings)); FormatSettingsDefinition.DEF_CHAR.setChoice(defaultSettings, FormatSettingsDefinition.HEX); assertEquals(Array.class, array.getValueClass(defaultSettings)); } @Test public void testDefaultSettingsOnTypedef() throws Exception { DataType byteDT = dataMgr.resolve(new ByteDataType(), null); SettingsDefinition[] bdefs = byteDT.getSettingsDefinitions(); Settings settings = byteDT.getDefaultSettings(); settings.setLong("format", FormatSettingsDefinition.OCTAL); settings.setString("color", "red"); settings.setLong("someLongValue", 10); TypedefDataType tdt = new TypedefDataType("ByteTypedef", byteDT); TypeDef td = (TypeDef) dataMgr.addDataType(tdt, null); SettingsDefinition[] sdefs = td.getSettingsDefinitions(); assertNotNull(sdefs); assertEquals(bdefs.length, sdefs.length); Settings defSettings = td.getDefaultSettings(); assertNull(defSettings.getValue("format")); assertNull(defSettings.getValue("color")); assertNull(defSettings.getValue("someLongValue")); } @Test public void testDefaultSettingsOnTypedef2() throws Exception { DataType byteDT = dataMgr.resolve(new ByteDataType(), null); SettingsDefinition[] bdefs = byteDT.getSettingsDefinitions(); Settings settings = byteDT.getDefaultSettings(); Settings defaultSettings = new SettingsImpl(byteDT.getDefaultSettings()); settings.setLong("format", FormatSettingsDefinition.OCTAL); bdefs[0].copySetting(settings, defaultSettings); TypedefDataType tdt = new TypedefDataType("ByteTypedef", byteDT); TypeDef td = (TypeDef) dataMgr.addDataType(tdt, null); Settings defSettings = td.getDefaultSettings(); assertNull(defSettings.getValue("format")); // change the default settings for Byte data type; should not // affect the typedef default settings settings.setLong("format", FormatSettingsDefinition.BINARY); bdefs[0].copySetting(settings, defaultSettings); defSettings = td.getDefaultSettings(); assertNull(defSettings.getValue("format")); } @Test public void testDefaultSettingsOnTypedefUndoRedo() throws Exception { DataType byteDT = dataMgr.resolve(new ByteDataType(), null); SettingsDefinition[] bdefs = byteDT.getSettingsDefinitions(); Settings settings = byteDT.getDefaultSettings(); Settings defaultSettings = new SettingsImpl(byteDT.getDefaultSettings()); settings.setLong("format", FormatSettingsDefinition.OCTAL); bdefs[0].copySetting(settings, defaultSettings); endTransaction(); startTransaction(); TypedefDataType tdt = new TypedefDataType("ByteTypedef", byteDT); TypeDef td = (TypeDef) dataMgr.addDataType(tdt, null); Settings defSettings = td.getDefaultSettings(); assertNull(defSettings.getValue("format")); endTransaction(); startTransaction(); defSettings.setLong("format", FormatSettingsDefinition.BINARY); endTransaction(); undo(program); defSettings = td.getDefaultSettings(); assertNull(defSettings.getValue("format")); redo(program); defSettings = td.getDefaultSettings(); assertEquals(new Long(FormatSettingsDefinition.BINARY), defSettings.getValue("format")); } @Test public void testDefaultSettingsOnDeletedTypdef() throws Exception { DataType byteDT = dataMgr.resolve(new ByteDataType(), null); SettingsDefinition[] bdefs = byteDT.getSettingsDefinitions(); Settings settings = byteDT.getDefaultSettings(); Settings defaultSettings = new SettingsImpl(byteDT.getDefaultSettings()); settings.setLong("format", FormatSettingsDefinition.OCTAL); bdefs[0].copySetting(settings, defaultSettings); TypedefDataType tdt = new TypedefDataType("ByteTypedef", byteDT); TypeDef td = (TypeDef) dataMgr.addDataType(tdt, null); long dtID = dataMgr.getID(td); endTransaction(); startTransaction(); // apply typedef program.getListing().createData(addr(50), td); endTransaction(); startTransaction(); dataMgr.remove(td, TaskMonitorAdapter.DUMMY_MONITOR); endTransaction(); // make sure accessing the settings does not blow up assertTrue(td.isDeleted()); assertNotNull(td.getDefaultSettings()); undo(program); td = (TypeDef) dataMgr.getDataType(dtID); assertTrue(!td.isDeleted()); Settings s = td.getDefaultSettings(); assertNull(s.getValue("format")); redo(program); assertTrue(td.isDeleted()); s = td.getDefaultSettings(); assertNull(s.getValue("format")); } private void startTransaction() { transactionID = program.startTransaction("Test"); } private void endTransaction() { program.endTransaction(transactionID, true); } private Address addr(long l) { return space.getAddress(l); } private void addBlock() throws Exception { Memory memory = program.getMemory(); memory.createInitializedBlock("test", addr(0), 100, (byte) 0, TaskMonitorAdapter.DUMMY_MONITOR, false); } }