From fdea8806312c96f664247c77d81aaefd461e7aed Mon Sep 17 00:00:00 2001 From: Pawel Piech Date: Wed, 13 Feb 2008 20:57:46 +0000 Subject: [PATCH] [179102] Re-aligned plugin and package names to confirm with Eclipse policy. --- plugins/org.eclipse.dd.tests.dsf/.classpath | 7 + plugins/org.eclipse.dd.tests.dsf/.cvsignore | 1 + plugins/org.eclipse.dd.tests.dsf/.project | 28 + .../.settings/org.eclipse.jdt.core.prefs | 65 + .../.settings/org.eclipse.jdt.ui.prefs | 3 + .../META-INF/MANIFEST.MF | 17 + plugins/org.eclipse.dd.tests.dsf/about.html | 24 + .../org.eclipse.dd.tests.dsf/build.properties | 6 + .../plugin.properties | 13 + plugins/org.eclipse.dd.tests.dsf/plugin.xml | 18 + .../service/MultiInstanceTestService.java | 59 + .../dd/dsf/tests/service/ServiceTests.java | 277 ++ .../dsf/tests/service/SimpleTestService.java | 53 + .../eclipse/dd/tests/dsf/DsfTestPlugin.java | 69 + .../eclipse/dd/tests/dsf/TestDsfExecutor.java | 50 + .../org/eclipse/dd/tests/dsf/ValueHolder.java | 28 + .../tests/dsf/concurrent/DsfQueryTests.java | 216 ++ .../dsf/concurrent/DsfSequenceTests.java | 315 ++ .../dd/tests/dsf/events/AbstractService.java | 110 + .../eclipse/dd/tests/dsf/events/Event1.java | 16 + .../eclipse/dd/tests/dsf/events/Event2.java | 15 + .../dd/tests/dsf/events/EventTest.java | 147 + .../eclipse/dd/tests/dsf/events/Service1.java | 42 + .../eclipse/dd/tests/dsf/events/Service2.java | 43 + .../eclipse/dd/tests/dsf/events/Service3.java | 50 + .../dd/tests/dsf/events/ShutdownSequence.java | 75 + .../dd/tests/dsf/events/StartupSequence.java | 39 + plugins/org.eclipse.dd.tests.gdb/.classpath | 7 + .../TestAppBuilder.launch | 21 + plugins/org.eclipse.dd.tests.gdb/.project | 38 + .../.settings/org.eclipse.jdt.core.prefs | 65 + .../META-INF/MANIFEST.MF | 23 + .../TestAppBuilder.xml | 19 + .../org.eclipse.dd.tests.gdb/build.properties | 5 + .../data/launch/bin/BreakpointTestApp.exe | Bin 0 -> 40216 bytes .../data/launch/bin/ExpressionTestApp.exe | Bin 0 -> 16921 bytes .../data/launch/bin/GDBMIGenericTestApp.exe | Bin 0 -> 9594 bytes .../data/launch/bin/MemoryTestApp.exe | Bin 0 -> 39963 bytes .../data/launch/bin/MultiThread.exe | Bin 0 -> 9106 bytes .../data/launch/bin/SpecialTestApp.exe | Bin 0 -> 9581 bytes .../data/launch/src/BreakpointTestApp.cc | 47 + .../data/launch/src/ExpressionTestApp.cc | 298 ++ .../data/launch/src/GDBMIGenericTestApp.cc | 15 + .../data/launch/src/Makefile | 14 + .../data/launch/src/MemoryTestApp.cc | 38 + .../data/launch/src/MultiThread.cc | 29 + .../data/launch/src/SpecialTestApp.cc | 15 + plugins/org.eclipse.dd.tests.gdb/plugin.xml | 16 + .../eclipse/dd/mi/service/ClassAccessor.java | 38 + .../org/eclipse/dd/tests/gdb/AllTests.java | 34 + .../org/eclipse/dd/tests/gdb/ExampleTest.java | 117 + .../dd/tests/gdb/ExpressionServiceTest.java | 2960 +++++++++++++++++ .../dd/tests/gdb/GDBProcessesTest.java | 183 + .../dd/tests/gdb/MIBreakpointsTest.java | 2762 +++++++++++++++ .../eclipse/dd/tests/gdb/MIMemoryTest.java | 1639 +++++++++ .../eclipse/dd/tests/gdb/MIRegistersTest.java | 428 +++ .../dd/tests/gdb/MIRunControlTest.java | 654 ++++ .../gdb/framework/AsyncCompletionWaitor.java | 125 + .../tests/gdb/framework/BackgroundRunner.java | 135 + .../dd/tests/gdb/framework/BaseTestCase.java | 100 + .../gdb/framework/ServiceEventWaitor.java | 104 + .../dd/tests/gdb/framework/SyncUtil.java | 314 ++ .../tests/gdb/launching/LaunchSequence.java | 262 ++ .../tests/gdb/launching/ShutdownSequence.java | 105 + .../gdb/launching/TestLaunchDelegate.java | 302 ++ .../dd/tests/gdb/launching/TestsPlugin.java | 97 + 66 files changed, 12795 insertions(+) create mode 100644 plugins/org.eclipse.dd.tests.dsf/.classpath create mode 100644 plugins/org.eclipse.dd.tests.dsf/.cvsignore create mode 100644 plugins/org.eclipse.dd.tests.dsf/.project create mode 100644 plugins/org.eclipse.dd.tests.dsf/.settings/org.eclipse.jdt.core.prefs create mode 100644 plugins/org.eclipse.dd.tests.dsf/.settings/org.eclipse.jdt.ui.prefs create mode 100644 plugins/org.eclipse.dd.tests.dsf/META-INF/MANIFEST.MF create mode 100644 plugins/org.eclipse.dd.tests.dsf/about.html create mode 100644 plugins/org.eclipse.dd.tests.dsf/build.properties create mode 100644 plugins/org.eclipse.dd.tests.dsf/plugin.properties create mode 100644 plugins/org.eclipse.dd.tests.dsf/plugin.xml create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/dsf/tests/service/MultiInstanceTestService.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/dsf/tests/service/ServiceTests.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/dsf/tests/service/SimpleTestService.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/DsfTestPlugin.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/TestDsfExecutor.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/ValueHolder.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/concurrent/DsfQueryTests.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/concurrent/DsfSequenceTests.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/AbstractService.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Event1.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Event2.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/EventTest.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Service1.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Service2.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/Service3.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/ShutdownSequence.java create mode 100644 plugins/org.eclipse.dd.tests.dsf/src/org/eclipse/dd/tests/dsf/events/StartupSequence.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/.classpath create mode 100644 plugins/org.eclipse.dd.tests.gdb/.externalToolBuilders/TestAppBuilder.launch create mode 100644 plugins/org.eclipse.dd.tests.gdb/.project create mode 100644 plugins/org.eclipse.dd.tests.gdb/.settings/org.eclipse.jdt.core.prefs create mode 100644 plugins/org.eclipse.dd.tests.gdb/META-INF/MANIFEST.MF create mode 100644 plugins/org.eclipse.dd.tests.gdb/TestAppBuilder.xml create mode 100644 plugins/org.eclipse.dd.tests.gdb/build.properties create mode 100755 plugins/org.eclipse.dd.tests.gdb/data/launch/bin/BreakpointTestApp.exe create mode 100755 plugins/org.eclipse.dd.tests.gdb/data/launch/bin/ExpressionTestApp.exe create mode 100755 plugins/org.eclipse.dd.tests.gdb/data/launch/bin/GDBMIGenericTestApp.exe create mode 100755 plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MemoryTestApp.exe create mode 100755 plugins/org.eclipse.dd.tests.gdb/data/launch/bin/MultiThread.exe create mode 100755 plugins/org.eclipse.dd.tests.gdb/data/launch/bin/SpecialTestApp.exe create mode 100644 plugins/org.eclipse.dd.tests.gdb/data/launch/src/BreakpointTestApp.cc create mode 100644 plugins/org.eclipse.dd.tests.gdb/data/launch/src/ExpressionTestApp.cc create mode 100644 plugins/org.eclipse.dd.tests.gdb/data/launch/src/GDBMIGenericTestApp.cc create mode 100644 plugins/org.eclipse.dd.tests.gdb/data/launch/src/Makefile create mode 100644 plugins/org.eclipse.dd.tests.gdb/data/launch/src/MemoryTestApp.cc create mode 100644 plugins/org.eclipse.dd.tests.gdb/data/launch/src/MultiThread.cc create mode 100644 plugins/org.eclipse.dd.tests.gdb/data/launch/src/SpecialTestApp.cc create mode 100644 plugins/org.eclipse.dd.tests.gdb/plugin.xml create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/ClassAccessor.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/AllTests.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/ExampleTest.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/ExpressionServiceTest.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/GDBProcessesTest.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIBreakpointsTest.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIMemoryTest.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIRegistersTest.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/MIRunControlTest.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/AsyncCompletionWaitor.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/BackgroundRunner.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/BaseTestCase.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/ServiceEventWaitor.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/framework/SyncUtil.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/LaunchSequence.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/ShutdownSequence.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/TestLaunchDelegate.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/launching/TestsPlugin.java 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 0000000000000000000000000000000000000000..6eb8b78a5b9965ec3247979c002e09ec99a468e6 GIT binary patch literal 40216 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 G^}hj;jg3VB literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9051861f97e3df5a0af67b67b7fd41de2c10e4df GIT binary patch literal 16921 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..6f604184d78dca9158a4d9a3929e29ae829b8b72 GIT binary patch literal 9594 zcmd^FYiwM{b)NfJ>dIPC6e&w|q&iEBl4;1gs|TepmK;+eDUmj~hhrmh7$sE+p%R=|5fqVYqfyaEoCjPN5n8))EjuVs!$#U4{ZaK{fU4D&DI8aT zg|Oc@kL8k=*uQTV)%-t^y4DYZkOPF8_N02)C71!%VI<-_ux?W7H)&NE3Tv=*SCy_Q1crgzT)qwwRDW=97j%O8O5q{aq++MgHrW z{(+`XYZ_gX^6zLm(DL8Y^fxrU5p)hVa{~>hzQ;*pY}uE^Vv!ISvucz{uUW$Z+bn`0 zJ60+N)hJbof6T#7SR5PYDAeT+2 zgDR=@sdB}`>VOI%vlG_)JlWb(zJRt+;^v{Vj@qFjrrVl-VSRYNg)tdfsHR0kc< zCtEa@$`?i7p+noY4+ZP}jbi8U(DuGy11d7Pb?BH3Trm!8(#E`5`X|j)Bp`q5`$sTk zuK2M6LvD*Q@@9S(=kp6W+kdTjEt0my>l*KU+x40-#_dSwAzi@~W1L`$!R=&<8oHRm zVD4rL16#)wMso1<+vC@~$-jiU$rhBKTmx%*{gRm8)B?oxswH@`s_9j%A;;|1E7J(8 zSW}L&t8Yk}HRjmtt1n5KHRsw%KQC#vAeSJ0Ueatyu8Z_pNwY;cj@s3eppnY3{y!f* z{V(JHKDFn-zTEj!Ks=Af-iLCXNG6W~`0m-W=)?Z;Ywjcq9DeH3=iy5xp1uLusW+q8 z z_jG@!J25bI+U=bD$6roQpB}hAF>oEs_~rgi>1vR=mZO zhaWkUx^W3LK62?yv|60GcqiKi`m+!1pL`VAr!MWqN*lknVsaUZof*F_YnxJ;y9TCS zesap5I5>qtTC;xo^s8rHVEKuGmhsCLnuDgsRZ~6GJiT=MRrk|RPSyT-{FN1l9}OP4 zG_j(SLyG$L|AbB$6Yz{ouTMwu@ps(mHzu6%>(jM&$6s*|Kf-o4&e4mDVQOVG=wZwZ zeHrb3U#(co7qf|-VKJ=a(}`{6vPec_U)dIG8Fk6U8CYwdu1TeEk{-o7xl?JH~dcbo!W1%ShvhSH@iri&zX|HtFwjc<21$m(!)^kkVi0zKk`D^fl0Y2fT&2 z0FnK<6_J50iNhx8>w6ISKEfD^Wr!D`pZW7h>07xd`95Wep(yPEA6+Q1>=e?ipppHR z1K*{lP&0h_?T9|&XApNGK8jdGG?*6RclPz&ljy=L@2*6*zuw=F=sGx3D@HX%tzB1> zRQFxt|20zFjX|@;IXr10LOh3YT#b~rLtCKja86BFfs8Fa2@_QKx*cl(?b{Z&!mO11 z7tq7`e@xq;hKUY|BgMK;AO^GFhZNDsRAui$+aDpy_a8-Pq=-4`vt+y3cG@G?hxj6* zeHagSp52GU^6VU0^X!KdbAZeyo0}dx=H!c!aAWo+P+rX5%VeH?4-zo7mSIpVT|`@K$J4c>M?@|;Qp*=I>X}Jq`5s@p!QZ49YokgSCi5G6He;pdKZ(1j;lmCOUvc&<}noD@{6~?I|uy4(p zk604!&i?HW4rzCI03Hw?(NCvEGFKW4ljYR0u#h}fsvN17Q|XXiGFhr*{V-j~m#d+l z$@uh|RX>{1Z zED7fhJ&-+mXg3IFwPtPgf>I&F8LftqaJnp>#_W~7P*X>p}N==xB0j=nFXntfe`^gWQ#1ETjvsbMF+3{u{I5EZ=Wke{RFE~KDYx}*E)@77kIyp4=(;j ze6Y3HYH4c4b5(QO0;hR-GuqlIoaO}!K7%)_gRG~rE@rm*o&{SL47J@Cx3Lq8trkOk z=~|0LOVhz7$6M~L^4hp%o6+e(C-~606pB=7rBzqp&QuUvBo?5`CMHxoug$XBSUZYA zD>jKzLu{z62er>vwcld&VpG_Fhn~2`Ll^N2aZl4mwap!9b`pR^J~;QqO|uqTtyV8~ z1TE;NZYg_tlkTkq*A~A;ne~42LOkUa5T?=+`C>lu(+~;qZA4q_!t(>LUv;{L(C=K@ zkBHgaL%=O}Bs=c?Tt_yWOn$DTqr=Ae*@BRpB4;Ip_u4VV;r7VcsNr@Kn13VN_UujD zR;yN$`C__I!$M6q5Xq4|j{TB@tw1uHPABu-a$kUpoVD3vEh)FK^|Ina-p{C%Hwq;m z>qg#em~3>S99F@_P7HudIEuUjH2TCPx5R6^SgUyt*elz<|FAtDy*LWlZ*qjWqVx!J zN9fGA>VwLiA>L;7VOHl4o_#RtPk0UICN|jYH$Uvyq^(5lANaPHJD!i&@5r}${ncLI z637?$jI7S5+M8@pK8ESd-nG%)a=!Ep&@BDzE1Vl9A#$0@^&<8%!2*+PraayOB9D1I zPTHa-ohPy?a2%PVUH=r3Cj1T}4fimjhSkrSoSpwgG7{l8TX;e{Z&g3v2 zVWlkmVkruJ+)S;FQd!}{Z2erSniGEJL=lBmiY<+l9K{PgUn~<1fq0cE7b4+v zMg?}1coq4hARsDnS1J537mQX?V_}fXproOMpN>k{E%+Ig{B{~bs7#IJ)2OZlHF)?^ zx6(6G1v*_C8w)Y9ekL5LWrI{DRm|eDPm|@^2o%iF`Qm8F$WkLCmGG#caQPaVylkBz zFj^*yx30q-%EYJIc=YZ=3k7XH%VcdeK3{>4KyawEP@OaOFti`RvtIJpHij(X zd_?kiZ*d+tE&`*EIMTdBF*x3HTmX*uAH?x)#o%~yWm{Pf*VYx_cx*Mn)Ej|eaMyvm z4%|rtLP{LtmkF(n_zHH zgJEzNfa7-vjYcM-UYzzrG@QiJ;wjYBsDujlyPr0#4Qa6fFo#es`|2#y!U zte5(D0lEY@Qx{nE{9hrDCP|$94g=hj<{^G`cLlg!3Un|s4;hoED1kT5vm8(zjBLpq+$9+1Mk55)Wbc@Rdk+^h4vkR< zgY)O$ZosM051C-bWy>5~4~+CR143%_?U;k(g=XJPaC_(A27w!Fz?t#my%KHDgtNf$ zo0AD9%e0|;!oz0vF*uFY;NOSHesB%bw>0X@-GT2@4Gg0Xunz?KeKOS-QRUwit!kzp zSF}<{f30XWioEYtwDNkq2UfJ2Xmd~N$Tx`cr%Eni(r+r7y-@eSistr2`9VeVO#s`2 zzf-hY5%g<{=Jo~chaXWijz|b*-{J8490L6jQ%8TDqTf+8X9Z)*`(6Y`e&NHqtJCVu zNPnT^%A=Y4WJlj}bNws1`l!rxu4v`Sxt&P2#>I7l6Fo21Rd5uY$wnL2`R>zUxp z^3W{Llg>iBIWlm zB%s@+|9zvOzJH}a-w@oa{{Mp5)AP;x-v=$f2Owqr^l##8M*m{56m(;I=&usmzNmlh zc<`dn1opQ)hyEI9V?UO?O#A_8GakZj6@Na5ei^i}N6Wrd{1mjYw*>nCGtj&d;Yw{q zd)@|Z)(`1xpiM|1^Zp!q5nKY-6IVXJcP|BP)?2G+7ArtAd>7^T4d>IKa}D@G(55{t zXwN~7H{av4n%;o2EPotykDkB9cDpzQnx9VdQoc}pL*wZ?iT@sGvz}Too<9QJugjBu zQRB_`{MY8-{~mPX_x&l*x9Rz7wHFG0lQw5Yj#nHs_i3ma^}|1)I_7DkiuvpWv2`drC`hY(yue2nAXO)vM;sY0RQPX@eys7AHXQK$@pz5~1W z1;a!85AeSSLH{i3{=T{hhm~?6jKYk+=~J6}M41WyyO1db*+OX~RS4waCrH(f3w1=w z)W*h6m6MyotoNv*$5?|BLEAvYJn&f(qLw+#oockI|d za3DCaZTs*5M}Xsvvsfi{BH*p?EQXvK5%fR2YukfEeS&8>^)Cs)jgR{r+pMJ$ohz ztz5tF-tW8fWoPa6f3N>~?zPrl`+d>%YaPc?_UBU-im{un_6Ir;?)!kobf_j3Q1eu? znyn@PL|n%K(BKjVFjWHP$5lZb;vH84k1L2cFXAYhm;A_!>z;{9@gl#f)p&t@6gXTf zz;H2?QZMm71doCKG2nQ;fjBSXse{*9;5iGrc{L%<%i=cuypXI0fAzKg0I%7=@v`{M zz#}^9XXUqM(!H&j17m)J(?7zrSbqSH7_B-=D;7$?p*p+lH_X7wxjYCfr191R>+?CjK;( zlKyEE|0I+$zRtw&K*)Fk*JUUlZ^KZ={{dG3ex&VF)p1I}Klws3F@HXt)2U*y{=w`} zEMJJ{3bB}qoxLZvCDotK7gD*^nRq^*%B$Fpjav&#)7gBiH=a**^bDm7tJ|V`#)7XA zc&vZlzSwXom(LExGwH(q*q(({JE%3{u0N58OU09n3thrk)^iTbN~VWm zBl%Pkh9>sKWAQ?2U%G$@_#i{99*n1l)avcqySjT~Z7uEU%=JCph{oDmI`n;P5d;eq zccj3NdB@!JwkXm z*MY;IhKR#&^WVK-dhRK8WbuQbI5Ov9{HOdQb0~R$x4-=H5&Y&*!vJx=d_m&WG(dBI z`J}|DabO1H_e-3b2bvhaOX9R(U>@T)A&yYBy?)X4KRNibH#TkCGO+6Xz;437&F>lb z)HVLV;rl@JhnsGKy;~3d+JBhz7hL(&8)#b&-SReY*SuJ$Jluzy?H4@v)J^i!X*;m; z$Izq-)xT;y_@w{uUqj@`i+3|PRC~>fBfomOl6VJ9n*Q#G(X3qaWTEb1>cGvUXZ*7X zJMx01seL9&U#VX;9*VyG^a1rT$j99?{%h37wYv^R-*&FN{B0)dihq0VDUs}Qg$|wj zHps8Lij4aHdjE&X>ScQs+HPDw+Yg5vx#Vp~*nIeXNZw(3Q%pO5=Z*2Vjny-*kG_5V zxo;i3{B38X?aIsFqC-dK!Ekjad>8x6kt5HnnH_i;2}Q`ds(_mf_a2@FoK08YtK@r_ z<@E5Up~i(&THC z5B>p+*GJ#bHz!Bm_}b-f_zs=>1~P4a+mY*^zVR#MKNPJ!_>6Ns3_TRBM&Lgb4P5V^ zeWd>2)Ba_bzcKQogI{mF;G)>hrw%pFW)?%=)<-{!oI!!OTf(=F6siyY%75gALlp<# zIx_NygJ1Vwu#?{RmYK(Vpa&M zWXbym!X1d?_OJf2zqd?_kfv^2TX6N_%Hg^Sm&HFw+A~+LUfwhhUGm9I9cY*rHO)J> zcVwtAqGJmdj!3NIWcB|wr8*T(^QjNvzqAbMLHKblV+dIeSZITHpLxog-$^a<#MiI+9Z8_7-i{)67@?H`^ zoAOWettK$wgMQ_k=zEU_vX(m&d>oMZDl4Es`73>k5eroMHZz#$TaExgBV|2e&IJGG z8Juv4|0^pvbgDcD_v!{*KGlu?en(nU+_mI{7!G2D7>S+fw;L*YI#lBB5FbvV*DC;rQNErgd*Nw>v)^Po!Ft`M%a{ zuD>Of$fSq!sg`82r2w9MOMkMrH5o6&TQl*Ip~OIIK9^9wFTxHCCx=F2$yD!1zp7}d zsAwfn`8{AD`&7mJ%HcvTneOY071V^=UIfhqokNxR^ra~RzxN9OCq7EFmd}YfC^09F%cCZFmdN131XWi=pAA(DY*xYY+zDqC)&%vr2gF! z4BQ|=`W^{(JuboSmnF#jUV_1D6t=*mp>_$f=Sh$sk)Uv=1bd#6VDB#^*cU|W8kltH z0tw!`R)Wj6OK|xm61?v^39kB#1P7m#;OZYq@cutaaBUsxa$wR8DKL+Zr3l@Ub%__;_4`+utj}9Uqk76OTx6=g%bgWYvjexNE5dcb_N0 zrwS7M{T&kA^MnMS{*eUtPDBeBnD)6A3GTZjoX7{2saVEzz=#k=uY;FZRp3{|6^^r=Y`ZC#g0WH!{HaCc;$^Ds> z@;BaBZ2;+^WD3v0gXtkWcB=PTaJ)C4LT{pMd^nd9fTN}~Oi&6B$!R{C=F&s`qU=<( zT+5eJZLE-srwe&)f(Dn_)db6G_Mn6FhmIWgGYouuvy@XC+YlR8p$g|zv}XWJbx09X zj#C#q1>IDT@Zj0F#cy&hwFi&hsaP7OOM-Rdo7lH+`SMtdDUD}}$V7H1UudFnr<~d( zhK{yh!$&7T!$+l{>2#*zueIZEZ^5)g1)Nj08Dq{^4`wgc4i@?{@&3H>H!P`+ZH@J2 zvzd5icp$DEMw2P@VZ7-}@56k9pSJ_4eJa2kj!$x!%}}+BWm0_w)x^7OqM)8syvwEg z2MX$dh{`9@C?V;-bV3~vk@vD%dVY6$crPNNU<9)* zy(4|w-F@`faea08D)KF3# zIN(=R4_P;zGn^V4%qCG28g|pz`0%iH5G#QQ=*4`CqywSYpB*V^#}slH4rtF%OV)@g zYN?-OG6NY>pg@1aEmYE<%_e&>u_G4u#^qj8lgjoHt}`Z{&M=~NLq2p+NKyPnR{Yjf zYIic7gZPIjzBkpcMJGmbIx$SQ>y5mocI8Z&jX?zyAbI9Y=aiRn8iKz1y*{NH8hm3+ ziM6#sPcGG$$l?hms@l+EITgEU@gO0bLx);$3pnXt*<2Os+eEil+K^i!I+YJ(2_!$XO&qy%v zO9|5c^OTzMerUjKU~0cj_;9?yajbG$g>NQuFg2JM0BW_wg0})D=%8q6@`wB%2WaL5H*Go* zfeD%HP=9HP{Szmc^qYhlw}>|?E8)SRLi-|gT-B%204+hpkRnj&0l3-(GZDO(jKq^< zJ?%Fz2l1?ova4@eiea#3B&nZjfa>fZ?T1bP5`YAs+X%Ro)BqIHgB*@m-zM?3J?o=t za?4e~om7ERz~@1M-C9+JZb~<=Rn-oSMhU4Uo^!h~jP_O4RMUa^i*Q!MsyYJ?6yZ|w zs)7blEr`82bZNR|R!uXQS`S8aOgD&W9)u{VH;5U6K$B`D9dF=`E?mfG7;uw-^YJ}a zbAv(5*7Whj?vY_5>O_N@SL6{{jRt;dZEP@}+l}5?RfV1Tc*yY0T38!H5kNy))#S7Z zqyv6TXD}pDRVNuoE;X)Qq^jl`(2CkvHj`uq;`v%t&2vshp7>_1g1C`f4Ao_15He47 zSm%7R*3`!K6ym*^l*_Qd`5H=xZ`Rsc_C`7BW2#!5C1S#vwK0|hRkg@DQvhc{o6&Td zvqm(nuZ_iqtE@Xgw$Auuv(Alo&hT~)0$kP9`WLsgw=AQx-MVpVmP!;0ja zm4utv|5TlA(mGHZ8yVsv07S2MHi$(T7EWCpPiJwQwHJjN1$9Eg`30oRW*gNKYg2)m z4Rf~1{UYVB*)%s6+nX3rHPSNbNUy5dLTc5F;?Krg)oe877mz*i%t%VrY&{hezFB@X z?|R&@Jvo`rq!nuR!y>$0RZlq)}Z%!m9gcvy>2`3y!L;`bu+bD76n+{*W#}(30l>q3U5>eEiK~MAc(D z4FQNfEW+ufdCX4NdTDZjo5v?(7uu{U`;ZLya`JX2cE;7fI*Cjw&bCoa{;tmn5(L3~ zunzMH+UY~Xf#J>M?@+73NBB_f^q~h=lfUotBKVjMgtWAiU-6>CeDrqu`Z6Q=0X6w$ zFB6}}oxc85A)zKeBqhV@Szs~r{^UnI@`6OcP$n?K2Y3+xqB@_a1E3b2q%fcEoj#6R z)Z{-&!acoBgb)2r9~(3^IquV)4a>gt0Q#SJCd_F85^6zzDHEi1ML22Tp!%kEtI5}S zjb>A;JDv#VYe`d(q&?xKlBwK~zXlYIl0Hs5IDLf_ddkT+`Y6OYh%*t6_T0l>&&?Mg zyV}W5Xn2Iv6okS@4IUq<8JxIqF!*HeIQf?-11!iY!ifxLc!ZhqQzQDtqB}Xi;p8yc zvV1b{!z|rZGUR*^u zUqaj-K`!#7Q+M;!p}Xo+oxgMc-kw#rj$`j5xPLoO$$_nQ#H<>zI-A+1hTum*2zfa3Dh(d;Y^OR#}Iwi z5P9&N;sM@OmmX7HPz&Qk5QvSmFLrv5CAn<2QO2|XIz*o?}OE~L?AbC9K`o~_|c%|ogF zxCg#Y!)J@heYtodmQ45K`CLt1&(_d4YhH5+bc2ST+&mmh&XVXKCp3V12Qxf-#6l3+Spa@c>NhPIHr2;HfntzvzdMHg$_ zLW3(+(yNhef-JKvsd0-8u9UG)BipUiqAi0O(_z_)m?4c>tiqg$Wc}nk465GL%jtbR zz}A)iR7azvFit&inDik(OL3(gmIhazi)O9T3`&C=`VgD_1I%U?2Gyy-Ynuz0#ld5I z@H*B|DYt_$Oy8*B^%~$O1&VS`1#i%h03n0P_UoZU>OPDNo+iy&;) z?m^H<8Ih+*WoR532s=T-K=d4mL=-2M9e748J}hQwqA=&0b-B>UUwe_9f#x%tN$S7o z9+`#|+uop9R5^%UFPtjC=q|>=ScDVRPH!Q*H=%0gI($$z4||b4#BiWN)U!T~A`m9? zp(k>;OORJJ|KXEpkpK1Lpdq~%fC(6Ea@r41TMjW7zNV-(bw>2X2WfBke=J42}YEGANyy?zgf!l&a!+FfE2BH_EZS0;z&x-f_l5w0F^yuxIC ze{?2rRY9XUDysQ`heAcT*5Kq_zwS3)6WhgX<6JIAfX+DgQ-(~k(ok@nLXRqF#~+Lq zmNZisxPpP4~)Wdl}GTy`&G^RM@i@EkD&9zDB3?^ zHhaZKxGY4xZh~r-R%nXSGNId`FxQSqE4Ad!q9_&SauP8^lE$0MtdR1n!dz_9L`><& z%2Hy8xD=&{n4TNPloZ)zh{W-zG5uc86X~fjAwQiN=AstmiW`1jv|U`SB40A-LN*Dl zj_z|L7l=W1r6G~;x>S9t=Ibw%F34L6SQGS1zt7X*2xw@J+$`c{P5iX@^8szJ3 zj(*;8Rhp)d3vHTc1XOoApO-O58C96;aHNu1#F~e6>Zny4$GD1cl@3IOEQ;zWrY&NP zRS_=SIeR%h$c(8nI8h@1G(Xq%G!=8^IHx>Snu^PQLM6{kHPgl+o6}^-FrZR3$9t)y z=4fHvLS_4bf~Nwa3%E#-rgDCw1Q)(saHw*a@2q)2TPjJRa25W9K@a!lkUxh#coM1b z;|8A-{_lA3n*TL}N7t=te&s<6d&GxjKJ6*0pI{Q_>enUR$8}D3X-iGIy@jiT4i@Ls z^v`2{ewmAF2Q0czaW>Qm^1o`yk~Ep#qozMlN(xwX-#*1fNKLC5CJ&|d#>y7Du*5aS zavHjgQ}oInrZCIa0srcCw6RrqR_y*(3wD^KkL2M`Q=d?WKjcWh+XA=lxaWcEB7AD7hQCexIp51hTC|urSO;bx>gTtNv!) z9&&u6!dzu1Jgw?KtlMx6=dwHD8C5Tn?RJKR>+lYioa3lXs(w<1XZ1mrAXwFPd(Gsk z2p8<7Y}e1M5bx_zDOIT%>xsm~R7%xffLRsFQV}ldbEucXBtZSGX4XfHig2Od$*`u> z&#GW1IYD|?{;3Gp|1t7ne^$S%qL>(6LnGW5z=0WudU;j9$J;l$V?7n&z5$TQfUthZ zh+(6kr{0)8HG{hfoJ;bUsaEwh720y0YDvE&eZG^!6osn)y>5Xc+dr^fL?T`G z!`$DXY0&x9KcV}cGNK4~KREgQ*l>?h{!>$swDY+mLf0KQQPp2+{73!Xj)~hLKqiBz z`b&)egh*Q32=_@i8J&rzRFpSuVQ!p|at9kfsVlLl4|6MpNg_}$6;a{{lSb~ouxSL< zE4q4@B{IzI7@7*T;fuQ8cWG4kbr+3Q?D_|E%TvV9;PwwE7L~eoBZ{q*-Ii1*&ZLM%vnwItgjMbTij5Z1CCqB? z7^Kwi0XwV9sUyNs9q)Hxs|_sp9bnYr`-r%rq;pWS&N4J+A-3f$62+5AY!k_=S?kc@ ztSfd-ZS5u8J&EWNLmJ(ZP|QWA?uWD@$mFV)we!5fHXggMbqPg}T4}RH+U+7uZ;eT* zSzAjw!_lTKHCs%jMPG< z5dQ+nR!g`E*crsK_N@5P(!6vqz7G>+m!|NJ3L6KLWYu{cWypq?+z9q<%<4aiUCUfr zShWQXEU`;GxD*M+C?>mK&DwnwX-ff%#J&Cq(J$c>%tNSrgsA^bFMHshDrO`X@j#H1VVmpFlzH}0(T>C z8@bb;+D}G1|4ZRB0In2YY`6UK|jAB+-ICVErvRY9$-%DOkat}2eXvjZI zay|dQ;ta!+gThdQ(a;GE06@X*AT27$8R9f{hG2d$)MV(FfnLMFat%g_MV7lQ3)gf* zvpq?`W}jp^`O0q^a;%%}R-t*tBoF{<2o~$rib<#H#3lw(n8pjW8p%sxihx+z5>k?_ zF}k*~I;)l2z1-NDG=xb)6--UfZU_aBE(FQXtILhR(sJTYylvFJ+e#qhhDYS{KI@1#Xpw@tG z7kG-BHgtcza<$=;C#KN(MLq)Ff$ws|hqv4?U#&vDnv+F9gTT8h;c65oaW-3>{u()N zVLchqJZY&igKRqF(rt~U z28Z!VqHYxKK9i+zRWBtUngBvyz*ftS_gY~132TvTvFy0jMSR5~?u8uH@sNx7x))JQ zi0b%}OY-fpNp!>A;ag}d3cqUU#F63-ZAOzz@{|GO@HOSpd zFCZNzOhex>@)pGlV+rg&*Ao7RmZ#}P3G6yRy7}za{!|J~}%bDcIvvrTomrm?FX2Bn)xjEgX-!YmV{fM{OVFTr9hP(1EZ%ZjJ zl2FR&wz{h8Qzt`lMn96R0LwdCPYsSXr-uWc-AL22(+Pwa#XhOzYt8wxoTe2><% z%mu-5wulPHl1_5W@xf_-(pAfhT*mQP&XR`;HVHEL5g#ALXZKp(@I;#)&HGM1`<`VA z-BhY@Y@bb9Vv-ZOtCW0PpRMU7%cs~DJ#JXiL#WP$=ut*sn`DIKX@X<`R?Lj9+g!n~ zl?vW9%DKX&JHc07t~bZvDs!>R=PjGlmzo5HGse#*K^(Z37Ea;!l+d#+Yv@G3E)E{n z(S=TT#s^)dMP*E5Io;!+S6#-{rHseq`Gh=P+0rb|H=X`6q#v)YU^`*x0xfv4MEU43 zs^ZWd)qSytXLkwDG1)T86xIDzkHq)=^%6OshAQ_5?%@VWw2 z*I!)T-;d%Qx6}#0l##CZY1R$?N-5~B^~aRo$emH1mJ%rcbVYv7RZ;&gRg7|DQH7_@ z&R=1ZGXLG{DXABwYE;*UTn($A>lO_|Jmybt4SGj^7_ zD65SaNOkMT7;=l1B)a4b+R7;wysapcx8YAqy>Ekmi%>jKpkBu@iEbtcb-&6sLqGF& zUqV5gs8Qi3nN&O{c9`iUG@Y-YFR?>$DR6GPrB>fg&ivl^unPY{x0oG_MYrHt*tYV_ zX4U--(ZM%BRp@o*CLc!SjZi!hFj4l2p!;=Fatc+2{$vO{7%iupw+eJvpersxtI%Hz zLtA?Z0<4_MbyXzD+Q)6w;cwXlGs;Q0vJ|`i){i0GA9Gnl4HJy7gq3Y)sk7YPMRk9x z$ThEoOS0PQVOO8(cDh_Ee^O#420UIC$w_94>RLjUf8XW)(m34XCw}^BB)-AnXx{QJlEmXI zvZJScyX6kgvuQ8oK6=tWY(<1#8QXw&O8E;e^RLHd9zWs1HAwhEPC@=J%eusq>v+-f zs5yUu6%k%(Q$L1?qr2b}R!->niMq_TjU%U|3>K?%*AJ|OaL+qfGQKk+Q8;651)QnNLjIdzLL+k`hi++>^$NXIcPpiE zM-pIm-cp4=tfBrh<7^B+!q>@tvjVF9&UH#ra&_qA$9)+Bxh8zpa#WS@83%oKW%jJ| z2v~DzrBZyQ+Hra?N^;jdFfz&J;{6zyZ9?_N0Ela}^78p8lBl9S$2nUsqkOqYF9R=^ z9-|H}r8q4worV8MNIEa;F*rvd^i|!4h!${paNyDtq+g^G)iSlmWzJ)Lhs;lm!K`s* z%$@5DGd4uJs{h$zZ#y&>ao~39xFqbT&g(s#l+E{KRp@CCFBehCYq4JLpL)3UY7MlkP72xazJEYicTmWH#nH*lta9wNR}6x6m5f(!!2aI9*R({hpF z>qkOV=;b04SKA3>8^AF#A51))GD0@PWssCOSBS|m_YmrTawqo^c77G|{w^)S#!3?}vU^Tzqd@(kE z%Y}wtPG#Vl@*8F94Wi70>!=g&)Zm?*@J>&{WkH@`t8Uk5_x%EO886hbK(hjymxM$9 z2LWhg1JIt@gsmGBv8N)kX8jO#MAEdX(5YX3>L4ttzC9U9chrVNVgE2lcKs(Rw1znw zhDHWcIUFq#*?pA@^=;q@3CycV=9_3SG_8MwyfhOTybpbW1_d_OfGIMx%5NdH8z07f zBzv+8X&7rZFz@IsZmOPjQx@q1#>L=UY-LvaCee5^xh9Rc{_I zil%Jdfa88J%Z7tI&bb@rM-t9IKu$g`Xf-*V#O9h^AaW9P&}B~Dd#OTo9CTsV7+CO1 zU{uE)F5)JOkZz^ppIpS97C{cZoss>K>iDTka$gCF&AY0QO3yQt+yUdEYV{9Os7u1aGtb_dUaMq4nZm1J$F zDHWpf5ms@nY!lvtGX+m}|F}t7V&F)XxMlNs6fU{E5=BtwbC3m6ZQ&#XUpGqQ;9@M9 zMpl)mmTewIGz3;SWh_$aRAhB2-_jDXx@3}h#SA(aNPR35RALB#lMrz@pNgz4k+F#9 z%Zw(Are#osZ81`6wo2QT#S4~sRtmk6W(x<7s6oSKkdkGXZ%cE-g%ovhqy8tdFrK+$ zJ({gy*ob%i@xPJfJLIR++x*uOz}t}AZp&|0ij~YC`Lb>raC+80y#MEz@lAyso)dYx zG*#*3*azpFJ`Lh@0e`NXLl^Re++$Kltxj-1{;P9ac#nD<`6jc~gPGB7G5;O=8w8=G zl_&8_6kn_Wi_%GU_h~M;({iWoYBDpKHzUPu{`Vo;$lH+IZfkoF&Jc#5rbS+L-ow#a zOY+eJXD=*5&!6{ z^H80~#`aH+1B_+tBj_z>4j4CRjVoW=0?kMzHm!0%lHv>AD0qJ^$+N|=9`qA!9Q~Bg zNd>Btu0X9kX{(l`j|=b$J2I9q?iwm5^~&4aO?m97B9nb64x%NPfZ2L?`sQ92Usc4* z=$_fGHec@ItBZI+oqGpSS4g5%q{hXXwt4eIE@!Qa6V2-M*NKv5J18RyTQ#+Zyal^x zuUc`&HtibO4j9X$B*b*vT|b79Hh1G-krIyKNZYzWt^AacXs2UMtCMCCn>mJ1v_8d| z;vz9-5i#v7O^CL4i2jwjx~SoPJ)my7}|rWP;^(u^30jHjT44hoEH zxmhgMc@jbu!6i(HwB43h8UYnqbTl18r*#<7vV%_N2F2>qj>d|SkbfoqH@2afp2r$Y z<>#q+^dqnHKyVQW2ygSJd3ytHLvkDP^Ej_cylH?jDPEG9(f#=<9mg9KJTGR(v$ul- z@4t}m2f&4S#+Z}NYZf)*ah41xDDS!QOfnVb>0=Jx{J_bGLwPmhSHu|#9#^KqJeZ7c zH)#A}0__M))?!`z?!_q4<$x~utoE8{cAE+eh(rvtSN-3WEzsuBqk_%{D705-A~g#35%Rzvmw zFA?xHA+}?g8{MPGem5>`$yYmuaq~$d;zU=(g^nD??#R1P{D#LjaG~<5ozFtH zKD!JrOu5fHI64Q%^l)-ZCS>pm4dV-y!*427;Q;d6!Fv(UF0{{2IJMT9YxDtu7m>3# z!*9O}9EO%N*PqkfwLTW>k*)LkM0lr}pH!HI>lvDJ+)kQPNc2$|Kg7V(&ff&)V!q4g z`w*_}AX&Z~=Yz+)wruG-Ken}JM-&Hr%AALCdbum#h^~o&)NyczsprIb=eSD+suCw4 zRL(q}P|w9inZP-sk}Zf=R`7cu^KQT`(_~Ry8ilWeq++pTK8vmCLrKga%G-vH(-_6T zYs`Z(lea?wgyIVzedgey#wh2a(cyHMNgkXJhxah@J%iCsO=9O@n))}QqiFoiIP`td zwnYPRoRB(%brZNes?I%y$#(h+Xnz`iJ3d=G*)ADLW4d!=d}ERCO?01)zaO7(A^G&d z$x*e#C=(l-WsA?~G$r5J#(Cqjy`zou$LAa0#*4>cO1-m<@$uQ-(Z=NXd}G--F#6@I z_Z@xGKW({KqYlw(Oat$YMmtCsH7|AT(rXDvW04tH&PcfL+F5?R z^l;4l=6r3;E%JC9$N9fB<2lCE;yg|bx@~}?8WV_nrw$Jxj)!gy|9|0Oyzvw?3A=Zp zf;TAVM;IGS@0B{A;nCI&70!b$$d}QFTsKT`z5*Ui=g;uC>xN0r5e%3$D6qR5_YF19 zJrJrvwHZ16x}nbDXJ|C63A2<1)iB)&x}2*r`atZ46P(vD%+_=V22aI(L!)ywhKCx2 z_XwJ)qRFW(!hD05BGNG1`C1X?AF`)pH#9rjT#+g;WX{WOIK_#&2~@R1_T=n_1ACG=900brb1#8hLDX#vEAP zu-^F&BwUx!UN=WqH=N@<3n3Z`$D2c}8@4%jA$1z;&)5U78_sj?M2={%YUJVN_>`S$ z*yCIXA-@pOfea7aZrJZU3xhPMwvi`mXYf>^8b0WJ5VlWEiWNAX5A(KaZoBSR7V3vL zj%5}LCaNApFNCEAC!5LcC1uBGO2N34KFlEU)bzQFM^g&MrSxZ|(^7LgM^g&Mr3_^E z8PX-ANINykrLE2C#6pTx`DvOn|;Q=*w`DjYPSW18O z`ovHnmr-+18%-$~OX*ubEH6RMT``(aFqY5{f13x*?uatg7m%eo{{^L$(6Ls@DLjlssYT(hNzEZ4C-IS>B^Wv$t%F^0%< zvZSsjvA(wroeRcUXx#Pa;~j|?9y9UYzeX~M$CkYRIBoNiqRlwEk@IRa{oU}4o!ocO z^KNV#Bk}463`c!xC)y3a^FcH!^ALYG-zFORn|zzdnd;O|sKfs`HNmQiniFea+-y}* zQ&n|3hU*o$4d`3E=TuR%yy~>7p5PhPJ~Ts>b5&1}76+j`E-)@i?x52 z$pBDd)!Tyu{hZ@VTszmeOB6R3BlO)oJh%iY;^didRx6lKu{o>M{1#d`RxRbWGPB)SlP6rK6(AEiG6jWyhZJxH%?qamV2$GUZ8H>G=3F!0!po*|1 zUM^StQa6ie66ux|A&f3BX0@AXr+Et&OWF#LK3yhsIayf-*U-~FmXKOQ&k(0EOBST_z8=8=yc9#lhzh%jH~HPq}?sBT1J zdW!&^cL{vOH%Ls9H{?l?giTn7G-7>*L%Wtt%!qzKi^bVO2a2>dE76*#i%^kEzw9#n zy1-~tb{Az@ZfMFBxjoRq(X>dz&}dpfvj$q!#qrW!?RBv!v9f8XdTJto1v{OEycg|P$DyuOts?k)*7q+5BbYg;`2lKV~}a=(3E3ET8~lCJ0|XL zBZME5P@_HwiHzmfm9WomkVOd&#hO=Ny1!)rIi*(c!U7o+r?VP}FJ#(Vt}f;QMGc6Z$wfJ>6`XSDu%?HMc#Z<8$Lx`U z9(|`t^qJEDau1vV>0^rlqY=<)tiYX1ARF#Lq1P-m7)NxG(tZ&NKs1niS~BN}0RX4y zsag`^@!CE5Q4^Oy3Ro+I0Bx+^E+;7lj3<0AfG^`CnSz#T&I0#%MZ2|cZ&HgcIX?^_ zJO#LiK52@4q4>c!4Jpn7AWqZeOm?$XMU${%a~-0h)*1NFCtrGg;lPI;efs&+Uq1i* z^9x_~`zq%C%X%^qbB*CwGd}n zyRJr|v;6jZ(iUmq_FK~Ba4uhv#==btt-p$eXJz@+>*}L?zg14+lz-%KzW~L_U1TLb zHYNXDIElvi?A9?f`=wu@<#%XUd52>B7*A0z<$K;$!HJh8Wm3s=w%OlmwgPdwA)Sm# zIgDz8rM7x?aDp+aC7RcMlqR=3UpalHzeXmaUCt$D&M#W50ZR6*=&!QjdFvSp`isknAbr$y0+@;HGq8<)8s;)^P?!KEabczZ&&<05UIo%fJc$f)8% ziDvQcF2Lp;eu+@(zuks_)aVncJf9Wxx>O%NrMC@Y15dd-mza4|c$CL08^0C5RVPO1 zmjGldo^_I#&O9<3i@hrKRukC?E<2IRb+%)AsvNdhCWH;tn`S0irkVmUKvixtewUL&WB1!c_3T&ZG1ai%Wr(O^!w|x;OHm%|X3q-M}*xTZw z?RJlHqw5lSw;k@Jn3g5E9jhzlx;pjTe>r%WTLwpCY?D@wX~)t^R5FX@z}wE6qHc@h zJ9)BLE;wK8W@p>NVv`Up8MQFkWzA5D{0=skQDxpLQ*LXhJXN%W!L<84C$HG1j7lpO zpa3iXNbOjH*!Gkc>8LcVcFB7zF1~^Q_1gH722Jl!HRhGH0!4Q%F^e?iW-pe-v?zxS zGFI`af}dj+3==RGDg+pE?BP=*n77nF#yRdFEyHE{KEQBL?u)cTi03rk&u||uM{Q=X z-+&puSKkL1VoyYgx|0_#+!txzK>T+a z?`Qa?zL(t@^no|Yieoe26`vPh#l=U%<8bkT@Xxr2Sc(VA+(so(g|jTJy;<>joF)Ibd1io(X+fh0I>Ots)xW_<3kC8>j5 z2_PXdjwc7G!!hUl*CMjDoL-y}+=6N~$WKhSBvZX3{V}|fh7XWYibRJ;di7>-6Gws1 zT3o!h7vF!jF{~V>?7diLBk-2J#W={`8a1w)k9Kn+2w2YX0HHdr^anZ+!6dEwBaT0g zqw!QCbZ3F?EFhW?w?91E$!{_KE%2LQ^Z=-qM9 zAJ_q=I>4-6+QVx*uD=+%4CpeTyBIL)C7ycu>&JyvTY)_fy5~X1LT=@ej`3k!mhL6c zy#%_2h7L1TB9C-z1ZXSuux|Mw;CS5IpVeCcz|u8>t`P|8us_oAdLJ%JcN6Gt0&qJM zV1D!+f7jr$bgavVVL+o`^gqht?+`B1i4Rz(Q7DR)TI(bo8z@Ux4Z3R3%_hS9th~Ds zw{#0Zw-9tpoBdh3`v4#v+@|jNs6TKI=;$~5vvdytVCn7$-TmX(_lSq?VbDDcIxB-R z?fnzDXI@b6W1xEsbZ;0K0yp2D!M)Y{`P=+~&%-HJhNWZtc@N$Fpt~P*vq@lnq~Y~l zTvpyopnC~)W2Ki3I{i=kehj)FQ=Tn+fHmRb@5i_(&;Cd^*8{M(zXXB3Cv5<8wd|zq zkGlAK3zwJf0O&3gjQ(eF0o>SoV%`Sbqv;}{#Z4=tdkBRf3t!uxr8}vNZZ4DtJn6M` zEoF2IuSB0^g(0Mm`8%zQ?q{HTehj^9%joXE9_wg;*`K}LTt@f84Oro@L75JsYFtbQ>oD6Eue^(IgP%PBD-UF&er)#%tT0;H zzU#Qw%ywMIwLrGlI9xL!iCWaqU>Pr#dcyV!Ns1Oa=DyyKxj2 z{MZgMtdO1n?UEbUHG=J$#$z1-Kek^wj%927?6{*s;l%{}*d8&g5YM3#dHTAaVPz0(-!` zzY6(mS`kuF(n8Z-t{@bD6)Iee;I2YN%HmCB@tI}ulgi>asK5j9tKS_dZIga?WL_D* zwJg58ES^K0V@ZO2YKpq541XiyZ0`wnkRP`rwE5v+r1Ck$ZGJeI(fbPG^e63f)CuYv z2wyY)b<_-Le}C-J_fz0&F;9qKO#QzB{PQ0De@6U4Hy%_}beAbVj+(0K5%=1|_UcJf z9+|#!e=Mb;=0|@Hm&LC{+|EOi|09Uo`AWv0COvi^GhljO!i}AuB>pwTZTWM2$E)8X zZvClzb*chY+#9b)oc$b4a(vTO1aVtlo8Z4w5a(|jE{>blFphoGY>1{p|7OHjA-!w~ z>YzW4xUHXz4;X%+RTHkgW${CZv%a!rnTq;)Gvc;B*QpwHo1y0pKuW9Y zYa`-z{+a2!5OF{91LSC3es?5}xSh8q{*p5OeTZL%^7uAF+WRqtkC^gO=bNJLN8HY1 zlm8zPx9wpa+rxNodVxGBZN>J8R(ymenHtWwrrVcxwx%+Dt$5olSHS$cnWJXFhaM~_ z9>dfzr7Xb0N}@H9A89oUh6%nt*N=G{ei$8-ssQH;BYk}k8H=sncFvaA`kt-ZVll+l zl*Gp6kio}_k}ZpuEMBUH8FYdnnKkDH#N=U1&a=~xWXX}i!TnZ2bmN+$d>dK2 zrE5bpW@A)l?~799Nlv7`o78h1W7Hzsm@hxXc678I^UD|MG^RN)ql33DvdkZ(Qoko* zMW3^F?bhhF*tV|j^-;Q&M0lXg#rMZ}#CQon=SghM`5U`7^sH8VAT{}fuVd|tWA=-m zyIQsC%=JCpt7D5=+FIHG zDz}=i?Bmfk);Am**o#2eN+zi~dSLSEw&)(Cc>DHPdrJo_7hPgAcA=+-igqp3Q$OxB zmq=JMT0-e^21-yd!NnIwO5W-4B#@4T5qMs=sVsT_MtisHy`ES~9`f;Jx_$d%*p{2m z4&j^ue2rkw!d0tQZ{LpjiWr@WTzQFEH$wBqM0gz!g A%>V!Z literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e89bc956e7f0a40120c112e312df3a52a33ab3b9 GIT binary patch literal 9106 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..cbe79e76c9bb0e2aa12f6e6609438768c43de0ef GIT binary patch literal 9581 zcmd^FdvH|Oc|Z5DVlhIN5atn7XJrX24{(=r1Rgt?{MWN{?svZL`5;3Gj?Yx9goKa|z%}UvlG&3!!5)`rXij zy(<{|$wGc8S;(v|nZCD$~L(VF^-6;t9J!uU>*kI z=OVHm#GAa7GaqrXjXFdtd16lv9DViApZxdBNX`hXiwOxNK4}>_jn{e9^ClK}HOh%0W?-t5GP1(}hwPh~eXvd=#KK*nmA* zqmfj;D0&VY=-xWuul3f8?Slhbd;E1M$fVZb#bn@&anN@*`pwcmIZQX@J1uLJye;0;_{Nvqcpcg}0Xhe?ofK`{L5jv*MT!#EkYd1e zl45{uBE=xtf99RhcjM!K1#{z#$UnXkqv_2nVsgV0ASRc$;K`yUm$QT%lQ(ZnA}nV~ zIqGg+mpn_%vD!B;OP(d?mXNE*A6m%9KiR_ox?lq9evjwXNE)1UCF?gjD6(}bf@2nV&hwp zIB@9AE9YcT?|bU8ev~Gn`dcldm)$?v24?cDizH)>r{AjHdOb$Hg-i;6u?24A^yO&5 z4_F2gbFaDWlucd-=Img*iz-fj?heqqN8fFSvVgHYz8FPc>zx=y`daV%FM^EqzJF$0 zyF1o9amH;Q|ECWoC(rcW9_zggVg0pj?eWDh59*>P1gw0OR(=E&A;|DmBxMywueKk2 z`fTdX6_oh&m9x}N)i_F?Tr~Q+`K=NU^{nlq%S{++WmM=OdWOD? z<9<)ISj-o*iM{0@olh0^1!2@(E{kL|Qch;V;Rw7Jorpy0Ly+{J)-q=^2O%3Uf_)As z4nhX&nO(wqHXf6XsNQwI%=rR&0+HkCSx~X9-V$?Ns}K6_hWKfF>-<>v3#=jL075Ng zn&p_-uhV-pJ)&tDv>x%ss2j&*7X9c|`n??1o}Ya%S$YMOemnO(<}&CT;Q20ZBhEwQ z`#gZiz?v+?*rdQgGmW6ZVkzy4Z%@*hJvmr1&$r|sR=De*y58If(k!1jx~Ve+ZK%&R!aXf z*kS)4(PL1&?1zJaT@B&m-E0 z@NnnYJs?)x&QUbSeo6^@DXg=(`LSb8z8DENW^Vu&kJ-CP=Gc#dK&Y(@g0t$}KO z#%IjomLj$jY4Q7rw%CfNYe~o;x0#%(B_ zOo!EEx)SBRy&osvv@zu44lmKYH-Y`Yr@ReogmvntXe(RnleM{mCzmpI6@fh~SAN8l zaA$f%FP#?2TxldomQ%-rLh^X2ax^Tb(gD3>vQ)`>LAsDHhk=*Lc=Vc~m(2_%GpQ(* zETpQ%bS@cI(!vh&&jfxXV*mIuYUKQom7C*Mi(x)n3^IvyE>%GX9$sZM$S5&Q)Y;{szX&inVEuktVS@y8hYFJKUYmVkLN=!vUBWRgWiLAOthhg1NM%Fe z)XM{p-6rDHbI<6Pql$2vtP{v+x4F~upqLTP0xgeE%ZF0fI6BQ*Q7;v88|f>}Lak}6 z(a16$(29jM3R%b^tym%zL)BqzX|a~KOvxpDi54fMI7}T2H2xD>(XQ~R^wDZrtCne1 z$8;WPt3}IK#r=^~lgKp7nWIh3#>_P)Z*a&N^#M3i?r+E@`uMSe7&x_x*AzvsO6UtYcELPf1Y8 zUM)GGByb-p6sq8e;%Em*%l$DN&6r>YZ2X{bGQPkMn)i=%U^a z@U@&W_W4|+d_7CfAp3lwaX14%!Tk35GR%L8#VGgNill43fM*9}zl!@U{#x9x)nql+ zEx>bmL-RbRVOay}+Af@idGkJvMb$wvu97Z#w&Brvo97KQKVENR6Bb(`2Dsi@O;|+t z*E#WJ@#XPm?$)Ml#$gk3*jxldDz~z#3vj0kh}|#dp~yNC8lKZ^SLuny4 z(7Xwy&sC-0XY67>Sc8Y1dX0xI;^$+;HPdWEE2^CY;C>I1$LmeCnydv@7d8Wpcu!qZ zzU4h$uMJXL{04Q_FB<0K$x*?z+!Fa>KJwDwgm?+j7CZ2~3--%)w-9={WjP{dbNc|d z+?s5C?6a-eY%=-T*49=VM`#O5?uVQ(KU;JAGs8aL6VogJZw^4`Q==DNcya_wAZS!kG-pz1i=a{#Ua=Gf9&V&o zN2#pvFjl=>D$EHlbFzrcieeulHOH`u=S#&Ij1OHUC=jm_LmRgh4#h7mR zNV*INP9dJ5+oEM4a{Ljy z7V+o$?9TgwSAc7WjCmP|Vcd+U2B*45cmuc#knvstNr~ay?m?vQk>%pvA&11<;7uTw z;YmbuXTbY{Ey%<>2U9NdGaf+X9Rt(6XV?YYE~Hs5Wvm-R7I7{jWxS`j030WQu}2*F zGNQrpUgMj<@xFsN-lZ5EPpYgd%i-L*0UVF1CYW*~2n_BvaJPXwWk8_BF@6!z;P{Q> z6ohO;6WDePrx6W~bGaWC;91-R+F}?(B#!UP`J4gn38YOhxUWE9aPqqYaBOE24DKQX z26q+qt^(I@K%fTqry7UX6ug$>_mU}RQ-k|X4Q?TD3qJ(M3u2Z_d%XB;0nU^K(Ny|x zkw%pyPJVv@ZbHjIB#!mChG^{Z4!aS;+4ji)eGQKHUJHTifXoD982$t*8;0lm0k`I=yo56!~;FD_(0FiL<;(wl|54W~vwWP)jz z&9iWw7^H6)5U8=&Hw$+MxSo69cF)3f;i9v@24~uj_edOjCVUw6?wm_ zc;)qY@2hy#(dJ&(kt>Mur%Eqj(r+rBZ=vpe70<1S@`H-!N`SEkf2VjgBk0!@&#epU zulE^_z_|#)>^mHOmqVaGB6ajvDf%77vsaXVQ9N&*;kS6-i{R*$k^VyQ%A=Y4V@Ka= zbN(y6`k2glu6X6iIiD53gha@1H=vGKDtYs8#3xKrQb%yLo(|3o56%2M-b@EaJUGoD z<;?ghN-oG< zf>O_WSo(X4EqrPH8mQ?H3;ppe@TNa3tT6oOBfoV?{8I5_P<{skLH;Gu|6Z>t@877< z*8=w{|G%MbtSSE&;N|^4D9fjRi~pXn-y{}+udNULRYH$1+MnGXn`#=A?^~Y5KM&rF zAIn}WUIK60L)Z(%w`TFLfj8sPvL6sX25-h&0`GqvJg-4GQx~8|Py9vCRZwoNr7K3N_2J&(Cbb`;-;CsNE`ZS_GyENW>hab}XI^<>k z5PX;Jzb1Q$I0c@cO!HDdU!2o;`cC3s25;t5Bii#Xzz^#DJP!8oad@?8uC*|jM z99#97l7xp4+&+AaquxC)^V6w9q2|v8ymSbo>hLg3`hL&8oqPPjfxY|qp96o}4DN}Z zDHRSYi)Q}VNg(om}4%fpYKs-6()h?J?0jGQzD^zPU;ZQn3` zd%8c<>l==Rne?<(d9spLf0eiA@&E4Y3V-|H&aK^p{?5L>y}kSVecf9Jd-?KgY8=BV zsgpi$foBM0uLytJ!5!V78R!u_#;HF>04Dz>fsY`#1;$} +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(); + } +}