diff --git a/plugins/org.eclipse.dd.tests.dsf/.classpath b/plugins/org.eclipse.dd.tests.dsf/.classpath new file mode 100644 index 00000000000..304e86186aa --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/plugins/org.eclipse.dd.tests.dsf/.cvsignore b/plugins/org.eclipse.dd.tests.dsf/.cvsignore new file mode 100644 index 00000000000..ba077a4031a --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/.cvsignore @@ -0,0 +1 @@ +bin diff --git a/plugins/org.eclipse.dd.tests.dsf/.project b/plugins/org.eclipse.dd.tests.dsf/.project new file mode 100644 index 00000000000..a662c11dc13 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/.project @@ -0,0 +1,28 @@ + + + org.eclipse.dd.tests.dsf + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/plugins/org.eclipse.dd.tests.dsf/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.dd.tests.dsf/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..8241d8c455d --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,65 @@ +#Thu Jun 07 11:08:23 PDT 2007 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning +org.eclipse.jdt.core.compiler.problem.nullReference=ignore +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/plugins/org.eclipse.dd.tests.dsf/.settings/org.eclipse.jdt.ui.prefs b/plugins/org.eclipse.dd.tests.dsf/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..28984618f01 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,3 @@ +#Thu Oct 12 11:27:35 PDT 2006 +eclipse.preferences.version=1 +internal.default.compliance=default diff --git a/plugins/org.eclipse.dd.tests.dsf/META-INF/MANIFEST.MF b/plugins/org.eclipse.dd.tests.dsf/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..2e88859313d --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/META-INF/MANIFEST.MF @@ -0,0 +1,17 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Debug Services Framework Unit Tests +Bundle-Vendor: Eclipse.org +Bundle-SymbolicName: org.eclipse.dd.tests.dsf;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.eclipse.dd.tests.dsf.DsfTestPlugin +Bundle-Localization: plugin +Bundle-ActivationPolicy: lazy +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.debug.core, + org.eclipse.debug.ui, + org.eclipse.dd.dsf, + org.junit4, + org.eclipse.ui, + org.eclipse.dd.dsf.ui +Bundle-RequiredExecutionEnvironment: J2SE-1.5 diff --git a/plugins/org.eclipse.dd.tests.dsf/about.html b/plugins/org.eclipse.dd.tests.dsf/about.html new file mode 100644 index 00000000000..cb740ae8bc8 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/about.html @@ -0,0 +1,24 @@ + + + + +About +

About This Content

+ +

