Bug 562164 - Add JUnit tests for IMemoryImporter and IMemoryExporter

* Added FileExport to implement base flow
* Added ExportRequest to aggregate operation configuration
* Extracted PlainTextExport extends FileExport
* Added ReadMemory to simplify interaction interface
* Extracted AddressableSize to reduce code duplication

Change-Id: I848c922cd1300799c0e9d1bff8213e8b06edc41c
Signed-off-by: Alexander Fedorov <alexander.fedorov@arsysop.ru>
This commit is contained in:
Alexander Fedorov 2020-04-26 15:45:56 +03:00
parent 0ab57c346a
commit 53a665be69
8 changed files with 358 additions and 111 deletions

View file

@ -0,0 +1,70 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alexander Fedorov (ArSysOp) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.core.memory.transport;
import java.math.BigInteger;
/**
*
* Aggregates memory export configuration
*
* @since 0.1
*
*/
public final class ExportRequest {
private final BigInteger start;
private final BigInteger end;
private final BigInteger addressable;
private final ReadMemory read;
public ExportRequest(BigInteger start, BigInteger end, BigInteger addressable, ReadMemory read) {
this.start = start;
this.end = end;
this.addressable = addressable;
this.read = read;
}
/**
*
* @return starting offset
*/
public BigInteger start() {
return start;
}
/**
*
* @return ending offset
*/
public BigInteger end() {
return end;
}
/**
*
* @return addressable size
*/
public BigInteger addressable() {
return addressable;
}
/**
*
* @return reader
*/
public ReadMemory read() {
return read;
}
}

View file

@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alexander Fedorov (ArSysOp) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.core.memory.transport;
import java.io.File;
import java.math.BigInteger;
import org.eclipse.core.runtime.ICoreRunnable;
/**
* Exports memory information to a given file
*
* @since 0.1
*/
public abstract class FileExport<O extends AutoCloseable> implements ICoreRunnable {
protected final BigInteger start;
protected final BigInteger end;
protected final BigInteger addressable;
protected final ReadMemory read;
protected final File file;
protected FileExport(File input, ExportRequest request) {
this.file = input;
this.start = request.start();
this.end = request.end();
this.addressable = request.addressable();
this.read = request.read();
}
}

View file

