bazel starlark: merge lib.syntax.util.EvaluationTestCase into BazelETC
//src/test/.../lib/syntax is now deleted.
The BETC diff is messy, even though the file was created by a move.
The only real changes are to the new{Module,Thread}Hook functions and
to the class declaration and its comments.
This change is a step towards a future in which tests do not (and cannot)
concern themselves with subtle internal details such as Starlark thread
creation.
PiperOrigin-RevId: 334417122
diff --git a/src/test/java/com/google/devtools/build/docgen/BUILD b/src/test/java/com/google/devtools/build/docgen/BUILD
index d261384..8703861 100644
--- a/src/test/java/com/google/devtools/build/docgen/BUILD
+++ b/src/test/java/com/google/devtools/build/docgen/BUILD
@@ -52,8 +52,6 @@
"//src/main/java/net/starlark/java/annot",
"//src/main/java/net/starlark/java/eval",
"//src/main/java/net/starlark/java/syntax",
- "//src/test/java/com/google/devtools/build/lib/starlark/util",
- "//src/test/java/com/google/devtools/build/lib/syntax/util",
"//third_party:guava",
"//third_party:junit4",
"//third_party:truth",
@@ -82,7 +80,6 @@
"//src/main/java/net/starlark/java/eval",
"//src/main/java/net/starlark/java/syntax",
"//src/test/java/com/google/devtools/build/lib/starlark/util",
- "//src/test/java/com/google/devtools/build/lib/syntax/util",
"//src/test/java/com/google/devtools/build/lib/testutil",
"//third_party:guava",
"//third_party:junit4",
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD
index 2c071f1..0d6f149 100644
--- a/src/test/java/com/google/devtools/build/lib/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/BUILD
@@ -44,7 +44,6 @@
"//src/test/java/net/starlark/java/syntax:srcs",
"//src/test/java/com/google/devtools/build/lib/starlarkdebug/server:srcs",
"//src/test/java/com/google/devtools/build/lib/supplier:srcs",
- "//src/test/java/com/google/devtools/build/lib/syntax/util:srcs",
"//src/test/java/com/google/devtools/build/lib/versioning:srcs",
"//src/test/java/com/google/devtools/build/lib/vfs:srcs",
"//src/test/java/com/google/devtools/build/lib/unsafe:srcs",
@@ -144,6 +143,7 @@
":AllTests",
"//src/main/java/com/google/devtools/build/lib/collect",
"//src/main/java/com/google/devtools/build/lib/collect/nestedset",
+ "//src/test/java/com/google/devtools/build/lib/starlark/util",
"//src/test/java/com/google/devtools/build/lib/testutil",
"//src/test/java/com/google/devtools/build/lib/testutil:JunitUtils",
"//third_party:guava",
@@ -167,7 +167,6 @@
"//src/main/java/com/google/devtools/build/lib/collect/nestedset",
"//src/main/java/com/google/devtools/build/lib/collect/nestedset:fingerprint_cache",
"//src/main/java/com/google/devtools/build/lib/collect/nestedset:testutils",
- "//src/main/java/com/google/devtools/build/lib/packages",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization:constants",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils",
@@ -175,7 +174,7 @@
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
"//src/main/java/net/starlark/java/eval",
- "//src/test/java/com/google/devtools/build/lib/syntax/util",
+ "//src/test/java/com/google/devtools/build/lib/starlark/util",
"//src/test/java/com/google/devtools/build/lib/testutil",
"//src/test/java/com/google/devtools/build/lib/testutil:JunitUtils",
"//third_party:guava",
diff --git a/src/test/java/com/google/devtools/build/lib/collect/nestedset/DepsetTest.java b/src/test/java/com/google/devtools/build/lib/collect/nestedset/DepsetTest.java
index d2fd290..5ef6a39 100644
--- a/src/test/java/com/google/devtools/build/lib/collect/nestedset/DepsetTest.java
+++ b/src/test/java/com/google/devtools/build/lib/collect/nestedset/DepsetTest.java
@@ -17,11 +17,8 @@
import static org.junit.Assert.assertThrows;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.collect.nestedset.Depset.ElementType;
-import com.google.devtools.build.lib.packages.StarlarkLibrary;
-import com.google.devtools.build.lib.packages.StructProvider;
-import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
+import com.google.devtools.build.lib.starlark.util.BazelEvaluationTestCase;
import net.starlark.java.eval.Dict;
import net.starlark.java.eval.Sequence;
import net.starlark.java.eval.StarlarkCallable;
@@ -37,15 +34,7 @@
@RunWith(JUnit4.class)
public final class DepsetTest {
- private final EvaluationTestCase ev =
- new EvaluationTestCase() {
- @Override
- protected Object newModuleHook(ImmutableMap.Builder<String, Object> predeclared) {
- predeclared.put("depset", StarlarkLibrary.COMMON.get("depset"));
- predeclared.put("struct", StructProvider.STRUCT);
- return null; // no client data
- }
- };
+ private final BazelEvaluationTestCase ev = new BazelEvaluationTestCase();
@Test
public void testConstructor() throws Exception {
diff --git a/src/test/java/com/google/devtools/build/lib/rules/config/BUILD b/src/test/java/com/google/devtools/build/lib/rules/config/BUILD
index 70ef1c3..d19008e 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/config/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/rules/config/BUILD
@@ -41,7 +41,6 @@
"//src/test/java/com/google/devtools/build/lib/actions/util",
"//src/test/java/com/google/devtools/build/lib/analysis/util",
"//src/test/java/com/google/devtools/build/lib/starlark/util",
- "//src/test/java/com/google/devtools/build/lib/syntax/util",
"//src/test/java/com/google/devtools/build/lib/testutil",
"//src/test/java/com/google/devtools/build/lib/testutil:TestConstants",
"//third_party:guava",
diff --git a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTest.java b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTest.java
index 3d80efb..914dcf2 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTest.java
@@ -27,7 +27,6 @@
import com.google.devtools.build.lib.packages.Type;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
import com.google.devtools.build.lib.starlark.util.BazelEvaluationTestCase;
-import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
import org.junit.Before;
import org.junit.Test;
@@ -38,7 +37,7 @@
@RunWith(JUnit4.class)
public final class ConfigFeatureFlagTest extends BuildViewTestCase {
- private final EvaluationTestCase ev = new BazelEvaluationTestCase();
+ private final BazelEvaluationTestCase ev = new BazelEvaluationTestCase();
private StarlarkRuleContext createRuleContext(String label) throws Exception {
return new StarlarkRuleContext(
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD b/src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD
index dd5796a..45fbea8 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD
@@ -682,7 +682,7 @@
deps = [
"//src/main/java/net/starlark/java/eval",
"//src/test/java/com/google/devtools/build/lib/packages:testutil",
- "//src/test/java/com/google/devtools/build/lib/syntax/util",
+ "//src/test/java/com/google/devtools/build/lib/starlark/util",
"//src/test/java/com/google/devtools/build/lib/testutil:TestConstants",
"//third_party:junit4",
],
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/StarlarkCcToolchainConfigureTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/StarlarkCcToolchainConfigureTest.java
index 2b6d281..cdb1253 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/StarlarkCcToolchainConfigureTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/StarlarkCcToolchainConfigureTest.java
@@ -14,7 +14,7 @@
package com.google.devtools.build.lib.rules.cpp;
import com.google.devtools.build.lib.packages.util.ResourceLoader;
-import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
+import com.google.devtools.build.lib.starlark.util.BazelEvaluationTestCase;
import com.google.devtools.build.lib.testutil.TestConstants;
import java.io.IOException;
import net.starlark.java.eval.Mutability;
@@ -25,7 +25,9 @@
/** Tests for cc autoconfiguration. */
@RunWith(JUnit4.class)
-public class StarlarkCcToolchainConfigureTest extends EvaluationTestCase {
+public class StarlarkCcToolchainConfigureTest {
+
+ private final BazelEvaluationTestCase ev = new BazelEvaluationTestCase();
@Test
public void testSplitEscaped() throws Exception {
@@ -50,12 +52,8 @@
.testExpression("split_escaped('a%:', ':')", StarlarkList.of(mu, "a:"));
}
- private Scenario newTest(String... starlarkOptions) throws IOException {
- return new Scenario(starlarkOptions)
- // A mock implementation of Label to be able to parse lib_cc_configure under default
- // Starlark environment (lib_cc_configure is meant to be used from the repository
- // environment).
- .setUp("def Label(arg):\n return 42")
+ private BazelEvaluationTestCase.Scenario newTest(String... starlarkOptions) throws IOException {
+ return ev.new Scenario(starlarkOptions)
.setUp(
ResourceLoader.readFromResources(
TestConstants.RULES_CC_REPOSITORY_EXECROOT
diff --git a/src/test/java/com/google/devtools/build/lib/rules/python/BUILD b/src/test/java/com/google/devtools/build/lib/rules/python/BUILD
index 7090e31..609423b 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/python/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/rules/python/BUILD
@@ -224,14 +224,12 @@
name = "PyInfoTest",
srcs = ["PyInfoTest.java"],
deps = [
- "//src/main/java/com/google/devtools/build/lib/actions",
"//src/main/java/com/google/devtools/build/lib/actions:artifacts",
"//src/main/java/com/google/devtools/build/lib/collect/nestedset",
"//src/main/java/com/google/devtools/build/lib/rules/python",
"//src/main/java/net/starlark/java/syntax",
"//src/test/java/com/google/devtools/build/lib/analysis/util",
"//src/test/java/com/google/devtools/build/lib/starlark/util",
- "//src/test/java/com/google/devtools/build/lib/syntax/util",
"//third_party:junit4",
"//third_party:truth",
],
@@ -248,7 +246,6 @@
"//src/main/java/net/starlark/java/syntax",
"//src/test/java/com/google/devtools/build/lib/analysis/util",
"//src/test/java/com/google/devtools/build/lib/starlark/util",
- "//src/test/java/com/google/devtools/build/lib/syntax/util",
"//third_party:junit4",
"//third_party:truth",
],
diff --git a/src/test/java/com/google/devtools/build/lib/rules/python/PyInfoTest.java b/src/test/java/com/google/devtools/build/lib/rules/python/PyInfoTest.java
index b8ec1c1..c427c8e 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/python/PyInfoTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/python/PyInfoTest.java
@@ -22,7 +22,6 @@
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.starlark.util.BazelEvaluationTestCase;
-import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
import net.starlark.java.syntax.Location;
import org.junit.Before;
import org.junit.Test;
@@ -33,7 +32,7 @@
@RunWith(JUnit4.class)
public class PyInfoTest extends BuildViewTestCase {
- private final EvaluationTestCase ev = new BazelEvaluationTestCase();
+ private final BazelEvaluationTestCase ev = new BazelEvaluationTestCase();
private Artifact dummyArtifact;
diff --git a/src/test/java/com/google/devtools/build/lib/rules/python/PyRuntimeInfoTest.java b/src/test/java/com/google/devtools/build/lib/rules/python/PyRuntimeInfoTest.java
index db6dbbc..cb6d95f 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/python/PyRuntimeInfoTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/python/PyRuntimeInfoTest.java
@@ -22,7 +22,6 @@
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.starlark.util.BazelEvaluationTestCase;
-import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
import com.google.devtools.build.lib.vfs.PathFragment;
import net.starlark.java.syntax.Location;
import org.junit.Before;
@@ -34,7 +33,7 @@
@RunWith(JUnit4.class)
public class PyRuntimeInfoTest extends BuildViewTestCase {
- private final EvaluationTestCase ev = new BazelEvaluationTestCase();
+ private final BazelEvaluationTestCase ev = new BazelEvaluationTestCase();
private Artifact dummyInterpreter;
private Artifact dummyFile;
diff --git a/src/test/java/com/google/devtools/build/lib/starlark/BUILD b/src/test/java/com/google/devtools/build/lib/starlark/BUILD
index c9cccfe..c126752 100644
--- a/src/test/java/com/google/devtools/build/lib/starlark/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/starlark/BUILD
@@ -72,7 +72,6 @@
"//src/test/java/com/google/devtools/build/lib/analysis/util",
"//src/test/java/com/google/devtools/build/lib/packages:testutil",
"//src/test/java/com/google/devtools/build/lib/starlark/util",
- "//src/test/java/com/google/devtools/build/lib/syntax/util",
"//src/test/java/com/google/devtools/build/lib/testutil",
"//src/test/java/com/google/devtools/build/lib/testutil:JunitUtils",
"//third_party:guava",
diff --git a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java
index 8b104c7..7a87200 100644
--- a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java
@@ -52,7 +52,6 @@
import com.google.devtools.build.lib.packages.Type;
import com.google.devtools.build.lib.skyframe.BzlLoadFunction;
import com.google.devtools.build.lib.starlark.util.BazelEvaluationTestCase;
-import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
import com.google.devtools.build.lib.testutil.MoreAsserts;
import com.google.devtools.build.lib.util.FileTypeSet;
import javax.annotation.Nullable;
@@ -78,7 +77,7 @@
@RunWith(JUnit4.class)
public final class StarlarkRuleClassFunctionsTest extends BuildViewTestCase {
- private final EvaluationTestCase ev = new BazelEvaluationTestCase();
+ private final BazelEvaluationTestCase ev = new BazelEvaluationTestCase();
private StarlarkRuleContext createRuleContext(String label) throws Exception {
return new StarlarkRuleContext(
@@ -735,7 +734,7 @@
assertThat(c.hasAttr("a1", Type.STRING)).isTrue();
}
- private static void evalAndExport(EvaluationTestCase ev, String... lines) throws Exception {
+ private static void evalAndExport(BazelEvaluationTestCase ev, String... lines) throws Exception {
ParserInput input = ParserInput.fromLines(lines);
Module module = ev.getModule();
StarlarkFile file = StarlarkFile.parse(input);
diff --git a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleContextTest.java b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleContextTest.java
index 380feae..52465e3 100644
--- a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleContextTest.java
+++ b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleContextTest.java
@@ -52,7 +52,6 @@
import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider;
import com.google.devtools.build.lib.rules.python.PyProviderUtils;
import com.google.devtools.build.lib.starlark.util.BazelEvaluationTestCase;
-import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
import com.google.devtools.build.lib.util.FileTypeSet;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -80,7 +79,7 @@
getRuleContextForStarlark(getConfiguredTarget(label)), null, getStarlarkSemantics());
}
- private final EvaluationTestCase ev = new BazelEvaluationTestCase();
+ private final BazelEvaluationTestCase ev = new BazelEvaluationTestCase();
/** A test rule that exercises the semantics of mandatory providers. */
private static final MockRule TESTING_RULE_FOR_MANDATORY_PROVIDERS =
diff --git a/src/test/java/com/google/devtools/build/lib/starlark/util/BUILD b/src/test/java/com/google/devtools/build/lib/starlark/util/BUILD
index 3f8eed9..5a36fc3 100644
--- a/src/test/java/com/google/devtools/build/lib/starlark/util/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/starlark/util/BUILD
@@ -30,9 +30,10 @@
"//src/main/java/net/starlark/java/eval",
"//src/main/java/net/starlark/java/syntax",
"//src/test/java/com/google/devtools/build/lib/analysis/util",
- "//src/test/java/com/google/devtools/build/lib/syntax/util",
+ "//src/test/java/com/google/devtools/build/lib/events:testutil",
"//src/test/java/com/google/devtools/build/lib/testutil:TestConstants",
"//third_party:guava",
"//third_party:junit4",
+ "//third_party:truth",
],
)
diff --git a/src/test/java/com/google/devtools/build/lib/starlark/util/BazelEvaluationTestCase.java b/src/test/java/com/google/devtools/build/lib/starlark/util/BazelEvaluationTestCase.java
index a49d14b..3d638fd 100644
--- a/src/test/java/com/google/devtools/build/lib/starlark/util/BazelEvaluationTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/starlark/util/BazelEvaluationTestCase.java
@@ -1,4 +1,4 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
+// Copyright 2006 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.
@@ -11,44 +11,110 @@
// 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.starlark.util;
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.analysis.starlark.StarlarkModules;
import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.EventCollector;
+import com.google.devtools.build.lib.events.EventKind;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.events.util.EventCollectionApparatus;
import com.google.devtools.build.lib.packages.BazelModuleContext;
import com.google.devtools.build.lib.packages.BazelStarlarkContext;
import com.google.devtools.build.lib.packages.SymbolGenerator;
+import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
import com.google.devtools.build.lib.rules.platform.PlatformCommon;
-import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
import com.google.devtools.build.lib.testutil.TestConstants;
+import com.google.devtools.common.options.Options;
+import com.google.devtools.common.options.OptionsParsingException;
+import java.util.ArrayList;
+import java.util.List;
+import net.starlark.java.eval.EvalException;
+import net.starlark.java.eval.Module;
+import net.starlark.java.eval.Mutability;
import net.starlark.java.eval.Starlark;
+import net.starlark.java.eval.StarlarkSemantics;
import net.starlark.java.eval.StarlarkThread;
+import net.starlark.java.syntax.Expression;
+import net.starlark.java.syntax.FileOptions;
+import net.starlark.java.syntax.ParserInput;
+import net.starlark.java.syntax.SyntaxError;
-/**
- * BazelEvaluationTestCase is a subclass of EvaluationTestCase that defines various Bazel built-ins
- * in the environment.
- */
-// TODO(adonovan): this is (and has always been) a mess, and an abuse of inheritance.
-// Once the production code API has disentangled Thread and Module, make this rational.
-public final class BazelEvaluationTestCase extends EvaluationTestCase {
+/** BazelEvaluationTestCase is a helper class for tests of Bazel loading-phase evaluation. */
+// TODO(adonovan): this helper class might be somewhat handy for testing core Starlark, but its
+// widespread use in tests of Bazel features greatly hinders the improvement of Bazel's loading
+// phase. The existence of tests based on this class forces Bazel to continue support scenarios in
+// which the test creates the environment, the threads, and so on, when these should be
+// implementation details of the loading phase. Instead, the lib.packages should present an API in
+// which the client provides files, flags, and arguments like a command-line tool, and all our tests
+// should be ported to use that API.
+public final class BazelEvaluationTestCase {
+ private final EventCollectionApparatus eventCollectionApparatus =
+ new EventCollectionApparatus(EventKind.ALL_EVENTS);
- @Override
- protected Object newModuleHook(ImmutableMap.Builder<String, Object> predeclared) {
- StarlarkModules.addPredeclared(predeclared);
- Starlark.addModule(predeclared, new PlatformCommon());
+ private StarlarkSemantics semantics = StarlarkSemantics.DEFAULT;
+ private StarlarkThread thread = null; // created lazily by getStarlarkThread
+ private Module module = null; // created lazily by getModule
- // Return the module's client data. (This one uses dummy values for tests.)
- return BazelModuleContext.create(
- Label.parseAbsoluteUnchecked("//test:label", /*defaultToMain=*/ false),
- "test/label.bzl",
- /*loads=*/ ImmutableMap.of(),
- /*bzlTransitiveDigest=*/ new byte[0]);
+ /**
+ * Parses the semantics flags and updates the semantics used to filter predeclared bindings, and
+ * carried by subsequently created threads. Causes a new StarlarkThread and Module to be created
+ * when next needed.
+ */
+ public final void setSemantics(String... options) throws OptionsParsingException {
+ this.semantics =
+ Options.parse(BuildLanguageOptions.class, options).getOptions().toStarlarkSemantics();
+
+ // Re-initialize the thread and module with the new semantics when needed.
+ this.thread = null;
+ this.module = null;
}
- @Override
- protected void newThreadHook(StarlarkThread thread) {
+ public ExtendedEventHandler getEventHandler() {
+ return eventCollectionApparatus.reporter();
+ }
+
+ // TODO(adonovan): don't let subclasses inherit vaguely specified "helpers".
+ // Separate all the tests clearly into tests of the scanner, parser, resolver,
+ // and evaluation.
+
+ /** Parses an expression. */
+ final Expression parseExpression(String... lines) throws SyntaxError.Exception {
+ return Expression.parse(ParserInput.fromLines(lines));
+ }
+
+ /** Updates a global binding in the module. */
+ // TODO(adonovan): rename setGlobal.
+ public BazelEvaluationTestCase update(String varname, Object value) throws Exception {
+ getModule().setGlobal(varname, value);
+ return this;
+ }
+
+ /** Returns the value of a global binding in the module. */
+ // TODO(adonovan): rename getGlobal.
+ public Object lookup(String varname) throws Exception {
+ return getModule().getGlobal(varname);
+ }
+
+ /** Joins the lines, parses them as an expression, and evaluates it. */
+ public final Object eval(String... lines) throws Exception {
+ ParserInput input = ParserInput.fromLines(lines);
+ return Starlark.eval(input, FileOptions.DEFAULT, getModule(), getStarlarkThread());
+ }
+
+ /** Joins the lines, parses them as a file, and executes it. */
+ public final void exec(String... lines)
+ throws SyntaxError.Exception, EvalException, InterruptedException {
+ ParserInput input = ParserInput.fromLines(lines);
+ Starlark.execFile(input, FileOptions.DEFAULT, getModule(), getStarlarkThread());
+ }
+
+ private static void newThread(StarlarkThread thread) {
// This StarlarkThread has no PackageContext, so attempts to create a rule will fail.
// Rule creation is tested by StarlarkIntegrationTest.
@@ -65,4 +131,325 @@
/*analysisRuleLabel=*/ null) // dummy value for tests
.storeInThread(thread);
}
+
+ private static Object newModule(ImmutableMap.Builder<String, Object> predeclared) {
+ StarlarkModules.addPredeclared(predeclared);
+ Starlark.addModule(predeclared, new PlatformCommon());
+
+ // Return the module's client data. (This one uses dummy values for tests.)
+ return BazelModuleContext.create(
+ Label.parseAbsoluteUnchecked("//test:label", /*defaultToMain=*/ false),
+ "test/label.bzl",
+ /*loads=*/ ImmutableMap.of(),
+ /*bzlTransitiveDigest=*/ new byte[0]);
+ }
+
+ public StarlarkThread getStarlarkThread() {
+ if (this.thread == null) {
+ Mutability mu = Mutability.create("test");
+ StarlarkThread thread = new StarlarkThread(mu, semantics);
+ thread.setPrintHandler(Event.makeDebugPrintHandler(getEventHandler()));
+ newThread(thread);
+ this.thread = thread;
+ }
+ return this.thread;
+ }
+
+ public Module getModule() {
+ if (this.module == null) {
+ ImmutableMap.Builder<String, Object> predeclared = ImmutableMap.builder();
+ Object clientData = newModule(predeclared);
+ Module module = Module.withPredeclared(semantics, predeclared.build());
+ module.setClientData(clientData);
+ this.module = module;
+ }
+ return this.module;
+ }
+
+ public void checkEvalError(String msg, String... input) throws Exception {
+ try {
+ exec(input);
+ fail("Expected error '" + msg + "' but got no error");
+ } catch (SyntaxError.Exception | EvalException | EventCollectionApparatus.FailFastException e) {
+ assertThat(e).hasMessageThat().isEqualTo(msg);
+ }
+ }
+
+ public void checkEvalErrorContains(String msg, String... input) throws Exception {
+ try {
+ exec(input);
+ fail("Expected error containing '" + msg + "' but got no error");
+ } catch (SyntaxError.Exception | EvalException | EventCollectionApparatus.FailFastException e) {
+ assertThat(e).hasMessageThat().contains(msg);
+ }
+ }
+
+ public void checkEvalErrorDoesNotContain(String msg, String... input) throws Exception {
+ try {
+ exec(input);
+ } catch (SyntaxError.Exception | EvalException | EventCollectionApparatus.FailFastException e) {
+ assertThat(e).hasMessageThat().doesNotContain(msg);
+ }
+ }
+
+ // Forward relevant methods to the EventCollectionApparatus
+ public BazelEvaluationTestCase setFailFast(boolean failFast) {
+ eventCollectionApparatus.setFailFast(failFast);
+ return this;
+ }
+
+ public BazelEvaluationTestCase assertNoWarningsOrErrors() {
+ eventCollectionApparatus.assertNoWarningsOrErrors();
+ return this;
+ }
+
+ public EventCollector getEventCollector() {
+ return eventCollectionApparatus.collector();
+ }
+
+ public Event assertContainsError(String expectedMessage) {
+ return eventCollectionApparatus.assertContainsError(expectedMessage);
+ }
+
+ public Event assertContainsWarning(String expectedMessage) {
+ return eventCollectionApparatus.assertContainsWarning(expectedMessage);
+ }
+
+ public Event assertContainsDebug(String expectedMessage) {
+ return eventCollectionApparatus.assertContainsDebug(expectedMessage);
+ }
+
+ public BazelEvaluationTestCase clearEvents() {
+ eventCollectionApparatus.clear();
+ return this;
+ }
+
+ /** Encapsulates a separate test which can be executed by a Scenario. */
+ protected interface Testable {
+ void run() throws Exception;
+ }
+
+ /**
+ * A test scenario (a script of steps). Beware: Scenario is an inner class that mutates its
+ * enclosing BazelEvaluationTestCase as it executes the script.
+ */
+ public final class Scenario {
+ private final SetupActions setup = new SetupActions();
+ private final String[] starlarkOptions;
+
+ public Scenario(String... starlarkOptions) {
+ this.starlarkOptions = starlarkOptions;
+ }
+
+ private void run(Testable testable) throws Exception {
+ setSemantics(starlarkOptions);
+ testable.run();
+ }
+
+ /** Allows the execution of several statements before each following test. */
+ public Scenario setUp(String... lines) {
+ setup.registerExec(lines);
+ return this;
+ }
+
+ /**
+ * Allows the update of the specified variable before each following test
+ *
+ * @param name The name of the variable that should be updated
+ * @param value The new value of the variable
+ * @return This {@code Scenario}
+ */
+ public Scenario update(String name, Object value) {
+ setup.registerUpdate(name, value);
+ return this;
+ }
+
+ /**
+ * Evaluates two expressions and asserts that their results are equal.
+ *
+ * @param src The source expression to be evaluated
+ * @param expectedEvalString The expression of the expected result
+ * @return This {@code Scenario}
+ * @throws Exception
+ */
+ public Scenario testEval(String src, String expectedEvalString) throws Exception {
+ runTest(createComparisonTestable(src, expectedEvalString, true));
+ return this;
+ }
+
+ /** Evaluates an expression and compares its result to the expected object. */
+ public Scenario testExpression(String src, Object expected) throws Exception {
+ runTest(createComparisonTestable(src, expected, false));
+ return this;
+ }
+
+ /** Evaluates an expression and compares its result to the ordered list of expected objects. */
+ public Scenario testExactOrder(String src, Object... items) throws Exception {
+ runTest(collectionTestable(src, items));
+ return this;
+ }
+
+ /** Evaluates an expression and checks whether it fails with the expected error. */
+ public Scenario testIfExactError(String expectedError, String... lines) throws Exception {
+ runTest(errorTestable(true, expectedError, lines));
+ return this;
+ }
+
+ /** Evaluates the expression and checks whether it fails with the expected error. */
+ public Scenario testIfErrorContains(String expectedError, String... lines) throws Exception {
+ runTest(errorTestable(false, expectedError, lines));
+ return this;
+ }
+
+ /** Looks up the value of the specified variable and compares it to the expected value. */
+ public Scenario testLookup(String name, Object expected) throws Exception {
+ runTest(createLookUpTestable(name, expected));
+ return this;
+ }
+
+ /**
+ * Creates a Testable that checks whether the evaluation of the given expression fails with the
+ * expected error.
+ *
+ * @param exactMatch whether the error message must be identical to the expected error.
+ */
+ private Testable errorTestable(
+ final boolean exactMatch, final String error, final String... lines) {
+ return new Testable() {
+ @Override
+ public void run() throws Exception {
+ if (exactMatch) {
+ checkEvalError(error, lines);
+ } else {
+ checkEvalErrorContains(error, lines);
+ }
+ }
+ };
+ }
+
+ /**
+ * Creates a Testable that checks whether the value of the expression is a sequence containing
+ * the expected elements.
+ */
+ private Testable collectionTestable(final String src, final Object... expected) {
+ return new Testable() {
+ @Override
+ public void run() throws Exception {
+ assertThat((Iterable<?>) eval(src)).containsExactly(expected).inOrder();
+ }
+ };
+ }
+
+ /**
+ * Creates a testable that compares the value of the expression to a specified result.
+ *
+ * @param src The expression to be evaluated
+ * @param expected Either the expected object or an expression whose evaluation leads to the
+ * expected object
+ * @param expectedIsExpression Signals whether {@code expected} is an object or an expression
+ * @return An instance of Testable that runs the comparison
+ */
+ private Testable createComparisonTestable(
+ final String src, final Object expected, final boolean expectedIsExpression) {
+ return new Testable() {
+ @Override
+ public void run() throws Exception {
+ Object actual = eval(src);
+ Object realExpected = expected;
+
+ // We could also print the actual object and compare the string to the expected
+ // expression, but then the order of elements would matter.
+ if (expectedIsExpression) {
+ realExpected = eval((String) expected);
+ }
+
+ assertThat(actual).isEqualTo(realExpected);
+ }
+ };
+ }
+
+ /**
+ * Creates a Testable that looks up the given variable and compares its value to the expected
+ * value
+ *
+ * @param name
+ * @param expected
+ * @return An instance of Testable that does both lookup and comparison
+ */
+ private Testable createLookUpTestable(final String name, final Object expected) {
+ return new Testable() {
+ @Override
+ public void run() throws Exception {
+ assertThat(lookup(name)).isEqualTo(expected);
+ }
+ };
+ }
+
+ /** Executes the given Testable */
+ void runTest(Testable testable) throws Exception {
+ run(new TestableDecorator(setup, testable));
+ }
+ }
+
+ /**
+ * A simple decorator that allows the execution of setup actions before running a {@code Testable}
+ */
+ static class TestableDecorator implements Testable {
+ private final SetupActions setup;
+ private final Testable decorated;
+
+ public TestableDecorator(SetupActions setup, Testable decorated) {
+ this.setup = setup;
+ this.decorated = decorated;
+ }
+
+ /** Executes all stored actions and updates plus the actual {@code Testable} */
+ @Override
+ public void run() throws Exception {
+ setup.executeAll();
+ decorated.run();
+ }
+ }
+
+ /** A container for collection actions that should be executed before a test */
+ class SetupActions {
+ private final List<Testable> setup;
+
+ public SetupActions() {
+ setup = new ArrayList<>();
+ }
+
+ /**
+ * Registers an update to a module variable to be bound before a test
+ *
+ * @param name
+ */
+ public void registerUpdate(final String name, final Object value) {
+ setup.add(
+ new Testable() {
+ @Override
+ public void run() throws Exception {
+ BazelEvaluationTestCase.this.update(name, value);
+ }
+ });
+ }
+
+ /** Registers a sequence of statements for execution prior to a test. */
+ public void registerExec(final String... lines) {
+ setup.add(
+ new Testable() {
+ @Override
+ public void run() throws Exception {
+ BazelEvaluationTestCase.this.exec(lines);
+ }
+ });
+ }
+
+ /** Executes all stored actions and updates */
+ public void executeAll() throws Exception {
+ for (Testable testable : setup) {
+ testable.run();
+ }
+ }
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/util/BUILD b/src/test/java/com/google/devtools/build/lib/syntax/util/BUILD
deleted file mode 100644
index f6828ba..0000000
--- a/src/test/java/com/google/devtools/build/lib/syntax/util/BUILD
+++ /dev/null
@@ -1,26 +0,0 @@
-package(
- default_visibility = ["//src:__subpackages__"],
-)
-
-filegroup(
- name = "srcs",
- srcs = glob(["**"]),
- visibility = ["//src:__subpackages__"],
-)
-
-java_library(
- name = "util",
- testonly = 1,
- srcs = glob(["*.java"]),
- deps = [
- "//src/main/java/com/google/devtools/build/lib/events",
- "//src/main/java/com/google/devtools/build/lib/packages/semantics",
- "//src/main/java/com/google/devtools/common/options",
- "//src/main/java/net/starlark/java/eval",
- "//src/main/java/net/starlark/java/syntax",
- "//src/test/java/com/google/devtools/build/lib/events:testutil",
- "//third_party:guava",
- "//third_party:junit4",
- "//third_party:truth",
- ],
-)
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/util/EvaluationTestCase.java b/src/test/java/com/google/devtools/build/lib/syntax/util/EvaluationTestCase.java
deleted file mode 100644
index dc4e466..0000000
--- a/src/test/java/com/google/devtools/build/lib/syntax/util/EvaluationTestCase.java
+++ /dev/null
@@ -1,454 +0,0 @@
-// Copyright 2006 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.util;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventCollector;
-import com.google.devtools.build.lib.events.EventKind;
-import com.google.devtools.build.lib.events.ExtendedEventHandler;
-import com.google.devtools.build.lib.events.util.EventCollectionApparatus;
-import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
-import com.google.devtools.common.options.Options;
-import com.google.devtools.common.options.OptionsParsingException;
-import java.util.LinkedList;
-import java.util.List;
-import net.starlark.java.eval.EvalException;
-import net.starlark.java.eval.Module;
-import net.starlark.java.eval.Mutability;
-import net.starlark.java.eval.Starlark;
-import net.starlark.java.eval.StarlarkSemantics;
-import net.starlark.java.eval.StarlarkThread;
-import net.starlark.java.syntax.Expression;
-import net.starlark.java.syntax.FileOptions;
-import net.starlark.java.syntax.ParserInput;
-import net.starlark.java.syntax.SyntaxError;
-
-/** Helper class for tests that evaluate Starlark code. */
-// TODO(adonovan): stop extending this class. Prefer composition over inheritance.
-// Rename it to EvaluationApparatus for consistency.
-//
-// TODO(adonovan): make predeclared env + semantics more like normal parameters.
-// The main challenge is when are the Thread and Module created?
-// They should have a consistent semantics, and the predeclared environment
-// cannot be changed after the Module is created.
-// Also, the fact that exec/eval/update/lookup can be used directly
-// or through a Scenario complicates the question of when we commit to
-// predeclared env + semantics.
-// For the most part, the predeclared env doesn't vary across a suite,
-// so it could be a constructor parameter.
-//
-// TODO(adonovan): this helper class might be somewhat handy for testing core Starlark, but its
-// widespread use in tests of Bazel features greatly hinders the improvement of Bazel's loading
-// phase. The existence of tests based on this class forces Bazel to continue support scenarios in
-// which the test creates the environment, the threads, and so on, when these should be
-// implemenation details of the loading phase. Instead, the lib.packages should present an API in
-// which the client provides files, flags, and arguments like a command-line tool, and all our tests
-// should be ported to use that API.
-public class EvaluationTestCase {
- private EventCollectionApparatus eventCollectionApparatus =
- new EventCollectionApparatus(EventKind.ALL_EVENTS);
-
- private StarlarkSemantics semantics = StarlarkSemantics.DEFAULT;
- private StarlarkThread thread = null; // created lazily by getStarlarkThread
- private Module module = null; // created lazily by getModule
-
- /**
- * Parses the semantics flags and updates the semantics used to filter predeclared bindings, and
- * carried by subsequently created threads. Causes a new StarlarkThread and Module to be created
- * when next needed.
- */
- public final void setSemantics(String... options) throws OptionsParsingException {
- this.semantics =
- Options.parse(BuildLanguageOptions.class, options).getOptions().toStarlarkSemantics();
-
- // Re-initialize the thread and module with the new semantics when needed.
- this.thread = null;
- this.module = null;
- }
-
- public ExtendedEventHandler getEventHandler() {
- return eventCollectionApparatus.reporter();
- }
-
- // TODO(adonovan): don't let subclasses inherit vaguely specified "helpers".
- // Separate all the tests clearly into tests of the scanner, parser, resolver,
- // and evaluation.
-
- /** Parses an expression. */
- protected final Expression parseExpression(String... lines) throws SyntaxError.Exception {
- return Expression.parse(ParserInput.fromLines(lines));
- }
-
- /** Updates a global binding in the module. */
- // TODO(adonovan): rename setGlobal.
- public EvaluationTestCase update(String varname, Object value) throws Exception {
- getModule().setGlobal(varname, value);
- return this;
- }
-
- /** Returns the value of a global binding in the module. */
- // TODO(adonovan): rename getGlobal.
- public Object lookup(String varname) throws Exception {
- return getModule().getGlobal(varname);
- }
-
- /** Joins the lines, parses them as an expression, and evaluates it. */
- public final Object eval(String... lines) throws Exception {
- ParserInput input = ParserInput.fromLines(lines);
- return Starlark.eval(input, FileOptions.DEFAULT, getModule(), getStarlarkThread());
- }
-
- /** Joins the lines, parses them as a file, and executes it. */
- public final void exec(String... lines)
- throws SyntaxError.Exception, EvalException, InterruptedException {
- ParserInput input = ParserInput.fromLines(lines);
- Starlark.execFile(input, FileOptions.DEFAULT, getModule(), getStarlarkThread());
- }
-
- // A hook for subclasses to alter a newly created thread,
- // e.g. by inserting thread-local values.
- protected void newThreadHook(StarlarkThread thread) {}
-
- // A hook for subclasses to alter the created module.
- // Implementations may add to the predeclared environment,
- // and return the module's client data value.
- protected Object newModuleHook(ImmutableMap.Builder<String, Object> predeclared) {
- return null; // no client data
- }
-
- public StarlarkThread getStarlarkThread() {
- if (this.thread == null) {
- Mutability mu = Mutability.create("test");
- StarlarkThread thread = new StarlarkThread(mu, semantics);
- thread.setPrintHandler(Event.makeDebugPrintHandler(getEventHandler()));
- newThreadHook(thread);
- this.thread = thread;
- }
- return this.thread;
- }
-
- public Module getModule() {
- if (this.module == null) {
- ImmutableMap.Builder<String, Object> predeclared = ImmutableMap.builder();
- Object clientData = newModuleHook(predeclared);
- Module module = Module.withPredeclared(semantics, predeclared.build());
- module.setClientData(clientData);
- this.module = module;
- }
- return this.module;
- }
-
- public void checkEvalError(String msg, String... input) throws Exception {
- try {
- exec(input);
- fail("Expected error '" + msg + "' but got no error");
- } catch (SyntaxError.Exception | EvalException | EventCollectionApparatus.FailFastException e) {
- assertThat(e).hasMessageThat().isEqualTo(msg);
- }
- }
-
- public void checkEvalErrorContains(String msg, String... input) throws Exception {
- try {
- exec(input);
- fail("Expected error containing '" + msg + "' but got no error");
- } catch (SyntaxError.Exception | EvalException | EventCollectionApparatus.FailFastException e) {
- assertThat(e).hasMessageThat().contains(msg);
- }
- }
-
- public void checkEvalErrorDoesNotContain(String msg, String... input) throws Exception {
- try {
- exec(input);
- } catch (SyntaxError.Exception | EvalException | EventCollectionApparatus.FailFastException e) {
- assertThat(e).hasMessageThat().doesNotContain(msg);
- }
- }
-
- // Forward relevant methods to the EventCollectionApparatus
- public EvaluationTestCase setFailFast(boolean failFast) {
- eventCollectionApparatus.setFailFast(failFast);
- return this;
- }
-
- public EvaluationTestCase assertNoWarningsOrErrors() {
- eventCollectionApparatus.assertNoWarningsOrErrors();
- return this;
- }
-
- public EventCollector getEventCollector() {
- return eventCollectionApparatus.collector();
- }
-
- public Event assertContainsError(String expectedMessage) {
- return eventCollectionApparatus.assertContainsError(expectedMessage);
- }
-
- public Event assertContainsWarning(String expectedMessage) {
- return eventCollectionApparatus.assertContainsWarning(expectedMessage);
- }
-
- public Event assertContainsDebug(String expectedMessage) {
- return eventCollectionApparatus.assertContainsDebug(expectedMessage);
- }
-
- public EvaluationTestCase clearEvents() {
- eventCollectionApparatus.clear();
- return this;
- }
-
- /** Encapsulates a separate test which can be executed by a Scenario. */
- protected interface Testable {
- void run() throws Exception;
- }
-
- /**
- * A test scenario (a script of steps). Beware: Scenario is an inner class that mutates its
- * enclosing EvaluationTestCase as it executes the script.
- */
- public final class Scenario {
- private final SetupActions setup = new SetupActions();
- private final String[] starlarkOptions;
-
- public Scenario(String... starlarkOptions) {
- this.starlarkOptions = starlarkOptions;
- }
-
- private void run(Testable testable) throws Exception {
- setSemantics(starlarkOptions);
- testable.run();
- }
-
- /** Allows the execution of several statements before each following test. */
- public Scenario setUp(String... lines) {
- setup.registerExec(lines);
- return this;
- }
-
- /**
- * Allows the update of the specified variable before each following test
- *
- * @param name The name of the variable that should be updated
- * @param value The new value of the variable
- * @return This {@code Scenario}
- */
- public Scenario update(String name, Object value) {
- setup.registerUpdate(name, value);
- return this;
- }
-
- /**
- * Evaluates two expressions and asserts that their results are equal.
- *
- * @param src The source expression to be evaluated
- * @param expectedEvalString The expression of the expected result
- * @return This {@code Scenario}
- * @throws Exception
- */
- public Scenario testEval(String src, String expectedEvalString) throws Exception {
- runTest(createComparisonTestable(src, expectedEvalString, true));
- return this;
- }
-
- /** Evaluates an expression and compares its result to the expected object. */
- public Scenario testExpression(String src, Object expected) throws Exception {
- runTest(createComparisonTestable(src, expected, false));
- return this;
- }
-
- /** Evaluates an expression and compares its result to the ordered list of expected objects. */
- public Scenario testExactOrder(String src, Object... items) throws Exception {
- runTest(collectionTestable(src, items));
- return this;
- }
-
- /** Evaluates an expression and checks whether it fails with the expected error. */
- public Scenario testIfExactError(String expectedError, String... lines) throws Exception {
- runTest(errorTestable(true, expectedError, lines));
- return this;
- }
-
- /** Evaluates the expresson and checks whether it fails with the expected error. */
- public Scenario testIfErrorContains(String expectedError, String... lines) throws Exception {
- runTest(errorTestable(false, expectedError, lines));
- return this;
- }
-
- /** Looks up the value of the specified variable and compares it to the expected value. */
- public Scenario testLookup(String name, Object expected) throws Exception {
- runTest(createLookUpTestable(name, expected));
- return this;
- }
-
- /**
- * Creates a Testable that checks whether the evaluation of the given expression fails with the
- * expected error.
- *
- * @param exactMatch whether the error message must be identical to the expected error.
- */
- private Testable errorTestable(
- final boolean exactMatch, final String error, final String... lines) {
- return new Testable() {
- @Override
- public void run() throws Exception {
- if (exactMatch) {
- checkEvalError(error, lines);
- } else {
- checkEvalErrorContains(error, lines);
- }
- }
- };
- }
-
- /**
- * Creates a Testable that checks whether the value of the expression is a sequence containing
- * the expected elements.
- */
- private Testable collectionTestable(final String src, final Object... expected) {
- return new Testable() {
- @Override
- public void run() throws Exception {
- assertThat((Iterable<?>) eval(src)).containsExactly(expected).inOrder();
- }
- };
- }
-
- /**
- * Creates a testable that compares the value of the expression to a specified result.
- *
- * @param src The expression to be evaluated
- * @param expected Either the expected object or an expression whose evaluation leads to the
- * expected object
- * @param expectedIsExpression Signals whether {@code expected} is an object or an expression
- * @return An instance of Testable that runs the comparison
- */
- private Testable createComparisonTestable(
- final String src, final Object expected, final boolean expectedIsExpression) {
- return new Testable() {
- @Override
- public void run() throws Exception {
- Object actual = eval(src);
- Object realExpected = expected;
-
- // We could also print the actual object and compare the string to the expected
- // expression, but then the order of elements would matter.
- if (expectedIsExpression) {
- realExpected = eval((String) expected);
- }
-
- assertThat(actual).isEqualTo(realExpected);
- }
- };
- }
-
- /**
- * Creates a Testable that looks up the given variable and compares its value to the expected
- * value
- *
- * @param name
- * @param expected
- * @return An instance of Testable that does both lookup and comparison
- */
- private Testable createLookUpTestable(final String name, final Object expected) {
- return new Testable() {
- @Override
- public void run() throws Exception {
- assertThat(lookup(name)).isEqualTo(expected);
- }
- };
- }
-
- /**
- * Executes the given Testable
- * @param testable
- * @throws Exception
- */
- protected void runTest(Testable testable) throws Exception {
- run(new TestableDecorator(setup, testable));
- }
- }
-
- /**
- * A simple decorator that allows the execution of setup actions before running a {@code Testable}
- */
- static class TestableDecorator implements Testable {
- private final SetupActions setup;
- private final Testable decorated;
-
- public TestableDecorator(SetupActions setup, Testable decorated) {
- this.setup = setup;
- this.decorated = decorated;
- }
-
- /**
- * Executes all stored actions and updates plus the actual {@code Testable}
- */
- @Override
- public void run() throws Exception {
- setup.executeAll();
- decorated.run();
- }
- }
-
- /**
- * A container for collection actions that should be executed before a test
- */
- class SetupActions {
- private List<Testable> setup;
-
- public SetupActions() {
- setup = new LinkedList<>();
- }
-
- /**
- * Registers an update to a module variable to be bound before a test
- *
- * @param name
- * @param value
- */
- public void registerUpdate(final String name, final Object value) {
- setup.add(
- new Testable() {
- @Override
- public void run() throws Exception {
- EvaluationTestCase.this.update(name, value);
- }
- });
- }
-
- /** Registers a sequence of statements for execution prior to a test. */
- public void registerExec(final String... lines) {
- setup.add(
- new Testable() {
- @Override
- public void run() throws Exception {
- EvaluationTestCase.this.exec(lines);
- }
- });
- }
-
- /**
- * Executes all stored actions and updates
- * @throws Exception
- */
- public void executeAll() throws Exception {
- for (Testable testable : setup) {
- testable.run();
- }
- }
- }
-}