aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2018-05-23 12:32:07 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-05-23 12:33:20 -0700
commit29eafdfe329b300dc42fddafde87bddae2f07a4c (patch)
tree7b20b5796aeb5c32ce66c3160ebdb8f56d32106e /src/test/java/com
parent3e951fcb946b9f8efdef7a84a2fb0fe03ede010e (diff)
Initial implementation of a Skylark debug server API.
I've pulled out the API for separate review. It includes all hooks from blaze/skylark used by the debugger. Debuggable thread contexts are currently declared in 3 places: - BuildFileAST (top-level evaluation of BUILD files) - SkylarkRuleConfiguredTargetUtil (rules) - SkylarkAspectFactory (aspects) The purpose of declaring these contexts is so that the debugger can track currently-active threads (and stop tracking them when the task is completed). Details of the actual debugging server are in unknown commit. PiperOrigin-RevId: 197770547
Diffstat (limited to 'src/test/java/com')
-rw-r--r--src/test/java/com/google/devtools/build/lib/syntax/EnvironmentDebuggingTest.java220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/EnvironmentDebuggingTest.java b/src/test/java/com/google/devtools/build/lib/syntax/EnvironmentDebuggingTest.java
new file mode 100644
index 0000000000..1e1add2620
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/syntax/EnvironmentDebuggingTest.java
@@ -0,0 +1,220 @@
+// Copyright 2018 The Bazel Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.syntax;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.events.Location.LineAndColumn;
+import com.google.devtools.build.lib.syntax.Debuggable.ReadyToPause;
+import com.google.devtools.build.lib.syntax.Debuggable.Stepping;
+import com.google.devtools.build.lib.syntax.Environment.LexicalFrame;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests of {@link Environment}s implementation of {@link Debuggable}. */
+@RunWith(JUnit4.class)
+public class EnvironmentDebuggingTest {
+
+ private static Environment newEnvironment() {
+ Mutability mutability = Mutability.create("test");
+ return Environment.builder(mutability).useDefaultSemantics().build();
+ }
+
+ /** Enter a dummy function scope with the given name, and the current environment's globals. */
+ private static void enterFunctionScope(Environment env, String functionName, Location location) {
+ FuncallExpression ast = new FuncallExpression(new Identifier("test"), ImmutableList.of());
+ ast.setLocation(location);
+ env.enterScope(
+ new BaseFunction(functionName) {},
+ LexicalFrame.create(env.mutability()),
+ ast,
+ env.getGlobals());
+ }
+
+ @Test
+ public void testListFramesFromGlobalFrame() throws Exception {
+ Environment env = newEnvironment();
+ env.update("a", 1);
+ env.update("b", 2);
+ env.update("c", 3);
+
+ ImmutableList<DebugFrame> frames = env.listFrames(Location.BUILTIN);
+
+ assertThat(frames).hasSize(1);
+ assertThat(frames.get(0))
+ .isEqualTo(
+ DebugFrame.builder()
+ .setFunctionName("<top level>")
+ .setLocation(Location.BUILTIN)
+ .setGlobalBindings(ImmutableMap.of("a", 1, "b", 2, "c", 3))
+ .build());
+ }
+
+ @Test
+ public void testListFramesFromChildFrame() throws Exception {
+ Environment env = newEnvironment();
+ env.update("a", 1);
+ env.update("b", 2);
+ env.update("c", 3);
+ Location funcallLocation =
+ Location.fromPathAndStartColumn(
+ PathFragment.create("foo/bar"), 0, 0, new LineAndColumn(12, 0));
+ enterFunctionScope(env, "function", funcallLocation);
+ env.update("a", 4); // shadow parent frame var
+ env.update("y", 5);
+ env.update("z", 6);
+
+ ImmutableList<DebugFrame> frames = env.listFrames(Location.BUILTIN);
+
+ assertThat(frames).hasSize(2);
+ assertThat(frames.get(0))
+ .isEqualTo(
+ DebugFrame.builder()
+ .setFunctionName("function")
+ .setLocation(Location.BUILTIN)
+ .setLexicalFrameBindings(ImmutableMap.of("a", 4, "y", 5, "z", 6))
+ .setGlobalBindings(ImmutableMap.of("a", 1, "b", 2, "c", 3))
+ .build());
+ assertThat(frames.get(1))
+ .isEqualTo(
+ DebugFrame.builder()
+ .setFunctionName("<top level>")
+ .setLocation(funcallLocation)
+ .setGlobalBindings(ImmutableMap.of("a", 1, "b", 2, "c", 3))
+ .build());
+ }
+
+ @Test
+ public void testStepIntoFunction() {
+ Environment env = newEnvironment();
+
+ ReadyToPause predicate = env.stepControl(Stepping.INTO);
+ enterFunctionScope(env, "function", Location.BUILTIN);
+
+ assertThat(predicate.test(env)).isTrue();
+ }
+
+ @Test
+ public void testStepIntoFallsBackToStepOver() {
+ // test that when stepping into, we'll fall back to stopping at the next statement in the
+ // current frame
+ Environment env = newEnvironment();
+
+ ReadyToPause predicate = env.stepControl(Stepping.INTO);
+
+ assertThat(predicate.test(env)).isTrue();
+ }
+
+ @Test
+ public void testStepIntoFallsBackToStepOut() {
+ // test that when stepping into, we'll fall back to stopping when exiting the current frame
+ Environment env = newEnvironment();
+ enterFunctionScope(env, "function", Location.BUILTIN);
+
+ ReadyToPause predicate = env.stepControl(Stepping.INTO);
+ env.exitScope();
+
+ assertThat(predicate.test(env)).isTrue();
+ }
+
+ @Test
+ public void testStepOverFunction() {
+ Environment env = newEnvironment();
+
+ ReadyToPause predicate = env.stepControl(Stepping.OVER);
+ enterFunctionScope(env, "function", Location.BUILTIN);
+
+ assertThat(predicate.test(env)).isFalse();
+ env.exitScope();
+ assertThat(predicate.test(env)).isTrue();
+ }
+
+ @Test
+ public void testStepOverFallsBackToStepOut() {
+ // test that when stepping over, we'll fall back to stopping when exiting the current frame
+ Environment env = newEnvironment();
+ enterFunctionScope(env, "function", Location.BUILTIN);
+
+ ReadyToPause predicate = env.stepControl(Stepping.OVER);
+ env.exitScope();
+
+ assertThat(predicate.test(env)).isTrue();
+ }
+
+ @Test
+ public void testStepOutOfInnerFrame() {
+ Environment env = newEnvironment();
+ enterFunctionScope(env, "function", Location.BUILTIN);
+
+ ReadyToPause predicate = env.stepControl(Stepping.OUT);
+
+ assertThat(predicate.test(env)).isFalse();
+ env.exitScope();
+ assertThat(predicate.test(env)).isTrue();
+ }
+
+ @Test
+ public void testStepOutOfOutermostFrame() {
+ Environment env = newEnvironment();
+
+ assertThat(env.stepControl(Stepping.OUT)).isNull();
+ }
+
+ @Test
+ public void testStepControlWithNoSteppingReturnsNull() {
+ Environment env = newEnvironment();
+
+ assertThat(env.stepControl(Stepping.NONE)).isNull();
+ }
+
+ @Test
+ public void testEvaluateVariableInScope() throws Exception {
+ Environment env = newEnvironment();
+ env.update("a", 1);
+
+ Object result = env.evaluate("a");
+
+ assertThat(result).isEqualTo(1);
+ }
+
+ @Test
+ public void testEvaluateVariableNotInScopeFails() throws Exception {
+ Environment env = newEnvironment();
+ env.update("a", 1);
+
+ try {
+ env.evaluate("b");
+ fail();
+ } catch (EvalException e) {
+ assertThat(e).hasMessageThat().isEqualTo("name 'b' is not defined");
+ }
+ }
+
+ @Test
+ public void testEvaluateExpressionOnVariableInScope() throws Exception {
+ Environment env = newEnvironment();
+ env.update("a", "string");
+
+ Object result = env.evaluate("a.startswith(\"str\")");
+
+ assertThat(result).isEqualTo(Boolean.TRUE);
+ }
+}