@ -22,7 +22,7 @@ import java.math.BigInteger;
* @since 0.1
*
*/
public class ImportRequest {
public final class ImportRequest {
private final BigInteger base;
private final BigInteger start;

View file

@ -0,0 +1,36 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alexander Fedorov (ArSysOp) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.core.memory.transport;
import java.math.BigInteger;
import org.eclipse.debug.core.DebugException;
/**
* Reads an array of bytes using the given offset
*
* @since 0.1
*/
public interface ReadMemory {
/**
* Reads an array of bytes from a memory starting from the given offset.
*
* @param offset
* @return the obtained data
* @throws DebugException
*/
byte[] from(BigInteger offset) throws DebugException;
}

View file

@ -0,0 +1,47 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alexander Fedorov (ArSysOp) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.internal.core.memory.transport;
import java.math.BigInteger;
import org.eclipse.cdt.debug.core.memory.transport.ReadMemory;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IMemoryBlockExtension;
import org.eclipse.debug.core.model.MemoryByte;
/**
* Reads memory from the given {@link IMemoryBlockExtension}
*
*/
public final class ReadMemoryBlock implements ReadMemory {
private final IMemoryBlockExtension memory;
private final long unit;
public ReadMemoryBlock(IMemoryBlockExtension memory) {
this.memory = memory;
this.unit = BigInteger.valueOf(1).longValue();
}
@Override
public byte[] from(BigInteger offset) throws DebugException {
MemoryByte[] received = memory.getBytesFromOffset(offset, unit);
byte[] bytes = new byte[received.length];
for (int i = 0; i < received.length; i++) {
bytes[i] = received[i].getValue();
}
return bytes;
}
}

View file

@ -0,0 +1,40 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alexander Fedorov (ArSysOp) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.internal.ui.memory.transport;
import java.math.BigInteger;
import java.util.function.Supplier;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IMemoryBlockExtension;
public class AddressableSize implements Supplier<BigInteger> {
private final IMemoryBlockExtension memory;
public AddressableSize(IMemoryBlockExtension memory) {
this.memory = memory;
}
@Override
public BigInteger get() {
try {
return BigInteger.valueOf(memory.getAddressableSize());
} catch (DebugException e1) {
// sane value for most cases
return BigInteger.ONE;
}
}
}

View file

@ -0,0 +1,111 @@
/*******************************************************************************
* Copyright (c) 2006, 2020 Wind River Systems, Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Ted R Williams (Wind River Systems, Inc.) - initial implementation
* Alexander Fedorov (ArSysOp) - headless part extraction
*******************************************************************************/
package org.eclipse.cdt.debug.ui.memory.transport;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import org.eclipse.cdt.debug.core.memory.transport.ExportRequest;
import org.eclipse.cdt.debug.core.memory.transport.FileExport;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
final class PlainTextExport extends FileExport<FileWriter> {
protected PlainTextExport(File output, ExportRequest request) {
super(output, request);
}
@Override
public void run(IProgressMonitor monitor) throws CoreException {
try {
// These variables control how the output will be formatted
// The output data is split by chunks of 1 addressable unit size.
final BigInteger dataCellSize = BigInteger.valueOf(1);
// show 32 bytes of data per line, total. Adjust number of columns to compensate
// for longer addressable unit size
final BigInteger numberOfColumns = BigInteger.valueOf(32).divide(addressable);
// deduce the number of data chunks to be output, per line
final BigInteger dataCellsPerLine = dataCellSize.multiply(numberOfColumns);
BigInteger transferAddress = start;
FileWriter writer = new FileWriter(file);
BigInteger jobs = end.subtract(transferAddress).divide(dataCellsPerLine);
BigInteger factor = BigInteger.ONE;
if (jobs.compareTo(BigInteger.valueOf(0x7FFFFFFF)) > 0) {
factor = jobs.divide(BigInteger.valueOf(0x7FFFFFFF));
jobs = jobs.divide(factor);
}
monitor.beginTask(Messages.getString("Exporter.ProgressTitle"), jobs.intValue()); //$NON-NLS-1$
BigInteger jobCount = BigInteger.ZERO;
while (transferAddress.compareTo(end) < 0 && !monitor.isCanceled()) {
BigInteger length = dataCellsPerLine;
if (end.subtract(transferAddress).compareTo(length) < 0)
length = end.subtract(transferAddress);
monitor.subTask(String.format(Messages.getString("Exporter.Progress"), length.toString(10), //$NON-NLS-1$
transferAddress.toString(16)));
StringBuilder buf = new StringBuilder();
for (int i = 0; i < length.divide(dataCellSize).intValue(); i++) {
if (i != 0) {
buf.append(" "); //$NON-NLS-1$
}
BigInteger from = transferAddress.add(dataCellSize.multiply(BigInteger.valueOf(i)));
byte[] bytes = read.from(from);
for (int byteIndex = 0; byteIndex < bytes.length; byteIndex++) {
String bString = BigInteger.valueOf(0xFF & bytes[byteIndex]).toString(16);
if (bString.length() == 1) {
buf.append("0"); //$NON-NLS-1$
}
buf.append(bString);
}
}
writer.write(buf.toString().toUpperCase());
writer.write("\n"); //$NON-NLS-1$
transferAddress = transferAddress.add(length);
jobCount = jobCount.add(BigInteger.ONE);
if (jobCount.compareTo(factor) == 0) {
jobCount = BigInteger.ZERO;
monitor.worked(1);
}
}
writer.close();
monitor.done();
} catch (IOException ex) {
MemoryTransportPlugin.getDefault().getLog()
.log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrFile"), ex)); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrFile"), ex)); //$NON-NLS-1$
} catch (DebugException ex) {
MemoryTransportPlugin.getDefault().getLog()
.log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrReadTarget"), ex)); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrReadTarget"), ex)); //$NON-NLS-1$
} catch (Exception ex) {
MemoryTransportPlugin.getDefault().getLog()
.log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.INTERNAL_ERROR, Messages.getString("Exporter.Falure"), ex)); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.INTERNAL_ERROR, Messages.getString("Exporter.Falure"), ex)); //$NON-NLS-1$
}
}
}

View file