June 5, 2007

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + \ No newline at end of file diff --git a/plugins/org.eclipse.dd.tests.dsf/build.properties b/plugins/org.eclipse.dd.tests.dsf/build.properties new file mode 100644 index 00000000000..786b1df9364 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + about.html diff --git a/plugins/org.eclipse.dd.tests.dsf/plugin.properties b/plugins/org.eclipse.dd.tests.dsf/plugin.properties new file mode 100644 index 00000000000..8dc99b1d8eb --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/plugin.properties @@ -0,0 +1,13 @@ +############################################################################### +# Copyright (c) 2006 Wind River Systems and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +pluginName=DSDP/DD Debugger Services Framework (DSF) Test Plugin +providerName=Eclipse.org + diff --git a/plugins/org.eclipse.dd.tests.dsf/plugin.xml b/plugins/org.eclipse.dd.tests.dsf/plugin.xml new file mode 100644 index 00000000000..aa2732002b6 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/plugin.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/dsf/tests/service/MultiInstanceTestService.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/dsf/tests/service/MultiInstanceTestService.java new file mode 100644 index 00000000000..2b70cf6bed1 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/dsf/tests/service/MultiInstanceTestService.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.tests.service; + +import java.util.Hashtable; + +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.tests.dsf.DsfTestPlugin; +import org.osgi.framework.BundleContext; + +public class MultiInstanceTestService extends AbstractDsfService { + + public static String PROP_INSTANCE_ID = "org.eclipse.dd.dsf.tests.service.MultiInstanceTestService.id"; //$NON-NLS-1$ + String fInstanceId; + + public MultiInstanceTestService(DsfSession session, String instanceId) { + super(session); + fInstanceId = instanceId; + } + + @Override + protected BundleContext getBundleContext() { + return DsfTestPlugin.getBundleContext(); + } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize( + new RequestMonitor(getExecutor(), requestMonitor) { + @Override + public void handleOK() { + doInitialize(requestMonitor); + } + }); + } + + private void doInitialize(RequestMonitor requestMonitor) { + Hashtable properties = new Hashtable(); + properties.put(PROP_INSTANCE_ID, fInstanceId); + register(new String[]{MultiInstanceTestService.class.getName()}, properties); + requestMonitor.done(); + } + + @Override + public void shutdown(RequestMonitor requestMonitor) { + unregister(); + super.shutdown(requestMonitor); + } +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/dsf/tests/service/ServiceTests.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/dsf/tests/service/ServiceTests.java new file mode 100644 index 00000000000..102c72e8b09 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/dsf/tests/service/ServiceTests.java @@ -0,0 +1,277 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.tests.service; + +import java.lang.reflect.Constructor; +import java.util.concurrent.ExecutionException; + +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.Sequence; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.tests.dsf.DsfTestPlugin; +import org.eclipse.dd.tests.dsf.TestDsfExecutor; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; + +public class ServiceTests { + TestDsfExecutor fExecutor; + + @Before public void startExecutor() throws ExecutionException, InterruptedException { + fExecutor = new TestDsfExecutor(); + } + + @After public void shutdownExecutor() throws ExecutionException, InterruptedException { + fExecutor.submit(new DsfRunnable() { public void run() { + fExecutor.shutdown(); + }}).get(); + if (fExecutor.exceptionsCaught()) { + Throwable[] exceptions = fExecutor.getExceptions(); + throw new ExecutionException(exceptions[0]); + } + fExecutor = null; + } + + private class CreateSessionStep extends Sequence.Step { + private DsfSession fSession; + @Override public void execute(RequestMonitor requestMonitor) { + fSession = DsfSession.startSession(fExecutor, "org.eclipse.dd.dsf.tests"); //$NON-NLS-1$ + requestMonitor.done(); + } + + DsfSession getSession() { return fSession; } + } + + private class ShutdownSessionStep extends Sequence.Step { + private CreateSessionStep fCreateSessionStep; + + ShutdownSessionStep(CreateSessionStep createSessionStep) { + fCreateSessionStep = createSessionStep; + } + + @Override + public void execute(RequestMonitor requestMonitor) { + DsfSession.endSession(fCreateSessionStep.getSession()); + requestMonitor.done(); + } + } + + private class InitializeServiceStep extends Sequence.Step { + CreateSessionStep fCreateSessionStep; + Class fServiceClass; + IDsfService fService; + + InitializeServiceStep(CreateSessionStep createSessionStep, Class serviceClass) { + fCreateSessionStep = createSessionStep; + fServiceClass = serviceClass; + } + IDsfService getService() { return fService; } + + @Override + public void execute(RequestMonitor requestMonitor) { + try { + Constructor c = fServiceClass.getConstructor(new Class[] {DsfSession.class}); + fService = c.newInstance(new Object[] {fCreateSessionStep.getSession()}); + } catch (Exception e) { + Assert.fail("Unexpected exception"); //$NON-NLS-1$ + } + fService.initialize(requestMonitor); + } + } + + private class InitializeMultiInstanceServiceStep extends InitializeServiceStep { + String fServiceId; + + InitializeMultiInstanceServiceStep(CreateSessionStep createSessionStep, Class serviceClass, String serviceId) { + super(createSessionStep, serviceClass); + fServiceId = serviceId; + } + @Override + IDsfService getService() { return fService; } + + @Override + public void execute(RequestMonitor requestMonitor) { + try { + Constructor c = + fServiceClass.getConstructor(new Class[] {DsfSession.class, String.class}); + fService = c.newInstance(new Object[] {fCreateSessionStep.getSession(), fServiceId}); + } catch (Exception e) { + Assert.fail("Unexpected exception"); //$NON-NLS-1$ + } + fService.initialize(requestMonitor); + } + } + + private class ShutdownServiceStep extends Sequence.Step { + InitializeServiceStep fInitializeServiceStep; + ShutdownServiceStep(InitializeServiceStep initStep) { + fInitializeServiceStep = initStep; + } + + @Override + public void execute(RequestMonitor requestMonitor) { + fInitializeServiceStep.getService().shutdown(requestMonitor); + } + } + + + abstract private class TestRetrievingReferenceStep extends Sequence.Step { + String fClass; + boolean fShouldSucceed; + + TestRetrievingReferenceStep(Class clazz, boolean shouldSucceed) { + fClass = clazz.getName(); + fShouldSucceed = shouldSucceed; + } + + abstract String getFilter(); + + @Override + public void execute(RequestMonitor requestMonitor) { + ServiceReference[] refs = null; + try { + refs = DsfTestPlugin.getBundleContext().getServiceReferences(fClass, getFilter()); + } catch (InvalidSyntaxException e) { + Assert.fail("Unexpected exception"); //$NON-NLS-1$ + } + if (fShouldSucceed) { + Assert.assertTrue(refs != null); + Assert.assertTrue(refs.length == 1); + IDsfService service = (IDsfService)DsfTestPlugin.getBundleContext().getService(refs[0]); + Assert.assertTrue(service != null); + DsfTestPlugin.getBundleContext().ungetService(refs[0]); + } else { + Assert.assertTrue(refs == null); + } + requestMonitor.done(); + } + } + + private class TestRetrievingSimpleServiceReferenceStep extends TestRetrievingReferenceStep { + CreateSessionStep fCreateSessionStep; + TestRetrievingSimpleServiceReferenceStep(Class clazz, boolean shouldSucceed, CreateSessionStep createSessionStep) { + super(clazz, shouldSucceed); + fCreateSessionStep = createSessionStep; + } + @Override + String getFilter() { + return "(" + IDsfService.PROP_SESSION_ID + "=" + fCreateSessionStep.getSession().getId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + } + + private class TestRetrievingMultiSessionServiceReferenceStep extends TestRetrievingSimpleServiceReferenceStep { + String fServiceId; + TestRetrievingMultiSessionServiceReferenceStep(Class clazz, boolean shouldSucceed, CreateSessionStep createSessionStep, + String serviceId) { + super(clazz, shouldSucceed, createSessionStep); + fServiceId = serviceId; + } + @Override + String getFilter() { + return "(&" + //$NON-NLS-1$ + "(" + IDsfService.PROP_SESSION_ID + "=" + fCreateSessionStep.getSession().getId() + ")" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + "(" + MultiInstanceTestService.PROP_INSTANCE_ID + "=" + fServiceId + ")" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ")"; //$NON-NLS-1$ + } + } + + @Test + public void singleServiceTest() throws InterruptedException, ExecutionException { + Sequence seq = new Sequence(fExecutor) { + CreateSessionStep fSessionStep; + InitializeServiceStep fServiceStep; + + @Override + public Step[] getSteps() { return fSteps; } + + final private Step[] fSteps = new Step[] + { + fSessionStep = new CreateSessionStep(), + fServiceStep = new InitializeServiceStep(fSessionStep, SimpleTestService.class), + new TestRetrievingSimpleServiceReferenceStep(SimpleTestService.class, true, fSessionStep), + new ShutdownServiceStep(fServiceStep), + new TestRetrievingSimpleServiceReferenceStep(SimpleTestService.class, false, fSessionStep), + new ShutdownSessionStep(fSessionStep) + }; + }; + fExecutor.execute(seq); + seq.get(); + } + + /** + * Creates two sessions and starts a single service within each session. + * Then it tests retrieving the reference to the service. + */ + @Test + public void singleServiceMultiSessionTest() throws InterruptedException, ExecutionException { + Sequence seq = new Sequence(fExecutor) { + CreateSessionStep fSession1Step; + CreateSessionStep fSession2Step; + InitializeServiceStep fSession1ServiceStep; + InitializeServiceStep fSession2ServiceStep; + + @Override + public Step[] getSteps() { return fSteps; } + + final private Step[] fSteps = new Step[] + { + fSession1Step = new CreateSessionStep(), + fSession2Step = new CreateSessionStep(), + fSession1ServiceStep = new InitializeServiceStep(fSession1Step, SimpleTestService.class), + fSession2ServiceStep = new InitializeServiceStep(fSession2Step, SimpleTestService.class), + new TestRetrievingSimpleServiceReferenceStep(SimpleTestService.class, true, fSession1Step), + new TestRetrievingSimpleServiceReferenceStep(SimpleTestService.class, true, fSession2Step), + new ShutdownServiceStep(fSession1ServiceStep), + new ShutdownServiceStep(fSession2ServiceStep), + new TestRetrievingSimpleServiceReferenceStep(SimpleTestService.class, false, fSession1Step), + new TestRetrievingSimpleServiceReferenceStep(SimpleTestService.class, false, fSession2Step), + new ShutdownSessionStep(fSession1Step), + new ShutdownSessionStep(fSession2Step) + }; + }; + fExecutor.execute(seq); + seq.get(); + } + + @Test + public void multiServiceServiceTest() throws InterruptedException, ExecutionException { + Sequence seq = new Sequence(fExecutor) { + CreateSessionStep fSessionStep; + InitializeServiceStep fService1Step; + InitializeServiceStep fService2Step; + + @Override + public Step[] getSteps() { return fSteps; } + + final private Step[] fSteps = new Step[] + { + fSessionStep = new CreateSessionStep(), + fService1Step = new InitializeMultiInstanceServiceStep(fSessionStep, MultiInstanceTestService.class, "1"), //$NON-NLS-1$ + fService2Step = new InitializeMultiInstanceServiceStep(fSessionStep, MultiInstanceTestService.class, "2"), //$NON-NLS-1$ + new TestRetrievingMultiSessionServiceReferenceStep(MultiInstanceTestService.class, true, fSessionStep, "1"), //$NON-NLS-1$ + new TestRetrievingMultiSessionServiceReferenceStep(MultiInstanceTestService.class, true, fSessionStep, "2"), //$NON-NLS-1$ + new ShutdownServiceStep(fService1Step), + new ShutdownServiceStep(fService2Step), + new TestRetrievingMultiSessionServiceReferenceStep(MultiInstanceTestService.class, false, fSessionStep, "1"), //$NON-NLS-1$ + new TestRetrievingMultiSessionServiceReferenceStep(MultiInstanceTestService.class, false, fSessionStep, "2"), //$NON-NLS-1$ + new ShutdownSessionStep(fSessionStep) + }; + }; + fExecutor.execute(seq); + seq.get(); + } + +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/dsf/tests/service/SimpleTestService.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/dsf/tests/service/SimpleTestService.java new file mode 100644 index 00000000000..902bf0885cb --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/dsf/tests/service/SimpleTestService.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.tests.service; + +import java.util.Hashtable; + +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.tests.dsf.DsfTestPlugin; +import org.osgi.framework.BundleContext; + +public class SimpleTestService extends AbstractDsfService { + + public SimpleTestService(DsfSession session) { + super(session); + } + + @Override + protected BundleContext getBundleContext() { + return DsfTestPlugin.getBundleContext(); + } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize( + new RequestMonitor(getExecutor(), requestMonitor) { + @Override + public void handleOK() { + doInitialize(requestMonitor); + } + }); + } + + private void doInitialize(RequestMonitor requestMonitor) { + register(new String[]{SimpleTestService.class.getName()}, new Hashtable()); + requestMonitor.done(); + } + + @Override + public void shutdown(RequestMonitor requestMonitor) { + unregister(); + super.shutdown(requestMonitor); + } +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/DsfTestPlugin.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/DsfTestPlugin.java new file mode 100644 index 00000000000..cd4e0288f17 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/DsfTestPlugin.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class DsfTestPlugin extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.dd.tests.dsf"; //$NON-NLS-1$ + + // The shared instance + private static DsfTestPlugin fgPlugin; + private static BundleContext fgBundleContext; + + /** + * The constructor + */ + public DsfTestPlugin() { + fgPlugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + fgBundleContext = context; + super.start(context); + } + + /* + * (non-Javadoc) + * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + super.stop(context); + fgBundleContext = null; + fgPlugin = null; + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static DsfTestPlugin getDefault() { + return fgPlugin; + } + + public static BundleContext getBundleContext() { + return fgBundleContext; + } + +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/TestDsfExecutor.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/TestDsfExecutor.java new file mode 100644 index 00000000000..37fe241a8bb --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/TestDsfExecutor.java @@ -0,0 +1,50 @@ +package org.eclipse.dd.tests.dsf; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor; + +/** + * DsfExecutor for use with unit tests. It records the exceptions that were + * thrown in the executor thread so that they can be re-thrown by the test. + * + */ +public class TestDsfExecutor extends DefaultDsfExecutor { + private List fExceptions = Collections.synchronizedList(new ArrayList()); + + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + if (r instanceof Future) { + Future future = (Future)r; + try { + if (future.isDone()) { + future.get(); + } + future.get(); + } catch (InterruptedException e) { // Ignore + } catch (CancellationException e) { // Ignore also + } catch (ExecutionException e) { + if (e.getCause() != null) { + fExceptions.add(e.getCause()); + } + } + } + } + + public boolean exceptionsCaught() { + return fExceptions.size() != 0; + } + + public Throwable[] getExceptions() { + synchronized (fExceptions) { + return fExceptions.toArray(new Throwable[fExceptions.size()]); + } + } + +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/ValueHolder.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/ValueHolder.java new file mode 100644 index 00000000000..c3b087dcc12 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/ValueHolder.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf; + +/** + * Utility class to hold a value retrieved in a runnable. + * Usage in a test is as follows: + *
+ *     final ValueHolder value = new ValueHolder();
+ *     fExecutor.execute(new Runnable() {
+ *         public void run() {
+ *             value.fValue = 1;
+ *         }
+ *     }); 
+ *     Assert.assertTrue(value.fValue == 1);
+ * 
+ */ +public class ValueHolder { + public V fValue; +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/concurrent/DsfQueryTests.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/concurrent/DsfQueryTests.java new file mode 100644 index 00000000000..e4015eba8ae --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/concurrent/DsfQueryTests.java @@ -0,0 +1,216 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf.concurrent; + +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import junit.framework.Assert; + +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.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.tests.dsf.DsfTestPlugin; +import org.eclipse.dd.tests.dsf.TestDsfExecutor; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests that excercise the Query object. + */ +public class DsfQueryTests { + TestDsfExecutor fExecutor; + + @Before + public void startServices() throws ExecutionException, InterruptedException { + fExecutor = new TestDsfExecutor(); + } + + @After + public void shutdownServices() throws ExecutionException, InterruptedException { + fExecutor.submit(new DsfRunnable() { public void run() { + fExecutor.shutdown(); + }}).get(); + if (fExecutor.exceptionsCaught()) { + Throwable[] exceptions = fExecutor.getExceptions(); + throw new ExecutionException(exceptions[0]); + } + fExecutor = null; + } + + @Test + public void simpleGetTest() throws InterruptedException, ExecutionException { + Query q = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + rm.setData(1); + rm.done(); + } + }; + // Check initial state + Assert.assertTrue(!q.isDone()); + Assert.assertTrue(!q.isCancelled()); + + fExecutor.execute(q); + Assert.assertEquals(1, (int)q.get()); + + // Check final state + Assert.assertTrue(q.isDone()); + Assert.assertTrue(!q.isCancelled()); + + } + + @Test + public void getWithMultipleDispatchesTest() throws InterruptedException, ExecutionException { + Query q = new Query() { + @Override + protected void execute(final DataRequestMonitor rm) { + fExecutor.execute(new DsfRunnable() { + public void run() { + rm.setData(1); + rm.done(); + } + @Override + public String toString() { return super.toString() + "\n getWithMultipleDispatchesTest() second runnable"; } //$NON-NLS-1$ + }); + } + @Override + public String toString() { return super.toString() + "\n getWithMultipleDispatchesTest() first runnable (query)"; } //$NON-NLS-1$ + }; + fExecutor.execute(q); + Assert.assertEquals(1, (int)q.get()); + } + + @Test (expected = ExecutionException.class) + public void exceptionOnGetTest() throws InterruptedException, ExecutionException { + Query q = new Query() { + @Override + protected void execute(final DataRequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, -1, "", null)); //$NON-NLS-1$ + rm.done(); + } + }; + + fExecutor.execute(q); + + try { + q.get(); + } finally { + Assert.assertTrue(q.isDone()); + Assert.assertTrue(!q.isCancelled()); + } + } + + @Test + public void cancelWhileWaitingTest() throws InterruptedException, ExecutionException { + final Query q = new Query() { + @Override + protected void execute(final DataRequestMonitor rm) { + // Call done with a delay of 1 second, to avoid stalling the tests. + fExecutor.schedule( + new DsfRunnable() { + public void run() { rm.done(); } + }, + 1, TimeUnit.SECONDS); + } + }; + + fExecutor.execute(q); + + // Note: no point in checking isDone() and isCancelled() here, because + // the value could change on timing. + + // This does not really guarantee that the cancel will be called after + // the call to Fugure.get(), but the 1ms delay in call to schedule should + // help. + new Job("DsfQueryTests cancel job") { @Override public IStatus run(IProgressMonitor monitor) { //$NON-NLS-1$ + q.cancel(false); + return Status.OK_STATUS; + }}.schedule(1); + + try { + q.get(); + } catch (CancellationException e) { + return; // Success + } finally { + Assert.assertTrue(q.isDone()); + Assert.assertTrue(q.isCancelled()); + } + Assert.assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$ + } + + @Test + public void cancelBeforeWaitingTest() throws InterruptedException, ExecutionException { + final Query q = new Query() { + @Override protected void execute(final DataRequestMonitor rm) { + Assert.fail("Query was cancelled, it should not be called."); //$NON-NLS-1$ + rm.done(); + } + }; + + // Cancel before invoking the query. + q.cancel(false); + + Assert.assertTrue(q.isDone()); + Assert.assertTrue(q.isCancelled()); + + // Start the query. + fExecutor.execute(q); + + // Block to retrieve data + try { + q.get(); + } catch (CancellationException e) { + return; // Success + } finally { + Assert.assertTrue(q.isDone()); + Assert.assertTrue(q.isCancelled()); + } + Assert.assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$ + } + + @Test + public void getTimeoutTest() throws InterruptedException, ExecutionException { + final Query q = new Query() { + @Override + protected void execute(final DataRequestMonitor rm) { + // Call done with a delay of 1 second, to avoid stalling the tests. + fExecutor.schedule( + new DsfRunnable() { + public void run() { rm.done(); } + }, + 1, TimeUnit.SECONDS); + } + }; + + fExecutor.execute(q); + + // Note: no point in checking isDone() and isCancelled() here, because + // the value could change on timing. + + try { + q.get(1, TimeUnit.MILLISECONDS); + } catch (TimeoutException e) { + return; // Success + } finally { + Assert.assertFalse("Query should not be done yet, it should have timed out first.", q.isDone()); //$NON-NLS-1$ + } + Assert.assertTrue("TimeoutException should have been thrown", false); //$NON-NLS-1$ + } + +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/concurrent/DsfSequenceTests.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/concurrent/DsfSequenceTests.java new file mode 100644 index 00000000000..0f1985acd73 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/concurrent/DsfSequenceTests.java @@ -0,0 +1,315 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf.concurrent; + +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import junit.framework.Assert; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.Sequence; +import org.eclipse.dd.tests.dsf.DsfTestPlugin; +import org.eclipse.dd.tests.dsf.TestDsfExecutor; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests that excercise the Sequence object. + */ +public class DsfSequenceTests { + TestDsfExecutor fExecutor; + + @Before + public void startExecutor() throws ExecutionException, InterruptedException { + fExecutor = new TestDsfExecutor(); + } + + @After + public void shutdownExecutor() throws ExecutionException, InterruptedException { + fExecutor.submit(new DsfRunnable() { public void run() { + fExecutor.shutdown(); + }}).get(); + if (fExecutor.exceptionsCaught()) { + Throwable[] exceptions = fExecutor.getExceptions(); + throw new ExecutionException(exceptions[0]); + } + fExecutor = null; + } + + @Test + public void simpleTest() throws InterruptedException, ExecutionException { + // Create a counter for tracking number of steps performed. + class IntegerHolder { int fInteger; } + final IntegerHolder stepCounter = new IntegerHolder(); + + // Create the steps of the sequence + final Sequence.Step[] steps = new Sequence.Step[] { + new Sequence.Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + stepCounter.fInteger++; + requestMonitor.done(); + } + }, + new Sequence.Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + stepCounter.fInteger++; + requestMonitor.done(); + } + } + }; + + // Create, start, and wait for the sequence. + Sequence sequence = new Sequence(fExecutor) { + @Override public Step[] getSteps() { return steps; } + }; + Assert.assertTrue(!sequence.isDone()); + Assert.assertTrue(!sequence.isCancelled()); + + fExecutor.execute(sequence); + sequence.get(); + + // Check the count + Assert.assertTrue(stepCounter.fInteger == 2); + + // Check post conditions + Assert.assertTrue(sequence.isDone()); + Assert.assertTrue(!sequence.isCancelled()); + } + + @Test (expected = ExecutionException.class) + public void rollbackTest() throws InterruptedException, ExecutionException { + // Create a counter for tracking number of steps performed and steps + // rolled back. + class IntegerHolder { int fInteger; } + final IntegerHolder stepCounter = new IntegerHolder(); + final IntegerHolder rollBackCounter = new IntegerHolder(); + + // Create the steps of the sequence + final Sequence.Step[] steps = new Sequence.Step[] { + new Sequence.Step() { + @Override public void execute(RequestMonitor requestMonitor) { + stepCounter.fInteger++; + requestMonitor.done(); + } + @Override public void rollBack(RequestMonitor requestMonitor) { + rollBackCounter.fInteger++; + requestMonitor.done(); + } + }, + new Sequence.Step() { + @Override public void execute(RequestMonitor requestMonitor) { + stepCounter.fInteger++; + requestMonitor.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, -1, "", null)); //$NON-NLS-1$ + requestMonitor.done(); + } + @Override public void rollBack(RequestMonitor requestMonitor) { + rollBackCounter.fInteger++; + requestMonitor.done(); + } + } + }; + + // Create and start. + Sequence sequence = new Sequence(fExecutor) { + @Override public Step[] getSteps() { return steps; } + }; + fExecutor.execute(sequence); + + // Block and wait for sequence to bomplete. + try { + sequence.get(); + } finally { + // Both steps should be performed + Assert.assertTrue(stepCounter.fInteger == 2); + // Only one step is rolled back, the first one. + Assert.assertTrue(rollBackCounter.fInteger == 1); + + // Check state from Future interface + Assert.assertTrue(sequence.isDone()); + Assert.assertTrue(!sequence.isCancelled()); + } + Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$ + } + + /** + * The goal of this test it to check that if an exception is thrown within + * the Step.execute(), the step will return from the Future.get() method. + */ + @Test (expected = ExecutionException.class) + public void exceptionTest() throws InterruptedException, ExecutionException { + final Sequence.Step[] steps = new Sequence.Step[] { + new Sequence.Step() { + @Override public void execute(RequestMonitor requestMonitor) { + throw new Error("Exception part of unit test."); //$NON-NLS-1$ + } + } + }; + + // Create and start. + Sequence sequence = new Sequence(fExecutor) { + @Override public Step[] getSteps() { return steps; } + }; + fExecutor.execute(sequence); + + // Block and wait for sequence to bomplete. + try { + sequence.get(); + } finally { + // Check state from Future interface + Assert.assertTrue(sequence.isDone()); + Assert.assertTrue(!sequence.isCancelled()); + } + Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$ + } + + + @Test (expected = CancellationException.class) + public void cancelBeforeWaitingTest() throws InterruptedException, ExecutionException { + // Create the sequence + final Sequence.Step[] steps = new Sequence.Step[] { + new Sequence.Step() { + @Override public void execute(RequestMonitor requestMonitor) { + Assert.assertTrue("Sequence was cancelled, it should not be called.", false); //$NON-NLS-1$ + } + } + }; + Sequence sequence = new Sequence(fExecutor) { + @Override public Step[] getSteps() { return steps; } + }; + + // Cancel before invoking the sequence. + sequence.cancel(false); + + Assert.assertTrue(!sequence.isDone()); + Assert.assertTrue(sequence.isCancelled()); + + // Start the sequence + fExecutor.execute(sequence); + + // Block and wait for sequence to bomplete. + try { + sequence.get(); + } finally { + Assert.assertTrue(sequence.isDone()); + Assert.assertTrue(sequence.isCancelled()); + } + Assert.assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$ + } + + + @Test (expected = CancellationException.class) + public void cancelFromStepTest() throws InterruptedException, ExecutionException { + // Create a counter for tracking number of steps performed and steps + // rolled back. + class IntegerHolder { int fInteger; } + final IntegerHolder stepCounter = new IntegerHolder(); + final IntegerHolder rollBackCounter = new IntegerHolder(); + + // Create the steps of the sequence + final Sequence.Step[] steps = new Sequence.Step[] { + new Sequence.Step() { + @Override public void execute(RequestMonitor requestMonitor) { + stepCounter.fInteger++; + requestMonitor.done(); + } + @Override public void rollBack(RequestMonitor requestMonitor) { + rollBackCounter.fInteger++; + requestMonitor.done(); + } + }, + new Sequence.Step() { + @Override public void execute(RequestMonitor requestMonitor) { + stepCounter.fInteger++; + + // Perform the cancel! + getSequence().cancel(false); + + requestMonitor.done(); + } + @Override public void rollBack(RequestMonitor requestMonitor) { + rollBackCounter.fInteger++; + requestMonitor.done(); + } + } + }; + + // Create and start sequence with a delay. Delay so that we call get() before + // cancel is called. + final Sequence sequence = new Sequence(fExecutor) { + @Override public Step[] getSteps() { return steps; } + }; + fExecutor.schedule(sequence, 1, TimeUnit.MILLISECONDS); + + // Block to retrieve data + try { + sequence.get(); + } finally { + // Both steps should be performed + Assert.assertTrue(stepCounter.fInteger == 2); + // Both roll-backs should be performed since cancel does not take effect until + // after the step is completed. + Assert.assertTrue(rollBackCounter.fInteger == 2); + + Assert.assertTrue(sequence.isDone()); + Assert.assertTrue(sequence.isCancelled()); + } + Assert.assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$ + } + + @Test (expected = CancellationException.class) + public void cancelBeforeWithProgressManagerTest() throws InterruptedException, ExecutionException { + // Create the sequence + final Sequence.Step[] steps = new Sequence.Step[] { + new Sequence.Step() { + @Override public void execute(RequestMonitor requestMonitor) { + Assert.assertTrue("Sequence was cancelled, it should not be called.", false); //$NON-NLS-1$ + } + } + }; + + // Create the progress monitor that we will cancel. + IProgressMonitor pm = new NullProgressMonitor(); + + // Create the seqeunce with our steps. + Sequence sequence = new Sequence(fExecutor, pm, "", "", null) { //$NON-NLS-1$ //$NON-NLS-2$ + @Override public Step[] getSteps() { return steps; } + }; + + // Cancel the progress monitor before invoking the sequence. Note + // that the state of the sequence doesn't change yet, because the + // sequence does not check the progress monitor until it is executed. + pm.setCanceled(true); + + // Start the sequence + fExecutor.execute(sequence); + + // Block and wait for sequence to bomplete. Exception is thrown, + // which is expected. + try { + sequence.get(); + } finally { + Assert.assertTrue(sequence.isDone()); + Assert.assertTrue(sequence.isCancelled()); + } + } + + +} \ No newline at end of file diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/AbstractService.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/AbstractService.java new file mode 100644 index 00000000000..94a5fdc9de2 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/AbstractService.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf.events; + +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.tests.dsf.DsfTestPlugin; +import org.osgi.framework.BundleContext; + +/** + * Test service class used to test event behavior. It has three types of events + * and three methods to receive the events. + * + */ +abstract public class AbstractService extends AbstractDsfService +{ + AbstractService(DsfSession session) { + super(session); + } + + @Override protected BundleContext getBundleContext() { + return DsfTestPlugin.getBundleContext(); + } + + @Override public void initialize(final RequestMonitor requestMonitor) { + super.initialize( + new RequestMonitor(getExecutor(), requestMonitor) { + @Override + public void handleOK() { + doInitialize(requestMonitor); + } + }); + } + + private void doInitialize(RequestMonitor requestMonitor) { + getSession().addServiceEventListener(this, null); + requestMonitor.done(); + } + + @Override public void shutdown(RequestMonitor requestMonitor) { + getSession().removeServiceEventListener(this); + super.shutdown(requestMonitor); + } + + /////////////////////////////////////////////////////////////////////////// + // Test API + /** Records the number in the event 1 object when this service received the event. */ + int fEvent1RecipientNumber; + + /** Records the number in the event 2 object when this service received the event. */ + int fEvent2RecipientNumber; + + /** Records the number in the event 3 object when this service received the event. */ + int fEvent3RecipientNumber; + + /** Simple event class 1 */ + public class Event1 { + // 1-based counter for the recipient of the event. + int fRecipientNumberCounter = 1; + } + + /** Simple event class 2. Note it doesn't have any relation to event 1 */ + public class Event2 { + int fRecipientNumberCounter = 1; + } + + /** Simple event class 3. Note it does sub-class event 1 */ + public class Event3 extends Event1 {} + + @ThreadSafe + public void dispatchEvent1() { + getSession().dispatchEvent(new Event1(), getProperties()); + } + + @ThreadSafe + public void dispatchEvent2() { + getSession().dispatchEvent(new Event2(), getProperties()); + } + + @ThreadSafe + public void dispatchEvent3() { + getSession().dispatchEvent(new Event3(), getProperties()); + } + + /** Handles event 1 (and event 3 which derives from event 1) */ + @DsfServiceEventHandler public void eventDispatched(Event1 e) { + fEvent1RecipientNumber = e.fRecipientNumberCounter++; + } + + /** Handles event 2 only */ + @DsfServiceEventHandler public void eventDispatched(Event2 e) { + fEvent2RecipientNumber = e.fRecipientNumberCounter++; + } + + /** Handles event 3 only */ + @DsfServiceEventHandler public void eventDispatched(Event3 e) { + fEvent3RecipientNumber = e.fRecipientNumberCounter++; + } +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Event1.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Event1.java new file mode 100644 index 00000000000..def8159ea60 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Event1.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf.events; + + +public class Event1 { + +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Event2.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Event2.java new file mode 100644 index 00000000000..cc7bdbe70df --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Event2.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf.events; + +public class Event2 extends Event1 { + +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/EventTest.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/EventTest.java new file mode 100644 index 00000000000..102be68b751 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/EventTest.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf.events; + +import java.util.concurrent.ExecutionException; + +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.tests.dsf.DsfTestPlugin; +import org.eclipse.dd.tests.dsf.TestDsfExecutor; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class EventTest { + + DsfSession fSession; + TestDsfExecutor fExecutor; + DsfServicesTracker fTracker; + Service1 fService1; + Service2 fService2; + Service3 fService3; + + @Before public void startServices() throws ExecutionException, InterruptedException { + fExecutor = new TestDsfExecutor(); + + fExecutor.submit(new DsfRunnable() { public void run() { + fSession = DsfSession.startSession(fExecutor, "org.eclipse.dd.dsf.tests"); //$NON-NLS-1$ + }}).get(); + + StartupSequence startupSeq = new StartupSequence(fSession); + fExecutor.execute(startupSeq); + startupSeq.get(); + + fExecutor.submit(new DsfRunnable() { public void run() { + fTracker = new DsfServicesTracker(DsfTestPlugin.getBundleContext(), fSession.getId()); + fService1 = fTracker.getService(Service1.class); + fService2 = fTracker.getService(Service2.class); + fService3 = fTracker.getService(Service3.class); + }}).get(); + Assert.assertNotNull(fService1); + Assert.assertNotNull(fService2); + Assert.assertNotNull(fService3); + } + + @After public void shutdownServices() throws ExecutionException, InterruptedException { + ShutdownSequence shutdownSeq = new ShutdownSequence(fSession); + fExecutor.execute(shutdownSeq); + shutdownSeq.get(); + + fExecutor.submit(new DsfRunnable() { public void run() { + fService1 = null; + fService2 = null; + fService3 = null; + fTracker.dispose(); + fTracker = null; + DsfSession.endSession(fSession); + fSession = null; + fExecutor.shutdown(); + }}).get(); + + if (fExecutor.exceptionsCaught()) { + Throwable[] exceptions = fExecutor.getExceptions(); + throw new ExecutionException(exceptions[0]); + } + fExecutor = null; + } + + /** + * Test only the startup and shutdown sequences. + */ + @Test public void startStopTest() { + } + + /** + * Tests dispatching event 1. The goal of the test is to make sure that + * recipients are called in the correct order. + */ + @Test public void event1Test() throws ExecutionException, InterruptedException { + fService1.dispatchEvent1(); + fExecutor.submit(new DsfRunnable() { public void run() { + Assert.assertTrue(1 == fService1.fEvent1RecipientNumber); + Assert.assertTrue(2 == fService2.fEvent1RecipientNumber); + Assert.assertTrue(3 == fService3.fEvent1RecipientNumber); + Assert.assertTrue(0 == fService1.fEvent2RecipientNumber); + Assert.assertTrue(0 == fService2.fEvent2RecipientNumber); + Assert.assertTrue(0 == fService3.fEvent2RecipientNumber); + Assert.assertTrue(0 == fService1.fEvent3RecipientNumber); + Assert.assertTrue(0 == fService2.fEvent3RecipientNumber); + Assert.assertTrue(0 == fService3.fEvent3RecipientNumber); + }}).get(); + } + + /** + * Tests dispatching event 2. The goal of the test is to make sure that + * recipients are called in the correct order, and that the other events + * are not registered. + */ + @Test public void event2Test() throws ExecutionException, InterruptedException { + fService1.dispatchEvent2(); + fExecutor.submit(new DsfRunnable() { public void run() { + Assert.assertTrue(0 == fService1.fEvent1RecipientNumber); + Assert.assertTrue(0 == fService2.fEvent1RecipientNumber); + Assert.assertTrue(0 == fService3.fEvent1RecipientNumber); + Assert.assertTrue(1 == fService1.fEvent2RecipientNumber); + Assert.assertTrue(2 == fService2.fEvent2RecipientNumber); + Assert.assertTrue(3 == fService3.fEvent2RecipientNumber); + Assert.assertTrue(0 == fService1.fEvent3RecipientNumber); + Assert.assertTrue(0 == fService2.fEvent3RecipientNumber); + Assert.assertTrue(0 == fService3.fEvent3RecipientNumber); + }}).get(); + } + + /** + * Tests dispatching event 2. The goal of the test is to make sure that + * both event 2 and even 3 recipients are called for this event. + *
+ * Note: When a single listener object has more than one method that that + * matches the event, both methods will be called. But there is currently + * no guaranteed order in which they should be called. + */ + @Test public void event3Test() throws ExecutionException, InterruptedException { + fService1.dispatchEvent3(); + fExecutor.submit(new DsfRunnable() { public void run() { + Assert.assertTrue(1 == fService1.fEvent1RecipientNumber || 2 == fService1.fEvent1RecipientNumber); + Assert.assertTrue(3 == fService2.fEvent1RecipientNumber || 4 == fService2.fEvent1RecipientNumber); + Assert.assertTrue(5 == fService3.fEvent1RecipientNumber || 6 == fService3.fEvent1RecipientNumber); + Assert.assertTrue(0 == fService1.fEvent2RecipientNumber); + Assert.assertTrue(0 == fService2.fEvent2RecipientNumber); + Assert.assertTrue(0 == fService3.fEvent2RecipientNumber); + Assert.assertTrue(1 == fService1.fEvent3RecipientNumber || 2 == fService1.fEvent3RecipientNumber); + Assert.assertTrue(3 == fService2.fEvent3RecipientNumber || 4 == fService2.fEvent3RecipientNumber); + Assert.assertTrue(5 == fService3.fEvent3RecipientNumber || 6 == fService3.fEvent3RecipientNumber); + }}).get(); + } + +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Service1.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Service1.java new file mode 100644 index 00000000000..34e3cd72bb2 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Service1.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf.events; + +import java.util.Hashtable; + +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.service.DsfSession; + +public class Service1 extends AbstractService { + Service1(DsfSession session) { + super(session); + } + + @Override public void initialize(final RequestMonitor requestMonitor) { + super.initialize( + new RequestMonitor(getExecutor(), requestMonitor) { + @Override + public void handleOK() { + doInitialize(requestMonitor); + } + }); + } + + private void doInitialize(RequestMonitor requestMonitor) { + register(new String[]{Service1.class.getName()}, new Hashtable()); + requestMonitor.done(); + } + + @Override public void shutdown(RequestMonitor requestMonitor) { + unregister(); + super.shutdown(requestMonitor); + } +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Service2.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Service2.java new file mode 100644 index 00000000000..a466c03e295 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Service2.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf.events; + +import java.util.Hashtable; + +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.service.DsfSession; + +public class Service2 extends AbstractService { + Service2(DsfSession session) { + super(session); + } + + @Override public void initialize(final RequestMonitor requestMonitor) { + super.initialize( + new RequestMonitor(getExecutor(), requestMonitor) { + @Override + public void handleOK() { + doInitialize(requestMonitor); + } + }); + } + + private void doInitialize(RequestMonitor requestMonitor) { + getServicesTracker().getService(Service1.class); + register(new String[]{Service2.class.getName()}, new Hashtable()); + requestMonitor.done(); + } + + @Override public void shutdown(RequestMonitor requestMonitor) { + unregister(); + super.shutdown(requestMonitor); + } +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Service3.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Service3.java new file mode 100644 index 00000000000..5069157e8d0 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Service3.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf.events; + +import java.util.Hashtable; + +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.tests.dsf.DsfTestPlugin; +import org.osgi.framework.BundleContext; + +public class Service3 extends AbstractService { + Service3(DsfSession session) { + super(session); + } + + @Override protected BundleContext getBundleContext() { + return DsfTestPlugin.getBundleContext(); + } + + @Override public void initialize(final RequestMonitor requestMonitor) { + super.initialize( + new RequestMonitor(getExecutor(), requestMonitor) { + @Override + public void handleOK() { + doInitialize(requestMonitor); + } + }); + } + + private void doInitialize(RequestMonitor requestMonitor) { + getServicesTracker().getService(Service1.class); + getServicesTracker().getService(Service2.class); + register(new String[]{Service3.class.getName()}, new Hashtable()); + requestMonitor.done(); + } + + @Override public void shutdown(RequestMonitor requestMonitor) { + unregister(); + super.shutdown(requestMonitor); + } +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/ShutdownSequence.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/ShutdownSequence.java new file mode 100644 index 00000000000..84112677e85 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/ShutdownSequence.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf.events; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.Sequence; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.tests.dsf.DsfTestPlugin; + +class ShutdownSequence extends Sequence { + + DsfSession fSession; + DsfServicesTracker fTracker; + + ShutdownSequence(DsfSession session) { + super(session.getExecutor()); + fSession = session; + } + + @Override + public Step[] getSteps() { return fSteps; } + + final Step[] fSteps = new Step[] { + new Step() { + @Override public void execute(RequestMonitor requestMonitor) { + fTracker = new DsfServicesTracker(DsfTestPlugin.getBundleContext(), fSession.getId()); + requestMonitor.done(); + } + + @Override public void rollBack(RequestMonitor requestMonitor) { + fTracker.dispose(); + fTracker = null; + requestMonitor.done(); + } + }, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { + shutdownService(Service3.class, requestMonitor); + }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { + shutdownService(Service2.class, requestMonitor); + }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { + shutdownService(Service1.class, requestMonitor); + }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { + fTracker.dispose(); + fTracker = null; + requestMonitor.done(); + }} + }; + + private void shutdownService(Class clazz, RequestMonitor requestMonitor) { + IDsfService service = fTracker.getService(clazz); + if (service != null) { + service.shutdown(requestMonitor); + } + else { + requestMonitor.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, -1, "Service '" + clazz.getName() + "' not found.", null)); //$NON-NLS-1$//$NON-NLS-2$ + requestMonitor.done(); + } + } + +} diff --git a/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/StartupSequence.java b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/StartupSequence.java new file mode 100644 index 00000000000..85d3c5dbef3 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/StartupSequence.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.dsf.events; + +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.Sequence; +import org.eclipse.dd.dsf.service.DsfSession; + +class StartupSequence extends Sequence { + DsfSession fSession; + + StartupSequence(DsfSession session) { + super(session.getExecutor()); + fSession = session; + } + + @Override + public Step[] getSteps() { return fSteps; } + + final Step[] fSteps = new Step[] { + new Step() { @Override public void execute(RequestMonitor requestMonitor) { + new Service1(fSession).initialize(requestMonitor); + }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { + new Service2(fSession).initialize(requestMonitor); + }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { + new Service3(fSession).initialize(requestMonitor); + }} + }; +} diff --git a/plugins/org.eclipse.dd.tests.gdb/.classpath b/plugins/org.eclipse.dd.tests.gdb/.classpath new file mode 100644 index 00000000000..304e86186aa --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/plugins/org.eclipse.dd.tests.gdb/.externalToolBuilders/TestAppBuilder.launch b/plugins/org.eclipse.dd.tests.gdb/.externalToolBuilders/TestAppBuilder.launch new file mode 100644 index 00000000000..5c664b7c490 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/.externalToolBuilders/TestAppBuilder.launch @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/org.eclipse.dd.tests.gdb/.project b/plugins/org.eclipse.dd.tests.gdb/.project new file mode 100644 index 00000000000..7eaa1391123 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/.project @@ -0,0 +1,38 @@ + + + org.eclipse.dd.tests.gdb + + + + + + org.eclipse.ui.externaltools.ExternalToolBuilder + clean,full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/TestAppBuilder.launch + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/plugins/org.eclipse.dd.tests.gdb/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.dd.tests.gdb/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..e598bffe12f --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,65 @@ +#Thu Jun 07 11:08:01 PDT 2007 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=ignore +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/plugins/org.eclipse.dd.tests.gdb/META-INF/MANIFEST.MF b/plugins/org.eclipse.dd.tests.gdb/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..326dfb185e7 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/META-INF/MANIFEST.MF @@ -0,0 +1,23 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: GDB/MI reference application tests +Bundle-SymbolicName: org.eclipse.dd.tests.gdb;singleton:=true +Bundle-Version: 1.0.0 +Bundle-Activator: org.eclipse.dd.tests.gdb.launching.TestsPlugin +Bundle-Vendor: Ericsson +Bundle-Localization: plugin +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.dd.dsf, + org.eclipse.dd.dsf.debug, + org.eclipse.cdt.core, + org.eclipse.cdt.launch, + org.eclipse.cdt.debug.core, + org.eclipse.dd.mi, + org.junit4, + org.eclipse.debug.core, + org.eclipse.cdt.debug.mi.core, + org.eclipse.swt, + org.eclipse.dd.gdb +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-ClassPath: . diff --git a/plugins/org.eclipse.dd.tests.gdb/TestAppBuilder.xml b/plugins/org.eclipse.dd.tests.gdb/TestAppBuilder.xml new file mode 100644 index 00000000000..3f8e9f07fed --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/TestAppBuilder.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/plugins/org.eclipse.dd.tests.gdb/build.properties b/plugins/org.eclipse.dd.tests.gdb/build.properties new file mode 100644 index 00000000000..aba8ab478f4 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/build.properties @@ -0,0 +1,5 @@ +output.tests.jar = bin/ +bin.includes = plugin.xml,\ + META-INF/,\ + . +source.. = src/ diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/BreakpointTestApp.exe b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/BreakpointTestApp.exe new file mode 100755 index 00000000000..6eb8b78a5b9 Binary files /dev/null and b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/BreakpointTestApp.exe differ diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/ExpressionTestApp.exe b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/ExpressionTestApp.exe new file mode 100755 index 00000000000..9051861f97e Binary files /dev/null and b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/ExpressionTestApp.exe differ diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/GDBMIGenericTestApp.exe b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/GDBMIGenericTestApp.exe new file mode 100755 index 00000000000..6f604184d78 Binary files /dev/null and b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/GDBMIGenericTestApp.exe differ diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MemoryTestApp.exe b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MemoryTestApp.exe new file mode 100755 index 00000000000..390d47e29a8 Binary files /dev/null and b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MemoryTestApp.exe differ diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MultiThread.exe b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MultiThread.exe new file mode 100755 index 00000000000..e89bc956e7f Binary files /dev/null and b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MultiThread.exe differ diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/SpecialTestApp.exe b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/SpecialTestApp.exe new file mode 100755 index 00000000000..cbe79e76c9b Binary files /dev/null and b/plugins/org.eclipse.dd.tests.gdb/data/launch/bin/SpecialTestApp.exe differ diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/src/BreakpointTestApp.cc b/plugins/org.eclipse.dd.tests.gdb/data/launch/src/BreakpointTestApp.cc new file mode 100644 index 00000000000..5474e540718 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/data/launch/src/BreakpointTestApp.cc @@ -0,0 +1,47 @@ +//============================================================================ +// Name : BreakpointTestApp.cpp +// Author : Francois Chouinard +// Version : 1.0 +// Copyright : Ericsson AB +// Description : Breakpoint test application +//============================================================================ + +#include +using namespace std; + +const int ARRAY_SIZE = 256; + +char charBlock[ARRAY_SIZE]; +int integerBlock[ARRAY_SIZE]; + +void zeroBlocks(int abc) +{ + for (int i = 0; i < ARRAY_SIZE; i++) { + charBlock[i] = '\0'; + integerBlock[i] = 0; + } +} + +void setBlocks() +{ + for (int i = 0; i < ARRAY_SIZE; i++) { + charBlock[i] = (char) i; + integerBlock[i] = i; + } +} + +void loop() +{ + int j; + + for (int i = 0; i < ARRAY_SIZE; i++) + j = i; +} + +int main() +{ + zeroBlocks(1); + loop(); + setBlocks(); + return 0; +} diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/src/ExpressionTestApp.cc b/plugins/org.eclipse.dd.tests.gdb/data/launch/src/ExpressionTestApp.cc new file mode 100644 index 00000000000..269b5bcf2d7 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/data/launch/src/ExpressionTestApp.cc @@ -0,0 +1,298 @@ +#include + +int gIntVar = 543; +double gDoubleVar = 543.543; +char gCharVar = 'g'; +bool gBoolVar = false; + +int gIntArray[2] = {987, 654}; +double gDoubleArray[2] = {987.654, 654.321}; +char gCharArray[2] = {'g', 'd'}; +bool gBoolArray[2] = {true, false}; + +int *gIntPtr = &gIntVar; +double *gDoublePtr = &gDoubleVar; +char *gCharPtr = &gCharVar; +bool *gBoolPtr = &gBoolVar; + +int *gIntPtr2 = (int*)0x8; +double *gDoublePtr2 = (double*)0x5432; +char *gCharPtr2 = (char*)0x4321; +bool *gBoolPtr2 = (bool*)0x12ABCDEF; + +class bar { +public: + int d; +private: + int e[2]; +}; + +class bar2 { +public: + int f; +private: + int g[2]; +}; + +class foo: public bar, bar2 { +public: + int a[2]; + bar b; +private: + int c; +}; + +struct Z { +public: + int x; + int y; +}; +struct childStruct { +public: + Z z; +}; +void locals2() { + // Check that we get the content of local variables with + // the same name as the calling method + int lIntVar = 6789; + double lDoubleArray[2] = {123.456, 6789.6789}; + char lCharVar = 'i'; + char *lCharPtr = &lCharVar; + bool *lBoolPtr2 = (bool*)0xABCDE123; + + return; +} + +void testLocals() { + + int lIntVar = 12345; + double lDoubleVar = 12345.12345; + char lCharVar = 'm'; + bool lBoolVar = false; + + int lIntArray[2] = {6789, 12345}; + double lDoubleArray[2] = {456.789, 12345.12345}; + char lCharArray[2] = {'i', 'm'}; + bool lBoolArray[2] = {true, false}; + + int *lIntPtr = &lIntVar; + double *lDoublePtr = &lDoubleVar; + char *lCharPtr = &lCharVar; + bool *lBoolPtr = &gBoolVar; + + int *lIntPtr2 = (int*)0x1; + double *lDoublePtr2 = (double*)0x2345; + char *lCharPtr2 = (char*)0x1234; + bool *lBoolPtr2 = (bool*)0x123ABCDE; + + locals2(); + + return; +} + +int testChildren() { + foo f; + + f.d = 1; + + return 0; +} + +int testWrite() { + int a[2] = {3, 456}; + + return 0; +} + +int testName1(int newVal) { + int a = newVal; + return a; +} + +int testName2(int newVal) { + int a = newVal; + return a; +} + +int testSameName1(int newVal) { + int a = newVal; + Z z; + z.x = newVal; + return a; +} +int testSameName1(int newVal, int ignore) { + int a = newVal; + Z z; + z.x = newVal; + return a; +} + + +int testSameName() { + testSameName1(1); + testSameName1(2, 0); + testSameName1(3); + + return 0; +} + +int testConcurrent() { + int a[2] = {28, 32}; + return a[0]; +} + +int testSubblock() { + int a = 8; + int b = 1; + if (a) { + int a = 12; + b = a; + } + return b; +} + +int testAddress() { + int a = 8; + int* a_ptr = &a; + + return a; +} + + + +int testUpdateChildren(int val) { + childStruct a; + a.z.x = val + 10; + a.z.y = val + 11; + + a.z.x = val + 20; + a.z.y = val + 21; + + return a.z.x; +} +int testUpdateChildren2(int val) { + childStruct a; + a.z.x = val + 10; + a.z.y = val + 11; + + a.z.x = val + 20; + a.z.y = val + 21; + + return a.z.x; +} + +int testDeleteChildren() { + foo f; + int a[1111]; + + return 1; +} + +int testUpdateGDBBug() { + // GDB 6.7 has a bug which will cause var-update not to show + // the new value of 'a' if we switch the format to binary, + // since binary of 3 is 11 which is the same as the old value + // in natural format + int a = 11; + a = 3; + return 0; +} + +int testUpdateIssue() { + double a = 1.99; + a = 1.22; +} + +int testUpdateIssue2() { + struct { + double d; + } z; + + z.d = 1.0; + z.d = 1.22; +} + +int testConcurrentReadAndUpdateChild() { + struct { + int d; + }z; + + z.d = 1; + z.d = 2; +} + +int testConcurrentUpdateOutOfScopeChildThenParent1() { + struct { + int d; + }z; + + z.d = 1; +} + +int testConcurrentUpdateOutOfScopeChildThenParent2() { + struct { + int d; + }z; + + z.d = 2; +} + +int testConcurrentUpdateOutOfScopeChildThenParent() { + testConcurrentUpdateOutOfScopeChildThenParent1(); + testConcurrentUpdateOutOfScopeChildThenParent2(); +} + +int testUpdateOfPointer() { + struct { + int a; + int* b; + }z; + + int c = 3; + + z.b = &(z.a); + z.a = 1; + + z.b = &c; + z.a = 2; +} + +int testCanWrite() { + int a; + int* b; + struct { + int in; + } c; + int d[2]; + + return 1; +} + +int main() { + printf("Running ExpressionTest App\n"); + + testLocals(); + testChildren(); + testWrite(); + testName1(1); + testName2(2); + testName1(3); + testSameName(); + testConcurrent(); + testSubblock(); + testAddress(); + testUpdateChildren(0); + testUpdateChildren(100); + testUpdateChildren2(200); + testDeleteChildren(); + testUpdateGDBBug(); + testUpdateIssue(); + testUpdateIssue2(); + testConcurrentReadAndUpdateChild(); + testConcurrentUpdateOutOfScopeChildThenParent(); + testUpdateOfPointer(); + testCanWrite(); + + return 0; +} + diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/src/GDBMIGenericTestApp.cc b/plugins/org.eclipse.dd.tests.gdb/data/launch/src/GDBMIGenericTestApp.cc new file mode 100644 index 00000000000..e4007b95427 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/data/launch/src/GDBMIGenericTestApp.cc @@ -0,0 +1,15 @@ +#include + +int main() { + printf("Running Generic App\n"); + + const char *path = "/tmp/dsftest.txt"; + const char *mode = "a"; + FILE* fd = fopen(path, mode); + fprintf(fd, "Running Generic App\n"); + fclose(fd); + + + return 0; +} + diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/src/Makefile b/plugins/org.eclipse.dd.tests.gdb/data/launch/src/Makefile new file mode 100644 index 00000000000..777b8b828b3 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/data/launch/src/Makefile @@ -0,0 +1,14 @@ +src = $(wildcard *.cc *.c) +destDir = ../bin +GCCFLAGS = -g -pthread + +all: + @mkdir -p $(destDir) +# Name the target with an .exe extension so that CVS does not +# include it when making a patch + @for file in $(src) ; \ + do \ + target=`basename $$file .c` ; \ + target=`basename $$target .cc` ; \ + g++ $(GCCFLAGS) $$file -o $(destDir)/$$target.exe ; \ + done diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/src/MemoryTestApp.cc b/plugins/org.eclipse.dd.tests.gdb/data/launch/src/MemoryTestApp.cc new file mode 100644 index 00000000000..bef0b930e0e --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/data/launch/src/MemoryTestApp.cc @@ -0,0 +1,38 @@ +//============================================================================ +// Name : MemoryTestApp.cpp +// Author : Francois Chouinard +// Version : 1.0 +// Copyright : Ericsson AB +// Description : Memory test application +//============================================================================ + +#include +using namespace std; + +const int ARRAY_SIZE = 256; + +char charBlock[ARRAY_SIZE]; +int integerBlock[ARRAY_SIZE]; + +void zeroBlocks() +{ + for (int i = 0; i < ARRAY_SIZE; i++) { + charBlock[i] = '\0'; + integerBlock[i] = 0; + } +} + +void setBlocks() +{ + for (int i = 0; i < ARRAY_SIZE; i++) { + charBlock[i] = (char) i; + integerBlock[i] = i; + } +} + +int main() +{ + zeroBlocks(); + setBlocks(); + return 0; +} diff --git a/plugins/org.eclipse.dd.tests.gdb/data/launch/src/MultiThread.cc b/plugins/org.eclipse.dd.tests.gdb/data/launch/src/MultiThread.cc new file mode 100644 index 00000000000..80f99fea6aa --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/data/launch/src/MultiThread.cc @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#define NUM_THREADS 5 + +void *PrintHello(void *threadid) +{ + int tid; + tid = (int)threadid; + printf("Hello World! It's me, thread #%d!\n", tid); + pthread_exit(NULL); +} + +int main(int argc, char *argv[]) +{ + pthread_t threads[NUM_THREADS]; + int rc, t; + for(t=0;t + +int main() { + printf("Running SpecialTestApp\n"); + + const char *path = "/tmp/dsftest.txt"; + const char *mode = "a"; + FILE* fd = fopen(path, mode); + fprintf(fd, "Running SpecialTestApp\n"); + fclose(fd); + + + return 0; +} + diff --git a/plugins/org.eclipse.dd.tests.gdb/plugin.xml b/plugins/org.eclipse.dd.tests.gdb/plugin.xml new file mode 100644 index 00000000000..e2b5a7c5bfd --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/plugin.xml @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/ClassAccessor.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/ClassAccessor.java new file mode 100644 index 00000000000..3d4bd45fdd3 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/ClassAccessor.java @@ -0,0 +1,38 @@ +package org.eclipse.dd.mi.service; + +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.mi.service.ExpressionService.MIExpressionDMC; + +public class ClassAccessor { + + public static class MIExpressionDMCAccessor { + private MIExpressionDMC miExprDmc; + + public MIExpressionDMCAccessor(IExpressionDMContext dmc) { + miExprDmc = (MIExpressionDMC) dmc; + } + + @Override + public boolean equals(Object other) { + return miExprDmc.equals(other); + } + + @Override + public int hashCode() { + return miExprDmc.hashCode(); + } + + @Override + public String toString() { + return miExprDmc.toString(); + } + + public String getExpression() { + return miExprDmc.getExpression(); + } + + public String getRelativeExpression() { + return miExprDmc.getRelativeExpression(); + } + } +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/AllTests.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/AllTests.java new file mode 100644 index 00000000000..94f304e8140 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/AllTests.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial Implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/* + * This class is meant to be empty. It enables us to define + * the annotations which list all the different JUnit class we + * want to run. When creating a new test class, it should be + * added to the list below. + */ + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + MIRegistersTest.class, + MIRunControlTest.class, + ExpressionServiceTest.class, + MIMemoryTest.class, + MIBreakpointsTest.class, + + /* Add your test class here */ + }) + +public class AllTests {} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/ExampleTest.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/ExampleTest.java new file mode 100644 index 00000000000..4604d9046ad --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/ExampleTest.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial Implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb; + +import static org.junit.Assert.assertTrue; + +import java.io.FileNotFoundException; + +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.dd.tests.gdb.framework.BackgroundRunner; +import org.eclipse.dd.tests.gdb.framework.BaseTestCase; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +/* + * This is an example of how to write new JUnit test cases + * for services of DSF. + * + * Each test class should extend BaseTestCase + * so as to automatically launch the application before + * each testcase and tear it down after. + * + * Also, each new test class must be added to the list within AllTest. + * + * Finally, each testcase should be @RunWith(BackgroundRunner.class) + * so as to release the UI thread and allow things such as + * timeouts to work in JUnit + */ + +// Each test must run with the BackgroundRunner so as +// to release the UI thread +@RunWith(BackgroundRunner.class) + +public class ExampleTest extends BaseTestCase { + + @BeforeClass + public static void beforeClassMethod() { + // Things to run once specifically for this class, + // before starting this set of tests. + // Any method name can be used + + // To choose your own test application, use the following form + // You must make sure the compiled binary is available in the + // specified location. + // If this method call is not made, the default GDBMIGenericTestApp + // will be used + setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, + "data/launch/bin/SpecialTestApp.exe"); + + // Other attributes can be changed here + } + + @AfterClass + public static void afterClassMethod() { + // Things to run once specifically for this class, + // after the launch has been performed + // Any method name can be used + } + + @Before + public void beforeMethod() { + // Things to run specifically for this class, + // before each test but after the launch has been performed + // The Launched used is for the default test application + // Any method name can be used + } + + @After + public void afterMethod() { + // Things to run specifically for this class + // after each test but before the launch has been torn down + // Any method name can be used + } + +// @Override +// public void baseBeforeMethod() { +// // Can be used to override and prevent the baseSetup from being run +// // The name baseBeforeMethod must be used +// } + +// @Override +// public void baseAfterMethod() { +// // Can be used to override and prevent the baseTeardown from being run +// // The name baseAfterMethod must be used +// } + + @Test + public void basicTest() { + // First test to run + assertTrue("", true); + } + + @Test(timeout=5000) + public void timeoutTest() { + // Second test to run, which will timeout if not finished on time + assertTrue("", true); + } + + @Test(expected=FileNotFoundException.class) + public void exceptionTest() throws FileNotFoundException { + // Third test to run which expects an exception + throw new FileNotFoundException("Just testing"); + } + +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/ExpressionServiceTest.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/ExpressionServiceTest.java new file mode 100644 index 00000000000..33ccdf3ae6b --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/ExpressionServiceTest.java @@ -0,0 +1,2960 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial Implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb; + +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.utils.Addr32; +import org.eclipse.cdt.utils.Addr64; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IExpressions; +import org.eclipse.dd.dsf.debug.service.IFormattedValues; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionChangedDMEvent; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMAddress; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMData; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData; +import org.eclipse.dd.dsf.debug.service.IRunControl.StepType; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.mi.service.ClassAccessor.MIExpressionDMCAccessor; +import org.eclipse.dd.mi.service.command.events.MIStoppedEvent; +import org.eclipse.dd.tests.gdb.framework.AsyncCompletionWaitor; +import org.eclipse.dd.tests.gdb.framework.BackgroundRunner; +import org.eclipse.dd.tests.gdb.framework.BaseTestCase; +import org.eclipse.dd.tests.gdb.framework.SyncUtil; +import org.eclipse.dd.tests.gdb.launching.TestsPlugin; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(BackgroundRunner.class) +public class ExpressionServiceTest extends BaseTestCase { + + private DsfSession fSession; + + private DsfServicesTracker fServicesTracker; + + private GDBControl fGdbControl; + + private IExpressions fExpService; + + private int fExprChangedEventCount = 0; + + private IExpressionDMContext fExprChangedCtx = null; + + private IExpressionDMContext globalExpressionCtx1 = null; + private IExpressionDMContext globalExpressionCtx2 = null; + + + @BeforeClass + public static void beforeClassMethod() { + setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, "data/launch/bin/ExpressionTestApp.exe"); + } + + @Before + public void init() { + fSession = getGDBLaunch().getSession(); + fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId()); + + fExpService = fServicesTracker.getService(IExpressions.class); + fGdbControl = fServicesTracker.getService(GDBControl.class); + fSession.addServiceEventListener(this, null); + clearExprChangedData(); + } + + @After + public void shutdown() { + fSession.removeServiceEventListener(this); + fExpService = null; + fServicesTracker.dispose(); + } + + // Handles ExpressionChangedEvent + @DsfServiceEventHandler + public void eventDispatched(IExpressionChangedDMEvent e) { + fExprChangedEventCount++; + fExprChangedCtx = e.getDMContext(); + } + + // Clears the counters + private void clearExprChangedData() { + fExprChangedEventCount = 0; + fExprChangedCtx = null; + } + + // Returns the total number of events received + private int getExprChangedCount() { + return fExprChangedEventCount; + } + + private IExpressionDMContext getExprChangedContext() { + return fExprChangedCtx; + } + + // ********************************************************************* + // Below are the tests for the expression service. + // ********************************************************************* + + /** + * Test that we can correctly evaluate integer expressions. + */ + @Test + public void testLiteralIntegerExpressions() throws Throwable { + // Create a map of expressions and their expected values. + Map tests = new HashMap(); + + tests.put("0 + 0 - 0", new String[] { "0x0", "0", "0", "0", "0" }); + tests.put("3 + 4", new String[] { "0x7", "07", "111", "7", "7" }); + tests.put("3 + 4 * 5", new String[] { "0x17", "027", "10111", "23", "23" }); + tests.put("5 * 3 + 4", new String[] { "0x13", "023", "10011", "19", "19" }); + tests.put("5 * (3 + 4)", new String[] { "0x23", "043", "100011", "35", "35" }); + tests.put("10 - 15", new String[] { "0xFFFFFFFB", "037777777773", "11111111111111111111111111111011", "-5", + "-5" }); + tests.put("10 + -15", new String[] { "0xFFFFFFFB", "037777777773", "11111111111111111111111111111011", "-5", + "-5" }); + + executeExpressionSubTests(tests, fGdbControl.getControlDMContext()); + } + + /** + * Test that we can correctly evaluate floating-point expressions. + */ + @Test + public void testLiteralFloatingPointExpressions() throws Throwable { + // Create a map of expressions and their expected values. + Map tests = new HashMap(); + + tests.put("3.1415 + 1.1111", new String[] { "0x4", "04", "100", "4", "4.2526000000000002" }); + tests.put("100.0 / 3.0", new String[] { "0x21", "041", "100001", "33", "33.333333333333336" }); + tests.put("-100.0 / 3.0", new String[] { "0xffffffffffffffdf", "01777777777777777777737", + "1111111111111111111111111111111111111111111111111111111111011111", "-33", "-33.333333333333336" }); + tests.put("-100.0 / -3.0", new String[] { "0x21", "041", "100001", "33", "33.333333333333336" }); + tests.put("100.0 / 0.5", new String[] { "0xc8", "0310", "11001000", "200", "200" }); + + executeExpressionSubTests(tests, fGdbControl.getControlDMContext()); + } + + /** + * Test that we can correctly evaluate C expressions involving local + * variables. + */ + @Test + public void testLocalVariables() throws Throwable { + // Run to the point where all local variables are initialized + SyncUtil.SyncRunToLocation("testLocals"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 16); + + // Create a map of expressions to expected values. + Map tests1 = new HashMap(); + + tests1.put("lIntVar", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345" }); + tests1.put("lDoubleVar", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345.123449999999" }); + tests1.put("lCharVar", new String[] { "0x6d", "0155", "1101101", "109", "109 'm'" }); + tests1.put("lBoolVar", new String[] { "0x0", "0", "0", "0", "false" }); + + tests1.put("lIntArray[1]", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345" }); + tests1.put("lDoubleArray[1]", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345.123449999999" }); + tests1.put("lCharArray[1]", new String[] { "0x6d", "0155", "1101101", "109", "109 'm'" }); + tests1.put("lBoolArray[1]", new String[] { "0x0", "0", "0", "0", "false" }); + + tests1.put("*lIntPtr", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345" }); + tests1.put("*lDoublePtr", new String[] { "0x3039", "030071", "11000000111001", "12345", "12345.123449999999" }); + tests1.put("*lCharPtr", new String[] { "0x6d", "0155", "1101101", "109", "109 'm'" }); + tests1.put("*lBoolPtr", new String[] { "0x0", "0", "0", "0", "false" }); + + tests1.put("lIntPtr2", new String[] { "0x1", "01", "1", "1", "0x1" }); + tests1.put("lDoublePtr2", new String[] { "0x2345", "021505", "10001101000101", "9029", "0x2345" }); + // GDB says a char* is out of bounds, but not the other pointers??? + // tests1.put("CharPtr2", new String[] { "0x1234", "011064", + // "1001000110100", "4660", "0x1234" }); + tests1.put("lBoolPtr2", new String[] { "0x123ABCDE", "02216536336", "10010001110101011110011011110", "305839326", "0x123ABCDE" }); + + executeExpressionSubTests(tests1, SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0)); + + // Step into the method and stop until all new local variables are + // initialized + SyncUtil.SyncStep(StepType.STEP_INTO); + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 5); + + // Create a map of expressions to expected values. + Map tests2 = new HashMap(); + + tests2.put("lIntVar", new String[] { "0x1a85", "015205", "1101010000101", "6789", "6789" }); + tests2.put("lDoubleArray[1]", + new String[] { "0x1a85", "015205", "1101010000101", "6789", "6789.6788999999999" }); + tests2.put("lCharVar", new String[] { "0x69", "0151", "1101001", "105", "105 'i'" }); + tests2.put("*lCharPtr", new String[] { "0x69", "0151", "1101001", "105", "105 'i'" }); + tests2.put("lBoolPtr2", new String[] { "0xABCDE123", "025363360443", "10101011110011011110000100100011", + "2882396451", "0xABCDE123" }); + + // check variables at current stack frame + executeExpressionSubTests(tests2, SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0)); + // check previous stack frame + executeExpressionSubTests(tests1, SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 1)); + + // Now return from the method and check that we see the + // original variables + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_RETURN); + + executeExpressionSubTests(tests1, SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0)); + } + + /** + * This tests verifies that we can deal with variables in a subblock hiding + * variables with the same name in the outer block. + */ + @Ignore("Sublocks do not work with GDB") + @Test + public void testSubBlock() throws Throwable { + SyncUtil.SyncRunToLocation("testSubblock"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 2); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + Map tests = new HashMap(); + + tests.put("a", new String[] { "0x8", "010", "1000", "8", "8" }); + tests.put("b", new String[] { "0x1", "01", "1", "1", "1" }); + + executeExpressionSubTests(tests, frameDmc); + + // Now enter a subblock with the same variable names + SyncUtil.SyncStep(StepType.STEP_OVER, 2); + + tests = new HashMap(); + + tests.put("a", new String[] { "0xc", "014", "1100", "12", "12" }); + tests.put("b", new String[] { "0x1", "01", "1", "1", "1" }); + + executeExpressionSubTests(tests, frameDmc); + + // Now step to change the b variable + SyncUtil.SyncStep(StepType.STEP_OVER, 1); + + tests = new HashMap(); + + tests.put("a", new String[] { "0xc", "014", "1100", "12", "12" }); + tests.put("b", new String[] { "0xc", "014", "1100", "12", "12" }); + + executeExpressionSubTests(tests, frameDmc); + + // Now exit the sub-block and check that we see the original a but the + // same b + SyncUtil.SyncStep(StepType.STEP_OVER, 1); + + tests = new HashMap(); + + tests.put("a", new String[] { "0x8", "010", "1000", "8", "8" }); + tests.put("b", new String[] { "0xc", "014", "1100", "12", "12" }); + + executeExpressionSubTests(tests, frameDmc); + } + + /** + * This tests verifies that we can obtain children properly. + */ + @Test + public void testChildren() throws Throwable { + + // Get the children of some variables + MIStoppedEvent stoppedEvent = SyncUtil.SyncRunToLocation("testChildren"); + doTestChildren(stoppedEvent); + + // Now do a step and get the children again, to test the internal cache + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + doTestChildren(stoppedEvent); + } + + /** + * This test verifies that the ExpressionService can write to a variable. + */ + @Test + public void testWriteVariable() throws Throwable { + SyncUtil.SyncRunToLocation("testWrite"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + final IExpressionDMContext exprDmc = SyncUtil.SyncCreateExpression(frameDmc, "a[1]"); + + writeAndCheck(exprDmc, "987", IFormattedValues.DECIMAL_FORMAT, "987"); + writeAndCheck(exprDmc, "16", IFormattedValues.HEX_FORMAT, "22"); + writeAndCheck(exprDmc, "0x2e", IFormattedValues.HEX_FORMAT, "46"); + writeAndCheck(exprDmc, "16", IFormattedValues.OCTAL_FORMAT, "14"); + writeAndCheck(exprDmc, "022", IFormattedValues.OCTAL_FORMAT, "18"); + writeAndCheck(exprDmc, "1011", IFormattedValues.BINARY_FORMAT, "11"); + writeAndCheck(exprDmc, "0b1001", IFormattedValues.BINARY_FORMAT, "9"); + writeAndCheck(exprDmc, "456", IFormattedValues.NATURAL_FORMAT, "456"); + + } + + /* + * This method does a write and then a read to make sure the new value was + * properly written. + */ + private void writeAndCheck(final IExpressionDMContext exprDmc, final String newValueFormatted, final String format, + final String newValueInDecimal) throws Throwable { + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + // Write the new value using its formatted value + fExpService.getExecutor().submit(new Runnable() { + public void run() { + fExpService.writeExpression( + exprDmc, + newValueFormatted, + format, + new RequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + wait.waitFinished(getStatus()); + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + assertTrue("ExprChangedEvent problem: expected 1, received " + getExprChangedCount(), + getExprChangedCount() == 1); + + clearExprChangedData(); + + wait.waitReset(); + + // Read the new value in decimal and check that it is what we expected + fExpService.getExecutor().submit(new Runnable() { + public void run() { + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.DECIMAL_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + wait.setReturnInfo(getData()); + } + + wait.waitFinished(getStatus()); + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + String actualDecimalValue = ((FormattedValueDMData) wait.getReturnInfo()).getFormattedValue(); + + assertTrue("Failed to correctly evaluate '" + exprDmc.getExpression() + "': expected '" + newValueInDecimal + + "', got '" + actualDecimalValue + "'", actualDecimalValue.equalsIgnoreCase(newValueInDecimal)); + + assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), + getExprChangedCount() == 0); + } + + /** + * This tests verifies that we handle invalid formats properly for a write. + */ + @Test + public void testWriteErrorFormat() throws Throwable { + SyncUtil.SyncRunToLocation("testWrite"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + IExpressionDMContext exprDmc = SyncUtil.SyncCreateExpression(frameDmc, "a[1]"); + + writeAndCheckError(exprDmc, "goodbye", IFormattedValues.DECIMAL_FORMAT); + writeAndCheckError(exprDmc, "abggg", IFormattedValues.HEX_FORMAT); + writeAndCheckError(exprDmc, "99", IFormattedValues.OCTAL_FORMAT); + writeAndCheckError(exprDmc, "234", IFormattedValues.BINARY_FORMAT); + writeAndCheckError(exprDmc, "hello", IFormattedValues.NATURAL_FORMAT); + writeAndCheckError(exprDmc, "1", "ThisFormatDoesNotExist"); + + IExpressionDMContext notWritableExprDmc = SyncUtil.SyncCreateExpression(frameDmc, "10+5"); + writeAndCheckError(notWritableExprDmc, "1", IFormattedValues.NATURAL_FORMAT); + } + + /* + * This method does a write that should use an invalid value or format, and + * verifies that the operation fails + */ + private void writeAndCheckError(final IExpressionDMContext exprDmc, final String invalidValueFormatted, + final String format) throws Throwable { + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + // Write the new value using its formatted value + fExpService.getExecutor().submit(new Runnable() { + public void run() { + fExpService.writeExpression(exprDmc, invalidValueFormatted, format, new RequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + wait.waitFinished(getStatus()); + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue("Got an OK status for an error test case. Should not be able to write value " + + invalidValueFormatted + " in " + format, !wait.isOK()); + + assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), + getExprChangedCount() == 0); + } + + /** + * This test tries multiple format reads during the same executor cycle, to + * make sure the internal MI commands are sequenced properly. + */ + @Test + public void testConcurrentReads() throws Throwable { + // Next we test that we can read the value more than once + // of the same variable object at the exact same time + + SyncUtil.SyncRunToLocation("testConcurrent"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc, "a[0]"); + + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("28")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating natural format", null)); + } + } + } + }); + + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.HEX_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equalsIgnoreCase("0x1c")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating hex format", null)); + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), + getExprChangedCount() == 0); + + } + + /** + * This test tries reads and listChildren during the same executor cycle, to + * make sure the internal MI commands are sequenced properly. + */ + @Test + public void testConcurrentReadChildren() throws Throwable { + // Next we test that we can retrieve children while reading the value + // and vice-versa + + SyncUtil.SyncRunToLocation("testConcurrent"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + // First we get the expected value of the array pointer. + final IExpressionDMContext addrDmc = SyncUtil.SyncCreateExpression(frameDmc, "&a"); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(addrDmc, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + wait.setReturnInfo(getData()); + } + + wait.waitFinished(getStatus()); + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + final String actualAddrStr = ((FormattedValueDMData) wait.getReturnInfo()).getFormattedValue(); + + wait.waitReset(); + + // Now perform the test + fExpService.getExecutor().submit(new Runnable() { + public void run() { + IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc, "a"); + + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals(actualAddrStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating natural format", null)); + } + } + } + }); + + wait.increment(); + fExpService.getSubExpressions(exprDmc, new DataRequestMonitor( + fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + IExpressionDMContext[] children = getData(); + int failedIndex = -1; + for (int i = 0; i < 2; i++) { + if (!children[i].getExpression().equals("a[" + i + "]")) { + failedIndex = i; + } + } + + if (failedIndex != -1) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting child number: " + failedIndex, null)); + } else { + wait.waitFinished(); + } + } + } + }); + + // Use different format to avoid triggering the cache + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.HEX_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals(actualAddrStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating hex format", null)); + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), + getExprChangedCount() == 0); + } + + /** + * This test tries reads and getChildrenCount during the same executor + * cycle, to make sure the internal MI commands are sequenced properly. + */ + @Test + public void testConcurrentReadChildrenCount() throws Throwable { + // Next we test that we can retrieve children count while reading the + // value and vice-versa + + SyncUtil.SyncRunToLocation("testConcurrent"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + // First we get the expected value of the array pointer. + final IExpressionDMContext addrDmc = SyncUtil.SyncCreateExpression(frameDmc, "&a"); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(addrDmc, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + wait.setReturnInfo(getData()); + } + + wait.waitFinished(getStatus()); + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + final String actualAddrStr = ((FormattedValueDMData) wait.getReturnInfo()).getFormattedValue(); + + wait.waitReset(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + wait.increment(); + IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc, "a"); + + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals(actualAddrStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating natural format", null)); + } + } + } + }); + + wait.increment(); + fExpService.getSubExpressionCount(exprDmc, new DataRequestMonitor(fExpService.getExecutor(), + null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + int count = getData(); + if (count != 2) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting count for children. Got" + count + "instead of 2", null)); + } else { + wait.waitFinished(); + } + } + } + }); + + // Use different format to avoid triggering the cache + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.HEX_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals(actualAddrStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating hex format", null)); + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), + getExprChangedCount() == 0); + } + + /** + * This test tries reads and writes during the same executor cycle, to make + * sure the internal MI commands are sequenced properly. + */ + @Test + public void testConcurrentReadWrite() throws Throwable { + // Next we test that we can deal with a write request and read request + // at + // the same time and vice-versa + + SyncUtil.SyncRunToLocation("testConcurrent"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final IExpressionDMContext exprDmc = SyncUtil.SyncCreateExpression(frameDmc, "a[1]"); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("32")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating natural format, got " + getData().getFormattedValue() + + " instead of 32", null)); + } + } + } + }); + + wait.increment(); + fExpService.writeExpression(exprDmc, "56", IFormattedValues.NATURAL_FORMAT, new RequestMonitor( + fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + wait.waitFinished(); + } + } + }); + + // Use different format to avoid triggering the cache + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.HEX_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("0x38")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating hex format, got " + getData().getFormattedValue() + + " instead of 0x38", null)); + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + assertTrue("ExprChangedEvent problem: expected 1, received " + getExprChangedCount(), + getExprChangedCount() == 1); + exprDmc.equals(getExprChangedContext()); + clearExprChangedData(); + } + + /** + * This test tries many different operations during the same executor cycle, + * to make sure the internal MI commands are sequenced properly. + */ + @Test + public void testConcurrentReadWriteChildren() throws Throwable { + // Finally, we go nuts and request two reads, while requesting + // a get children and get children count. + // Note that we don't request a write, because a write is allowed to + // go through at any time and we don't exactly know when it will + // change the value we are reading. + + SyncUtil.SyncRunToLocation("testConcurrent"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final IExpressionDMContext exprDmc = SyncUtil.SyncCreateExpression(frameDmc, "a[1]"); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("32")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating natural format, got " + getData().getFormattedValue() + + " instead of 32", null)); + } + } + } + }); + + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.HEX_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("0x20")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating hex format, got " + getData().getFormattedValue() + + " instead of 0x20", null)); + } + } + } + }); + + wait.increment(); + fExpService.getSubExpressionCount(exprDmc, new DataRequestMonitor(fExpService.getExecutor(), + null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData() != 0) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting child count; expecting 0 got " + getData(), null)); + } else { + wait.waitFinished(); + } + } + } + }); + + wait.increment(); + fExpService.getSubExpressions(exprDmc, new DataRequestMonitor( + fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().length != 0) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 0 got " + getData().length, null)); + } else { + wait.waitFinished(); + } + } + } + }); + + // Must use a different format or else the cache will be triggered + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.OCTAL_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("040")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating hex format, got " + getData().getFormattedValue() + + " instead of 040", null)); + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), + getExprChangedCount() == 0); + exprDmc.equals(getExprChangedContext()); + clearExprChangedData(); + } + + /** + * This test verifies that the ExpressionService caches the evaluation of an + * expression in a specific format. It verifies this by: 1- reading a + * variable 2- writing to that variable 3- reading the variable in a new + * format and seeing the new value 4- reading the variable in the same + * format as step 1 and seeing the old value cached Note that all above + * steps must be done within the same Runnable submitted to the executor. + * This allows the cache to be triggered before it is invalidated by a write + * command, since the write command will need an new executor cycle to send + * an MI command to the back-end + */ + @Test + public void testWriteCache() throws Throwable { + // Test the cache by changing a value but triggering a read before the + // write clears the cache + + SyncUtil.SyncRunToLocation("testConcurrent"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final IExpressionDMContext exprDmc = SyncUtil.SyncCreateExpression(frameDmc, "a[1]"); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("32")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating natural format, got " + getData().getFormattedValue() + + " instead of 32", null)); + } + } + } + }); + + wait.increment(); + fExpService.writeExpression(exprDmc, "56", IFormattedValues.NATURAL_FORMAT, new RequestMonitor( + fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + wait.waitFinished(); + } + } + }); + + // Must use a different format or else the cache will be + // triggered + // This will prove that the write has changed the backend + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.OCTAL_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("070")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating hex format, got " + getData().getFormattedValue() + + " instead of 070", null)); + } + } + } + }); + + // Test that the cache is triggered, giving us the old value + // This happens because we are calling this operation on the + // same executor run call. + // NOTE that this is not a problem, because the writeExpression + // will eventually + // reset the cache (we'll test this below). + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("32")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating natural format, got " + getData().getFormattedValue() + + " instead of 32", null)); + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + // Now that we know the writeExpressions completed and the cache was + // reset, do a similar + // request as above to see that the cache has indeed been reset + wait.waitReset(); + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + wait.increment(); + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc, + IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("56")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating natural format, got " + getData().getFormattedValue() + + " instead of 56", null)); + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + assertTrue("ExprChangedEvent problem: expected 1, received " + getExprChangedCount(), + getExprChangedCount() == 1); + exprDmc.equals(getExprChangedContext()); + clearExprChangedData(); + } + + /** + * Test that we can correctly retrieve the address and type size of an + * expression + */ + @Test + public void testExprAddress() throws Throwable { + + SyncUtil.SyncRunToLocation("testAddress"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 2); + + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final IExpressionDMContext exprDmc = SyncUtil.SyncCreateExpression(frameDmc, "a"); + + final IExpressionDMContext exprDmc2 = SyncUtil.SyncCreateExpression(frameDmc, "a_ptr"); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + // First get the address of 'a' through 'a_ptr' + fExpService.getExecutor().submit(new Runnable() { + public void run() { + fExpService.getFormattedExpressionValue(fExpService.getFormattedValueContext(exprDmc2, + IFormattedValues.NATURAL_FORMAT), new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + wait.setReturnInfo(getData()); + } + + wait.waitFinished(getStatus()); + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + String actualAddrStr = ((FormattedValueDMData) wait.getReturnInfo()).getFormattedValue(); + wait.waitReset(); + + // Now check the address through our getAddressData + checkAddressData(exprDmc, actualAddrStr, 4); + + assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), + getExprChangedCount() == 0); + } + + + /** + * Test that we can correctly evaluate C expressions involving global + * variables. + * + * @return void + */ + // @Test + public void testGlobalVariables() throws Throwable { + + // Step to a stack level of 2 to be able to test differen stack frames + MIStoppedEvent stoppedEvent = SyncUtil.SyncRunToLocation("locals2"); + + // Create a map of expressions to expected values. + Map tests = new HashMap(); + + // Global variables + tests.put("gIntVar", new String[] { "0x21F", "01037", "1000011111", "543", "543" }); + tests.put("gDoubleVar", new String[] { "0x21F", "01037", "1000011111", "543", "543.54300000000001" }); + tests.put("gCharVar", new String[] { "0x67", "0147", "1100111", "103", "103 'g'" }); + tests.put("gBoolVar", new String[] { "0x0", "0", "0", "0", "false" }); + + tests.put("gIntArray[1]", new String[] { "0x28E", "01216", "1010001110", "654", "654" }); + tests.put("gDoubleArray[1]", new String[] { "0x28E", "01216", "1010001110", "654", "654.32100000000003" }); + tests.put("gCharArray[1]", new String[] { "0x64", "0144", "1100100", "100", "100 'd'" }); + tests.put("gBoolArray[1]", new String[] { "0x0", "0", "0", "0", "false" }); + + tests.put("*gIntPtr", new String[] { "0x21F", "01037", "1000011111", "543", "543" }); + tests.put("*gDoublePtr", new String[] { "0x21F", "01037", "1000011111", "543", "543.54300000000001" }); + tests.put("*gCharPtr", new String[] { "0x67", "0147", "1100111", "103", "103 'g'" }); + tests.put("*gBoolPtr", new String[] { "0x0", "0", "0", "0", "false" }); + + tests.put("gIntPtr2", new String[] { "0x8", "010", "1000", "8", "0x8" }); + tests.put("gDoublePtr2", new String[] { "0x5432", "052062", "101010000110010", "21554", "0x5432" }); + // GDB says a char* is out of bounds, but not the other pointers??? + // tests.put("gCharPtr2", new String[] { "0x4321", "041441", + // "100001100100001", "17185", "0x4321" }); + tests.put("gBoolPtr2", new String[] { "0x12ABCDEF", "02252746757", "10010101010111100110111101111", + "313249263", "0x12ABCDEF" }); + + // Try different stack frames + executeExpressionSubTests(tests, SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0)); + executeExpressionSubTests(tests, SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 1)); + executeExpressionSubTests(tests, SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 2)); + } + + /** + * This test verifies that the ExpressionService can handle having a + * variable with the same name in two different methods but at the same + * stack depth. + */ + @Test + public void testNamingSameDepth() throws Throwable { + SyncUtil.SyncRunToLocation("testName1"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + Map tests = new HashMap(); + tests.put("a", new String[] { "0x1", "01", "1", "1", "1" }); + executeExpressionSubTests(tests, frameDmc); + + SyncUtil.SyncRunToLocation("testName2"); + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_INTO, 1); + frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + tests = new HashMap(); + tests.put("a", new String[] { "0x2", "02", "10", "2", "2" }); + executeExpressionSubTests(tests, frameDmc); + + SyncUtil.SyncRunToLocation("testName1"); + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_INTO, 1); + frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + tests = new HashMap(); + tests.put("a", new String[] { "0x3", "03", "11", "3", "3" }); + executeExpressionSubTests(tests, frameDmc); + } + + /** + * This test verifies that the ExpressionService can handle having a + * variable with the same name in two methods that also have the same name + */ + @Test + public void testNamingSameMethod() throws Throwable { + SyncUtil.SyncRunToLocation("testSameName"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_INTO, 2); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + Map tests = new HashMap(); + tests.put("a", new String[] { "0x1", "01", "1", "1", "1" }); + executeExpressionSubTests(tests, frameDmc); + + SyncUtil.SyncStep(StepType.STEP_RETURN); + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_INTO, 2); + frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + tests = new HashMap(); + tests.put("a", new String[] { "0x2", "02", "10", "2", "2" }); + executeExpressionSubTests(tests, frameDmc); + + SyncUtil.SyncStep(StepType.STEP_RETURN); + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_INTO, 2); + frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + tests = new HashMap(); + tests.put("a", new String[] { "0x3", "03", "11", "3", "3" }); + executeExpressionSubTests(tests, frameDmc); + } + + /** + * This test verifies that the ExpressionService can handle having a + * child variable with the same name in two methods that also have the same name + */ + @Test + public void testChildNamingSameMethod() throws Throwable { + SyncUtil.SyncRunToLocation("testSameName"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_INTO, 4); + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + // First create the var object and all its children + IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "z"); + + fExpService.getSubExpressions( + parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().length != 2) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 2 got " + getData().length, null)); + } else { + // now get the value of the child + final String valueStr = "1"; + final IExpressionDMContext child = getData()[0]; + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + child.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + + }); + } + + + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + SyncUtil.SyncStep(StepType.STEP_RETURN); + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_INTO, 4); + final IFrameDMContext frameDmc2 = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + // First create the var object and all its children + IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc2, "z"); + + fExpService.getSubExpressions( + parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().length != 2) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 2 got " + getData().length, null)); + } else { + // now get the value of the child + final String valueStr = "2"; + final IExpressionDMContext child = getData()[0]; + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + child.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + + }); + } + + + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + SyncUtil.SyncStep(StepType.STEP_RETURN); + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_INTO, 4); + final IFrameDMContext frameDmc3 = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + // First create the var object and all its children + IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc3, "z"); + + fExpService.getSubExpressions( + parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().length != 2) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 2 got " + getData().length, null)); + } else { + // now get the value of the child + final String valueStr = "3"; + final IExpressionDMContext child = getData()[0]; + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + child.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + + }); + } + + + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + } + + /** + * This test verifies that the ExpressionService properly updates + * children variables, when we do not update the parent explicitly + */ + @Test + public void testUpdatingChildren() throws Throwable { + SyncUtil.SyncRunToLocation("testUpdateChildren"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 2); + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + doUpdateTest(frameDmc, 0); + + // Re-run the test to test out-of-scope update again + SyncUtil.SyncStep(StepType.STEP_RETURN); + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_INTO, 3); + final IFrameDMContext frameDmc2 = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + doUpdateTest(frameDmc2, 100); + + // Re-run the test within a different method test out-of-scope updates + SyncUtil.SyncStep(StepType.STEP_RETURN); + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_INTO, 3); + final IFrameDMContext frameDmc3 = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + doUpdateTest(frameDmc3, 200); + + } + + + public void doUpdateTest(final IFrameDMContext frameDmc, final int baseValue) throws Throwable { + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + // First create the var object and all its children + IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "a"); + + fExpService.getSubExpressions( + parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().length != 1) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 1 got " + getData().length, null)); + } else { + // Now list the children of this child + fExpService.getSubExpressions( + getData()[0], + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + final IExpressionDMContext[] childDmcs = getData(); + + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (childDmcs.length != 2) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 2 got " + childDmcs.length, null)); + } else { + // now get the value of the two children + for (int i =0; i<2; i++) { + final String valueStr = Integer.toString(baseValue + i + 10); + final int finali = i; + + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(childDmcs[i], IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + childDmcs[finali].getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + + }); + } + } + } + }); + } + + + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + // Now step to change the value of a.z.x and a.z.y and verify the changed values. + // This will confirm that the parent "a" will have been properly updated + // It is a better test to do it for two children because it tests concurrent update requests + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 2); + final IFrameDMContext frameDmc2 = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + // First create the var object and all its children + IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc2, "a"); + + fExpService.getSubExpressions( + parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().length != 1) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 1 got " + getData().length, null)); + } else { + // Now list the children of this child + fExpService.getSubExpressions( + getData()[0], + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + final IExpressionDMContext[] childDmcs = getData(); + + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (childDmcs.length != 2) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 2 got " + childDmcs.length, null)); + } else { + // now get the value of the two children + for (int i =0; i<2; i++) { + final String valueStr = Integer.toString(baseValue + i + 20); + final int finali = i; + + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(childDmcs[i], IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + childDmcs[finali].getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + + }); + } + } + } + }); + } + + + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + } + + /** + * This test creates a variable object with children (not an array) and then gets these children + * to be deleted because of a large number of other variable objects being created. + * We then check that the expression service can handle a request for one of those deleted children, + * which has a complex path. + */ + @Test + public void testDeleteChildren() throws Throwable { + SyncUtil.SyncRunToLocation("testDeleteChildren"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + // First create the var object and all its children + IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "f"); + + fExpService.getSubExpressions( + parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().length != 5) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 5 got " + getData().length, null)); + } else { + String childStr = "((bar) f)"; + if (!getData()[0].getExpression().equals(childStr)) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Got child " + getData()[0].getExpression() + " instead of " + childStr, null)); + } else { + // Now list the children of the first element + fExpService.getSubExpressions( + getData()[0], + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().length != 2) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 2 got " + getData().length, null)); + } else { + String childStr = "((((bar) f)).d)"; + if (!getData()[0].getExpression().equals(childStr)) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Got child " + getData()[0].getExpression() + " instead of " + childStr, null)); + } else { + wait.setReturnInfo(getData()[0]); + wait.waitFinished(); + } + } + } + } + }); + } + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + final IExpressionDMContext deletedChildDmc = (IExpressionDMContext)wait.getReturnInfo(); + + wait.waitReset(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + // Now create more than 1000 expressions to trigger the deletion of the children + // that were created above + for (int i=0; i<1100; i++) { + IExpressionDMContext dmc = fExpService.createExpression(frameDmc, "a[" + i + "]"); + + wait.increment(); + fExpService.getExpressionData( + dmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + wait.waitFinished(); + } + } + }); + } + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + // Evaluate the expression of a child that we know is deleted to make sure + // the expression service can handle that + fExpService.getExpressionData( + deletedChildDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + wait.waitFinished(); + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + } + + /** + * GDB 6.7 has a bug which will cause var-update not to show + * the new value of 'a' if we switch the format to binary, + * since binary of 3 is 11 which is the same as the old value + * in natural format. Our expression service should work around this. + * + * int main() { + * int a = 11; + * a = 3; + * return 0; + * } + */ + @Test + public void testUpdateGDBBug() throws Throwable { + SyncUtil.SyncRunToLocation("testUpdateGDBBug"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + // First create the var object and all its children + IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc, "a"); + + // This call will create the variable object in natural format and then change + // it to binary to fetch the value + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(exprDmc, IFormattedValues.BINARY_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("1011")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating binary format, expected 1011 but got " + + getData().getFormattedValue(), null)); + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + // Now step to change the value of "a" and ask for it again + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + final IFrameDMContext frameDmc2 = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + // First create the var object and all its children + IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc2, "a"); + + // This call will create the variable object in natural format and then change + // it to binary to fetch the value + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(exprDmc, IFormattedValues.BINARY_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("11")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating binary format, expected 11 but got " + + getData().getFormattedValue(), null)); + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + } + + /** + * var-update will not show a change if eval-expression is the same + * in the current format. This is a problem for us because we don't + * know if another format changed: + * + * int main() { + * double a = 1.99; + * a = 1.11; + * } + * + * If a is displayed in anything but natural, both values of a are the same + * and we won't know it changed in the natural format. + * + * The test below is in case GDB fixes var-update to keep track of the last + * printed value through eval-expression. Until they do that, we do not have + * a problem because of our caching: where, if we change formats since the last + * var-update, it is impossible for us to set the format back + * to the one of the last -var-update, since we already have that value in our cache. + * So, the -var-update will show a change because of the new current format. + * But if GDB has eval-expression reset their stored printed_value, this test + * will fail and we'll know we have to fix something. + */ + @Test + public void testUpdateIssue() throws Throwable { + SyncUtil.SyncRunToLocation("testUpdateIssue"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + // First create the var object and all its children + IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc, "a"); + + // check that we have the proper value + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("1.99")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating a, expected 1.99 but got " + + getData().getFormattedValue(), null)); + } + } + } + }); + + // ask for hex to set the format to hex + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(exprDmc, IFormattedValues.HEX_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("0x1")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating a, expected 0x1 but got " + + getData().getFormattedValue(), null)); + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + // Now step to change the value of "a" and ask for it again but in the natural format + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + final IFrameDMContext frameDmc2 = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + // First create the var object and all its children + IExpressionDMContext exprDmc = fExpService.createExpression(frameDmc2, "a"); + + // trigger the var-update in the last format (hex) + // then request the actual value in natural which should not be taken from the cache + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("1.22")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating natural format, expected 1.22 but got " + + getData().getFormattedValue(), null)); + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + } + + /** + * var-update will not show a change if eval-expression is the same + * in the current format. This is a problem for us because we don't + * know if another format changed: + * + * int main() { + * struct { + * double d; + * } z; + * + * z.d = 1.0; + * z.d = 1.22; + * } + * + * If a is displayed in anything but natural, both values of a are the same + * and we won't know it changed in the natural format. + * This test uses a child to increase the value of the test. + * Also, it avoids the cache saving us since we start with the 1.0 value + * which is the same in natural and decimal + */ + @Test + public void testUpdateIssue2() throws Throwable { + SyncUtil.SyncRunToLocation("testUpdateIssue2"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "z"); + + fExpService.getSubExpressions( + parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().length != 1) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 1 got " + getData().length, null)); + } else { + // check that we have the proper value + // This will cache the value 1 in the natural format cache + final String valueStr = "1"; + globalExpressionCtx1 = getData()[0]; + + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + }); + + // ask for decimal to set the format to decimal + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.DECIMAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + } + }); + + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + // Now step to change the value of "a" in natural but it remains the same in decimal + SyncUtil.SyncStep(StepType.STEP_OVER, 1); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + // trigger the var-update in the last format (decimal) + // then request the actual value in natural which should not be taken from the cache + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + if (getData().getFormattedValue().equals("1.22")) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating natural format, expected 1.22 but got " + + getData().getFormattedValue(), null)); + } + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + } + + /** + * This test verifies the state handling of a child variable object + * to make sure that our locking scheme works even though we must deal + * with an update call, internally + */ + @Test + public void testConcurrentReadAndUpdateChild() throws Throwable { + SyncUtil.SyncRunToLocation("testConcurrentReadAndUpdateChild"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 1); + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + // Ask for one value to create the var object + fExpService.getExecutor().submit(new Runnable() { + public void run() { + // First create the var object and all its children + IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "z"); + + wait.increment(); + fExpService.getSubExpressions( + parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().length != 1) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 1 got " + getData().length, null)); + } else { + // now get the value of the child + final String valueStr = "01"; + globalExpressionCtx1 = getData()[0]; + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.OCTAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + }); + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + // Now do two reads in two different formats + // We need to make sure that the locking properly works although we are calling + // the internal update method, which does affect the state of the object + fExpService.getExecutor().submit(new Runnable() { + public void run() { + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.BINARY_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + final String valueStr = "1"; + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + }); + + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.HEX_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + final String valueStr = "0x1"; + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + } + + /** + * This test verifies some of the logic of dealing with out-of-scope variables. + * This particular scenario is that we create a parent with a child and then + * have them go out of scope. Then we request the child which will update the parent + * and mark it as out-of-scope and recreate the child. The parent is not re-created. + * We then ask twice for the parent which is already known to be out-of-scope and we need + * to make sure that the parent is re-created once and only once. + * We had a bug where we would enter an infinite loop in this case. + */ + @Test(timeout=5000) + public void testConcurrentUpdateOutOfScopeChildThenParent() throws Throwable { + SyncUtil.SyncRunToLocation("testConcurrentUpdateOutOfScopeChildThenParent"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_INTO, 2); + + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + // First create the var object and its child + globalExpressionCtx1 = fExpService.createExpression(frameDmc, "z"); + + wait.increment(); + fExpService.getSubExpressions( + globalExpressionCtx1, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().length != 1) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 1 got " + getData().length, null)); + } else { + // now get the value of the child + final String valueStr = "1"; + globalExpressionCtx2 = getData()[0]; + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx2, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx2.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + }); + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + SyncUtil.SyncStep(StepType.STEP_RETURN); + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_INTO, 2); + + // Now step to another method to make the previous variable objects out-of-scope + // then first request the child and then the parent. We want to test this order + fExpService.getExecutor().submit(new Runnable() { + public void run() { + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx2, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + final String valueStr = "2"; + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx2.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + final String valueStr = "{...}"; + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + }); + + // Ask a second time but in a different format, to avoid the cache + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.DECIMAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + final String valueStr = "{...}"; + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(valueStr)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + valueStr, null)); + } + } + }); + + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + //TODO although this test passes, the variable z is created twice, without being + // deleted in GDB. We should fix this + } + + /** + * This test verifies that we properly update a pointer and its child since they can both + * change and be reported by var-update + */ + @Test + public void testUpdateOfPointer() throws Throwable { + SyncUtil.SyncRunToLocation("testUpdateOfPointer"); + MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 3); + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final String firstValue = "1"; + final String secondValue = "2"; + final String thirdValue = "3"; + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc, "z"); + + fExpService.getSubExpressions( + parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().length != 2) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 2 got " + getData().length, null)); + } else { + // check that we have the proper value for both children + globalExpressionCtx1 = getData()[0]; + globalExpressionCtx2 = getData()[1]; + + // Get the value of the first child + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(firstValue)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + firstValue, null)); + } + } + }); + + // Get the value of the second child + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx2, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + wait.setReturnInfo(getData().getFormattedValue()); + wait.waitFinished(); + } + } + }); + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + final String pointerValue = (String)wait.getReturnInfo(); + wait.waitReset(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + // also get the child of the pointer + fExpService.getSubExpressions( + globalExpressionCtx2, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().length != 1) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 1 got " + getData().length, null)); + } else { + // Get the value of the child of the pointer + globalExpressionCtx2 = getData()[0]; + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx2, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(firstValue)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx2.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + firstValue, null)); + } + } + }); + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + // Now step to change the values of all the children + stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER, 2); + final IFrameDMContext frameDmc2 = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + IExpressionDMContext parentDmc = fExpService.createExpression(frameDmc2, "z"); + + fExpService.getSubExpressions( + parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().length != 2) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 2 got " + getData().length, null)); + } else { + // check that we have the proper value for both children + globalExpressionCtx1 = getData()[0]; + globalExpressionCtx2 = getData()[1]; + + // Get the value of the first child + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx1, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(secondValue)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx1.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + secondValue, null)); + } + } + }); + + // Get the value of the second child + wait.increment(); + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx2, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (!getData().getFormattedValue().equals(pointerValue)) { + // The value should have changed + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx2.getExpression() + ", got " + getData().getFormattedValue() + + " instead of some other value", null)); + } + } + }); + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + // also get the child of the pointer + fExpService.getSubExpressions( + globalExpressionCtx2, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().length != 1) { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed getting children; expecting 1 got " + getData().length, null)); + } else { + // Get the value of the child of the pointer + globalExpressionCtx2 = getData()[0]; + fExpService.getFormattedExpressionValue( + fExpService.getFormattedValueContext(globalExpressionCtx2, IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData().getFormattedValue().equals(thirdValue)) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed evaluating " + globalExpressionCtx2.getExpression() + ", got " + getData().getFormattedValue() + + " instead of " + thirdValue, null)); + } + } + }); + } + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + } + + /** + * This test verifies that we properly return if we can write to different expressions + */ + @Test + public void testCanWrite() throws Throwable { + MIStoppedEvent stoppedEvent = SyncUtil.SyncRunToLocation("testCanWrite"); + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + final int exprCount = 5; + final IExpressionDMContext dmcs[] = new IExpressionDMContext[exprCount]; + final boolean expectedValues[] = new boolean[exprCount]; + + int exprIndex = 0; + dmcs[exprIndex] = fExpService.createExpression(frameDmc, "a"); + expectedValues[exprIndex] = true; + exprIndex++; + dmcs[exprIndex] = fExpService.createExpression(frameDmc, "b"); + expectedValues[exprIndex] = true; + exprIndex++; + dmcs[exprIndex] = fExpService.createExpression(frameDmc, "c"); + expectedValues[exprIndex] = false; + exprIndex++; + dmcs[exprIndex] = fExpService.createExpression(frameDmc, "d"); + expectedValues[exprIndex] = false; + exprIndex++; + dmcs[exprIndex] = fExpService.createExpression(frameDmc, "d[1]"); + expectedValues[exprIndex] = true; + exprIndex++; + + for (int index = 0; index < exprCount; index++) { + final int finalIndex = index; + wait.increment(); + fExpService.canWriteExpression( + dmcs[finalIndex], + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData() == expectedValues[finalIndex]) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed establishing proper canWrite for " + dmcs[finalIndex].getExpression() + + ", got " + getData() + " instead of " + expectedValues[finalIndex], null)); + } + + + } + }); + } + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + } + + /** + * This test verifies that we properly return if we can write to an expression + * that is an L-Value or a Constant + */ + @Ignore("Only works in versions later than GDB6.7") + @Test + public void testCanWriteLValue() throws Throwable { + MIStoppedEvent stoppedEvent = SyncUtil.SyncRunToLocation("testCanWrite"); // Re-use test + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + final int exprCount = 2; + final IExpressionDMContext dmcs[] = new IExpressionDMContext[exprCount]; + final boolean expectedValues[] = new boolean[exprCount]; + + int exprIndex = 0; + dmcs[exprIndex] = fExpService.createExpression(frameDmc, "&a"); + expectedValues[exprIndex] = false; + exprIndex++; + dmcs[exprIndex] = fExpService.createExpression(frameDmc, "1"); + expectedValues[exprIndex] = false; + exprIndex++; + + for (int index = 0; index < exprCount; index++) { + final int finalIndex = index; + wait.increment(); + fExpService.canWriteExpression( + dmcs[finalIndex], + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else if (getData() == expectedValues[finalIndex]) { + wait.waitFinished(); + } else { + wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Failed establishing proper canWrite for " + dmcs[finalIndex].getExpression() + + ", got " + getData() + " instead of " + expectedValues[finalIndex], null)); + } + + + } + }); + } + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + wait.waitReset(); + } + + /** + * Executes a group of sub-tests. + * + * @param tests: + * A Map in which the key is an expression to evaluate and the + * value is an array of expected values, one for each of the + * formats supported by the Expressions service (hex, octal, + * binary, decimal, natural). + */ + private void executeExpressionSubTests(final Map tests, IDMContext dmc) + throws Throwable + { + + // Now evaluate each of the above expressions and compare the actual + // value against + // the expected value. + for (final String expressionToEvaluate : tests.keySet()) { + + // Get an IExpressionDMContext object representing the expression to + // be evaluated. + final IExpressionDMContext exprDMC = SyncUtil.SyncCreateExpression(dmc, expressionToEvaluate); + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + // Get the list of available format IDs for this expression and for + // each one, + // get the value of the expression + fExpService.getExecutor().submit(new Runnable() { + public void run() { + fExpService.getAvailableFormats(exprDMC, new DataRequestMonitor( + fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + final String[] formatIds = getData(); + + // Now run the current sub-test using each of + // the formats available for the type of + // the expression in the sub-test. + + for (final String formatId : formatIds) { + // Get a FormattedValueCMContext object for + // the expression-formatID pair. + final FormattedValueDMContext valueDmc = fExpService.getFormattedValueContext( + exprDMC, formatId); + + // Increment the number of completed + // requests to wait for, since we will send + // multiple concurrent requests + wait.increment(); + + // Evaluate the expression represented by + // the FormattedValueDMContext object + // This actually evaluates the expression. + fExpService.getFormattedExpressionValue(valueDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + wait.waitFinished(getStatus()); + } else { + + // Get the + // FormattedValueDMData + // object from the waiter. + FormattedValueDMData exprValueDMData = getData(); + + final String[] expectedValues = tests.get(expressionToEvaluate); + + // Check the value of the + // expression for + // correctness. + String actualValue = exprValueDMData.getFormattedValue(); + String expectedValue; + + if (formatId.equals(IFormattedValues.HEX_FORMAT)) + expectedValue = expectedValues[0]; + else if (formatId.equals(IFormattedValues.OCTAL_FORMAT)) + expectedValue = expectedValues[1]; + else if (formatId.equals(IFormattedValues.BINARY_FORMAT)) + expectedValue = expectedValues[2]; + else if (formatId.equals(IFormattedValues.DECIMAL_FORMAT)) + expectedValue = expectedValues[3]; + else if (formatId.equals(IFormattedValues.NATURAL_FORMAT)) + expectedValue = expectedValues[4]; + else + expectedValue = "[Unrecognized format ID: " + formatId + "]"; + + if (actualValue.equalsIgnoreCase(expectedValue)) { + wait.waitFinished(); + } else { + String errorMsg = "Failed to correctly evalutate '" + + expressionToEvaluate + "': expected '" + expectedValue + + "', got '" + actualValue + "'"; + wait.waitFinished(new Status(IStatus.ERROR, + TestsPlugin.PLUGIN_ID, errorMsg, null)); + } + } + } + }); + } + } + } + }); + } + }); + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), + getExprChangedCount() == 0); + } + } + + private boolean addressesEqual(IExpressionDMAddress addrToTest, String addrStr, int size) { + IAddress addr; + if (addrStr.length() <= 10) { + addr = new Addr32(addrStr); + } else { + addr = new Addr64(addrStr); + } + return addrToTest.getAddress().equals(addr) && addrToTest.getSize() == size; + } + + private void checkAddressData(final IExpressionDMContext dmc, String actualAddrStr, int actualAddrSize) throws Throwable { + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + fExpService.getExpressionAddressData(dmc, new DataRequestMonitor(fExpService + .getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + wait.setReturnInfo(getData()); + } + + wait.waitFinished(getStatus()); + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + IExpressionDMAddress addr = (IExpressionDMAddress)wait.getReturnInfo(); + + assertTrue("Unable to get address", addr != null); + assertTrue("Received wrong address of " + addr.toString() + " instead of (" + + actualAddrStr + ", " + actualAddrSize + ")", + addressesEqual(addr, actualAddrStr, actualAddrSize)); + } + + private void doTestChildren(MIStoppedEvent stoppedEvent) throws Throwable { + + final IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(stoppedEvent.getDMContext(), 0); + + final IExpressionDMContext exprDMC = SyncUtil.SyncCreateExpression(frameDmc, "f"); + + IExpressionDMContext[] children = + getChildren(exprDMC, new String[] {"bar", "bar2", "a", "b", "c"}); + + // f.bar + IExpressionDMContext[] children1 = + getChildren(children[0], new String[] {"d", "e"}); + // f.bar.d + getChildren(children1[0], new String[0]); + // f.bar.e + IExpressionDMContext[] children2 = + getChildren(children1[1], new String[] {"e[0]", "e[1]"}); + // f.bar.e[0] + getChildren(children2[0], new String[0]); + // f.bar.e[1] + getChildren(children2[1], new String[0]); + + // f.bar2 + children1 = getChildren(children[1], new String[] {"f", "g"}); + // f.bar2.f + getChildren(children1[0], new String[0]); + // f.bar2.g + children2 = getChildren(children1[1], new String[] {"g[0]", "g[1]"}); + // f.bar2.g[0] + getChildren(children2[0], new String[0]); + // f.bar2.g[1] + getChildren(children2[1], new String[0]); + + // f.a + children1 = getChildren(children[2], new String[] {"a[0]", "a[1]"}); + // f.a[0] + getChildren(children1[0], new String[0]); + // f.a[1] + getChildren(children1[1], new String[0]); + + // f.b + children1 = getChildren(children[3], new String[] {"d", "e"}); + // f.b.d + getChildren(children1[0], new String[0]); + // f.b.e + children2 = getChildren(children1[1], new String[] {"e[0]", "e[1]"}); + // f.b.e[0] + getChildren(children2[0], new String[0]); + // f.b.e[1] + getChildren(children2[1], new String[0]); + + // f.c + getChildren(children[4], new String[0]); + + assertTrue("ExprChangedEvent problem: expected 0, received " + getExprChangedCount(), + getExprChangedCount() == 0); + } + + private IExpressionDMContext[] getChildren( + final IExpressionDMContext parentDmc, + String[] expectedValues) throws Throwable { + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fExpService.getExecutor().submit(new Runnable() { + public void run() { + + fExpService.getSubExpressions(parentDmc, + new DataRequestMonitor(fExpService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + wait.setReturnInfo(getData()); + } + wait.waitFinished(getStatus()); + } + }); + } + }); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + IExpressionDMContext[] childDmcs = + (IExpressionDMContext[]) wait.getReturnInfo(); + + String[] childExpressions = new String[childDmcs.length]; + MIExpressionDMCAccessor[] childDmcsAccessor = new MIExpressionDMCAccessor[childDmcs.length]; + + // Convert to a MIExpressionDMCAccessor to be able to call getRelativeExpression + // Also convert to String[] to be able to use Arrays.toString() + for (int i = 0; i < childExpressions.length; i++) { + childDmcsAccessor[i] = new MIExpressionDMCAccessor(childDmcs[i]); + childExpressions[i] = childDmcsAccessor[i].getRelativeExpression(); + } + assertTrue("Expected " + Arrays.toString(expectedValues) + " but got " + Arrays.toString(childExpressions), + expectedValues.length == childExpressions.length); + + for (int i = 0; i < childDmcsAccessor.length; i++) { + assertTrue("Expected: " + expectedValues[i] + " got: " + childDmcsAccessor[i].getRelativeExpression(), + childDmcsAccessor[i].getRelativeExpression().equals(expectedValues[i])); + } + + return childDmcs; + } +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/GDBProcessesTest.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/GDBProcessesTest.java new file mode 100644 index 00000000000..1f8fe3aba88 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/GDBProcessesTest.java @@ -0,0 +1,183 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson AB - Initial implementation of Test cases + *******************************************************************************/ +package org.eclipse.dd.tests.gdb; + + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.gdb.service.GDBRunControl; +import org.eclipse.dd.gdb.service.GDBRunControl.GDBProcessData; +import org.eclipse.dd.gdb.service.GDBRunControl.GDBThreadData; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.tests.gdb.framework.AsyncCompletionWaitor; +import org.eclipse.dd.tests.gdb.framework.BaseTestCase; +import org.eclipse.dd.tests.gdb.launching.TestsPlugin; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class GDBProcessesTest extends BaseTestCase { + /* + * Path to executable + */ + private static final String EXEC_PATH = "data/launch/bin/"; + /* + * Name of the executable + */ + private static final String EXEC_NAME = "MultiThread.exe"; + + + private DsfSession fSession; + private DsfServicesTracker fServicesTracker; + + private GDBControl fGdbCtrl; + private GDBRunControl fRunCtrl; + + /* + * Create a waiter and a generic completion object. They will be used to + * wait for asynchronous call completion. + */ + private final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); + + @Before + public void init() throws Exception { + fSession = getGDBLaunch().getSession(); + fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId()); + /* + * Get the GDBProcesses & MIRunControl service. + */ + fRunCtrl = fServicesTracker.getService(GDBRunControl.class); + fGdbCtrl = fServicesTracker.getService(GDBControl.class); + } + + @After + public void tearDown() { + fRunCtrl = null; + fServicesTracker.dispose(); + } + + @BeforeClass + public static void beforeClassMethod() { + setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, + EXEC_PATH + EXEC_NAME); + } + + @Test + /* + * Get the process data for the current program. Process is executable name in case of GDB back end + */ + public void getProcessData() throws InterruptedException{ + /* + * Create a request monitor + */ + final DataRequestMonitor rm = + new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + + /* + * Ask the service to get model data for the process. + * There is only one process in case of GDB back end. + */ + fSession.getExecutor().submit(new Runnable() { + public void run() { + fRunCtrl.getProcessData(fGdbCtrl.getGDBDMContext(), rm); + } + }); + /* + * Wait for the operation to get over + */ + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + /* + * Assert false if status is not OK + */ + Assert.assertTrue(fWait.getMessage(), fWait.isOK()); + + /* + * Get process data + */ + GDBProcessData processData = rm.getData(); + + if(processData == null) + Assert.fail("No process data is returned for Process DMC"); + else{ + /* + * Name of the process is the executable name in case of GDB back-end. + */ + assertEquals("Process data should be executable name " + EXEC_NAME, EXEC_NAME, processData.getName()); + } + } + + /* + * getThreadData() for multiple threads + */ + @Test + public void getThreadData() throws InterruptedException{ + final DataRequestMonitor rm = + new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + + /* + * Create an execution DMC + */ + final IMIExecutionDMContext dmc = fRunCtrl.createMIExecutionContext(fGdbCtrl.getGDBDMContext(), 1); + + /* + * getModelData for Execution DMC + */ + fRunCtrl.getExecutor().submit(new Runnable() { + public void run() { + fRunCtrl.getThreadData(dmc, rm); + } + }); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + GDBThreadData threadData = rm.getData(); + if(threadData == null) + fail("Thread data not returned for thread id = " + dmc.getThreadId()); + else{ + // Thread id is only a series of numbers + Pattern pattern = Pattern.compile("\\d*", Pattern.MULTILINE); //$NON-NLS-1$ + Matcher matcher = pattern.matcher(threadData.getId()); + assertTrue("Thread ID is a series of number", matcher.find()); + // Name is blank in case of GDB back end + assertEquals("Thread name is blank for GDB Back end", "", threadData.getName()); + } + fWait.waitReset(); + } +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIBreakpointsTest.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIBreakpointsTest.java new file mode 100644 index 00000000000..b54c70b9c04 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIBreakpointsTest.java @@ -0,0 +1,2762 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial Implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IBreakpoints; +import org.eclipse.dd.dsf.debug.service.IExpressions; +import org.eclipse.dd.dsf.debug.service.IFormattedValues; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointDMContext; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointDMData; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsAddedEvent; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsRemovedEvent; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsUpdatedEvent; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.gdb.service.command.GDBControlDMContext; +import org.eclipse.dd.mi.service.MIBreakpointDMData; +import org.eclipse.dd.mi.service.MIBreakpoints; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.MIBreakpoints.MIBreakpointDMContext; +import org.eclipse.dd.mi.service.command.events.MIBreakpointHitEvent; +import org.eclipse.dd.mi.service.command.events.MIWatchpointScopeEvent; +import org.eclipse.dd.mi.service.command.events.MIWatchpointTriggerEvent; +import org.eclipse.dd.tests.gdb.framework.AsyncCompletionWaitor; +import org.eclipse.dd.tests.gdb.framework.BackgroundRunner; +import org.eclipse.dd.tests.gdb.framework.BaseTestCase; +import org.eclipse.dd.tests.gdb.framework.SyncUtil; +import org.eclipse.dd.tests.gdb.launching.TestsPlugin; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +/* + * This is the Breakpoint Service test suite. + * + * It is meant to be a regression suite to be executed automatically against + * the DSF nightly builds. + * + * It is also meant to be augmented with a proper test case(s) every time a + * feature is added or in the event (unlikely :-) that a bug is found in the + * Breakpoint Service. + * + * Refer to the JUnit4 documentation for an explanation of the annotations. + */ + +@RunWith(BackgroundRunner.class) +public class MIBreakpointsTest extends BaseTestCase { + + // Global constants + public static final String PLUGIN_ID = "org.eclipse.cdt.debug.core" ; //$NON-NLS-1$ + public static final String TEST_APPL = "data/launch/bin/BreakpointTestApp.exe"; //$NON-NLS-1$ + public static final String SOURCE_PATH = "data/launch/src"; //$NON-NLS-1$ + + public static final String SOURCE_PROJECT = "MIBreakpointsTest"; + public static final String SOURCE_FOLDER = "src"; + public static final String SOURCE_FILE = "BreakpointTestApp.cc"; //$NON-NLS-1$ + + // Asynchronous Completion + private final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); + + // Services references + private DsfSession fSession; + private GDBControlDMContext fGdbControlDmc; + private DsfServicesTracker fServicesTracker; + private MIRunControl fRunControl; + private IBreakpoints fBreakpointService; + + // Event Management + private static Boolean lock = true; + enum Events { BP_ADDED, BP_UPDATED, BP_REMOVED, BP_HIT, WP_HIT, WP_OOS } + final int BP_ADDED = Events.BP_ADDED.ordinal(); + final int BP_UPDATED = Events.BP_UPDATED.ordinal(); + final int BP_REMOVED = Events.BP_REMOVED.ordinal(); + final int BP_HIT = Events.BP_HIT.ordinal(); + final int WP_HIT = Events.WP_HIT.ordinal(); + final int WP_OOS = Events.WP_OOS.ordinal(); + private int[] fBreakpointEvents = new int[Events.values().length]; + private boolean fBreakpointEvent; + private int fBreakpointEventCount; + private int fBreakpointRef; + + // Some useful constants + final String BREAKPOINT_TYPE_TAG = MIBreakpoints.BREAKPOINT_TYPE; + final String BREAKPOINT_TAG = MIBreakpoints.BREAKPOINT; + final String WATCHPOINT_TAG = MIBreakpoints.WATCHPOINT; + + final String FILE_NAME_TAG = MIBreakpoints.FILE_NAME; + final String LINE_NUMBER_TAG = MIBreakpoints.LINE_NUMBER; + final String FUNCTION_TAG = MIBreakpoints.FUNCTION; + final String ADDRESS_TAG = MIBreakpoints.ADDRESS; + final String CONDITION_TAG = MIBreakpoints.CONDITION; + final String IGNORE_COUNT_TAG = MIBreakpoints.IGNORE_COUNT; + final String IS_ENABLED_TAG = MIBreakpoints.IS_ENABLED; + final String THREAD_ID_TAG = MIBreakpointDMData.THREAD_ID; + final String NUMBER_TAG = MIBreakpointDMData.NUMBER; + + final String EXPRESSION_TAG = MIBreakpoints.EXPRESSION; + final String READ_TAG = MIBreakpoints.READ; + final String WRITE_TAG = MIBreakpoints.WRITE; + + // Target application 'special' locations + private final int LINE_NUMBER_1 = 20; + private final int LINE_NUMBER_2 = 21; + private final int LINE_NUMBER_3 = 27; + private final int LINE_NUMBER_4 = 35; + private final String FUNCTION = "zeroBlocks"; + private final String SIGNED_FUNCTION = "zeroBlocks(int)"; + private final String NO_CONDITION = ""; + + // NOTE: The back-end can reformat the condition. In order for the + // comparison to work, better specify the condition as the back-end + // would have it. + private final String CONDITION_1 = "i == 128"; + private final String CONDITION_2 = "i == 64"; + private final String CONDITION_3 = "j == 20"; + private final int IGNORE_COUNT_1 = 128; + private final int IGNORE_COUNT_2 = 20; + + private final String EXPRESSION_1 = "charBlock[20]"; + private final String EXPRESSION_2 = "j"; + + // Error messages + final String UNKNOWN_EXECUTION_CONTEXT = "Unknown execution context"; + final String INVALID_BREAKPOINT_LOCATION = "Invalid breakpoint location"; + final String BREAKPOINT_INSERTION_FAILURE = "Breakpoint insertion failure"; + final String UNKNOWN_BREAKPOINT = "Unknown breakpoint"; + + // ======================================================================== + // Housekeeping stuff + // ======================================================================== + + @BeforeClass + public static void testSuiteInitialization() { + // Select the binary to run the tests against + setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, TEST_APPL); + setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, SOURCE_PATH); + } + + @AfterClass + public static void testSuiteCleanup() { + } + + @Before + public void testCaseInitialization() { + + // Get a reference to the breakpoint service + fSession = getGDBLaunch().getSession(); + fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId()); + assert(fServicesTracker != null); + + GDBControl gdbControl = fServicesTracker.getService(GDBControl.class); + fGdbControlDmc = gdbControl.getGDBDMContext(); + assert(fGdbControlDmc != null); + + fRunControl = fServicesTracker.getService(MIRunControl.class); + assert(fRunControl != null); + + fBreakpointService = fServicesTracker.getService(IBreakpoints.class); + assert(fBreakpointService != null); + + // Register to breakpoint events + fRunControl.getSession().addServiceEventListener(MIBreakpointsTest.this, null); + + clearEventCounters(); + } + + @After + public void testCaseCleanup() { + + // Clear the references (not strictly necessary) + fRunControl.getSession().removeServiceEventListener(MIBreakpointsTest.this); + fBreakpointService = null; + fRunControl = null; + fServicesTracker = null; + + clearEventCounters(); + } + + // ======================================================================== + // Event Management Functions + // ======================================================================== + + /* ----------------------------------------------------------------------- + * eventDispatched + * ------------------------------------------------------------------------ + * Processes BreakpointHitEvent. + * ------------------------------------------------------------------------ + * @param e The BreakpointEvent + * ------------------------------------------------------------------------ + */ + @DsfServiceEventHandler + public void eventDispatched(IBreakpointsAddedEvent e) { + synchronized (lock) { + fBreakpointEvents[BP_ADDED]++; + fBreakpointEventCount++; + fBreakpointRef = ((MIBreakpointDMContext) e.getBreakpoints()[0]).getReference(); + fBreakpointEvent = true; + lock.notifyAll(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(IBreakpointsUpdatedEvent e) { + synchronized (lock) { + fBreakpointEvents[BP_UPDATED]++; + fBreakpointEventCount++; + fBreakpointRef = ((MIBreakpointDMContext) e.getBreakpoints()[0]).getReference(); + fBreakpointEvent = true; + lock.notifyAll(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(IBreakpointsRemovedEvent e) { + synchronized (lock) { + fBreakpointEvents[BP_REMOVED]++; + fBreakpointEventCount++; + fBreakpointRef = ((MIBreakpointDMContext) e.getBreakpoints()[0]).getReference(); + fBreakpointEvent = true; + lock.notifyAll(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(MIBreakpointHitEvent e) { + synchronized (lock) { + fBreakpointEvents[BP_HIT]++; + fBreakpointEventCount++; + fBreakpointRef = e.getNumber(); + fBreakpointEvent = true; + lock.notifyAll(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(MIWatchpointTriggerEvent e) { + synchronized (lock) { + fBreakpointEvents[WP_HIT]++; + fBreakpointEventCount++; + fBreakpointRef = e.getNumber(); + fBreakpointEvent = true; + lock.notifyAll(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(MIWatchpointScopeEvent e) { + synchronized (lock) { + fBreakpointEvents[WP_OOS]++; + fBreakpointEventCount++; + fBreakpointRef = e.getNumber(); + fBreakpointEvent = true; + lock.notifyAll(); + } + } + + // Clears the counters + private void clearEventCounters() { + synchronized (lock) { + for (int i = 0; i < fBreakpointEvents.length; i++) { + fBreakpointEvents[i] = 0; + } + fBreakpointEvent = false; + fBreakpointEventCount = 0; + } + } + + // Get the breakpoint hit count + private int getBreakpointEventCount(int event) { + int count = 0; + synchronized (lock) { + count = fBreakpointEvents[event]; + } + return count; + } + + // Suspends the thread until an event is flagged + // NOTE: too simple for real life but good enough for this test suite + private void waitForBreakpointEvent() { + synchronized (lock) { + while (!fBreakpointEvent) { + try { + lock.wait(); + } catch (InterruptedException ex) { + } + } + fBreakpointEvent = false; + } + } + + // ======================================================================== + // Helper Functions + // ======================================================================== + + /* ------------------------------------------------------------------------ + * evaluateExpression + * ------------------------------------------------------------------------ + * Invokes the ExpressionService to evaluate an expression. In theory, + * we shouldn't rely on another service to test this one but we need a + * way to access a variable from the test application in order verify + * that the memory operations (read/write) are working properly. + * ------------------------------------------------------------------------ + * @param expression Expression to resolve @return Resolved expression + * @throws InterruptedException + * ------------------------------------------------------------------------ + */ + private BigInteger evaluateExpression(String expression) throws Throwable { + + final IExpressions fExpressionService = fServicesTracker.getService(IExpressions.class); + assert (fExpressionService != null); + + // Get a stack context (temporary - should be an MIcontainerDMC) + final IExpressionDMContext expressionDMC = SyncUtil.SyncCreateExpression(fGdbControlDmc, expression); + final FormattedValueDMContext formattedValueDMC = SyncUtil.SyncGetFormattedValue(fExpressionService, + expressionDMC, IFormattedValues.DECIMAL_FORMAT); + + // Create the DataRequestMonitor which will store the operation result in the wait object + final DataRequestMonitor drm = + new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + + // Evaluate the expression (asynchronously) + fWait.waitReset(); + fSession.getExecutor().submit(new Runnable() { + public void run() { + fExpressionService.getFormattedExpressionValue(formattedValueDMC, drm); + } + }); + + // Wait for completion + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Return the string formatted by the back-end + String result = ""; + Object returnInfo = fWait.getReturnInfo(); + if (returnInfo instanceof FormattedValueDMData) + result = ((FormattedValueDMData) returnInfo).getFormattedValue(); + return new BigInteger(result); + } + + /* ------------------------------------------------------------------------ + * getBreakpoints + * ------------------------------------------------------------------------ + * Retrieves the installed breakpoints list + * ------------------------------------------------------------------------ + * Typical usage: + * IBreakpointDMContext[] breakpoints = getBreakpoints(context); + * ------------------------------------------------------------------------ + * @param context the execution context + * ------------------------------------------------------------------------ + */ + private IBreakpointDMContext[] getBreakpoints(final IBreakpointsTargetDMContext context) throws InterruptedException + { + // Clear the completion waiter + fWait.waitReset(); + + // Set the Request Monitor + final DataRequestMonitor drm = + new DataRequestMonitor(fBreakpointService.getExecutor(), null) { + @Override + protected void handleCompleted() { + fWait.waitFinished(getStatus()); + } + }; + + // Issue the breakpoint request + fWait.waitReset(); + fBreakpointService.getExecutor().submit(new Runnable() { + public void run() { + fBreakpointService.getBreakpoints(context, drm); + } + }); + + // Wait for completion + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Return the string formatted by the back-end + return drm.getData(); + } + + /* ------------------------------------------------------------------------ + * getBreakpoint + * ------------------------------------------------------------------------ + * Retrieves the installed breakpoint + * ------------------------------------------------------------------------ + * Typical usage: + * IBreakpointDMContext breakpoint = ...; + * IBreakpointDMData bp = getBreakpoint(breakpoint); + * ------------------------------------------------------------------------ + * @param breakpoint the breakpoint to retrieve + * ------------------------------------------------------------------------ + */ + private IBreakpointDMData getBreakpoint(final IBreakpointDMContext breakpoint) throws InterruptedException + { + // Clear the completion waiter + fWait.waitReset(); + + // Set the Request Monitor + final DataRequestMonitor drm = + new DataRequestMonitor(fBreakpointService.getExecutor(), null) { + @Override + protected void handleCompleted() { + fWait.waitFinished(getStatus()); + } + }; + + // Issue the breakpoint request + fWait.waitReset(); + fBreakpointService.getExecutor().submit(new Runnable() { + public void run() { + fBreakpointService.getBreakpointDMData(breakpoint, drm); + } + }); + + // Wait for completion + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Return the string formatted by the back-end + return drm.getData(); + } + + /* ------------------------------------------------------------------------ + * insertBreakpoint + * ------------------------------------------------------------------------ + * Issues an add breakpoint request. + * ------------------------------------------------------------------------ + * Typical usage: + * bp = insertBreakpoint(context, attributes); + * assertTrue(fWait.getMessage(), fWait.isOK()); + * ------------------------------------------------------------------------ + * @param context the execution context + * @param attributes the breakpoint attributes + * ------------------------------------------------------------------------ + */ + private IBreakpointDMContext insertBreakpoint(final IBreakpointsTargetDMContext context, + final Map attributes) throws InterruptedException + { + // Clear the completion waiter + fWait.waitReset(); + + // Set the Request Monitor + final DataRequestMonitor drm = + new DataRequestMonitor(fBreakpointService.getExecutor(), null) { + @Override + protected void handleCompleted() { + fWait.waitFinished(getStatus()); + } + }; + + // Issue the remove breakpoint request + fBreakpointService.getExecutor().submit(new Runnable() { + public void run() { + fBreakpointService.insertBreakpoint(context, attributes, drm); + } + }); + + // Wait for the result and return the breakpoint id + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + return drm.getData(); + } + + /* ------------------------------------------------------------------------ + * removeBreakpoint + * ------------------------------------------------------------------------ + * Issues a remove breakpoint request. + * ------------------------------------------------------------------------ + * Typical usage: + * IBreakpointDMContext breakpoint = ...; + * removeBreakpoint(context, breakpoint); + * assertTrue(fWait.getMessage(), fWait.isOK()); + * ------------------------------------------------------------------------ + * @param breakpoint the breakpoint to remove + * ------------------------------------------------------------------------ + */ + private void removeBreakpoint(final IBreakpointDMContext breakpoint) throws InterruptedException + { + // Clear the completion waiter + fWait.waitReset(); + + // Set the Request Monitor + final RequestMonitor rm = + new RequestMonitor(fBreakpointService.getExecutor(), null) { + @Override + protected void handleCompleted() { + fWait.waitFinished(getStatus()); + } + }; + + // Issue the add breakpoint request + fBreakpointService.getExecutor().submit(new Runnable() { + public void run() { + fBreakpointService.removeBreakpoint(breakpoint, rm); + } + }); + + // Wait for the result + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + } + + /* ------------------------------------------------------------------------ + * updateBreakpoint + * ------------------------------------------------------------------------ + * Issues an update breakpoint request. + * ------------------------------------------------------------------------ + * Typical usage: + * updateBreakpoint(context, breakpoint, properties); + * assertTrue(fWait.getMessage(), fWait.isOK()); + * ------------------------------------------------------------------------ + * @param breakpoint the breakpoint to update + * @param delta the delta properties + * ------------------------------------------------------------------------ + */ + private void updateBreakpoint(final IBreakpointDMContext breakpoint, + final Map delta) throws InterruptedException + { + // Clear the completion waiter + fWait.waitReset(); + + // Set the Request Monitor + final RequestMonitor rm = + new RequestMonitor(fBreakpointService.getExecutor(), null) { + @Override + protected void handleCompleted() { + fWait.waitFinished(getStatus()); + } + }; + + // Issue the update breakpoint request + fBreakpointService.getExecutor().submit(new Runnable() { + public void run() { + fBreakpointService.updateBreakpoint(breakpoint, delta, rm); + } + }); + + // Wait for the result + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + } + + // ======================================================================== + // Test Cases + // ------------------------------------------------------------------------ + // Templates: + // ------------------------------------------------------------------------ + // @Test + // public void basicTest() { + // // First test to run + // assertTrue("", true); + // } + // ------------------------------------------------------------------------ + // @Test(timeout=5000) + // public void timeoutTest() { + // // Second test to run, which will timeout if not finished on time + // assertTrue("", true); + // } + // ------------------------------------------------------------------------ + // @Test(expected=FileNotFoundException.class) + // public void exceptionTest() throws FileNotFoundException { + // // Third test to run which expects an exception + // throw new FileNotFoundException("Just testing"); + // } + // ======================================================================== + + /////////////////////////////////////////////////////////////////////////// + // Add Breakpoint tests + /////////////////////////////////////////////////////////////////////////// + + // ------------------------------------------------------------------------ + // insertBreakpoint_InvalidContext + // ------------------------------------------------------------------------ + // @Test + public void insertBreakpoint_InvalidContext() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Perform the test + String expected = UNKNOWN_EXECUTION_CONTEXT; + insertBreakpoint(null, breakpoint); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure that no BreakpointEvent was received + assertTrue("BreakpointEvent problem: expected " + 0 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 0); + } + + // ------------------------------------------------------------------------ + // insertBreakpoint_InvalidFileName + // ------------------------------------------------------------------------ + // @Test + public void insertBreakpoint_InvalidFileName() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE + "_bad"); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Perform the test + String expected = BREAKPOINT_INSERTION_FAILURE; + insertBreakpoint(fGdbControlDmc, breakpoint); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure that no BreakpointEvent was received + assertTrue("BreakpointEvent problem: expected " + 0 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 0); + } + + // ------------------------------------------------------------------------ + // insertBreakpoint_InvalidLineNumber + // ------------------------------------------------------------------------ + // @Test + public void insertBreakpoint_InvalidLineNumber() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, 0); + + // Perform the test + String expected = BREAKPOINT_INSERTION_FAILURE; + insertBreakpoint(fGdbControlDmc, breakpoint); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure that no BreakpointEvent was received + assertTrue("BreakpointEvent problem: expected " + 0 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 0); + } + + // ------------------------------------------------------------------------ + // insertBreakpoint_InvalidFunctionName + // ------------------------------------------------------------------------ + // @Test + public void insertBreakpoint_InvalidFunctionName() throws Throwable { + + // Create a function breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(FUNCTION_TAG, "invalid-function-name"); + + // Perform the test + String expected = BREAKPOINT_INSERTION_FAILURE; + insertBreakpoint(fGdbControlDmc, breakpoint); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure that no BreakpointEvent was received + assertTrue("BreakpointEvent problem: expected " + 0 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 0); + } + + // ------------------------------------------------------------------------ + // insertBreakpoint_InvalidAddress + // ------------------------------------------------------------------------ + // @Test + public void insertBreakpoint_InvalidAddress() throws Throwable { + + // Create an address breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(ADDRESS_TAG, "0x0"); + + // Perform the test + String expected = BREAKPOINT_INSERTION_FAILURE; + insertBreakpoint(fGdbControlDmc, breakpoint); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure that no BreakpointEvent was received + assertTrue("BreakpointEvent problem: expected " + 0 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 0); + } + + // ------------------------------------------------------------------------ + // insertBreakpoint_LineNumber + // Set a breakpoint on a line number. + // Ensure that it is set correctly at the back-end. + // ------------------------------------------------------------------------ + // @Test + public void insertBreakpoint_LineNumber() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Perform the test + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure that the breakpoint was correctly installed + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong file name)", + breakpoint1.getFileName().equals(SOURCE_FILE)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong line number)", + breakpoint1.getLineNumber() == LINE_NUMBER_1); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong condition)", + breakpoint1.getCondition().equals(NO_CONDITION)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong ignore count)", + breakpoint1.getIgnoreCount() == 0); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong state)", + breakpoint1.isEnabled()); + + // Ensure the BreakpointService holds only the right breakpoints + IBreakpointDMContext[] breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 1 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 1); + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(breakpoints[0]); + assertTrue("BreakpointService problem: breakpoint mismatch", + breakpoint1.equals(breakpoint2)); + } + + // ------------------------------------------------------------------------ + // insertBreakpoint_Disabled + // Set a disabled breakpoint on a line number. + // Ensure that it is set correctly at the back-end. + // ------------------------------------------------------------------------ + // @Test + public void insertBreakpoint_Disabled() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + breakpoint.put(IS_ENABLED_TAG, false); + + // Perform the test + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure that the breakpoint was correctly installed + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong file name)", + breakpoint1.getFileName().equals(SOURCE_FILE)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong line number)", + breakpoint1.getLineNumber() == LINE_NUMBER_1); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong condition)", + breakpoint1.getCondition().equals(NO_CONDITION)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong ignore count)", + breakpoint1.getIgnoreCount() == 0); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong state)", + !breakpoint1.isEnabled()); + + // Ensure the BreakpointService holds only the right breakpoints + IBreakpointDMContext[] breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 1 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 1); + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(breakpoints[0]); + assertTrue("BreakpointService problem: breakpoint mismatch", + breakpoint1.equals(breakpoint2)); + } + + // ------------------------------------------------------------------------ + // insertBreakpoint_FunctionName + // Set a breakpoint on a function name. + // Ensure that it is set correctly at the back-end. + // ------------------------------------------------------------------------ + // @Test + public void insertBreakpoint_FunctionName() throws Throwable { + + // Create a function breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(FUNCTION_TAG, FUNCTION); + + // Perform the test + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure that the breakpoint was correctly installed + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong file name)", + breakpoint1.getFileName().equals(SOURCE_FILE)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong function)", + breakpoint1.getFunctionName().equals(SIGNED_FUNCTION)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong condition)", + breakpoint1.getCondition().equals(NO_CONDITION)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong ignore count)", + breakpoint1.getIgnoreCount() == 0); + + // Ensure the BreakpointService holds only the right breakpoints + IBreakpointDMContext[] breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 1 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 1); + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(breakpoints[0]); + assertTrue("BreakpointService problem: breakpoint mismatch", + breakpoint1.equals(breakpoint2)); + } + + // ------------------------------------------------------------------------ + // insertBreakpoint_Condition + // Set a conditional breakpoint. + // Ensure that it is set correctly at the back-end. + // ------------------------------------------------------------------------ + // @Test + public void insertBreakpoint_Condition() throws Throwable { + + // Create a conditional line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + breakpoint.put(CONDITION_TAG, CONDITION_1); + + // Perform the test + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure that the breakpoint was correctly installed + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong file name)", + breakpoint1.getFileName().equals(SOURCE_FILE)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong line number)", + breakpoint1.getLineNumber() == LINE_NUMBER_1); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong condition)", + breakpoint1.getCondition().equals(CONDITION_1)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong ignore count)", + breakpoint1.getIgnoreCount() == 0); + + // Ensure the BreakpointService holds only the right breakpoints + IBreakpointDMContext[] breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 1 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 1); + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(breakpoints[0]); + assertTrue("BreakpointService problem: breakpoint mismatch", + breakpoint1.equals(breakpoint2)); + } + + // ------------------------------------------------------------------------ + // insertBreakpoint_IgnoreCnt + // Set a breakpoint with an ignore count. + // Ensure that it is set correctly at the back-end. + // ------------------------------------------------------------------------ + @Test + public void insertBreakpoint_IgnoreCnt() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + breakpoint.put(IGNORE_COUNT_TAG, IGNORE_COUNT_1); + + // Perform the test + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure that the breakpoint was correctly installed + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong file name)", + breakpoint1.getFileName().equals(SOURCE_FILE)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong line number)", + breakpoint1.getLineNumber() == LINE_NUMBER_1); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong condition)", + breakpoint1.getCondition().equals(NO_CONDITION)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong ignore count)", + breakpoint1.getIgnoreCount() == IGNORE_COUNT_1); + + // Ensure the BreakpointService holds only the right breakpoints + IBreakpointDMContext[] breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 1 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 1); + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(breakpoints[0]); + assertTrue("BreakpointService problem: breakpoint mismatch", + breakpoint1.equals(breakpoint2)); + } + + // ------------------------------------------------------------------------ + // insertBreakpoint_MultipleBreakpoints + // Set multiple distinct breakpoints. + // Ensure that the state is kosher. + // ------------------------------------------------------------------------ + // @Test + public void insertBreakpoint_MultipleBreakpoints() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Perform the test + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure that the breakpoint was correctly installed + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong file name)", + breakpoint1.getFileName().equals(SOURCE_FILE)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong line number)", + breakpoint1.getLineNumber() == LINE_NUMBER_1); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong condition)", + breakpoint1.getCondition().equals(NO_CONDITION)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong ignore count)", + breakpoint1.getIgnoreCount() == 0); + + // Create a function breakpoint + breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(FUNCTION_TAG, FUNCTION); + + // Perform the test + ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure that the breakpoint was correctly installed + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong file name)", + breakpoint2.getFileName().equals(SOURCE_FILE)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong function)", + breakpoint2.getFunctionName().equals(SIGNED_FUNCTION)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong condition)", + breakpoint2.getCondition().equals(NO_CONDITION)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong ignore count)", + breakpoint2.getIgnoreCount() == 0); + + // Ensure the BreakpointService holds only the right breakpoints + IBreakpointDMContext[] breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 2 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 2); + MIBreakpointDMData svc_bp1 = (MIBreakpointDMData) getBreakpoint(breakpoints[0]); + MIBreakpointDMData svc_bp2 = (MIBreakpointDMData) getBreakpoint(breakpoints[1]); + + // The breakpoint references are not necessarily retrieved in the order the + // breakpoints were initially set... + int ref1 = breakpoint1.getNumber(); + int ref2 = svc_bp1.getNumber(); + if (ref1 == ref2) { + assertTrue("BreakpointService problem: breakpoint mismatch", svc_bp1.equals(breakpoint1)); + assertTrue("BreakpointService problem: breakpoint mismatch", svc_bp2.equals(breakpoint2)); + } else { + assertTrue("BreakpointService problem: breakpoint mismatch", svc_bp1.equals(breakpoint2)); + assertTrue("BreakpointService problem: breakpoint mismatch", svc_bp2.equals(breakpoint1)); + } + } + + // ------------------------------------------------------------------------ + // insertBreakpoint_Duplicate + // Set 2 identical breakpoints. + // For GDB, no problem... + // ------------------------------------------------------------------------ + // @Test + public void insertBreakpoint_Duplicate() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Perform the test + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure that the breakpoint was correctly installed + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong file name)", + breakpoint1.getFileName().equals(SOURCE_FILE)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong line number)", + breakpoint1.getLineNumber() == LINE_NUMBER_1); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong condition)", + breakpoint1.getCondition().equals(NO_CONDITION)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong ignore count)", + breakpoint1.getIgnoreCount() == 0); + + // Create a second line breakpoint, same attributes... + ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure that the breakpoint was correctly installed + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong file name)", + breakpoint2.getFileName().equals(SOURCE_FILE)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong line number)", + breakpoint2.getLineNumber() == LINE_NUMBER_1); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong condition)", + breakpoint2.getCondition().equals(NO_CONDITION)); + assertTrue("BreakpointService problem: breakpoint mismatch (wrong ignore count)", + breakpoint2.getIgnoreCount() == 0); + + // Ensure the BreakpointService holds only the right breakpoints + IBreakpointDMContext[] breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 2 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 2); + MIBreakpointDMData svc_bp1 = (MIBreakpointDMData) getBreakpoint(breakpoints[0]); + MIBreakpointDMData svc_bp2 = (MIBreakpointDMData) getBreakpoint(breakpoints[1]); + + // The breakpoint references are not necessarily retrieved in the order the + // breakpoints were initially set... + int ref1 = breakpoint1.getNumber(); + int ref2 = svc_bp1.getNumber(); + if (ref1 == ref2) { + assertTrue("BreakpointService problem: breakpoint mismatch", svc_bp1.equals(breakpoint1)); + assertTrue("BreakpointService problem: breakpoint mismatch", svc_bp2.equals(breakpoint2)); + } else { + assertTrue("BreakpointService problem: breakpoint mismatch", svc_bp1.equals(breakpoint2)); + assertTrue("BreakpointService problem: breakpoint mismatch", svc_bp2.equals(breakpoint1)); + } + } + + /////////////////////////////////////////////////////////////////////////// + // Add Watchpoint tests + /////////////////////////////////////////////////////////////////////////// + + // ------------------------------------------------------------------------ + // insertWatchpoint_Write + // Set a write watchpoint. + // Ensure that the state is kosher. + // ------------------------------------------------------------------------ + // @Test + public void insertWatchpoint_Write() throws Throwable { + + // Create a write watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_1); + watchpoint.put(WRITE_TAG, true); + + // Perform the test + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure that the watchpoint was correctly installed + MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong expression)", + watchpoint1.getExpression().equals(EXPRESSION_1)); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong read state)", + !watchpoint1.isReadWatchpoint()); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong write state)", + watchpoint1.isWriteWatchpoint()); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong access state)", + !watchpoint1.isAccessWatchpoint()); + + // Ensure the BreakpointService holds only the right watchpoints + IBreakpointDMContext[] watchpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 1 + " watchpoints(s), received " + + watchpoints.length, watchpoints.length == 1); + MIBreakpointDMData watchpoint2 = (MIBreakpointDMData) getBreakpoint(watchpoints[0]); + assertTrue("BreakpointService problem: breakpoint mismatch", + watchpoint1.equals(watchpoint2)); + } + + // ------------------------------------------------------------------------ + // insertWatchpoint_Read + // Set a read watchpoint. + // Ensure that the state is kosher. + // ------------------------------------------------------------------------ + // @Test + public void insertWatchpoint_Read() throws Throwable { + + // Create a read watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_1); + watchpoint.put(READ_TAG, true); + + // Perform the test + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure that the watchpoint was correctly installed + MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong expression)", + watchpoint1.getExpression().equals(EXPRESSION_1)); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong read state)", + watchpoint1.isReadWatchpoint()); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong write state)", + !watchpoint1.isWriteWatchpoint()); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong access state)", + !watchpoint1.isAccessWatchpoint()); + + // Ensure the BreakpointService holds only the right watchpoints + IBreakpointDMContext[] watchpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 1 + " watchpoints(s), received " + + watchpoints.length, watchpoints.length == 1); + MIBreakpointDMData watchpoint2 = (MIBreakpointDMData) getBreakpoint(watchpoints[0]); + assertTrue("BreakpointService problem: breakpoint mismatch", + watchpoint1.equals(watchpoint2)); + } + + // ------------------------------------------------------------------------ + // insertWatchpoint_Access + // Set an access watchpoint. + // Ensure that the state is kosher. + // ------------------------------------------------------------------------ + // @Test + public void insertWatchpoint_Access() throws Throwable { + + // Create an access watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_1); + watchpoint.put(READ_TAG, true); + watchpoint.put(WRITE_TAG, true); + + // Perform the test + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure that the watchpoint was correctly installed + MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong expression)", + watchpoint1.getExpression().equals(EXPRESSION_1)); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong read state)", + !watchpoint1.isReadWatchpoint()); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong write state)", + !watchpoint1.isWriteWatchpoint()); + assertTrue("BreakpointService problem: watchpoint mismatch (wrong access state)", + watchpoint1.isAccessWatchpoint()); + + // Ensure the BreakpointService holds only the right watchpoints + IBreakpointDMContext[] watchpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 1 + " watchpoints(s), received " + + watchpoints.length, watchpoints.length == 1); + MIBreakpointDMData watchpoint2 = (MIBreakpointDMData) getBreakpoint(watchpoints[0]); + assertTrue("BreakpointService problem: breakpoint mismatch", + watchpoint1.equals(watchpoint2)); + } + + /////////////////////////////////////////////////////////////////////////// + // Remove Breakpoint tests + /////////////////////////////////////////////////////////////////////////// + + // ------------------------------------------------------------------------ + // removeBreakpoint_SimpleCase + // Set a breakpoint and then remove it. + // Ensure that the state is kosher. + // ------------------------------------------------------------------------ + // @Test + public void removeBreakpoint_SimpleCase() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Install the breakpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Remove the installed breakpoint + removeBreakpoint(ref); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_REMOVED event(s), received " + + getBreakpointEventCount(BP_REMOVED), getBreakpointEventCount(BP_REMOVED) == 1); + clearEventCounters(); + + // Ensure the breakpoint was effectively removed + IBreakpointDMContext[] breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 0 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 0); + } + + // ------------------------------------------------------------------------ + // removeBreakpoint_InvalidBreakpoint + // Try removing a non-existing breakpoint. + // ------------------------------------------------------------------------ + // @Test + public void removeBreakpoint_InvalidBreakpoint() throws Throwable { + + // Create an invalid breakpoint reference + IBreakpointDMContext invalid_ref = + new MIBreakpointDMContext((MIBreakpoints) fBreakpointService, new IDMContext[] { fGdbControlDmc }, 0); + + // Remove the invalid breakpoint + String expected = UNKNOWN_BREAKPOINT; + removeBreakpoint(invalid_ref); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure that right BreakpointEvents were received + assertTrue("BreakpointEvent problem: expected " + 0 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 0); + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Install the breakpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + IBreakpointDMContext saved_ref = ref; + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Ensure the breakpoint list is OK + IBreakpointDMContext[] breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 1 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 1); + + // Remove the installed breakpoint + removeBreakpoint(ref); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_REMOVED event(s), received " + + getBreakpointEventCount(BP_REMOVED), getBreakpointEventCount(BP_REMOVED) == 1); + clearEventCounters(); + + // Ensure the breakpoint list is OK + breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 0 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 0); + + // Remove the un-installed breakpoint + removeBreakpoint(saved_ref); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure that right BreakpointEvents were received + assertTrue("BreakpointEvent problem: expected " + 0 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 0); + + // Ensure the breakpoint list is OK + breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 0 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 0); + + // Re-install the breakpoint + ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Remove an un-installed breakpoint (again) + removeBreakpoint(saved_ref); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure that right BreakpointEvents were received + assertTrue("BreakpointEvent problem: expected " + 0 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 0); + + // Ensure that the existing breakpoint is unaffected + breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 1 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 1); + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(breakpoints[0]); + assertTrue("BreakpointService problem: breakpoint mismatch", + breakpoint1.equals(breakpoint2)); + } + + // ------------------------------------------------------------------------ + // removeBreakpoint_MixedCase + // Set a number of breakpoints and then remove them in disorder. + // Ensure that the right breakpoints are left after each iteration. + // ------------------------------------------------------------------------ + // @Test + public void removeBreakpoint_MixedCase() throws Throwable { + + // Create a line breakpoint + for (int i = 0; i < 4; i++) { + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1 + i); + insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + int expected = i + 1; + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + expected + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == expected); + assertTrue("BreakpointEvent problem: expected " + expected + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == expected); + } + clearEventCounters(); + + // Get the list of breakpoints + IBreakpointDMContext[] breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + 4 + " breakpoint(s), received " + + breakpoints.length, breakpoints.length == 4); + + // Remove the breakpoint one at a time in the following order: 1, 3, 2, 4 + int[] indices = { 0, 2, 1, 3 }; + int breakpoints_left = 4; + for (int i = 0; i < breakpoints_left; i++) { + + // Remove the selected breakpoint + IBreakpointDMContext index = breakpoints[indices[i]]; + removeBreakpoint(index); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + breakpoints_left--; + + // Ensure that right BreakpointEvents were received + int expected = i + 1; + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + expected + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == expected); + assertTrue("BreakpointEvent problem: expected " + expected + " BREAKPOINT_REMOVED event(s), received " + + getBreakpointEventCount(BP_REMOVED), getBreakpointEventCount(BP_REMOVED) == expected); + + // Ensure the breakpoint was effectively removed + IBreakpointDMContext[] remaining_breakpoints = getBreakpoints(fGdbControlDmc); + assertTrue("BreakpointService problem: expected " + breakpoints_left + " breakpoint(s), received " + + remaining_breakpoints.length, remaining_breakpoints.length == breakpoints_left); + for (int j = 0; i < breakpoints_left; i++) { + assertTrue("BreakpointService problem: removed breakpoint still present (" + index + ")", + remaining_breakpoints[j] != index); + } + } + clearEventCounters(); + } + + /////////////////////////////////////////////////////////////////////////// + // Breakpoint Update tests + /////////////////////////////////////////////////////////////////////////// + + // ------------------------------------------------------------------------ + // updateBreakpoint_InvalidBreakpoint + // Updates a non-existing breakpoint. + // For GDB, no problem... + // ------------------------------------------------------------------------ + // @Test + public void updateBreakpoint_InvalidBreakpoint() throws Throwable { + + // Create an invalid breakpoint reference + IBreakpointDMContext invalid_ref = + new MIBreakpointDMContext((MIBreakpoints) fBreakpointService, new IDMContext[] { fGdbControlDmc }, 0); + + // Update the invalid breakpoint + String expected = UNKNOWN_BREAKPOINT; + Map properties = new HashMap(); + properties.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + properties.put(FILE_NAME_TAG, SOURCE_FILE); + properties.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + updateBreakpoint(invalid_ref, properties); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure that no BreakpointEvent was received + assertTrue("BreakpointEvent problem: expected " + 0 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 0); + } + + // ------------------------------------------------------------------------ + // updateBreakpoint_AddCondition + // Set a breakpoint and then add a condition. + // Ensure that the new breakpoint reflects the changes + // ------------------------------------------------------------------------ + // @Test + public void updateBreakpoint_AddCondition() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Install the breakpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Modify the condition + Map delta = new HashMap(); + delta.put(CONDITION_TAG, CONDITION_1); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Verify the state of the breakpoint + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", + breakpoint2.getCondition().equals(CONDITION_1)); + } + + // ------------------------------------------------------------------------ + // updateBreakpoint_RemoveCondition + // Set a conditional breakpoint and then remove the condition. + // Ensure that the new breakpoint reflects the changes + // ------------------------------------------------------------------------ + // @Test + public void updateBreakpoint_RemoveCondition() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + breakpoint.put(CONDITION_TAG, CONDITION_1); + + // Install the breakpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Remove the condition + Map delta = new HashMap(); + delta.put(CONDITION_TAG, null); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Verify the state of the breakpoint + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", + breakpoint2.getCondition().equals("")); + } + + // ------------------------------------------------------------------------ + // updateBreakpoint_ModifyCondition + // Set a conditional breakpoint and then modify the condition. + // Ensure that the new breakpoint reflects the changes + // ------------------------------------------------------------------------ + // @Test + public void updateBreakpoint_ModifyCondition() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + breakpoint.put(CONDITION_TAG, CONDITION_1); + + // Install the breakpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Update the condition + Map delta = new HashMap(); + delta.put(CONDITION_TAG, CONDITION_2); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Verify the state of the breakpoint + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", + breakpoint2.getCondition().equals(CONDITION_2)); + } + + // ------------------------------------------------------------------------ + // updateWatchpoint_AddCondition + // Set a watchpoint and then add a condition. + // Ensure that the new breakpoint reflects the changes + // ------------------------------------------------------------------------ + // @Test + public void updateWatchpoint_AddCondition() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint(SOURCE_FILE + ":" + LINE_NUMBER_1, true); + SyncUtil.SyncResumeUntilStopped(); + clearEventCounters(); + + // Create a write watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_1); + watchpoint.put(WRITE_TAG, true); + + // Install the watchpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Add the condition + Map delta = new HashMap(); + delta.put(CONDITION_TAG, CONDITION_1); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Verify the state of the watchpoint + MIBreakpointDMData watchpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", + watchpoint2.getCondition().equals(CONDITION_1)); + } + + // ------------------------------------------------------------------------ + // updateWatchpoint_RemoveCondition + // Set a conditional watchpoint and then remove the condition. + // Ensure that the new breakpoint reflects the changes + // ------------------------------------------------------------------------ + // @Test + public void updateWatchpoint_RemoveCondition() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint(SOURCE_FILE + ":" + LINE_NUMBER_1, true); + SyncUtil.SyncResumeUntilStopped(); + clearEventCounters(); + + // Create a write watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_1); + watchpoint.put(WRITE_TAG, true); + watchpoint.put(CONDITION_TAG, CONDITION_1); + + // Install the watchpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Remove the condition + Map delta = new HashMap(); + delta.put(CONDITION_TAG, null); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Verify the state of the watchpoint + MIBreakpointDMData watchpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", + watchpoint2.getCondition().equals("")); + } + + // ------------------------------------------------------------------------ + // updateWatchpoint_ModifyCondition + // Set a conditional watchpoint and then modify the condition. + // Ensure that the new breakpoint reflects the changes + // ------------------------------------------------------------------------ + // @Test + public void updateWatchpoint_ModifyCondition() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint(SOURCE_FILE + ":" + LINE_NUMBER_1, true); + SyncUtil.SyncResumeUntilStopped(); + clearEventCounters(); + + // Create a write watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_1); + watchpoint.put(WRITE_TAG, true); + watchpoint.put(CONDITION_TAG, CONDITION_1); + + // Install the watchpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Update the condition + Map delta = new HashMap(); + delta.put(CONDITION_TAG, CONDITION_2); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Verify the state of the breakpoint + MIBreakpointDMData watchpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", + watchpoint2.getCondition().equals(CONDITION_2)); + } + + // ------------------------------------------------------------------------ + // updateBreakpoint_AddCount + // Set a breakpoint and then add an ignore count. + // Ensure that the new breakpoint reflects the changes + // ------------------------------------------------------------------------ + // @Test + public void updateBreakpoint_AddCount() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Install the breakpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Add a count + Map delta = new HashMap(); + delta.put(IGNORE_COUNT_TAG, IGNORE_COUNT_2); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Verify the state of the breakpoint + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong count)", + breakpoint2.getIgnoreCount() == IGNORE_COUNT_2); + } + + // ------------------------------------------------------------------------ + // updateBreakpoint_RemoveCount + // Set a conditional breakpoint and then remove the count.. + // Ensure that the new breakpoint reflects the changes + // ------------------------------------------------------------------------ + // @Test + public void updateBreakpoint_RemoveCount() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + breakpoint.put(IGNORE_COUNT_TAG, IGNORE_COUNT_2); + + // Install the breakpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Remove the count + Map delta = new HashMap(); + delta.put(IGNORE_COUNT_TAG, null); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Verify the state of the breakpoint + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong count)", + breakpoint2.getIgnoreCount() == 0); + } + + // ------------------------------------------------------------------------ + // updateBreakpoint_ModifyCount + // Set a conditional breakpoint and then modify the count. + // Ensure that the new breakpoint reflects the changes + // ------------------------------------------------------------------------ + // @Test + public void updateBreakpoint_ModifyCount() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + breakpoint.put(IGNORE_COUNT_TAG, IGNORE_COUNT_1); + + // Install the breakpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Update the count + Map delta = new HashMap(); + delta.put(IGNORE_COUNT_TAG, IGNORE_COUNT_2); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Verify the state of the breakpoint + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong count)", + breakpoint2.getIgnoreCount() == IGNORE_COUNT_2); + } + + // ------------------------------------------------------------------------ + // updateBreakpoint_Disable + // Set 2 breakpoints and disable the first one. + // Ensure that we stop on the second one. + // ------------------------------------------------------------------------ + // @Test + public void updateBreakpoint_Disable() throws Throwable { + + // Create a first line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Install the breakpoint + IBreakpointDMContext ref1 = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Create a second line breakpoint + breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_2); + + // Install the breakpoint + IBreakpointDMContext ref2 = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 2); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 2); + clearEventCounters(); + + // Verify the state of the breakpoints + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref1); + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref2); + assertTrue("BreakpointService problem: breakpoint state error", + breakpoint1.isEnabled() && breakpoint2.isEnabled()); + + // Disable the first breakpoint + Map delta = new HashMap(); + delta.put(IS_ENABLED_TAG, false); + updateBreakpoint(ref1, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Verify the state of the breakpoints + breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref1); + breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref2); + assertTrue("BreakpointService problem: breakpoint state error", + !breakpoint1.isEnabled() && breakpoint2.isEnabled()); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the BreakpointEvent was received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + assertTrue("BreakpointService problem: breakpoint mismatch", + fBreakpointRef == breakpoint2.getNumber()); + clearEventCounters(); + } + + // ------------------------------------------------------------------------ + // updateBreakpoint_Enable + // In a loop, set 2 breakpoints and disable the first one. After hitting + // the second one, enable the first one again. + // Ensure that we stop on the first one on the next iteration. + // ------------------------------------------------------------------------ + // @Test + public void updateBreakpoint_Enable() throws Throwable { + + // Create a first line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Install the breakpoint + IBreakpointDMContext ref1 = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Create a second line breakpoint + breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_2); + + // Install the breakpoint + IBreakpointDMContext ref2 = insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 2); + assertTrue("BreakpointEvent problem: expected " + 2 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 2); + clearEventCounters(); + + // Verify the state of the breakpoints + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref1); + MIBreakpointDMData breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref2); + assertTrue("BreakpointService problem: breakpoint state error", + breakpoint1.isEnabled() && breakpoint2.isEnabled()); + + // Disable the first breakpoint + Map delta = new HashMap(); + delta.put(IS_ENABLED_TAG, false); + updateBreakpoint(ref1, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Verify the state of the breakpoints + breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref1); + breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref2); + assertTrue("BreakpointService problem: breakpoint state error", + !breakpoint1.isEnabled() && breakpoint2.isEnabled()); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the BreakpointEvent was received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + assertTrue("BreakpointService problem: breakpoint mismatch", + fBreakpointRef == breakpoint2.getNumber()); + clearEventCounters(); + + // Enable the first breakpoint + delta = new HashMap(); + delta.put(IS_ENABLED_TAG, true); + updateBreakpoint(ref1, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Verify the state of the breakpoints + breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref1); + breakpoint2 = (MIBreakpointDMData) getBreakpoint(ref2); + assertTrue("BreakpointService problem: breakpoint state error", + breakpoint1.isEnabled() && breakpoint2.isEnabled()); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the BreakpointEvent was received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + assertTrue("BreakpointService problem: breakpoint mismatch", + fBreakpointRef == breakpoint1.getNumber()); + clearEventCounters(); + } + + /////////////////////////////////////////////////////////////////////////// + // Breakpoint Hit tests + /////////////////////////////////////////////////////////////////////////// + + // ------------------------------------------------------------------------ + // breakpointHit_LineNumber + // Set a breakpoint on a line number. + // ------------------------------------------------------------------------ + // @Test + public void breakpointHit_LineNumber() throws Throwable { + + // Create a line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Install the breakpoint + MIBreakpointDMContext ref = (MIBreakpointDMContext) insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(); + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + assertTrue("BreakpointService problem: breakpoint mismatch", + fBreakpointRef == breakpoint1.getNumber()); + clearEventCounters(); + } + + // ------------------------------------------------------------------------ + // breakpointHit_Function + // Set a breakpoint on a function name. + // ------------------------------------------------------------------------ + // @Test + public void breakpointHit_Function() throws Throwable { + + // Create a function breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(FUNCTION_TAG, FUNCTION); + + // Install the breakpoint + MIBreakpointDMContext ref = (MIBreakpointDMContext) insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(); + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + assertTrue("BreakpointService problem: breakpoint mismatch", + fBreakpointRef == breakpoint1.getNumber()); + clearEventCounters(); + } + + // ------------------------------------------------------------------------ + // breakpointHit_Condition + // Set a breakpoint on a line where a variable being increased (loop). + // Set a condition so that the break occurs only after variable == count. + // Ensure that the variable was increased 'count' times. + // ------------------------------------------------------------------------ + // @Test + public void breakpointHit_Condition() throws Throwable { + + // Create a conditional line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + breakpoint.put(CONDITION_TAG, CONDITION_1); + + // Install the breakpoint + MIBreakpointDMContext ref = (MIBreakpointDMContext) insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(); + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + assertTrue("BreakpointService problem: breakpoint mismatch", + fBreakpointRef == breakpoint1.getNumber()); + clearEventCounters(); + + // Verify that the condition is met + int i = evaluateExpression("i").intValue(); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", i == 128); + } + + // ------------------------------------------------------------------------ + // breakpointHit_UpdatedCondition + // Set a breakpoint on a line where a variable being increased (loop). + // Set a condition so that the break occurs only after variable == count. + // Ensure that the variable was increased 'count' times. + // ------------------------------------------------------------------------ + // @Test + public void breakpointHit_UpdatedCondition() throws Throwable { + + // Create a conditional line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Install the breakpoint + MIBreakpointDMContext ref = (MIBreakpointDMContext) insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Add the condition + Map delta = new HashMap(); + delta.put(CONDITION_TAG, CONDITION_1); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(); + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + assertTrue("BreakpointService problem: breakpoint mismatch", + fBreakpointRef == breakpoint1.getNumber()); + clearEventCounters(); + + // Verify that the condition is met + int i = evaluateExpression("i").intValue(); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", i == 128); + } + + // ------------------------------------------------------------------------ + // breakpointHit_Count + // Set a breakpoint on a line where a variable being increased (loop). + // Set an ignore count != 0. + // Ensure that the variable was increased 'ignoreCount' times. + // ------------------------------------------------------------------------ + @Test + public void breakpointHit_Count() throws Throwable { + + // Create a conditional line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + breakpoint.put(IGNORE_COUNT_TAG, IGNORE_COUNT_2); + + // Install the breakpoint + MIBreakpointDMContext ref = (MIBreakpointDMContext) insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(); + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + assertTrue("BreakpointService problem: breakpoint mismatch", + fBreakpointRef == breakpoint1.getNumber()); + clearEventCounters(); + + // Verify that the condition is met + int i = evaluateExpression("i").intValue(); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", i == IGNORE_COUNT_2); + } + + // ------------------------------------------------------------------------ + // breakpointHit_UpdatedCount + // Set a breakpoint on a line where a variable being increased (loop). + // Set an ignore count != 0. + // Ensure that the variable was increased 'ignoreCount' times. + // ------------------------------------------------------------------------ + // @Test + public void breakpointHit_UpdatedCount() throws Throwable { + + // Create a conditional line breakpoint + Map breakpoint = new HashMap(); + breakpoint.put(BREAKPOINT_TYPE_TAG, BREAKPOINT_TAG); + breakpoint.put(FILE_NAME_TAG, SOURCE_FILE); + breakpoint.put(LINE_NUMBER_TAG, LINE_NUMBER_1); + + // Install the breakpoint + MIBreakpointDMContext ref = (MIBreakpointDMContext) insertBreakpoint(fGdbControlDmc, breakpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Add a count + Map delta = new HashMap(); + delta.put(IGNORE_COUNT_TAG, IGNORE_COUNT_2); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(); + MIBreakpointDMData breakpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_HIT event(s), received " + + getBreakpointEventCount(BP_HIT), getBreakpointEventCount(BP_HIT) == 1); + assertTrue("BreakpointService problem: breakpoint mismatch", + fBreakpointRef == breakpoint1.getNumber()); + clearEventCounters(); + + // Verify that the condition is met + int i = evaluateExpression("i").intValue(); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", i == IGNORE_COUNT_2); + } + + // ------------------------------------------------------------------------ + // breakpointHit_WriteWatchpoint + // Set a write watchpoint and go. + // Ensure that the correct event is received. + // ------------------------------------------------------------------------ + // @Test + public void breakpointHit_WriteWatchpoint() throws Throwable { + + // Create a write watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_1); + watchpoint.put(WRITE_TAG, true); + + // Install the watchpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(); + MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " WATCHPOINT_HIT event(s), received " + + getBreakpointEventCount(WP_HIT), getBreakpointEventCount(WP_HIT) == 1); + assertTrue("BreakpointService problem: watchpoint mismatch", + fBreakpointRef == watchpoint1.getNumber()); + clearEventCounters(); + + // Verify that the condition is met + int i = evaluateExpression("i").intValue(); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", i == IGNORE_COUNT_2); + } + + // ------------------------------------------------------------------------ + // breakpointHit_ReadWatchpoint + // Set a read watchpoint and go. + // Ensure that the correct event is received. + // ------------------------------------------------------------------------ + // @Test + public void breakpointHit_ReadWatchpoint() throws Throwable { + + // Create a write watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_1); + watchpoint.put(READ_TAG, true); + + // Install the watchpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(); + MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " WATCHPOINT_HIT event(s), received " + + getBreakpointEventCount(WP_HIT), getBreakpointEventCount(WP_HIT) == 1); + assertTrue("BreakpointService problem: watchpoint mismatch", + fBreakpointRef == watchpoint1.getNumber()); + clearEventCounters(); + + // Verify that the condition is met + int i = evaluateExpression("i").intValue(); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", i == IGNORE_COUNT_2); + } + + // ------------------------------------------------------------------------ + // breakpointHit_AccessWatchpoint + // Set an access watchpoint and go. + // Ensure that the correct event is received. + // ------------------------------------------------------------------------ + // @Test + public void breakpointHit_AccessWatchpoint() throws Throwable { + + // Create an access watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_1); + watchpoint.put(READ_TAG, true); + watchpoint.put(WRITE_TAG, true); + + // Install the watchpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(); + MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " WATCHPOINT_HIT event(s), received " + + getBreakpointEventCount(WP_HIT), getBreakpointEventCount(WP_HIT) == 1); + assertTrue("BreakpointService problem: watchpoint mismatch", + fBreakpointRef == watchpoint1.getNumber()); + clearEventCounters(); + + // Verify that the condition is met + int i = evaluateExpression("i").intValue(); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", i == IGNORE_COUNT_2); + } + + // ------------------------------------------------------------------------ + // breakpointHit_watchpointUpdateCount + // Set a write watchpoint, add an ignoreCount and go. + // Ensure that the correct event is received. + // ------------------------------------------------------------------------ + @Test + public void breakpointHit_watchpointUpdateCount() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint(SOURCE_FILE + ":" + LINE_NUMBER_3, true); + SyncUtil.SyncAddBreakpoint(SOURCE_FILE + ":" + LINE_NUMBER_4, true); + SyncUtil.SyncResumeUntilStopped(); + clearEventCounters(); + + // Create a write watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_2); + watchpoint.put(WRITE_TAG, true); + + // Install the watchpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Add a count + Map delta = new HashMap(); + delta.put(IGNORE_COUNT_TAG, IGNORE_COUNT_2); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(); + MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " WATCHPOINT_HIT event(s), received " + + getBreakpointEventCount(WP_HIT), getBreakpointEventCount(WP_HIT) == 1); + assertTrue("BreakpointService problem: watchpoint mismatch", + fBreakpointRef == watchpoint1.getNumber()); + clearEventCounters(); + + // Verify that the condition is met + int j = evaluateExpression("j").intValue(); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", j == IGNORE_COUNT_2); + } + + // ------------------------------------------------------------------------ + // breakpointHit_watchpointUpdateCondition + // Set a write watchpoint, add a condition and go. + // Ensure that the correct event is received. + // ------------------------------------------------------------------------ + // @Test + public void breakpointHit_watchpointUpdateCondition() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint(SOURCE_FILE + ":" + LINE_NUMBER_3, true); + SyncUtil.SyncAddBreakpoint(SOURCE_FILE + ":" + LINE_NUMBER_4, true); + SyncUtil.SyncResumeUntilStopped(); + clearEventCounters(); + + // Create a write watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_2); + watchpoint.put(WRITE_TAG, true); + + // Install the watchpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Add a condition + Map delta = new HashMap(); + delta.put(CONDITION_TAG, CONDITION_3); + updateBreakpoint(ref, delta); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_UPDATED event(s), received " + + getBreakpointEventCount(BP_UPDATED), getBreakpointEventCount(BP_UPDATED) == 1); + clearEventCounters(); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(); + MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " WATCHPOINT_HIT event(s), received " + + getBreakpointEventCount(WP_HIT), getBreakpointEventCount(WP_HIT) == 1); + assertTrue("BreakpointService problem: watchpoint mismatch", + fBreakpointRef == watchpoint1.getNumber()); + clearEventCounters(); + + // Verify that the condition is met + int j = evaluateExpression("j").intValue(); + assertTrue("BreakpointEvent problem: breakpoint mismatch (wrong condition)", j == IGNORE_COUNT_2); + } + + // ------------------------------------------------------------------------ + // breakpointHit_WatchpointOutOfScope + // Set an access watchpoint and watch it go out of scope. + // Ensure that the correct event is received. + // ------------------------------------------------------------------------ + // @ T e s t removed due to lack of cooperation from GDB :-) + public void breakpointHit_WatchpointOutOfScope() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint(SOURCE_FILE + ":" + LINE_NUMBER_1, true); + SyncUtil.SyncAddBreakpoint(SOURCE_FILE + ":" + LINE_NUMBER_3, true); + SyncUtil.SyncResumeUntilStopped(); + clearEventCounters(); + + // Create a write watchpoint + Map watchpoint = new HashMap(); + watchpoint.put(BREAKPOINT_TYPE_TAG, WATCHPOINT_TAG); + watchpoint.put(EXPRESSION_TAG, EXPRESSION_2); + watchpoint.put(READ_TAG, true); + watchpoint.put(WRITE_TAG, true); + + // Install the watchpoint + IBreakpointDMContext ref = insertBreakpoint(fGdbControlDmc, watchpoint); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure that right BreakpointEvents were received + waitForBreakpointEvent(); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT_ADDED event(s), received " + + getBreakpointEventCount(BP_ADDED), getBreakpointEventCount(BP_ADDED) == 1); + clearEventCounters(); + + // Run until the breakpoint is hit and the event generated + SyncUtil.SyncResumeUntilStopped(); + + // Ensure the correct BreakpointEvent was received + waitForBreakpointEvent(); + MIBreakpointDMData watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected " + 1 + " BREAKPOINT event(s), received " + + fBreakpointEventCount, fBreakpointEventCount == 1); + assertTrue("BreakpointEvent problem: expected " + 1 + " WATCHPOINT_HIT event(s), received " + + getBreakpointEventCount(WP_OOS), getBreakpointEventCount(WP_OOS) == 1); + assertTrue("BreakpointService problem: watchpoint mismatch", + fBreakpointRef == watchpoint1.getNumber()); + clearEventCounters(); + + // Ensure the watchpoint is gone + getBreakpoints(fGdbControlDmc); + watchpoint1 = (MIBreakpointDMData) getBreakpoint(ref); + assertTrue("BreakpointEvent problem: expected watchpoint to be deleted after going out of scope", + watchpoint1 == null); + } + +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIMemoryTest.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIMemoryTest.java new file mode 100644 index 00000000000..31632a7e2c2 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIMemoryTest.java @@ -0,0 +1,1639 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson AB - Initial Implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.utils.Addr64; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.debug.service.IExpressions; +import org.eclipse.dd.dsf.debug.service.IFormattedValues; +import org.eclipse.dd.dsf.debug.service.IMemory; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData; +import org.eclipse.dd.dsf.debug.service.IMemory.IMemoryChangedEvent; +import org.eclipse.dd.dsf.debug.service.IMemory.IMemoryDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.StepType; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.gdb.service.command.GDBControlDMContext; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.tests.gdb.framework.AsyncCompletionWaitor; +import org.eclipse.dd.tests.gdb.framework.BackgroundRunner; +import org.eclipse.dd.tests.gdb.framework.BaseTestCase; +import org.eclipse.dd.tests.gdb.framework.SyncUtil; +import org.eclipse.dd.tests.gdb.launching.TestsPlugin; +import org.eclipse.debug.core.model.MemoryByte; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +/* + * This is the Memory Service test suite. + * + * It is meant to be a regression suite to be executed automatically against + * the DSF nightly builds. + * + * It is also meant to be augmented with a proper test case(s) every time a + * feature is added or in the event (unlikely :-) that a bug is found in the + * Memory Service. + * + * Refer to the JUnit4 documentation for an explanation of the annotations. + */ + +@RunWith(BackgroundRunner.class) +public class MIMemoryTest extends BaseTestCase { + + private final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); + private DsfSession fSession; + private DsfServicesTracker fServicesTracker; + private GDBControlDMContext fGdbControlDmc; + private MIRunControl fRunControl; + private IMemory fMemoryService; + private IExpressions fExpressionService; + + // Keeps track of the MemoryChangedEvents + private final int BLOCK_SIZE = 256; + private IAddress fBaseAddress; + private Integer fMemoryChangedEventCount = new Integer(0); + private boolean[] fMemoryAddressesChanged = new boolean[BLOCK_SIZE]; + + // ======================================================================== + // Housekeeping stuff + // ======================================================================== + + @BeforeClass + public static void testSuiteInitialization() { + // Select the binary to run the tests against + setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, "data/launch/bin/MemoryTestApp.exe"); + } + + @AfterClass + public static void testSuiteCleanup() { + } + + @Before + public void testCaseInitialization() { + fSession = getGDBLaunch().getSession(); + + // Get a reference to the memory service + fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId()); + assert(fServicesTracker != null); + + GDBControl gdbControl = fServicesTracker.getService(GDBControl.class); + fGdbControlDmc = gdbControl.getGDBDMContext(); + assert(fGdbControlDmc != null); + + fRunControl = fServicesTracker.getService(MIRunControl.class); + assert(fRunControl != null); + + fMemoryService = fServicesTracker.getService(IMemory.class); + assert(fMemoryService != null); + + fExpressionService = fServicesTracker.getService(IExpressions.class); + assert(fExpressionService != null); + + fSession.addServiceEventListener(MIMemoryTest.this, null); + fBaseAddress = null; + clearEventCounters(); + } + + @After + public void testCaseCleanup() { + // Clear the references (not strictly necessary) + fBaseAddress = null; + fSession.removeServiceEventListener(MIMemoryTest.this); + fExpressionService = null; + fMemoryService = null; + fRunControl = null; + fServicesTracker.dispose(); + fServicesTracker = null; + clearEventCounters(); + } + + // ======================================================================== + // Helper Functions + // ======================================================================== + + /* ------------------------------------------------------------------------ + * eventDispatched + * ------------------------------------------------------------------------ + * Processes MemoryChangedEvents. + * First checks if the memory block base address was set so the individual + * test can control if it wants to verify the event(s). + * ------------------------------------------------------------------------ + * @param e The MemoryChangedEvent + * ------------------------------------------------------------------------ + */ + @DsfServiceEventHandler + public void eventDispatched(IMemoryChangedEvent e) { + synchronized(fMemoryChangedEventCount) { + fMemoryChangedEventCount++; + } + IAddress[] addresses = e.getAddresses(); + for (int i = 0; i < addresses.length; i++) { + int offset = Math.abs(addresses[i].distanceTo(fBaseAddress).intValue()); + if (offset < BLOCK_SIZE) + synchronized(fMemoryAddressesChanged) { + fMemoryAddressesChanged[offset] = true; + } + } + } + + // Clears the counters + private void clearEventCounters() { + synchronized(fMemoryChangedEventCount) { + fMemoryChangedEventCount = 0; + } + synchronized(fMemoryAddressesChanged) { + for (int i = 0; i < BLOCK_SIZE; i++) + fMemoryAddressesChanged[i] = false; + } + } + + // Returns the total number of events received + private int getEventCount() { + int count; + synchronized(fMemoryChangedEventCount) { + count = fMemoryChangedEventCount; + } + return count; + } + + // Returns the number of distinct addresses reported + private int getAddressCount() { + int count = 0; + synchronized(fMemoryAddressesChanged) { + for (int i = 0; i < BLOCK_SIZE; i++) + if (fMemoryAddressesChanged[i]) + count++; + } + return count; + } + + /* ------------------------------------------------------------------------ + * evaluateExpression + * ------------------------------------------------------------------------ + * Invokes the ExpressionService to evaluate an expression. In theory, we + * shouldn't rely on another service to test this one but we need a way to + * access a variable from the test application in order verify that the + * memory operations (read/write) are working properly. + * ------------------------------------------------------------------------ + * @param expression Expression to resolve + * @return Resolved expression + * @throws InterruptedException + * ------------------------------------------------------------------------ + */ + private IAddress evaluateExpression(String expression) throws Throwable + { + // Create the expression and format contexts + final IExpressionDMContext expressionDMC = SyncUtil.SyncCreateExpression(fGdbControlDmc, expression); + final FormattedValueDMContext formattedValueDMC = SyncUtil.SyncGetFormattedValue(fExpressionService, expressionDMC, IFormattedValues.HEX_FORMAT); + + // Create the DataRequestMonitor which will store the operation result in the wait object + final DataRequestMonitor drm = + new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + + // Evaluate the expression (asynchronously) + fSession.getExecutor().submit(new Runnable() { + public void run() { + fExpressionService.getFormattedExpressionValue(formattedValueDMC, drm); + } + }); + + // Wait for completion + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Return the string formatted by the back-end + String result = ""; + Object returnInfo = fWait.getReturnInfo(); + if (returnInfo instanceof FormattedValueDMData) + result = ((FormattedValueDMData) returnInfo).getFormattedValue(); + return new Addr64(result); + } + + /* ------------------------------------------------------------------------ + * readMemory + * ------------------------------------------------------------------------ + * Issues a memory read request. The result is stored in fWait. + * ------------------------------------------------------------------------ + * Typical usage: + * getMemory(dmc, address, offset, count); + * fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + * assertTrue(fWait.getMessage(), fWait.isOK()); + * ------------------------------------------------------------------------ + * @param dmc the data model context + * @param address the memory block address + * @param offset the offset in the buffer + * @param count the number of bytes to read + * @throws InterruptedException + * ------------------------------------------------------------------------ + */ + private void readMemory(final IMemoryDMContext dmc, final IAddress address, + final long offset, final int word_size, final int count) + throws InterruptedException + { + // Set the Data Request Monitor + final DataRequestMonitor drm = + new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + + // Issue the get memory request + fSession.getExecutor().submit(new Runnable() { + public void run() { + fMemoryService.getMemory(dmc, address, offset, word_size, count, drm); + } + }); + } + + /* ------------------------------------------------------------------------ + * readMemoryByteAtOffset + * ------------------------------------------------------------------------ + * Issues a memory read request. The result is stored in fWait. + * ------------------------------------------------------------------------ + * Typical usage: + * getMemory(dmc, address, offset, count); + * fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + * assertTrue(fWait.getMessage(), fWait.isOK()); + * ------------------------------------------------------------------------ + * @param dmc the data model context + * @param address the memory block address + * @param offset the offset in the buffer + * @param count the number of bytes to read + * @param result the expected byte + * @throws InterruptedException + * ------------------------------------------------------------------------ + */ + private void readMemoryByteAtOffset(final IMemoryDMContext dmc, final IAddress address, + final long offset, final int word_size, final int count, final MemoryByte[] result) + throws InterruptedException + { + // Set the Data Request Monitor + final DataRequestMonitor drm = + new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + result[(int) offset] = getData()[0]; + } + fWait.waitFinished(getStatus()); + } + }; + + // Issue the get memory request + fSession.getExecutor().submit(new Runnable() { + public void run() { + fMemoryService.getMemory(dmc, address, offset, word_size, count, drm); + } + }); + } + + /* ------------------------------------------------------------------------ + * writeMemory + * ------------------------------------------------------------------------ + * Issues a memory write request. + * ------------------------------------------------------------------------ + * Typical usage: + * writeMemory(dmc, address, offset, count, buffer); + * fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + * assertTrue(fWait.getMessage(), fWait.isOK()); + * ------------------------------------------------------------------------ + * @param dmc the data model context + * @param address the memory block address (could be an expression) + * @param offset the offset from address + * @param count the number of bytes to write + * @param buffer the byte buffer to write from + * @throws InterruptedException + * ------------------------------------------------------------------------ + */ + private void writeMemory(final IMemoryDMContext dmc, final IAddress address, + final long offset, final int word_size, final int count, final byte[] buffer) + throws InterruptedException + { + // Set the Data Request Monitor + final RequestMonitor rm = + new RequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + fWait.waitFinished(getStatus()); + } + }; + + // Issue the get memory request + fSession.getExecutor().submit(new Runnable() { + public void run() { + fMemoryService.setMemory(dmc, address, offset, word_size, count, buffer, rm); + } + }); + } + + /* ------------------------------------------------------------------------ + * fillMemory + * ------------------------------------------------------------------------ + * Issues a memory write request. + * ------------------------------------------------------------------------ + * Typical usage: + * writeMemory(dmc, address, offset, count, buffer); + * fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + * assertTrue(fWait.getMessage(), fWait.isOK()); + * ------------------------------------------------------------------------ + * @param dmc the data model context + * @param address the memory block address (could be an expression) + * @param offset the offset from address + * @param count the number of bytes to write + * @param pattern the byte pattern to write + * @throws InterruptedException + * ------------------------------------------------------------------------ + */ + private void fillMemory(final IMemoryDMContext dmc, final IAddress address, + final long offset, final int word_size, final int count, final byte[] pattern) + throws InterruptedException + { + // Set the Data Request Monitor + final RequestMonitor rm = + new RequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleCompleted() { + fWait.waitFinished(getStatus()); + } + }; + + // Issue the fill memory request + fSession.getExecutor().submit(new Runnable() { + public void run() { + fMemoryService.fillMemory(dmc, address, offset, word_size, count, pattern, rm); + } + }); + } + + // ======================================================================== + // Test Cases + // ------------------------------------------------------------------------ + // Templates: + // ------------------------------------------------------------------------ + // @ Test + // public void basicTest() { + // // First test to run + // assertTrue("", true); + // } + // ------------------------------------------------------------------------ + // @ Test(timeout=5000) + // public void timeoutTest() { + // // Second test to run, which will timeout if not finished on time + // assertTrue("", true); + // } + // ------------------------------------------------------------------------ + // @ Test(expected=FileNotFoundException.class) + // public void exceptionTest() throws FileNotFoundException { + // // Third test to run which expects an exception + // throw new FileNotFoundException("Just testing"); + // } + // ======================================================================== + + /////////////////////////////////////////////////////////////////////////// + // getMemory tests + /////////////////////////////////////////////////////////////////////////// + + // ------------------------------------------------------------------------ + // readWithNullContext + // Test that a null context is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void readWithNullContext() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + IMemoryDMContext dmc = null; + long offset = 0; + int word_size = 1; + int count = 1; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + String expected = "Unknown context type"; + fWait.waitReset(); + readMemory(dmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // readWithInvalidAddress + // Test that an invalid address is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void readWithInvalidAddress() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = 1; + fBaseAddress = new Addr64("0"); + + // Perform the test + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + +// // Un-comment this part if GDB returns a bunch of 'N/A's +// // when the address is invalid +// assertTrue(fWait.getMessage(), fWait.isOK()); +// MemoryByte[] buffer = (MemoryByte[]) fWait.getReturnInfo(); +// assertTrue("Wrong value: expected '-1, 0', received '" + buffer[0].getValue() + ", " + buffer[0].getFlags() + "'", +// (buffer[0].getValue() == (byte) -1) && (buffer[0].getFlags() == (byte) 0)); + + // Un-comment this part if GDB returns an error message + // when the address is invalid + String expected = "Unable to read memory"; // Error msg returned by gdb + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // readWithInvalidWordSize + // Test that an invalid word size is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void readWithInvalidWordSize() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int count = -1; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + String expected = "Word size not supported (!= 1)"; + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, 0, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, 2, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // readWithInvalidCount + // Test that an invalid count is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void readWithInvalidCount() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = -1; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + String expected = "Invalid word count (< 0)"; + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // readCharVaryingBaseAddress + // Test the reading of individual bytes by varying the base address + // ------------------------------------------------------------------------ + @Test + public void readCharVaryingBaseAddress() throws Throwable { + + // Run to the point where the variable is zeroed + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = 1; + fBaseAddress = evaluateExpression("&charBlock"); + + // Verify that all bytes are '0' + for (int i = 0; i < BLOCK_SIZE; i++) { + IAddress address = fBaseAddress.add(i); + fWait.waitReset(); + readMemory(fGdbControlDmc, address, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + MemoryByte[] buffer = (MemoryByte[]) fWait.getReturnInfo(); + assertTrue("Wrong value read at offset " + i + ": expected '" + 0 + "', received '" + buffer[0].getValue() + "'", + (buffer[0].getValue() == (byte) 0)); + } + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:setBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Verify that all bytes are set + for (int i = 0; i < BLOCK_SIZE; i++) { + IAddress address = fBaseAddress.add(i); + fWait.waitReset(); + readMemory(fGdbControlDmc, address, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + MemoryByte[] buffer = (MemoryByte[]) fWait.getReturnInfo(); + assertTrue(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong value read at offset " + i + ": expected '" + i + "', received '" + buffer[0].getValue() + "'", + (buffer[0].getValue() == (byte) i)); + } + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // readCharVaryingOffset + // Test the reading of individual bytes by varying the offset + // ------------------------------------------------------------------------ + @Test + public void readCharVaryingOffset() throws Throwable { + + // Run to the point where the array is zeroed + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + int word_size = 1; + int count = 1; + fBaseAddress = evaluateExpression("&charBlock"); + + // Verify that all bytes are '0' + for (int offset = 0; offset < BLOCK_SIZE; offset++) { + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + MemoryByte[] buffer = (MemoryByte[]) fWait.getReturnInfo(); + assertTrue("Wrong value read at offset " + offset + ": expected '" + 0 + "', received '" + buffer[0].getValue() + "'", + (buffer[0].getValue() == (byte) 0)); + } + + // Run to the point where the array is set + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:setBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Verify that all bytes are set + for (int offset = 0; offset < BLOCK_SIZE; offset++) { + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + MemoryByte[] buffer = (MemoryByte[]) fWait.getReturnInfo(); + assertTrue("Wrong value read at offset " + offset + ": expected '" + offset + "', received '" + buffer[0].getValue() + "'", + (buffer[0].getValue() == (byte) offset)); + } + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // readCharArray + // Test the reading of a byte array + // ------------------------------------------------------------------------ + @Test + public void readCharArray() throws Throwable { + + // Run to the point where the variable is zeroed + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = BLOCK_SIZE; + fBaseAddress = evaluateExpression("&charBlock"); + + // Get the memory block + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + MemoryByte[] buffer = (MemoryByte[]) fWait.getReturnInfo(); + + // Verify that all bytes are '0' + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + 0 + "', received '" + buffer[i].getValue() + "'", + (buffer[i].getValue() == (byte) 0)); + } + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:setBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Get the memory block + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + buffer = (MemoryByte[]) fWait.getReturnInfo(); + + // Verify that all bytes are '0' + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + i + "', received '" + buffer[i].getValue() + "'", + (buffer[i].getValue() == (byte) i)); + } + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + /////////////////////////////////////////////////////////////////////////// + // setMemory tests + /////////////////////////////////////////////////////////////////////////// + + // ------------------------------------------------------------------------ + // writeWithNullContext + // Test that a null context is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void writeWithNullContext() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = 1; + byte[] buffer = new byte[count]; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + String expected = "Unknown context type"; + fWait.waitReset(); + writeMemory(null, fBaseAddress, offset, word_size, count, buffer); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // writeWithInvalidAddress + // Test that an invalid address is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void writeWithInvalidAddress() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = 1; + byte[] buffer = new byte[count]; + fBaseAddress = new Addr64("0"); + + // Perform the test + fWait.waitReset(); + writeMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count, buffer); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + String expected = "Cannot access memory at address"; // Error msg returned by gdb + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // writeWithInvalidWordSize + // Test that an invalid word size is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void writeWithInvalidWordSize() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int count = -1; + byte[] buffer = new byte[1]; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + String expected = "Word size not supported (!= 1)"; + fWait.waitReset(); + writeMemory(fGdbControlDmc, fBaseAddress, offset, 0, count, buffer); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + fWait.waitReset(); + writeMemory(fGdbControlDmc, fBaseAddress, offset, 2, count, buffer); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // writeWithInvalidCount + // Test that an invalid count is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void writeWithInvalidCount() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = -1; + byte[] buffer = new byte[1]; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + String expected = "Invalid word count (< 0)"; + fWait.waitReset(); + writeMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count, buffer); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // writeWithInvalidBuffer + // Test that the buffer contains at least count bytes + // ------------------------------------------------------------------------ + @Test + public void writeWithInvalidBuffer() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = 10; + byte[] buffer = new byte[count - 1]; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + String expected = "Buffer too short"; + fWait.waitReset(); + writeMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count, buffer); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // writeCharVaryingAddress + // Test the writing of individual bytes by varying the base address + // ------------------------------------------------------------------------ + @Test + public void writeCharVaryingAddress() throws Throwable { + + // Run to the point where the variable is zeroed + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = BLOCK_SIZE; + byte[] buffer = new byte[count]; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + for (int i = 0; i < count; i++) { + + // [1] Ensure that the memory byte = 0 + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, i, word_size, 1); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + MemoryByte[] block = (MemoryByte[]) fWait.getReturnInfo(); + assertTrue("Wrong value read at offset " + i + ": expected '" + 0 + "', received '" + block[0].getValue() + "'", + (block[0].getValue() == (byte) 0)); + + // [2] Write a byte value (count - i - 1) + IAddress address = fBaseAddress.add(i); + fWait.waitReset(); + byte expected = (byte) (count - i - 1); + buffer[0] = expected; + writeMemory(fGdbControlDmc, address, offset, word_size, 1, buffer); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // [3] Verify that the correct MemoryChangedEvent was sent + // (I hardly believe there are no synchronization problems here...) + assertTrue("MemoryChangedEvent problem at offset " + i + ": expected " + (i + 1) + " events, received " + getEventCount(), + getEventCount() == (i + 1)); + assertTrue("MemoryChangedEvent problem at offset " + i, fMemoryAddressesChanged[i]); + + // [4] Verify that the memory byte was written correctly + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, i, word_size, 1); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + block = (MemoryByte[]) fWait.getReturnInfo(); + assertTrue("Wrong value read at offset " + i + ": expected '" + expected + "', received '" + block[0].getValue() + "'", + (block[0].getValue() == expected)); + } + + // Ensure the MemoryChangedEvent events were received + assertTrue("MemoryChangedEvent problem: expected " + BLOCK_SIZE + " events, received " + getEventCount(), + getEventCount() == BLOCK_SIZE); + assertTrue("MemoryChangedEvent problem: expected " + BLOCK_SIZE + " distinct addresses, received " + getAddressCount(), + getEventCount() == BLOCK_SIZE); + } + + // ------------------------------------------------------------------------ + // writeCharVaryingOffset + // Test the writing of individual bytes by varying the base address + // ------------------------------------------------------------------------ + @Test + public void writeCharVaryingOffset() throws Throwable { + + // Run to the point where the variable is zeroed + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + int word_size = 1; + int count = BLOCK_SIZE; + byte[] buffer = new byte[count]; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + for (int offset = 0; offset < count; offset++) { + + // [1] Ensure that the memory byte = 0 + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, 1); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + MemoryByte[] block = (MemoryByte[]) fWait.getReturnInfo(); + assertTrue("Wrong value read at offset " + offset + ": expected '" + 0 + "', received '" + block[0].getValue() + "'", + (block[0].getValue() == (byte) 0)); + + // [2] Write a byte value (count - offset - 1) + fWait.waitReset(); + byte expected = (byte) (count - offset - 1); + buffer[0] = expected; + writeMemory(fGdbControlDmc, fBaseAddress, offset, word_size, 1, buffer); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // [3] Verify that the correct MemoryChangedEvent was sent + assertTrue("MemoryChangedEvent problem at offset " + offset + ": expected " + (offset + 1) + " events, received " + getEventCount(), + getEventCount() == (offset + 1)); + assertTrue("MemoryChangedEvent problem at offset " + offset, fMemoryAddressesChanged[offset]); + + // [4] Verify that the memory byte was written correctly + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, 1); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + block = (MemoryByte[]) fWait.getReturnInfo(); + assertTrue("Wrong value read at offset " + offset + ": expected '" + expected + "', received '" + block[0].getValue() + "'", + (block[0].getValue() == expected)); + } + + // Ensure the MemoryChangedEvent events were received + assertTrue("MemoryChangedEvent problem: expected " + BLOCK_SIZE + " events, received " + getEventCount(), + getEventCount() == BLOCK_SIZE); + assertTrue("MemoryChangedEvent problem: expected " + BLOCK_SIZE + " distinct addresses, received " + getAddressCount(), + getAddressCount() == BLOCK_SIZE); + } + + // ------------------------------------------------------------------------ + // writeCharArray + // Test the writing of a byte array + // ------------------------------------------------------------------------ + @Test + public void writeCharArray() throws Throwable { + + // Run to the point where the variable is zeroed + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = BLOCK_SIZE; + fBaseAddress = evaluateExpression("&charBlock"); + + // Make sure that the memory block is zeroed + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + MemoryByte[] block = (MemoryByte[]) fWait.getReturnInfo(); + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + 0 + "', received '" + block[i].getValue() + "'", + (block[i].getValue() == (byte) 0)); + } + + // Write an initialized memory block + byte[] buffer = new byte[count]; + for (int i = 0; i < count; i++) { + buffer[i] = (byte) i; + } + fWait.waitReset(); + writeMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count, buffer); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Make sure that the memory block is initialized + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + block = (MemoryByte[]) fWait.getReturnInfo(); + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + 0 + "', received '" + block[i].getValue() + "'", + (block[i].getValue() == (byte) i)); + } + + // Ensure the MemoryChangedEvent events were received + assertTrue("MemoryChangedEvent problem: expected " + 1 + " event, received " + getEventCount(), + getEventCount() == 1); + assertTrue("MemoryChangedEvent problem: expected " + BLOCK_SIZE + " distinct addresses, received " + getAddressCount(), + getAddressCount() == BLOCK_SIZE); + } + + /////////////////////////////////////////////////////////////////////////// + // fillMemory tests + /////////////////////////////////////////////////////////////////////////// + + // ------------------------------------------------------------------------ + // fillWithNullContext + // Test that a null context is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void fillWithNullContext() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = 1; + byte[] pattern = new byte[count]; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + String expected = "Unknown context type"; + fWait.waitReset(); + fillMemory(null, fBaseAddress, offset, word_size, count, pattern); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // fillWithInvalidAddress + // Test that an invalid address is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void fillWithInvalidAddress() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = 1; + byte[] pattern = new byte[count]; + fBaseAddress = new Addr64("0"); + + // Perform the test + fWait.waitReset(); + fillMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count, pattern); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + String expected = "Cannot access memory at address"; // Error msg returned by gdb + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // fillWithInvalidWordSize + // Test that an invalid word size is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void fillWithInvalidWordSize() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int count = 1; + byte[] pattern = new byte[1]; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + String expected = "Word size not supported (!= 1)"; + fWait.waitReset(); + fillMemory(fGdbControlDmc, fBaseAddress, offset, 0, count, pattern); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + fWait.waitReset(); + fillMemory(fGdbControlDmc, fBaseAddress, offset, 2, count, pattern); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // fillWithInvalidCount + // Test that an invalid count is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void fillWithInvalidCount() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = -1; + byte[] pattern = new byte[1]; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + String expected = "Invalid repeat count (< 0)"; + fWait.waitReset(); + fillMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count, pattern); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // fillWithInvalidPattern + // Test that an empty pattern is caught and generates an error + // ------------------------------------------------------------------------ + @Test + public void fillWithInvalidPattern() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = 1; + byte[] pattern = new byte[0]; + fBaseAddress = evaluateExpression("&charBlock"); + + // Perform the test + String expected = "Empty pattern"; + fWait.waitReset(); + fillMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count, pattern); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertFalse(fWait.getMessage(), fWait.isOK()); + assertTrue("Wrong error message: expected '" + expected + "', received '" + fWait.getMessage() + "'", + fWait.getMessage().contains(expected)); + + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + + // ------------------------------------------------------------------------ + // writePatternVaryingAddress + // Test the writing of the pattern by varying the base address + // ------------------------------------------------------------------------ + @Test + public void writePatternVaryingAddress() throws Throwable { + + // Run to the point where the variable is zeroed + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = 1; + int length = 4; + byte[] pattern = new byte[length]; + for (int i = 0; i < length; i++) pattern[i] = (byte) i; + fBaseAddress = evaluateExpression("&charBlock"); + + // Ensure that the memory is zeroed + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count * length); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + MemoryByte[] block = (MemoryByte[]) fWait.getReturnInfo(); + for (int i = 0; i < (count * length); i++) + assertTrue("Wrong value read at offset " + i + ": expected '" + 0 + "', received '" + block[i].getValue() + "'", + (block[i].getValue() == (byte) 0)); + + for (int i = 0; i < BLOCK_SIZE; i += length) { + IAddress address = fBaseAddress.add(i); + fWait.waitReset(); + fillMemory(fGdbControlDmc, address, offset, word_size, count, pattern); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + } + + // Verify that the memory is correctly set + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, 0, word_size, count * length); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + block = (MemoryByte[]) fWait.getReturnInfo(); + for (int i = 0; i < count; i++) + for (int j = 0; j < length; j++) { + int index = i * length + j; + assertTrue("Wrong value read at offset " + index + ": expected '" + j + "', received '" + block[index].getValue() + "'", + (block[index].getValue() == (byte) j)); + } + + // Ensure the MemoryChangedEvent events were received + assertTrue("MemoryChangedEvent problem: expected " + (BLOCK_SIZE / length) + " events, received " + getEventCount(), + getEventCount() == (BLOCK_SIZE / length)); + assertTrue("MemoryChangedEvent problem: expected " + BLOCK_SIZE + " distinct addresses, received " + getAddressCount(), + getAddressCount() == BLOCK_SIZE); + } + + // ------------------------------------------------------------------------ + // writePatternVaryingOffset + // Test the writing of the pattern by varying the base address + // ------------------------------------------------------------------------ + @Test + public void writePatternVaryingOffset() throws Throwable { + + // Run to the point where the variable is zeroed + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = 64; + int length = 4; + byte[] pattern = new byte[length]; + for (int i = 0; i < length; i++) pattern[i] = (byte) i; + fBaseAddress = evaluateExpression("&charBlock"); + + // Ensure that the memory is zeroed + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count * length); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + MemoryByte[] block = (MemoryByte[]) fWait.getReturnInfo(); + for (int i = 0; i < (count * length); i++) + assertTrue("Wrong value read at offset " + i + ": expected '" + 0 + "', received '" + block[i].getValue() + "'", + (block[i].getValue() == (byte) 0)); + + for (int i = 0; i < (BLOCK_SIZE / length); i++) { + offset = i * length; + fWait.waitReset(); + fillMemory(fGdbControlDmc, fBaseAddress, offset, word_size, 1, pattern); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + } + + // Verify that the memory is correctly set + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, 0, word_size, count * length); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + block = (MemoryByte[]) fWait.getReturnInfo(); + for (int i = 0; i < count; i++) + for (int j = 0; j < length; j++) { + int index = i * length + j; + assertTrue("Wrong value read at offset " + index + ": expected '" + j + "', received '" + block[index].getValue() + "'", + (block[index].getValue() == (byte) j)); + } + + // Ensure the MemoryChangedEvent events were received + assertTrue("MemoryChangedEvent problem: expected " + (BLOCK_SIZE / length) + " events, received " + getEventCount(), + getEventCount() == (BLOCK_SIZE / length)); + assertTrue("MemoryChangedEvent problem: expected " + BLOCK_SIZE + " distinct addresses, received " + getAddressCount(), + getAddressCount() == BLOCK_SIZE); + } + + // ------------------------------------------------------------------------ + // writePatternCountTimes + // Test the writing of the pattern [count] times + // ------------------------------------------------------------------------ + @Test + public void writePatternCountTimes() throws Throwable { + + // Run to the point where the variable is zeroed + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = 64; + int length = 4; + byte[] pattern = new byte[length]; + for (int i = 0; i < length; i++) pattern[i] = (byte) i; + fBaseAddress = evaluateExpression("&charBlock"); + + // Ensure that the memory is zeroed + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count * length); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + MemoryByte[] block = (MemoryByte[]) fWait.getReturnInfo(); + for (int i = 0; i < (count * length); i++) + assertTrue("Wrong value read at offset " + i + ": expected '" + 0 + "', received '" + block[i].getValue() + "'", + (block[i].getValue() == (byte) 0)); + + // Write the pattern [count] times + fWait.waitReset(); + fillMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count, pattern); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Verify that the memory is correctly set + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count * length); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + block = (MemoryByte[]) fWait.getReturnInfo(); + for (int i = 0; i < count; i++) + for (int j = 0; j < length; j++) { + int index = i * length + j; + assertTrue("Wrong value read at offset " + index + ": expected '" + j + "', received '" + block[index].getValue() + "'", + (block[index].getValue() == (byte) j)); + } + + // Ensure the MemoryChangedEvent events were received + assertTrue("MemoryChangedEvent problem: expected " + 1 + " events, received " + getEventCount(), + getEventCount() == 1); + assertTrue("MemoryChangedEvent problem: expected " + BLOCK_SIZE + " distinct addresses, received " + getAddressCount(), + getAddressCount() == BLOCK_SIZE); + } + + // ------------------------------------------------------------------------ + // asynchronousReadWrite + // Test the asynchronous reading/writing of individual bytes (varying offset) + // ------------------------------------------------------------------------ + @Test + public void asynchronousReadWrite() throws Throwable { + + // Run to the point where the array is zeroed + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:zeroBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + int word_size = 1; + int count = 1; + fBaseAddress = evaluateExpression("&charBlock"); + + // Verify asynchronously that all bytes are '0' + fWait.waitReset(); + MemoryByte[] buffer = new MemoryByte[BLOCK_SIZE]; + for (int offset = 0; offset < BLOCK_SIZE; offset++) { + fWait.increment(); + readMemoryByteAtOffset(fGdbControlDmc, fBaseAddress, offset, word_size, count, buffer); + } + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + for (int offset = 0; offset < BLOCK_SIZE; offset++) { + assertTrue("Wrong value read at offset " + offset + ": expected '" + 0 + "', received '" + buffer[offset].getValue() + "'", + (buffer[offset].getValue() == (byte) 0)); + } + + // Write asynchronously + fWait.waitReset(); + for (int offset = 0; offset < BLOCK_SIZE; offset++) { + fWait.increment(); + byte[] block = new byte[count]; + block[0] = (byte) offset; + writeMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count, block); + } + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + // Ensure the MemoryChangedEvent events were received + assertTrue("MemoryChangedEvent problem: expected " + BLOCK_SIZE + " events, received " + getEventCount(), + getEventCount() == BLOCK_SIZE); + assertTrue("MemoryChangedEvent problem: expected " + BLOCK_SIZE + " distinct addresses, received " + getAddressCount(), + getAddressCount() == BLOCK_SIZE); + + // Verify asynchronously that all bytes are set + fWait.waitReset(); + for (int offset = 0; offset < BLOCK_SIZE; offset++) { + fWait.increment(); + readMemoryByteAtOffset(fGdbControlDmc, fBaseAddress, offset, word_size, count, buffer); + } + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + for (int offset = 0; offset < BLOCK_SIZE; offset++) { + assertTrue("Wrong value read at offset " + offset + ": expected '" + offset + "', received '" + buffer[offset].getValue() + "'", + (buffer[offset].getValue() == (byte) offset)); + } + } + + // ------------------------------------------------------------------------ + // memoryCacheRead + // Get a bunch of blocks to exercise the memory cache + // ------------------------------------------------------------------------ + @Test + public void memoryCacheRead() throws Throwable { + + // Run to the point where the variable is initialized + SyncUtil.SyncAddBreakpoint("MemoryTestApp.cc:setBlocks", true); + SyncUtil.SyncResumeUntilStopped(); + SyncUtil.SyncStep(StepType.STEP_RETURN); + + // Setup call parameters + long offset = 0; + int word_size = 1; + int count = BLOCK_SIZE; + fBaseAddress = evaluateExpression("&charBlock"); + + // Get the 'reference' memory block + fWait.waitReset(); + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + MemoryByte[] buffer = (MemoryByte[]) fWait.getReturnInfo(); + + // Verify that all bytes are set to 'i' + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + i + "', received '" + buffer[i].getValue() + "'", + (buffer[i].getValue() == (byte) i)); + } + + // Clear the cache + SyncUtil.SyncStep(StepType.STEP_OVER); + + // Get a first block + fWait.waitReset(); + offset = 0; + count = 64; + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + buffer = (MemoryByte[]) fWait.getReturnInfo(); + + // Verify that all bytes are correctly set + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + offset + i + "', received '" + buffer[i].getValue() + "'", + (buffer[i].getValue() == (byte) (offset + i))); + } + + // Get a second block + fWait.waitReset(); + offset = 128; + count = 64; + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + buffer = (MemoryByte[]) fWait.getReturnInfo(); + + // Verify that all bytes are correctly set + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + offset + i + "', received '" + buffer[i].getValue() + "'", + (buffer[i].getValue() == (byte) (offset + i))); + } + + // Get a third block between the first 2 + fWait.waitReset(); + offset = 80; + count = 32; + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + buffer = (MemoryByte[]) fWait.getReturnInfo(); + + // Verify that all bytes are correctly set + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + offset + i + "', received '" + buffer[i].getValue() + "'", + (buffer[i].getValue() == (byte) (offset + i))); + } + + // Get a block that is contiguous to the end of an existing block + fWait.waitReset(); + offset = 192; + count = 32; + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + buffer = (MemoryByte[]) fWait.getReturnInfo(); + + // Verify that all bytes are correctly set + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + offset + i + "', received '" + buffer[i].getValue() + "'", + (buffer[i].getValue() == (byte) (offset + i))); + } + + // Get a block that ends beyond an existing block + fWait.waitReset(); + offset = 192; + count = 64; + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + buffer = (MemoryByte[]) fWait.getReturnInfo(); + + // Verify that all bytes are correctly set + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + offset + i + "', received '" + buffer[i].getValue() + "'", + (buffer[i].getValue() == (byte) (offset + i))); + } + + // Get a block that will require 2 reads (for the gaps between blocks 1-2 and 2-3) + fWait.waitReset(); + offset = 32; + count = 128; + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + buffer = (MemoryByte[]) fWait.getReturnInfo(); + + // Verify that all bytes are correctly set + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + offset + i + "', received '" + buffer[i].getValue() + "'", + (buffer[i].getValue() == (byte) (offset + i))); + } + + // Get a block that involves multiple cached blocks + fWait.waitReset(); + offset = 48; + count = 192; + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + buffer = (MemoryByte[]) fWait.getReturnInfo(); + + // Verify that all bytes are set to 'i' + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + offset + i + "', received '" + buffer[i].getValue() + "'", + (buffer[i].getValue() == (byte) (offset + i))); + } + + // Get the whole block + fWait.waitReset(); + offset = 0; + count = BLOCK_SIZE; + readMemory(fGdbControlDmc, fBaseAddress, offset, word_size, count); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + buffer = (MemoryByte[]) fWait.getReturnInfo(); + + // Verify that all bytes are correctly set + for (int i = 0; i < count; i++) { + assertTrue("Wrong value read at offset " + i + ": expected '" + offset + i + "', received '" + buffer[i].getValue() + "'", + (buffer[i].getValue() == (byte) (offset + i))); + } + // Ensure no MemoryChangedEvent event was received + assertTrue("MemoryChangedEvent problem: expected " + 0 + ", received " + getEventCount(), getEventCount() == 0); + } + +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIRegistersTest.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIRegistersTest.java new file mode 100644 index 00000000000..d2006049a4a --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIRegistersTest.java @@ -0,0 +1,428 @@ +package org.eclipse.dd.tests.gdb; + + +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.List; + +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.debug.service.IFormattedValues; +import org.eclipse.dd.dsf.debug.service.IRegisters; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData; +import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterDMContext; +import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterGroupDMContext; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.gdb.service.command.GDBControlDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.MIStack; +import org.eclipse.dd.mi.service.command.events.MIStoppedEvent; +import org.eclipse.dd.tests.gdb.framework.AsyncCompletionWaitor; +import org.eclipse.dd.tests.gdb.framework.BackgroundRunner; +import org.eclipse.dd.tests.gdb.framework.BaseTestCase; +import org.eclipse.dd.tests.gdb.framework.SyncUtil; +import org.eclipse.dd.tests.gdb.launching.TestsPlugin; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(BackgroundRunner.class) + +public class MIRegistersTest extends BaseTestCase { + + final int NUMBER_OF_REGISTERS = 50; + /* + * Path to executable + */ + private static final String EXEC_PATH = "data/launch/bin/"; + /* + * Name of the executable + */ + private static final String EXEC_NAME = "MultiThread.exe"; + + // Will be used to wait for asynchronous call to complete + //private final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); + private DsfSession fSession; + private DsfServicesTracker fServicesTracker; + private GDBControlDMContext fGdbControlDmc; + private IRegisters fRegService; + private MIRunControl fRunControl; + private MIStack fStack; + + @Before + public void init() throws Exception { + fSession = getGDBLaunch().getSession(); + // We obtain the services we need after the new + // launch has been performed + fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId()); + + GDBControl gdbControl = fServicesTracker.getService(GDBControl.class); + fGdbControlDmc = gdbControl.getGDBDMContext(); + + fRegService = fServicesTracker.getService(IRegisters.class); + fRunControl = fServicesTracker.getService(MIRunControl.class); + fStack = fServicesTracker.getService(MIStack.class); + +// This is the way to have the entire application run +// final IDMContext execDMContext = ((MIRunControl)fRunControl).getExecutionDMC(); +// fRunControl.getExecutor().submit(new Runnable() { +// public void run() { +// fRunControl.resume(execDMContext, null); +// } +// }); + + } + + @BeforeClass + public static void beforeClassMethod() { + setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, + EXEC_PATH + EXEC_NAME); + } + + + @After + public void tearDown() { + fRegService = null; + fRunControl = null; + fStack = null; + } + + /* + * This is a common support method which gets the Register Group Information + * and verifies it. + */ + private IRegisterGroupDMContext getRegisterGroup() throws Throwable { + final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); + + final DataRequestMonitor regGroupDone = + new DataRequestMonitor(fRegService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + + fWait.waitFinished(getStatus()); + } + }; + + fRegService.getExecutor().submit(new Runnable() { + public void run() { + fRegService.getRegisterGroups(fGdbControlDmc, regGroupDone); + } + }); + + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + IRegisterGroupDMContext[] regGroupsDMCs = (IRegisterGroupDMContext[])fWait.getReturnInfo(); + assertTrue("There was more than one register group (" + regGroupsDMCs.length + ")", //$NON-NLS-1$ + regGroupsDMCs.length == 1 ); + fWait.waitReset(); + + return(regGroupsDMCs[0]); + } + + /* + * This is a common support method which gets the Registers names. + */ + + private IRegisterDMContext[] getRegisters(final IFrameDMContext frameDmc) throws Throwable { + final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); + final IRegisterGroupDMContext regGroupsDMC = getRegisterGroup(); + + final DataRequestMonitor regDone = + new DataRequestMonitor(fRegService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + + fWait.waitFinished(getStatus()); + } + }; + + fRegService.getExecutor().submit(new Runnable() { + public void run() { +// fRegService.getRegisters(regGroupsDMC, frameDmc, regDone); + fWait.waitFinished( + new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Commented out some code until it can compile", null)); + } + }); + + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + IRegisterDMContext[] regContexts = (IRegisterDMContext[]) fWait.getReturnInfo(); + + fWait.waitReset(); + + assertTrue("The number of registers should have been " + NUMBER_OF_REGISTERS + + " instead of " + regContexts.length, + regContexts.length == NUMBER_OF_REGISTERS); + + return(regContexts); + } + + /************************************************************************* + * + * The tests for the register service. + * + *************************************************************************/ + + @Test + public void getRegisterGroups() throws Throwable { + final IRegisterGroupDMContext regGroupsDMC = getRegisterGroup(); + + assertTrue("The name of the main group should be: General Registers instead of: " + + regGroupsDMC.getName(), + regGroupsDMC.getName().equals("General Registers")); + } + + @Test + public void getRegistersLength() throws Throwable { + IMIExecutionDMContext execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + final IRegisterDMContext[] regDMCs = getRegisters(frameDmc); + assertTrue("The number of registers should have been " + NUMBER_OF_REGISTERS + + " instead of " + regDMCs.length, + regDMCs.length == NUMBER_OF_REGISTERS); + + } + + @Test + public void getRegisters() throws Throwable { + IMIExecutionDMContext execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + final IRegisterDMContext[] regDMCs = getRegisters(frameDmc); + List regNames = Arrays.asList("eax","ecx","edx","ebx","esp","ebp","esi","edi","eip","eflags","cs","ss","ds","es","fs","gs","st0","st1","st2","st3","st4","st5","st6","st7","fctrl","fstat","ftag","fiseg","fioff","foseg","fooff","fop","xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7","mxcsr","orig_eax","mm0","mm1","mm2","mm3","mm4","mm5","mm6","mm7"); + for(IRegisterDMContext reg: regDMCs){ + String regName = reg.getName(); + Assert.assertFalse("GDB does not support register name: " + regName, !regNames.contains(regName)); + } + } + + //private static String REGISTER_VALUE = "16"; + private String getModelDataForRegisterDataValue(IFrameDMContext frameDmc, String format, int regNo) throws Throwable { + final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); + + final IRegisterDMContext[] regDMCs = getRegisters(frameDmc); + final FormattedValueDMContext valueDmc = fRegService.getFormattedValueContext(regDMCs[regNo], format); + + final DataRequestMonitor regRm = + new DataRequestMonitor(fRegService.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + + fWait.waitFinished(getStatus()); + } + }; + + fRegService.getExecutor().submit(new Runnable() { + public void run() { + fRegService.getFormattedExpressionValue(valueDmc, regRm); + } + }); + + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(fWait.getMessage(), fWait.isOK()); + + + FormattedValueDMData data = (FormattedValueDMData)fWait.getReturnInfo(); + String val = data.getFormattedValue(); + fWait.waitReset(); + return val; + } + + + private static String REGISTER_VALUE = ""; + @Test + public void getModelDataForRegisterDataValueNatural() throws Throwable { + IMIExecutionDMContext execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 0); + REGISTER_VALUE = val; + assertTrue("Register Value is not in NATURAL format " , Integer.parseInt(val)== Integer.parseInt(REGISTER_VALUE)); + } + + @Test + public void getModelDataForRegisterDataValueHex() throws Throwable { + IMIExecutionDMContext execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.HEX_FORMAT, 0); + assertTrue("Register Value is not in HEX_FORMAT " ,val.startsWith("0x")); + } + + @Test + public void getModelDataForRegisterDataValueBinary() throws Throwable { + IMIExecutionDMContext execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.BINARY_FORMAT, 0); + assertTrue("Register Value is not in BINARY_FORMAT " , val.equals(Integer.toBinaryString(Integer.parseInt(REGISTER_VALUE)))); + } + + @Test + public void getModelDataForRegisterDataValueDecimal() throws Throwable { + IMIExecutionDMContext execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.DECIMAL_FORMAT , 0); + assertTrue("Register Value is not in DECIMAL_FORMAT" ,Integer.parseInt(val) == Integer.parseInt(REGISTER_VALUE)); + } + + @Test + public void getModelDataForRegisterDataValueOctal() throws Throwable { + IMIExecutionDMContext execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.OCTAL_FORMAT, 0); + assertTrue("Register Value is not in OCTAL_FORMAT " ,val.startsWith("0")); + } + + + @Test + public void compareRegisterForMultipleExecutionContexts() throws Throwable { + final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); + + IMIExecutionDMContext execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + + String regVal0 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 0); + String regVal1 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 1); + String regVal2 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 2); + String regVal3 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 3); + String regVal4 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 4); + String regVal5 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 5); + + MIStoppedEvent stoppedEvent = SyncUtil.SyncRunToLine(EXEC_NAME + ".cc", "22"); + execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 2); + frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + String thread2RegVal0 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 0); + String thread2RegVal1 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 1); + String thread2RegVal2 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 2); + String thread2RegVal3 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 3); + String thread2RegVal4 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 4); + String thread2RegVal5 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 5); + + // Set execution context to 1 + execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 0); + + // Re-set the execution context to 2 and Fetch from the Cache + execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 2); + frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + String dupliThread2RegVal0 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 0); + String dupliThread2RegVal1 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 1); + String dupliThread2RegVal2 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 2); + String dupliThread2RegVal3 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 3); + String dupliThread2RegVal4 = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 4); + String dupliThread2RegVal5= getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 5); + + // If Values not equal , then context haven't been re-set properly + assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal0.equals(dupliThread2RegVal0)); + assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal1.equals(dupliThread2RegVal1)); + assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal2.equals(dupliThread2RegVal2)); + assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal3.equals(dupliThread2RegVal3)); + assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal4.equals(dupliThread2RegVal4)); + assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal5.equals(dupliThread2RegVal5)); + + } + + private void writeRegister(IFrameDMContext frameDmc, final int regIndex, final String regValue, final String formatId) throws Throwable { + final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); + +// final MIRegisterGroupDMC grpDmc = new MIRegisterGroupDMC( (MIRegisters)fRegService , 0 , "General Registers" ) ; + final IRegisterDMContext[] regDMCs = getRegisters(frameDmc); + + + final RequestMonitor writeDone = + new RequestMonitor(fRegService.getExecutor(), null) { + @Override + protected void handleCompleted() { + fWait.waitFinished(getStatus()); + } + }; + + fRegService.getExecutor().submit(new Runnable() { + public void run() { +// fRegService.writeRegister(grpDmc, regDMCs[regIndex], regValue, +// formatId, writeDone); + fWait.waitFinished( + new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "Commented out some code until it can compile", null)); + + } + }); + + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + fWait.waitReset(); + } + + + @Test + public void writeRegisterNaturalFormat() throws Throwable{ + IMIExecutionDMContext execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + String regValue = "10"; + int regIndex = 3; + writeRegister(frameDmc, 3, regValue, IFormattedValues.NATURAL_FORMAT); + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, regIndex); + assertTrue("Failed writing register. New value should have been " + regValue, regValue.equals(val)); + } + + @Test + public void writeRegisterHEXFormat() throws Throwable{ + IMIExecutionDMContext execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + String regValue = "0x10"; + int regIndex = 3; + writeRegister(frameDmc, 3, regValue, IFormattedValues.HEX_FORMAT); + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.HEX_FORMAT, regIndex); + assertTrue("Failed writing register. New value should have been " + regValue, regValue.equals(val)); + } + + @Test + @Ignore + public void writeRegisterBinaryFormat() throws Throwable{ + IMIExecutionDMContext execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + //String regValue = "0100101001"; + String regValue = "10"; + int regIndex = 3; + writeRegister(frameDmc, 3, regValue, IFormattedValues.BINARY_FORMAT); + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.BINARY_FORMAT, regIndex); + assertTrue("Failed writing register. New value should have been " + regValue + " instead of " + val, regValue.equals(val)); + } + + @Test + public void writeRegisterOctalFormat() throws Throwable{ + IMIExecutionDMContext execDmc = fRunControl.createMIExecutionContext(fGdbControlDmc, 1); + IFrameDMContext frameDmc = SyncUtil.SyncGetStackFrame(execDmc, 0); + //String regValue = "10"; + String regValue = "012"; + int regIndex = 3; + writeRegister(frameDmc, 3, regValue, IFormattedValues.OCTAL_FORMAT); + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.OCTAL_FORMAT, regIndex); + assertTrue("Failed writing register. New value should have been " + regValue + "instead of " + val, regValue.equals(val)); + } + +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIRunControlTest.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIRunControlTest.java new file mode 100644 index 00000000000..46405971cd8 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIRunControlTest.java @@ -0,0 +1,654 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson AB - Initial implementation of Test cases + *******************************************************************************/ +package org.eclipse.dd.tests.gdb; + + +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMData; +import org.eclipse.dd.dsf.debug.service.IRunControl.IResumedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.IStartedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.dd.dsf.debug.service.IRunControl.StepType; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.gdb.service.command.GDBControlDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.MIStack; +import org.eclipse.dd.mi.service.command.events.MIStoppedEvent; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.tests.gdb.framework.AsyncCompletionWaitor; +import org.eclipse.dd.tests.gdb.framework.BaseTestCase; +import org.eclipse.dd.tests.gdb.framework.ServiceEventWaitor; +import org.eclipse.dd.tests.gdb.framework.SyncUtil; +import org.eclipse.dd.tests.gdb.launching.TestsPlugin; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + + +/* + * Tests MIRunControl class for Multi-threaded application. + */ +public class MIRunControlTest extends BaseTestCase { + + private DsfServicesTracker fServicesTracker; + + private GDBControl fGDBCtrl; + private MIRunControl fRunCtrl; + private MIStack fStack; + + /* + * Boolean variables for testing events. Test thread create event only when this is set to true + */ + private boolean fIsTestingThreadCreateEvent = false; + /* + * Boolean variables for error from events. Set to true only if there is an error in the event being tested. + */ + private boolean fIsEventError = false; + + + /* + * Path to executable + */ + private static final String EXEC_PATH = "data/launch/bin/"; + /* + * Name of the executable + */ + private static final String EXEC_NAME = "MultiThread.exe"; + private static final String SOURCE_NAME = "MultiThread.cc"; + + + /* + * Variable to wait for asynchronous call to complete + */ + private final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); + + @Before + public void init() throws Exception { + fServicesTracker = + new DsfServicesTracker(TestsPlugin.getBundleContext(), + getGDBLaunch().getSession().getId()); + /* + * Get the MIRunControl & MIStack service. + */ + fGDBCtrl = fServicesTracker.getService(GDBControl.class); + fRunCtrl = fServicesTracker.getService(MIRunControl.class); + fStack = fServicesTracker.getService(MIStack.class); + /* + * Add to the Listeners list + */ + getGDBLaunch().getSession().addServiceEventListener(this, null); + } + + @After + public void tearDown() { + fRunCtrl = null; + fStack = null; + fServicesTracker.dispose(); + } + + @BeforeClass + public static void beforeClassMethod() { + setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, + EXEC_PATH + EXEC_NAME); + } + + + /* + * For Multi-threaded application - In case of one thread, Thread id should start with 1. + */ + @Test + public void getExecutionContext() throws InterruptedException{ + //TestsPlugin.debugMethod("getExecutionContext()"); + /* + * Create a request monitor + */ + final DataRequestMonitor rm = + new DataRequestMonitor(fRunCtrl.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + + /* + * Test getExecutionContexts() when only one thread exist. + */ + fRunCtrl.getExecutor().submit(new Runnable() { + public void run() { + fRunCtrl.getExecutionContexts(fGDBCtrl.getGDBDMContext(), rm); + } + }); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + Assert.assertTrue(fWait.getMessage(), fWait.isOK()); + + /* + * Get data from the Request Monitor + */ + IRunControl.IExecutionDMContext[] ctxts = rm.getData(); + + // Context can not be null + if(ctxts == null) + Assert.fail("Context returned is null. Atleast one context should have been returned"); + else{ + // Only one Context in this case + if(ctxts.length > 1) + Assert.fail("Context returned canot be more than 1. This test case is for single context application."); + IMIExecutionDMContext dmc = (IMIExecutionDMContext)ctxts[0]; + // Thread id for the main thread should be one + Assert.assertEquals(1, dmc.getThreadId()); + } + fWait.waitReset(); + } + + + /* + * Get Execution DMCs for a valid container DMC + * Testing for two execution DMC with id 1 & 2 + */ + @Test + public void getExecutionContexts() throws InterruptedException{ + //TestsPlugin.debugMethod("getExecutionContexts()"); + /* + * Create a request monitor + */ + final DataRequestMonitor rmExecutionCtxts = + new DataRequestMonitor(fRunCtrl.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + /* + * Also Testing Thread create event. Set boolean variable to true + */ + fIsTestingThreadCreateEvent = true; + try{ + /* + * Run till line for 2 threads to be created + */ + SyncUtil.SyncRunToLine(fGDBCtrl.getGDBDMContext(), SOURCE_NAME, "22", true); + } + catch(Throwable t){ + Assert.fail("Exception in SyncUtil.SyncRunToLine: " + t.getMessage()); + } + /* + * Re-set the boolean variable for testing thread create event. + */ + fIsTestingThreadCreateEvent = false; + /* + * Check if error in thread create event + */ + if(fIsEventError){ + Assert.fail("Thread create event has failed."); + } + /* + * Test getExecutionContexts for a valid container DMC + */ + fRunCtrl.getExecutor().submit(new Runnable() { + public void run() { + fRunCtrl.getExecutionContexts(fGDBCtrl.getGDBDMContext(), rmExecutionCtxts); + } + }); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + Assert.assertTrue(fWait.getMessage(), fWait.isOK()); + fWait.waitReset(); + /* + * Get data + */ + IRunControl.IExecutionDMContext[] data = rmExecutionCtxts.getData(); + /* + * Contexts returned can not be null + */ + if(data == null) + Assert.fail("No context returned. 2 Contexts with id 1 & 2 should have been returned"); + else{ + // 2 Contexts shd be returned + Assert.assertTrue(data.length==2); + IMIExecutionDMContext dmc1 = (IMIExecutionDMContext)data[0]; + IMIExecutionDMContext dmc2 = (IMIExecutionDMContext)data[1]; + // Context ids should be 1 & 2 + Assert.assertTrue(dmc1.getThreadId()==2 && dmc2.getThreadId() == 1); + } + } + + /* + * Testing getModelData() for ExecutionDMC + */ + @Test + public void getModelDataForThread() throws InterruptedException{ + //TestsPlugin.debugMethod("getModelDataForThread("); + /* + * Create a request monitor + */ + final DataRequestMonitor rm = + new DataRequestMonitor(fRunCtrl.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + /* + * Call getModelData for Execution DMC + */ + fRunCtrl.getExecutor().submit(new Runnable() { + public void run() { + fRunCtrl.getExecutionData(fRunCtrl.createMIExecutionContext(fGDBCtrl.getGDBDMContext(), 1), rm); + } + }); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + Assert.assertTrue(fWait.getMessage(), fWait.isOK()); + + IRunControl.IExecutionDMData data = rm.getData(); + if(data == null) + Assert.fail("No data returned."); + else{ + /* + * getModelData should return StateChangeReason. + */ + Assert.assertTrue(" State change reason for a normal execution should be CONTAINER." , + StateChangeReason.CONTAINER == data.getStateChangeReason()); + } + } + + @Test + public void getModelDataForThreadWhenStep() throws Throwable { + //TestsPlugin.debugMethod("getModelDataForThread()"); + /* + * Run till step returns + */ + final MIStoppedEvent stoppedEvent = SyncUtil.SyncStep(StepType.STEP_OVER); + + final DataRequestMonitor rm = + new DataRequestMonitor(fRunCtrl.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + /* + * getModelData for Execution DMC + */ + fRunCtrl.getExecutor().submit(new Runnable() { + public void run() { + fRunCtrl.getExecutionData(stoppedEvent.getDMContext(), rm); + } + }); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + Assert.assertTrue(fWait.getMessage(), fWait.isOK()); + + IRunControl.IExecutionDMData data = rm.getData(); + if(data == null) + Assert.fail("No data Returned."); + else{ + /* + * getModelData for Execution DMC in case Step has been performed. + */ + Assert.assertTrue("getModelData for ExecutionDMC in case of step should be STEP." , + StateChangeReason.STEP == data.getStateChangeReason()); + } + } + + /* + * getModelData() for ExecutionDMC when a breakpoint is hit + */ + @Test + public void getModelDataForThreadWhenBreakpoint() throws Throwable { + //TestsPlugin.debugMethod("getModelDataForThreadWhenBreakpoint()"); + /* + * Add a breakpoint + */ + SyncUtil.SyncAddBreakpoint(SOURCE_NAME + ":21", false); + + /* + * Resume till the breakpoint is hit + */ + final MIStoppedEvent stoppedEvent = SyncUtil.SyncResumeUntilStopped(); + + final DataRequestMonitor rm = + new DataRequestMonitor(fRunCtrl.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + fRunCtrl.getExecutor().submit(new Runnable() { + public void run() { + fRunCtrl.getExecutionData(stoppedEvent.getDMContext(), rm); + } + }); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + Assert.assertTrue(fWait.getMessage(), fWait.isOK()); + + IRunControl.IExecutionDMData data = rm.getData(); + if(data == null) + Assert.fail("No data Returned."); + else{ + /* + * getModelData for ExecutionDMC in case a breakpoint is hit + */ + Assert.assertTrue("getModelData for an Execution DMC when a breakpoint is hit is not BREAKPOINT and is " + data.getStateChangeReason(), + StateChangeReason.BREAKPOINT == data.getStateChangeReason()); + } + } + + /* + * getModelData() for Container DMC + */ + @Test + public void getModelDataForContainer() throws InterruptedException{ + //TestsPlugin.debugMethod("getModelDataForContainer()"); + final DataRequestMonitor rm = + new DataRequestMonitor(fRunCtrl.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + + fRunCtrl.getExecutor().submit(new Runnable() { + public void run() { + fRunCtrl.getExecutionData(fGDBCtrl.getGDBDMContext(), rm); + } + }); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + Assert.assertTrue(fWait.getMessage(), fWait.isOK()); + + IRunControl.IExecutionDMData data = rm.getData(); + if(data == null) + Assert.fail("No data returned."); + else{ + /* + * StateChangeReason in getModelData for Container DMC is null. + */ + Assert.assertNull(data.getStateChangeReason()); + } + } + + /* + * getExecutionContexts for an invalid container DMC + */ + @Ignore + @Test + public void getExecutionContextsForInvalidContainerDMC() throws InterruptedException{ + //TestsPlugin.debug("getExecutionContextsForInvalidContainerDMC()"); + final DataRequestMonitor rm = + new DataRequestMonitor(fRunCtrl.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + fWait.setReturnInfo(getData()); + } + fWait.waitFinished(getStatus()); + } + }; + final IContainerDMContext ctxt = new GDBControlDMContext("-1", getClass().getName() + ":" + 1); + fRunCtrl.getExecutor().submit(new Runnable() { + public void run() { + // Pass an invalid dmc + fRunCtrl.getExecutionContexts(fGDBCtrl.getGDBDMContext(), rm); + } + }); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + Assert.assertTrue(fWait.getMessage(), !fWait.isOK()); + + IStatus status = rm.getStatus(); + Assert.assertEquals("Error message for invalid container", IStatus.ERROR, status.getSeverity()); + } + + /* + * Test Thread Create event for thread ID. Thread IDs should be GDB generated thread ids. + */ + @DsfServiceEventHandler + public void eventDispatched(IStartedDMEvent e) { + if(fIsTestingThreadCreateEvent){ + if(((IMIExecutionDMContext)e.getExecutionContext()).getThreadId() != 2) + /* + * Set variable if thread create event is unsuccesful + */ + fIsEventError = true; + } + } + + /* + * Cache after ContainerSuspendEvent should be re-set + */ + @Test + public void cacheAfterContainerSuspendEvent() throws InterruptedException{ + //TestsPlugin.debugMethod("cacheAfterContainerSuspendEvent()"); + final IExecutionDMContext dmc = fRunCtrl.createMIExecutionContext(fGDBCtrl.getGDBDMContext(), 1); + /* + * Step to fire ContainerSuspendEvent + */ + try { + SyncUtil.SyncStep(dmc, StepType.STEP_OVER); + } catch (Throwable e) { + Assert.fail("Exception in SyncUtil.SyncStep: " + e.getMessage()); + } + /* + * Cache should be re-set + */ + //TODO TRy going to back end and fetching values instead + //Assert.assertEquals(fRunCtrl.getCache().getCachedContext().size(), 0); + } + + + //Also test Cache after ContainerResumeEvent + @Test + public void resume() throws InterruptedException{ + //TestsPlugin.debugMethod("resume()"); + + final DataRequestMonitor rm = + new DataRequestMonitor(fRunCtrl.getExecutor(), null) { + @Override + protected void handleCompleted() { + fWait.waitFinished(getStatus()); + //TestsPlugin.debug("handleCompleted over"); + } + }; + final ServiceEventWaitor eventWaitor = + new ServiceEventWaitor( + getGDBLaunch().getSession(), + IResumedDMEvent.class); + + fRunCtrl.getExecutor().submit(new Runnable() { + public void run() { + fRunCtrl.resume(fGDBCtrl.getGDBDMContext(), rm); + } + }); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + + try { + eventWaitor.waitForEvent(ServiceEventWaitor.WAIT_FOREVER); + } catch (Exception e) { + Assert.fail("Exception raised:: " + e.getMessage()); + e.printStackTrace(); + return; + } + if (fWait.isOK() == false) + Assert.assertTrue(fWait.getMessage(), false); + Assert.assertFalse("Target is suspended. It should have been running", fRunCtrl.isSuspended(fGDBCtrl.getGDBDMContext())); + fWait.waitReset(); + } + + + + + @Test + public void resumeContainerContext() throws InterruptedException{ + //TestsPlugin.debugMethod("resumeContainerContext()"); + final DataRequestMonitor rm = + new DataRequestMonitor(fRunCtrl.getExecutor(), null) { + @Override + protected void handleCompleted() { + fWait.waitFinished(getStatus()); + } + }; + + final ServiceEventWaitor eventWaitor = + new ServiceEventWaitor( + getGDBLaunch().getSession(), + IResumedDMEvent.class); + + fRunCtrl.getExecutor().submit(new Runnable() { + public void run() { + fRunCtrl.resume(fGDBCtrl.getGDBDMContext(), rm); + } + }); + fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + try { + eventWaitor.waitForEvent(ServiceEventWaitor.WAIT_FOREVER); + //TestsPlugin.debug("DsfMIRunningEvent received"); + } catch (Exception e) { + Assert.fail("Exception raised:: " + e.getMessage()); + e.printStackTrace(); + return; + } + + if (fWait.isOK() == false) + Assert.assertTrue(fWait.getMessage(), false); + Assert.assertFalse("Target is suspended. It should have been running", fRunCtrl.isSuspended(fGDBCtrl.getGDBDMContext())); + fWait.waitReset(); + } + + // PP: test no longer applies, the resume command now takes a strongly-typed execution context as an argument. + // +// @Test +// public void resumeFrameContext() throws Throwable { +// //TestsPlugin.debugMethod("resumeFrameContext()"); +// final DataRequestMonitor rm = +// new DataRequestMonitor(fRunCtrl.getExecutor(), null) { +// @Override +// protected void handleCompleted() { +// fWait.waitFinished(getStatus()); +// } +// }; +// final ServiceEventWaitor eventWaitor = +// new ServiceEventWaitor( +// getGDBLaunch().getSession(), +// IResumedDMEvent.class); +// +// IExecutionDMContext execDmc = fRunCtrl.createMIExecutionContext(fGDBCtrl.getGDBDMContext(), 1); +// final IFrameDMContext dmc = SyncUtil.SyncGetStackFrame(execDmc, 0); +// fRunCtrl.getExecutor().submit(new Runnable() { +// public void run() { +// fRunCtrl.resume(dmc, rm); +// } +// }); +// fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); +// +// try { +// eventWaitor.waitForEvent(ServiceEventWaitor.WAIT_FOREVER); +// } catch (Exception e) { +// Assert.fail("Exception raised:: " + e.getMessage()); +// e.printStackTrace(); +// return; +// } +// +// if (fWait.isOK() == false) +// Assert.assertTrue(fWait.getMessage(), false); +// Assert.assertFalse("Target is suspended. It should have been running", fRunCtrl.isSuspended(fGDBCtrl.getGDBDMContext())); +// fWait.waitReset(); +// } + +// @Test +// public void resumeAndSuspend() throws InterruptedException{ +// final DataRequestMonitor rm = +// new DataRequestMonitor(fRunCtrl.getExecutor(), null) { +// @Override +// protected void handleCompleted() { +// if (getStatus().isOK()) { +// assert true; +// fWait.setReturnInfo(getData()); +// } +// System.out.println("Wait Finished called on getTHreads rm with status " + getStatus().getMessage()); +// fWait.waitFinished(getStatus()); +// } +// }; +// final MIExecutionDMC dmc = new MIExecutionDMC(fRunCtrl, 1); +// fRunCtrl.getExecutor().submit(new Runnable() { +// public void run() { +// fRunCtrl.resume(dmc, rm); +// } +// }); +// fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); +// if (fWait.isOK() == false) +// Assert.assertTrue(fWait.getMessage(), false); +// System.out.println("Message from isSuspended " +fRunCtrl.isSuspended(dmc)); +// Assert.assertFalse("Target is suspended. It should have been running", fRunCtrl.isSuspended(dmc)); +// fWait.waitReset(); +// +// final DataRequestMonitor rmSuspend = +// new DataRequestMonitor(fRunCtrl.getExecutor(), null) { +// @Override +// protected void handleCompleted() { +// if (getStatus().isOK()) { +// assert true; +// fWait.setReturnInfo(getData()); +// } +// System.out.println("Wait Finished called on getTHreads rm with status " + getStatus().getMessage()); +// fWait.waitFinished(getStatus()); +// } +// }; +// +// final ServiceEventWaitor eventWaitor = +// new ServiceEventWaitor( +// getGDBLaunch().getSession(), +// DsfMIStoppedEvent.class); +// +// fRunCtrl.getExecutor().submit(new Runnable() { +// public void run() { +// fRunCtrl.suspend(dmc, rmSuspend); +// } +// }); +// fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); +// try { +// eventWaitor.waitForEvent(ServiceEventWaitor.WAIT_FOREVER); +// } catch (Exception e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// +// if (fWait.isOK() == false) +// Assert.assertTrue(fWait.getMessage(), false); +// System.out.println("Message from isSuspended !!! " +fRunCtrl.isSuspended(dmc)); +// Assert.assertTrue("Target is running. It should have been suspended.", fRunCtrl.isSuspended(dmc)); +// fWait.waitReset(); +// } +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/AsyncCompletionWaitor.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/AsyncCompletionWaitor.java new file mode 100644 index 00000000000..c66ab38e789 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/AsyncCompletionWaitor.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial Implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb.framework; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.tests.gdb.launching.TestsPlugin; + +public class AsyncCompletionWaitor { + + /* + * Indicates we will wait forever. Otherwise the time specified + * is in milliseconds. + */ + public final static int WAIT_FOREVER = 0; + + /* + * Private control space. + */ + private IStatus fStatus; + private Object fReturnInfo; + private boolean fWaitFinished; + private int fNumWaiting; + + /* + * Main constructor. + */ + public AsyncCompletionWaitor() { + waitReset(); + } + + /* + * A timeout of WAIT_FOREVER indicates we wait until the operation is + * completed by a call to waitFinished. Or if we are interrupted + * with an exception. + */ + public synchronized void waitUntilDone(int timeout) throws InterruptedException { + if (fWaitFinished) return; + + wait(timeout); + } + + + /* + * Indicates that we are done with the operation and the code + * waiting ( waitUntilDone ) will be allowed to continue. + */ + public void waitFinished() { + waitFinished(new Status(IStatus.OK, TestsPlugin.PLUGIN_ID, "")); + } + + public synchronized void waitFinished(IStatus status) { + + if (fWaitFinished) { + ((MultiStatus)fStatus).merge( + new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, + "waitFinished called too many times!", null)); + } + + ((MultiStatus)fStatus).merge(status); + + if (fNumWaiting == 0 || --fNumWaiting == 0) { + fWaitFinished = true; + notifyAll(); + } + } + + /* + * Resets the state so we allow ourselves to be reused instead + * of having to create a new wait object each time. + */ + public synchronized void waitReset() { + fWaitFinished = false; + fStatus = new MultiStatus(TestsPlugin.PLUGIN_ID, 0, "", null); //$NON-NLS-1$ + fReturnInfo = null; + fNumWaiting = 0; + } + + public boolean isOK() { + if ( fStatus == null ) { + // We timed out + return false; + } + + return fStatus.isOK(); + } + + public String getMessage() { + if ( fStatus == null ) { + return "Timed out"; //$NON-NLS-1$ + } + + // Build a concatenation of all messages + String fullMessage = ""; + IStatus[] children = fStatus.getChildren(); + for (int i=0; i 0) { + fullMessage += "\"" + children[i].getMessage() + "\", ";//$NON-NLS-1$//$NON-NLS-2$ + } + } + // Remove the trailing comma and space before returning (as long as they are there) + return fullMessage.length() <= 2 ? fullMessage : fullMessage.substring(0, fullMessage.length() - 2); + } + + public void setReturnInfo(Object info) { + fReturnInfo = info ; + } + + public Object getReturnInfo() { + return fReturnInfo; + } + + public void increment() { + fNumWaiting++; + } +} \ No newline at end of file diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/BackgroundRunner.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/BackgroundRunner.java new file mode 100644 index 00000000000..ef85d412722 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/BackgroundRunner.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial Implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb.framework; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.QualifiedName; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.dd.tests.gdb.launching.TestsPlugin; +import org.eclipse.swt.widgets.Display; +import org.junit.internal.runners.InitializationError; +import org.junit.internal.runners.TestClassRunner; +import org.junit.runner.notification.RunNotifier; + +/** + * This runner starts an eclipse job ro run the tests, so as + * to release the UI thread. + */ +@SuppressWarnings("restriction") +public class BackgroundRunner extends TestClassRunner { + + public BackgroundRunner(Class klass) throws InitializationError { + super(klass); + } + + final static QualifiedName BACKGROUND_TEST_EXECUTION_FINISHED = new QualifiedName(TestsPlugin.getDefault().getBundle().getSymbolicName(), "background_test_execution_finished"); //$NON-NLS-1$ + + void invokeSuperRunImpl(RunNotifier notifier) { + super.run(notifier); + } + + /* + * This method overrides the one from TestClassRunner. + * What we do here is start a background job which will call + * TestClassRunner.run; this enables us to release + * the main UI thread. + * + * This has been adapted from the JUnits tests of TargetManagement + * (RSECoreTestCase and RSEWaitAndDispatchUtil) + */ + @Override + public void run(final RunNotifier notifier) { + + // Start the test in a background thread + Job job = new Job("GDB/MI JUnit Test Case Execution Job") { + @Override + protected IStatus run(IProgressMonitor monitor) { + invokeSuperRunImpl(notifier); + monitor.done(); + setProperty(BACKGROUND_TEST_EXECUTION_FINISHED, Boolean.TRUE); + + // The job never fails. The test result is the real result. + return Status.OK_STATUS; + } + }; + + // The job is not complete yet + job.setProperty(BACKGROUND_TEST_EXECUTION_FINISHED, Boolean.FALSE); + // schedule the job to run immediatelly + job.schedule(); + + // wait till the job finishes executing + waitAndDispatch(0, new BackgroundTestExecutionJobWaiter(job)); + } + + public interface IInterruptCondition { + public boolean isTrue(); + public void dispose(); + } + + private final static class BackgroundTestExecutionJobWaiter implements IInterruptCondition { + private final Job job; + + public BackgroundTestExecutionJobWaiter(Job job) { + assert job != null; + this.job = job; + } + + public boolean isTrue() { + // Interrupt the wait method if the job signaled that it has finished. + return ((Boolean)job.getProperty(BACKGROUND_TEST_EXECUTION_FINISHED)).booleanValue(); + } + + public void dispose() { + // nothing to do + } + } + + public static boolean waitAndDispatch(long timeout, IInterruptCondition condition) { + assert timeout >= 0 && condition != null; + + boolean isTimedOut= false; + if (timeout >= 0 && condition != null) { + long start = System.currentTimeMillis(); + Display display = Display.findDisplay(Thread.currentThread()); + if (display != null) { + // ok, we are running within a display thread --> keep the + // display event dispatching running. + long current = System.currentTimeMillis(); + while (timeout == 0 || (current - start) < timeout) { + if (condition.isTrue()) break; + if (!display.readAndDispatch()) display.sleep(); + current = System.currentTimeMillis(); + } + isTimedOut = (current - start) >= timeout && timeout > 0; + } else { + // ok, we are not running within a display thread --> we can + // just block the thread here + long current = System.currentTimeMillis(); + while (timeout == 0 || (current - start) < timeout) { + if (condition.isTrue()) break; + try { Thread.sleep(50); } catch (InterruptedException e) { /* ignored on purpose */ } + current = System.currentTimeMillis(); + } + isTimedOut = (current - start) >= timeout && timeout > 0; + } + } + + // Signal the interrupt condition that we are done here + // and it can cleanup whatever necessary. + condition.dispose(); + + return isTimedOut; + } + +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/BaseTestCase.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/BaseTestCase.java new file mode 100644 index 00000000000..7e86c586dec --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/BaseTestCase.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial Implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb.framework; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.dd.gdb.launching.GdbLaunch; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationType; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.core.ILaunchManager; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; + +/** + * This is the base class for the GDB/MI Unit tests. + * It provides the @Before and @After methods which setup + * and teardown the launch, for each test. + * If these methods are overwridden by a subclass, the new method + * must call super.baseSetup or super.baseTeardown itself, if this + * code is to be run. + */ +public class BaseTestCase { + + private static final String DEFAULT_TEST_APP = "data/launch/bin/GDBMIGenericTestApp"; + + private static GdbLaunch fLaunch; + private static Map attrs = new HashMap(); + + public GdbLaunch getGDBLaunch() { return fLaunch; } + + public static void setLaunchAttribute(String key, Object value) { + attrs.put(key, value); + } + + @BeforeClass + public static void baseBeforeClassMethod() { + // Setup information for the launcher + attrs.put(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, DEFAULT_TEST_APP); + + attrs.put(ICDTLaunchConfigurationConstants.ATTR_USE_TERMINAL, true); + attrs.put(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, true); + attrs.put(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT); + } + + @Before + public void baseBeforeMethod() throws Exception { + System.out.println("===================================================================="); + System.out.println("Launching test application: " + attrs.get(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME)); + System.out.println("===================================================================="); + + ILaunchManager launchMgr = DebugPlugin.getDefault().getLaunchManager(); + ILaunchConfigurationType lcType = launchMgr.getLaunchConfigurationType("org.eclipse.dd.tests.gdb.TestLaunch"); + assert lcType != null; + + ILaunchConfigurationWorkingCopy lcWorkingCopy = lcType.newInstance( + null, + launchMgr.generateUniqueLaunchConfigurationNameFrom("Test Launch")); //$NON-NLS-1$ + assert lcWorkingCopy != null; + lcWorkingCopy.setAttributes(attrs); + + final ILaunchConfiguration lc = lcWorkingCopy.doSave(); + assert lc != null; + + fLaunch = (GdbLaunch)lc.launch(ILaunchManager.DEBUG_MODE, new NullProgressMonitor()); + assert fLaunch != null; + + // Now initialize our SyncUtility, since we have the launcher + SyncUtil.initialize(fLaunch.getSession()); + } + + @After + public void baseAfterMethod() throws Exception { + System.out.println("===================================================================="); + System.out.println("Tearing down test application: " + attrs.get(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME)); + System.out.println("===================================================================="); + if (fLaunch != null) { + fLaunch.terminate(); + fLaunch = null; + } + } + + @AfterClass + public static void baseAfterClassMehod() throws Exception { + } +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/ServiceEventWaitor.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/ServiceEventWaitor.java new file mode 100644 index 00000000000..07e1ee77f75 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/ServiceEventWaitor.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial Implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb.framework; + +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; + +/* + * This class provides a way to wait for an asynchronous ServerEvent + * to occur. The user of this class specifies which event is of + * interest using the proper constructor or the registerForEvent() method. + * waitForEvent() can then be called to block until the event occurs or + * the timeout elapses. + * + * Note that if the event occurs after regsiterForEvent() is called but + * before waitForEvent() is called, waitForEvent() will return immediatly + * since it will know the event has already occured. + */ + +public class ServiceEventWaitor { + /* + * Indicates we will wait forever. Otherwise the time specified + * is in milliseconds. + */ + public final static int WAIT_FOREVER = 0 ; + + /* The type of event to wait for */ + private Class fEventTypeClass; + private DsfSession fSession; + private V fEvent; + + + /* Empty contructor. registerForEvent() should be called when + * this constructor is used. + */ + public ServiceEventWaitor(DsfSession session) { + fSession = session; + } + + /* Contructor that takes the eventClass as parameter. This is a shortcut + * that avoids calling registerForEvent() + */ + public ServiceEventWaitor(DsfSession session, Class eventClass) { + this(session); + registerForEvent(eventClass); + } + + /* Specify which event to wait for, and add ourselves as + * a listener with the session + */ + public void registerForEvent(Class eventClass) { + fEventTypeClass = eventClass; + fEvent = null; + fSession.addServiceEventListener(this, null); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + if (fEventTypeClass != null) fSession.removeServiceEventListener(this); + } + + /* Block until 'timeout' or the previously specified event has been + * received. The reason we don's specify the event as a parameter + * is that we must be ready for the event to occur event before + * this method is called. + */ + public synchronized V waitForEvent(int timeout) throws Exception { + if (fEventTypeClass == null) { + throw new Exception("Event to wait for has not been specified!"); + } + // The event might have already been received + if (fEvent != null) return fEvent; + + wait(timeout); + + if (fEvent == null) { + throw new Exception("Timed out waiting for ServiceEvent: " + fEventTypeClass.getName()); + } + return fEvent; + } + + /* + * Listen to all possible events by having the base class be the parameter. + * and then igure out if that event is the one we were waiting for. + */ + @DsfServiceEventHandler + public void eventDispatched(V event) { + if (fEventTypeClass.isAssignableFrom(event.getClass())) { + synchronized(this) { + fEvent = event; + notifyAll(); + } + } + } +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/SyncUtil.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/SyncUtil.java new file mode 100644 index 00000000000..006d6e9df81 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/SyncUtil.java @@ -0,0 +1,314 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson AB - Initial implementation of Test cases + *******************************************************************************/ +package org.eclipse.dd.tests.gdb.framework; + +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.Callable; + +import junit.framework.Assert; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IExpressions; +import org.eclipse.dd.dsf.debug.service.IFormattedValues; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.IFormattedDataDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.StepType; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.MIStack; +import org.eclipse.dd.mi.service.command.commands.MIBreakDelete; +import org.eclipse.dd.mi.service.command.commands.MIBreakInsert; +import org.eclipse.dd.mi.service.command.commands.MIBreakList; +import org.eclipse.dd.mi.service.command.commands.MIExecContinue; +import org.eclipse.dd.mi.service.command.commands.MIExecFinish; +import org.eclipse.dd.mi.service.command.commands.MIExecNext; +import org.eclipse.dd.mi.service.command.commands.MIExecStep; +import org.eclipse.dd.mi.service.command.commands.MIExecUntil; +import org.eclipse.dd.mi.service.command.events.MIStoppedEvent; +import org.eclipse.dd.mi.service.command.output.MIBreakInsertInfo; +import org.eclipse.dd.mi.service.command.output.MIBreakListInfo; +import org.eclipse.dd.mi.service.command.output.MIBreakpoint; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.tests.gdb.launching.TestsPlugin; + +public class SyncUtil { + + private static GDBControl fGDBControl; + private static MIRunControl fRunControl; + private static MIStack fStack; + private static IExpressions fExpressions; + private static DsfSession fSession; + + // Initialize some common things, once the session has been established + public static void initialize(DsfSession session) { + fSession = session; + + DsfServicesTracker tracker = + new DsfServicesTracker(TestsPlugin.getBundleContext(), + fSession.getId()); + + fGDBControl = tracker.getService(GDBControl.class); + fRunControl = tracker.getService(MIRunControl.class); + fStack = tracker.getService(MIStack.class); + fExpressions = tracker.getService(IExpressions.class); + } + + public static MIStoppedEvent SyncStep(final StepType stepType, int numSteps) throws Throwable { + MIStoppedEvent retVal = null; + for (int i=0; i eventWaitor = + new ServiceEventWaitor( + fSession, + MIStoppedEvent.class); + + fRunControl.getExecutor().submit(new Runnable() { + public void run() { + // No need for a RequestMonitor since we will wait for the + // ServiceEvent telling us the program has been suspended again + switch(stepType) { + case STEP_INTO: + fGDBControl.queueCommand(new MIExecStep(dmc), null); + break; + case STEP_OVER: + fGDBControl.queueCommand(new MIExecNext(dmc), null); + break; + case STEP_RETURN: + fGDBControl.queueCommand(new MIExecFinish(fStack.createFrameDMContext(dmc, 0)), null); + break; + default: + Assert.assertTrue("Unsupported step type; " + stepType.toString(), false); + } + } + }); + + // Wait for the execution to suspend after the step + return eventWaitor.waitForEvent(ServiceEventWaitor.WAIT_FOREVER); + } + + public static MIStoppedEvent SyncRunToLine(final IExecutionDMContext dmc, final String fileName, final String lineNo, + final boolean skipBreakpoints) throws Throwable { + + final ServiceEventWaitor eventWaitor = + new ServiceEventWaitor( + fSession, + MIStoppedEvent.class); + + fRunControl.getExecutor().submit(new Runnable() { + public void run() { + // No need for a RequestMonitor since we will wait for the + // ServiceEvent telling us the program has been suspended again + + fGDBControl.queueCommand( + new MIExecUntil(dmc, fileName + ":" + lineNo), //$NON-NLS-1$ + null); + } + }); + + // Wait for the execution to suspend after the step + return eventWaitor.waitForEvent(ServiceEventWaitor.WAIT_FOREVER); + } + + public static MIStoppedEvent SyncRunToLine(final String fileName, final String lineNo, + final boolean skipBreakpoints) throws Throwable { + return SyncRunToLine(fGDBControl.getGDBDMContext(), fileName, lineNo, skipBreakpoints); + } + + public static MIStoppedEvent SyncRunToLine(final String fileName, final String lineNo) throws Throwable { + return SyncRunToLine(fGDBControl.getGDBDMContext(), fileName, lineNo, false); + } + + + public static int SyncAddBreakpoint(final String location) throws Throwable { + return SyncAddBreakpoint(location, true); + } + + public static int SyncAddBreakpoint(final String location, boolean temporary) + throws Throwable { + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + DataRequestMonitor addBreakDone = + new DataRequestMonitor(fRunControl.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + wait.setReturnInfo(getData()); + } + + wait.waitFinished(getStatus()); + } + }; + + fGDBControl.queueCommand( + new MIBreakInsert(fGDBControl.getGDBDMContext(), temporary, false, null, 0, location, 0), + addBreakDone); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + MIBreakInsertInfo info = (MIBreakInsertInfo) wait.getReturnInfo(); + return info.getMIBreakpoints()[0].getNumber(); + } + + + public static int[] SyncGetBreakpointList() throws Throwable { + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + DataRequestMonitor listDRM = + new DataRequestMonitor(fRunControl.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + wait.setReturnInfo(getData()); + } + wait.waitFinished(getStatus()); + } + }; + + fGDBControl.queueCommand(new MIBreakList(fGDBControl.getGDBDMContext()), listDRM); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + + MIBreakpoint[] breakpoints = listDRM.getData().getMIBreakpoints(); + int[] result = new int[breakpoints.length]; + for (int i = 0; i < breakpoints.length; i++) { + result[i] = breakpoints[i].getNumber(); + } + return result; + } + + public static void SyncDeleteBreakpoint(int breakpointIndex) throws Throwable { + SyncDeleteBreakpoint(new int[] {breakpointIndex}); + } + + public static void SyncDeleteBreakpoint(int[] breakpointIndices) throws Throwable { + + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + DataRequestMonitor deleteBreakDone = + new DataRequestMonitor(fRunControl.getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + wait.setReturnInfo(getData()); + } + + wait.waitFinished(getStatus()); + } + }; + + fGDBControl.queueCommand( + new MIBreakDelete(fGDBControl.getGDBDMContext(), breakpointIndices), //$NON-NLS-1$ + deleteBreakDone); + + wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); + assertTrue(wait.getMessage(), wait.isOK()); + } + + + public static MIStoppedEvent SyncResumeUntilStopped(final IExecutionDMContext dmc) throws Throwable { + final ServiceEventWaitor eventWaitor = + new ServiceEventWaitor( + fSession, + MIStoppedEvent.class); + + fRunControl.getExecutor().submit(new Runnable() { + public void run() { + // No need for a RequestMonitor since we will wait for the + // ServiceEvent telling us the program has been suspended again + fGDBControl.queueCommand( + new MIExecContinue(dmc), + null); + } + }); + + // Wait for the execution to suspend after the step + return eventWaitor.waitForEvent(ServiceEventWaitor.WAIT_FOREVER); + } + + public static MIStoppedEvent SyncResumeUntilStopped() throws Throwable { + return SyncResumeUntilStopped(fGDBControl.getGDBDMContext()); + } + + public static MIStoppedEvent SyncRunToLocation(final String location) throws Throwable { + // Set a temporary breakpoint and run to it. + // Note that if there were other breakpoints set ahead of this one, + // they will stop execution earlier than planned + SyncAddBreakpoint(location, true); + return SyncResumeUntilStopped(); + } + + public static IFrameDMContext SyncGetStackFrame(final IExecutionDMContext execCtx, final int level) throws Throwable { + class StackFrameQuery extends Query { + @Override + protected void execute(final DataRequestMonitor rm) { + fStack.getFrames(execCtx, new DataRequestMonitor(fSession.getExecutor(), rm) { + @Override + protected void handleOK() { + if (getData().length > level) { + rm.setData(getData()[level]); + } else { + rm.setStatus(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, "Frame not available")); + } + rm.done(); + } + }); + } + } + + StackFrameQuery sfQuery = new StackFrameQuery(); + fSession.getExecutor().execute(sfQuery); + return sfQuery.get(); + } + + public static IExpressionDMContext SyncCreateExpression(final IDMContext parentCtx, final String expression) + throws Throwable { + Callable callable = new Callable() { + public IExpressionDMContext call() throws Exception { + return fExpressions.createExpression(parentCtx, expression); + } + }; + return fSession.getExecutor().submit(callable).get(); + } + + public static FormattedValueDMContext SyncGetFormattedValue( + final IFormattedValues service, final IFormattedDataDMContext dmc, final String formatId) throws Throwable + { + Callable callable = new Callable() { + public FormattedValueDMContext call() throws Exception { + return service.getFormattedValueContext(dmc, formatId); + } + }; + return fSession.getExecutor().submit(callable).get(); + } +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/LaunchSequence.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/LaunchSequence.java new file mode 100644 index 00000000000..1519319ee3a --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/LaunchSequence.java @@ -0,0 +1,262 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb.launching; + +import java.util.concurrent.TimeUnit; + +import org.eclipse.cdt.debug.core.CDebugCorePlugin; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector; +import org.eclipse.cdt.debug.mi.core.IMILaunchConfigurationConstants; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.Sequence; +import org.eclipse.dd.dsf.debug.service.StepQueueManager; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.gdb.launching.GdbLaunch; +import org.eclipse.dd.gdb.service.GDBRunControl; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.mi.service.CSourceLookup; +import org.eclipse.dd.mi.service.ExpressionService; +import org.eclipse.dd.mi.service.MIBreakpoints; +import org.eclipse.dd.mi.service.MIBreakpointsManager; +import org.eclipse.dd.mi.service.MIMemory; +import org.eclipse.dd.mi.service.MIRegisters; +import org.eclipse.dd.mi.service.MIStack; +import org.eclipse.dd.mi.service.command.commands.MIBreakInsert; +import org.eclipse.dd.mi.service.command.commands.MIExecRun; +import org.eclipse.dd.mi.service.command.events.MIStoppedEvent; +import org.eclipse.dd.mi.service.command.output.MIBreakInsertInfo; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.debug.core.DebugException; + +public class LaunchSequence extends Sequence { + + public class EntryPointHitEventListener { + boolean fAborted = false; + boolean fFinished = false; + final RequestMonitor fRequestMonitor; + + EntryPointHitEventListener(RequestMonitor requestMonitor) { + fRequestMonitor = requestMonitor; + } + + @DsfServiceEventHandler + public void eventDispatched(@SuppressWarnings("unused") + MIStoppedEvent e) { + fFinished = true; + if (!fAborted) { + fSession.removeServiceEventListener(this); + fRequestMonitor.done(); + } + } + } + + + Step[] fSteps = new Step[] { + // Create and initialize the Connection service. + new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + // + // Create the connection. + // + fCommandControl = new GDBControl( + fSession, getGDBPath(), fExecPath, GDBControl.SessionType.RUN, 30); + fCommandControl.initialize(requestMonitor); + } + }, + /* + * If needed, insert breakpoint at main and run to it. + */ + new Step() { + private boolean fStopInMain = false; + private String fStopSymbol = null; + + /** + * @return The return value actually indicates whether the get operation succeeded, + * not whether to stop. + */ + private boolean readStopAtMain(RequestMonitor requestMonitor) { + try { + fStopInMain = fLaunch.getLaunchConfiguration().getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, false ); + } catch (CoreException e) { + requestMonitor.setStatus(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, -1, "Cannot retrieve the entry point symbol", e)); //$NON-NLS-1$ + requestMonitor.done(); + return false; + } + return true; + } + + private boolean readStopSymbol(RequestMonitor requestMonitor) { + try { + fStopSymbol = fLaunch.getLaunchConfiguration().getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT ); + } catch (CoreException e) { + requestMonitor.setStatus(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, DebugException.CONFIGURATION_INVALID, "Cannot retrieve the entry point symbol", e)); //$NON-NLS-1$ + requestMonitor.done(); + return false; + } + return true; + } + + @Override + public void execute(final RequestMonitor requestMonitor) { + if (!readStopAtMain(requestMonitor)) return; + if (!fStopInMain) { + requestMonitor.done(); + return; + } + + if (!readStopSymbol(requestMonitor)) return; + + // Create a listener to wait for the stopped event, and register as even handler. + // This handler will execute the requestMonitor. + final EntryPointHitEventListener entryPointHitListener = new EntryPointHitEventListener(requestMonitor); + fSession.addServiceEventListener(entryPointHitListener, null); + + // Create a time-out, to abort if breakpoint not hit. + fSession.getExecutor().schedule( + new Runnable() { public void run() { + // Only process the event if we have not finished yet (hit the breakpoint). + if (!entryPointHitListener.fFinished) { + // Mark the listener as aborted, and unregister it as event listener. + entryPointHitListener.fAborted = true; + fSession.removeServiceEventListener(entryPointHitListener); + + // Submit the error result for the step. + requestMonitor.setStatus(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, DebugException.TARGET_REQUEST_FAILED, "Timed out running to entry point.", null)); //$NON-NLS-1$ + requestMonitor.done(); + } + }}, + 60, TimeUnit.SECONDS); + + // Insert a breakpoint at the requested stop symbol. + fCommandControl.queueCommand( + new MIBreakInsert(fCommandControl.getGDBDMContext(), true, false, null, 0, fStopSymbol, 0), + new DataRequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + + // After the break-insert is done, execute the -exec-run command. + fCommandControl.queueCommand( + new MIExecRun(fCommandControl.getGDBDMContext(), new String[0]), + new DataRequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + // Note : Do we not need to do something with the original requestMonitor? + // Do nothing. Execution was resumed and the EntryPointHitEventListener + // will resume execution + } + } + ); + } + }); + } + }, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new GDBRunControl(fSession).initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new StepQueueManager(fSession).initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new MIMemory(fSession).initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new MIStack(fSession).initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new ExpressionService(fSession).initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + fSourceLookup = new CSourceLookup(fSession); + fSourceLookup.initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + fSourceLookup.setSourceLookupDirector( + fCommandControl.getGDBDMContext(), + ((CSourceLookupDirector)fLaunch.getSourceLocator())); + requestMonitor.done(); + }}, + new Step() { @Override + public void execute(final RequestMonitor requestMonitor) { + // Create the low-level breakpoint service + final MIBreakpoints bpService = new MIBreakpoints(fSession); + bpService.initialize(new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + requestMonitor.done(); + } + }); + }}, + new Step() { @Override + public void execute(final RequestMonitor requestMonitor) { + // Create high-level breakpoint service and install breakpoints + // for the GDB debug context. + final MIBreakpointsManager bpmService = new MIBreakpointsManager(fSession, CDebugCorePlugin.PLUGIN_ID); + bpmService.initialize(new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + bpmService.startTrackingBreakpoints(fCommandControl.getGDBDMContext(), requestMonitor); + } + }); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new MIRegisters(fSession).initialize(requestMonitor); + }}, + /*new Step() { public void execute(RequestMonitor requestMonitor) { + new GDBVariables(fSession).initialize(requestMonitor); + }},*/ + }; + + final DsfSession fSession; + final GdbLaunch fLaunch; + final IPath fExecPath; + + GDBControl fCommandControl; + CSourceLookup fSourceLookup; + + public LaunchSequence(DsfSession session, GdbLaunch launch, IPath execPath) { + super(session.getExecutor()); + fSession = session; + fLaunch = launch; + fExecPath = execPath; + } + + @Override + public Step[] getSteps() { + return fSteps; + } + + private IPath getGDBPath() { + IPath retVal = new Path("gdb.exe"); //$NON-NLS-1$ + try { + retVal = new Path( fLaunch.getLaunchConfiguration().getAttribute( IMILaunchConfigurationConstants.ATTR_DEBUG_NAME, IMILaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT ) ); + } catch (CoreException e) { + } + return retVal; + } + +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/ShutdownSequence.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/ShutdownSequence.java new file mode 100644 index 00000000000..787826a4a29 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/ShutdownSequence.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb.launching; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.Sequence; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.gdb.service.GDBRunControl; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.mi.service.CSourceLookup; +import org.eclipse.dd.mi.service.ExpressionService; +import org.eclipse.dd.mi.service.MIBreakpoints; +import org.eclipse.dd.mi.service.MIBreakpointsManager; +import org.eclipse.dd.mi.service.MIMemory; +import org.eclipse.dd.mi.service.MIRegisters; +import org.eclipse.dd.mi.service.MIStack; + + +public class ShutdownSequence extends Sequence { + + String fSessionId; + String fApplicationName; + String fDebugModelId; + DsfServicesTracker fTracker; + + + public ShutdownSequence(DsfExecutor executor, String sessionId, RequestMonitor requestMonitor) { + super(executor, requestMonitor); + fSessionId = sessionId; + } + + @Override + public Step[] getSteps() { return fSteps; } + + private final Step[] fSteps = new Step[] { + new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + fTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSessionId); + requestMonitor.done(); + } + + @Override + public void rollBack(RequestMonitor requestMonitor) { + fTracker.dispose(); + fTracker = null; + requestMonitor.done(); + } + }, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { shutdownService(MIRegisters.class, requestMonitor); }}, + new Step() { + // Uninstall the breakpoints before the service is shut down. + @Override + public void execute(RequestMonitor requestMonitor) { + MIBreakpointsManager bpm = fTracker.getService(MIBreakpointsManager.class); + GDBControl commandControl = fTracker.getService(GDBControl.class); + if (bpm != null && commandControl != null) { + bpm.stopTrackingBreakpoints(commandControl.getGDBDMContext(), requestMonitor); + } else { + requestMonitor.setStatus(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, + "Needed services not found.", null)); //$NON-NLS-1$ + requestMonitor.done(); + } + } + }, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { shutdownService(MIBreakpointsManager.class, requestMonitor); }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { shutdownService(MIBreakpoints.class, requestMonitor); }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { shutdownService(CSourceLookup.class, requestMonitor); }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { shutdownService(ExpressionService.class, requestMonitor); }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { shutdownService(MIStack.class, requestMonitor); }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { shutdownService(MIMemory.class, requestMonitor); }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { shutdownService(GDBRunControl.class, requestMonitor); }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { shutdownService(GDBControl.class, requestMonitor); }}, + new Step() { @Override public void execute(RequestMonitor requestMonitor) { + fTracker.dispose(); + fTracker = null; + requestMonitor.done(); + }} + }; + + @SuppressWarnings("unchecked") + private void shutdownService(Class clazz, RequestMonitor requestMonitor) { + IDsfService service = fTracker.getService(clazz); + if (service != null) { + service.shutdown(requestMonitor); + } + else { + requestMonitor.setStatus(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, + "Service '" + clazz.getName() + "' not found.", null)); //$NON-NLS-1$//$NON-NLS-2$ + requestMonitor.done(); + } + } +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/TestLaunchDelegate.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/TestLaunchDelegate.java new file mode 100644 index 00000000000..9ff059d98fe --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/TestLaunchDelegate.java @@ -0,0 +1,302 @@ +/******************************************************************************* + * Copyright (c) 2004, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb.launching; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.launch.AbstractCLaunchDelegate; +import org.eclipse.cdt.launch.internal.ui.LaunchMessages; +import org.eclipse.cdt.launch.internal.ui.LaunchUIPlugin; +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.cdt.utils.spawner.ProcessFactory; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.debug.model.DsfMemoryBlockRetrieval; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.gdb.launching.GdbLaunch; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.mi.service.command.AbstractCLIProcess; +import org.eclipse.dd.mi.service.command.MIInferiorProcess; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.IStatusHandler; +import org.eclipse.debug.core.model.ILaunchConfigurationDelegate2; +import org.eclipse.debug.core.model.IMemoryBlockRetrieval; +import org.eclipse.debug.core.model.IPersistableSourceLocator; +import org.eclipse.debug.core.model.ISourceLocator; +import org.eclipse.debug.core.sourcelookup.IPersistableSourceLocator2; + +/** + * The launch configuration delegate for the CDI debugger session types. + */ +@ThreadSafe +public class TestLaunchDelegate extends AbstractCLaunchDelegate + implements ILaunchConfigurationDelegate2 +{ + public final static String GDB_DEBUG_MODEL_ID = "org.eclipse.dd.tests.gdb"; //$NON-NLS-1$ + + /* (non-Javadoc) + * @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#launch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void launch( ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor ) throws CoreException { + if ( monitor == null ) { + monitor = new NullProgressMonitor(); + } + if ( mode.equals( ILaunchManager.DEBUG_MODE ) ) { + launchDebugger( config, launch, monitor ); + } + } + + private void launchDebugger( ILaunchConfiguration config, ILaunch launch, IProgressMonitor monitor ) throws CoreException { + monitor.beginTask("Launching debugger session", 10); //$NON-NLS-1$ + if ( monitor.isCanceled() ) { + return; + } + try { + String debugMode = config.getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE, ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN ); + if ( debugMode.equals( ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN ) ) { + launchLocalDebugSession( config, launch, monitor ); + } + } + finally { + monitor.done(); + } + } + + private void launchLocalDebugSession( ILaunchConfiguration config, ILaunch l, IProgressMonitor monitor ) throws CoreException { + if ( monitor.isCanceled() ) { + return; + } + final GdbLaunch launch = (GdbLaunch)l; + + monitor.subTask("Debugging using GDB/MI reference for DSF"); //$NON-NLS-1$ + IPath exePath = new Path(getProgramName(config)); + verifyBinary(exePath); + + setDefaultSourceLocator(launch, config); + + monitor.worked( 1 ); + + // Create and invoke the launch sequence to create the debug control and services + final LaunchSequence launchSequence = + new LaunchSequence(launch.getSession(), launch, exePath); + launch.getSession().getExecutor().execute(launchSequence); + try { + launchSequence.get(); + } catch (InterruptedException e1) { + throw new DebugException(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, "Interrupted Exception in dispatch thread", e1)); //$NON-NLS-1$ + } catch (ExecutionException e1) { + throw new DebugException(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Error in launch sequence", e1.getCause())); //$NON-NLS-1$ + } + + launch.initializeControl(); + + // Add the CLI and "inferior" process objects to the launch. + final AtomicReference cliProcessRef = new AtomicReference(); + final AtomicReference inferiorProcessRef = new AtomicReference(); + try { + launch.getDsfExecutor().submit( new Callable() { + public Object call() throws CoreException { + DsfServicesTracker tracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), launch.getSession().getId()); + GDBControl gdb = tracker.getService(GDBControl.class); + if (gdb != null) { + cliProcessRef.set(gdb.getCLIProcess()); + inferiorProcessRef.set(gdb.getInferiorProcess()); + } + tracker.dispose(); + return null; + } + }).get(); + launch.addProcess(DebugPlugin.newProcess(launch, cliProcessRef.get(), "gdb")); //$NON-NLS-1$ + launch.addProcess(DebugPlugin.newProcess(launch, inferiorProcessRef.get(), exePath.lastSegment())); + } catch (InterruptedException e) { + throw new CoreException(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, 0, "Interrupted while waiting for get process callable.", e)); //$NON-NLS-1$ + } catch (ExecutionException e) { + throw (CoreException)e.getCause(); + } catch (RejectedExecutionException e) { + throw new CoreException(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, 0, "Debugger shut down before launch was completed.", e)); //$NON-NLS-1$ + } + + // Create a memory retrieval and register it with session + try { + launch.getDsfExecutor().submit( new Callable() { + public Object call() throws CoreException { + DsfServicesTracker tracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), launch.getSession().getId()); + GDBControl gdbControl = tracker.getService(GDBControl.class); + if (gdbControl != null) { + IMemoryBlockRetrieval memRetrieval = new DsfMemoryBlockRetrieval( + GDB_DEBUG_MODEL_ID, gdbControl.getGDBDMContext()); + launch.getSession().registerModelAdapter(IMemoryBlockRetrieval.class, memRetrieval); + } + tracker.dispose(); + return null; + } + }).get(); + } catch (InterruptedException e) { + throw new CoreException(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, 0, "Interrupted while waiting for get process callable.", e)); //$NON-NLS-1$ + } catch (ExecutionException e) { + throw (CoreException)e.getCause(); + } catch (RejectedExecutionException e) { + throw new CoreException(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID, 0, "Debugger shut down before launch was completed.", e)); //$NON-NLS-1$ + } + } + + /* + * Verify that the specified file exists on the file system. + */ + private void verifyBinary(IPath exePath) throws CoreException { + try { + new FileReader(exePath.toFile()); + } catch (Exception e) { + Throwable exception = new FileNotFoundException(exePath.toOSString() + " does not exist"); //$NON-NLS-1$ + int code = ICDTLaunchConfigurationConstants.ERR_PROGRAM_NOT_BINARY; + throw new CoreException(new Status(IStatus.ERROR, getPluginID(), code, exception == null ? "" : exception.getLocalizedMessage(), //$NON-NLS-1$ + exception)); + } + } + + + /* (non-Javadoc) + * @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#getPluginID() + */ + @Override + protected String getPluginID() { + return LaunchUIPlugin.getUniqueIdentifier(); + } + + /** + * Performs a runtime exec on the given command line in the context of the + * specified working directory, and returns the resulting process. If the + * current runtime does not support the specification of a working + * directory, the status handler for error code + * ERR_WORKING_DIRECTORY_NOT_SUPPORTED is queried to see if + * the exec should be re-executed without specifying a working directory. + * + * @param cmdLine + * the command line + * @param workingDirectory + * the working directory, or null + * @return the resulting process or null if the exec is + * cancelled + * @see Runtime + */ + protected Process exec( String[] cmdLine, String[] environ, File workingDirectory, boolean usePty ) throws CoreException { + Process p = null; + try { + if ( workingDirectory == null ) { + p = ProcessFactory.getFactory().exec( cmdLine, environ ); + } + else { + if ( usePty && PTY.isSupported() ) { + p = ProcessFactory.getFactory().exec( cmdLine, environ, workingDirectory, new PTY() ); + } + else { + p = ProcessFactory.getFactory().exec( cmdLine, environ, workingDirectory ); + } + } + } + catch( IOException e ) { + if ( p != null ) { + p.destroy(); + } + abort( "Error starting process.", e, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR ); //$NON-NLS-1$ + } + catch( NoSuchMethodError e ) { + // attempting launches on 1.2.* - no ability to set working + // directory + IStatus status = new Status( IStatus.ERROR, LaunchUIPlugin.getUniqueIdentifier(), ICDTLaunchConfigurationConstants.ERR_WORKING_DIRECTORY_NOT_SUPPORTED, LaunchMessages.getString( "LocalDsfLaunchDelegate.9" ), e ); //$NON-NLS-1$ + IStatusHandler handler = DebugPlugin.getDefault().getStatusHandler( status ); + if ( handler != null ) { + Object result = handler.handleStatus( status, this ); + if ( result instanceof Boolean && ((Boolean)result).booleanValue() ) { + p = exec( cmdLine, environ, null, usePty ); + } + } + } + return p; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#preLaunchCheck(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public boolean preLaunchCheck( ILaunchConfiguration config, String mode, IProgressMonitor monitor ) throws CoreException { + // no pre launch check for core file + if ( mode.equals( ILaunchManager.DEBUG_MODE ) ) { + if ( ICDTLaunchConfigurationConstants.DEBUGGER_MODE_CORE.equals( config.getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE, ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN ) ) ) + return true; + } + return super.preLaunchCheck( config, mode, monitor ); +// return true; + } + + /////////////////////////////////////////////////////////////////////////// + // ILaunchConfigurationDelegate2 + @Override + public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException { + return false; + } + + @Override + public boolean finalLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException { + return true; + } + + @Override + public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException { + // Need to configure the source locator before creating the launch + // because once the launch is created and added to launch manager, + // the adapters will be created for the whole session, including + // the source lookup adapter. + ISourceLocator locator = getSourceLocator(configuration); + + return new GdbLaunch(configuration, mode, locator); + } + + private ISourceLocator getSourceLocator(ILaunchConfiguration configuration) throws CoreException { + String type = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, (String)null); + if (type == null) { + type = configuration.getType().getSourceLocatorId(); + } + if (type != null) { + IPersistableSourceLocator locator = DebugPlugin.getDefault().getLaunchManager().newSourceLocator(type); + String memento = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, (String)null); + if (memento == null) { + locator.initializeDefaults(configuration); + } else { + if(locator instanceof IPersistableSourceLocator2) + ((IPersistableSourceLocator2)locator).initializeFromMemento(memento, configuration); + else + locator.initializeFromMemento(memento); + } + return locator; + } + return null; + } +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/TestsPlugin.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/TestsPlugin.java new file mode 100644 index 00000000000..fb23fddcfcd --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/TestsPlugin.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.gdb.launching; + +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.eclipse.core.runtime.Plugin; +import org.osgi.framework.BundleContext; + +/** + * The main plugin class to be used in the desktop. + */ +public class TestsPlugin extends Plugin { + //The shared instance. + private static TestsPlugin plugin; + //Resource bundle. + private ResourceBundle resourceBundle; + private static BundleContext bundleContext; + + public static final String PLUGIN_ID = "org.eclipse.dd.tests.gdb"; //$NON-NLS-1$ + + /** + * The constructor. + */ + public TestsPlugin() { + super(); + plugin = this; + try { + resourceBundle = ResourceBundle.getBundle("org.eclipse.dd.tests.gdb.TestsPluginResources"); //$NON-NLS-1$ + } + catch (MissingResourceException x) { + resourceBundle = null; + } + } + /** + * This method is called upon plug-in activation + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + bundleContext = context; + } + /** + * This method is called when the plug-in is stopped + */ + @Override + public void stop(BundleContext context) throws Exception { + super.stop(context); + } + /** + * Returns the shared instance. + */ + public static TestsPlugin getDefault() { + return plugin; + } + + /** + * Returns the string from the plugin's resource bundle, + * or 'key' if not found. + */ + public static String getResourceString(String key) { + ResourceBundle bundle = TestsPlugin.getDefault().getResourceBundle(); + try { + return (bundle != null) ? bundle.getString(key) : key; + } + catch (MissingResourceException e) { + return key; + } + } + /** + * Returns the plugin's resource bundle, + */ + public ResourceBundle getResourceBundle() { + return resourceBundle; + } + /** + * Returns the plugin's bundle context, + */ + public static BundleContext getBundleContext() { + return bundleContext; + } + /** + * Convenience method which returns the unique identifier of this plugin. + */ + public static String getUniqueIdentifier() { + return getDefault().getBundle().getSymbolicName(); + } +}