@ -15,19 +15,16 @@
package org.eclipse.cdt.debug.ui.memory.transport;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import org.eclipse.cdt.debug.core.memory.transport.ExportRequest;
import org.eclipse.cdt.debug.core.memory.transport.ReadMemory;
import org.eclipse.cdt.debug.internal.core.memory.transport.ReadMemoryBlock;
import org.eclipse.cdt.debug.internal.core.memory.transport.TransportJob;
import org.eclipse.cdt.debug.internal.ui.memory.transport.AddressableSize;
import org.eclipse.cdt.debug.ui.memory.transport.model.IMemoryExporter;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IMemoryBlock;
import org.eclipse.debug.core.model.IMemoryBlockExtension;
import org.eclipse.debug.core.model.MemoryByte;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
@ -453,110 +450,13 @@ public class PlainTextExporter implements IMemoryExporter {
@Override
public void exportMemory() {
Job job = new Job("Memory Export to Plain Text File") { //$NON-NLS-1$
@Override
public IStatus run(IProgressMonitor monitor) {
try {
final BigInteger addressableSize = getAdressableSize();
// These variables control how the output will be formatted
// The output data is split by chunks of 1 addressable unit size.
final BigInteger dataCellSize = BigInteger.valueOf(1);
// show 32 bytes of data per line, total. Adjust number of columns to compensate
// for longer addressable unit size
final BigInteger numberOfColumns = BigInteger.valueOf(32).divide(addressableSize);
// deduce the number of data chunks to be output, per line
final BigInteger dataCellsPerLine = dataCellSize.multiply(numberOfColumns);
BigInteger transferAddress = fStartAddress;
FileWriter writer = new FileWriter(fOutputFile);
BigInteger jobs = fEndAddress.subtract(transferAddress).divide(dataCellsPerLine);
BigInteger factor = BigInteger.ONE;
if (jobs.compareTo(BigInteger.valueOf(0x7FFFFFFF)) > 0) {
factor = jobs.divide(BigInteger.valueOf(0x7FFFFFFF));
jobs = jobs.divide(factor);
}
monitor.beginTask(Messages.getString("Exporter.ProgressTitle"), jobs.intValue()); //$NON-NLS-1$
BigInteger jobCount = BigInteger.ZERO;
while (transferAddress.compareTo(fEndAddress) < 0 && !monitor.isCanceled()) {
BigInteger length = dataCellsPerLine;
if (fEndAddress.subtract(transferAddress).compareTo(length) < 0)
length = fEndAddress.subtract(transferAddress);
monitor.subTask(String.format(Messages.getString("Exporter.Progress"), length.toString(10), //$NON-NLS-1$
transferAddress.toString(16)));
StringBuilder buf = new StringBuilder();
for (int i = 0; i < length.divide(dataCellSize).intValue(); i++) {
if (i != 0)
buf.append(" "); //$NON-NLS-1$
MemoryByte bytes[] = ((IMemoryBlockExtension) fMemoryBlock).getBytesFromAddress(
transferAddress.add(dataCellSize.multiply(BigInteger.valueOf(i))),
dataCellSize.longValue());
for (int byteIndex = 0; byteIndex < bytes.length; byteIndex++) {
String bString = BigInteger.valueOf(0xFF & bytes[byteIndex].getValue()).toString(16);
if (bString.length() == 1)
buf.append("0"); //$NON-NLS-1$
buf.append(bString);
}
}
writer.write(buf.toString().toUpperCase());
writer.write("\n"); //$NON-NLS-1$
transferAddress = transferAddress.add(length);
jobCount = jobCount.add(BigInteger.ONE);
if (jobCount.compareTo(factor) == 0) {
jobCount = BigInteger.ZERO;
monitor.worked(1);
}
}
writer.close();
monitor.done();
} catch (IOException ex) {
MemoryTransportPlugin.getDefault().getLog()
.log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrFile"), ex)); //$NON-NLS-1$
return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrFile"), ex); //$NON-NLS-1$
} catch (DebugException ex) {
MemoryTransportPlugin.getDefault().getLog()
.log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrReadTarget"), ex)); //$NON-NLS-1$
return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.REQUEST_FAILED, Messages.getString("Exporter.ErrReadTarget"), ex); //$NON-NLS-1$
} catch (Exception ex) {
MemoryTransportPlugin.getDefault().getLog()
.log(new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.INTERNAL_ERROR, Messages.getString("Exporter.Falure"), ex)); //$NON-NLS-1$
return new Status(IStatus.ERROR, MemoryTransportPlugin.getUniqueIdentifier(),
DebugException.INTERNAL_ERROR, Messages.getString("Exporter.Falure"), ex); //$NON-NLS-1$
}
return Status.OK_STATUS;
}
};
ReadMemory read = new ReadMemoryBlock((IMemoryBlockExtension) fMemoryBlock);
BigInteger addressable = new AddressableSize((IMemoryBlockExtension) fMemoryBlock).get();
ExportRequest request = new ExportRequest(fStartAddress, fEndAddress, addressable, read);
PlainTextExport memoryExport = new PlainTextExport(fOutputFile, request);
TransportJob job = new TransportJob("Memory Export to Plain Text File", memoryExport);
job.setUser(true);
job.schedule();
}
private BigInteger getAdressableSize() {
BigInteger addressableSize;
try {
addressableSize = BigInteger.valueOf(((IMemoryBlockExtension) fMemoryBlock).getAddressableSize());
} catch (DebugException e1) {
// sane value for most cases
addressableSize = BigInteger.ONE;
}
return addressableSize;
}
}