Add a library of test options for use in scenario tests.
Bug: 118122395
Change-Id: I8ba3d5822761c028a5f3d81935f161bbe8967937
Merged-In: I524d39b983cab8683bd90752d185658d54b89f75
(cherry picked from commit ddb1623814be10c69bacac0ced9f3c39f558c0c0)
diff --git a/libraries/options/Android.bp b/libraries/options/Android.bp
new file mode 100644
index 0000000..2d572d4
--- /dev/null
+++ b/libraries/options/Android.bp
@@ -0,0 +1,23 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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.
+
+java_library_static {
+ name: "platform-test-options",
+ sdk_version: "24",
+ srcs: [ "src/**/*.java" ],
+ libs: [
+ "androidx.test.runner",
+ "junit",
+ ],
+}
diff --git a/libraries/options/src/android/platform/test/options/BooleanOption.java b/libraries/options/src/android/platform/test/options/BooleanOption.java
new file mode 100644
index 0000000..a8cb948
--- /dev/null
+++ b/libraries/options/src/android/platform/test/options/BooleanOption.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 android.platform.test.option;
+
+/** A boolean option for a scenario. */
+public class BooleanOption extends TestOption<Boolean> {
+ public BooleanOption(String optionName) {
+ super(optionName);
+ }
+
+ @Override
+ protected Boolean parseValueFromString(String value) {
+ return Boolean.valueOf(value);
+ }
+}
diff --git a/libraries/options/src/android/platform/test/options/DoubleOption.java b/libraries/options/src/android/platform/test/options/DoubleOption.java
new file mode 100644
index 0000000..ccd389c
--- /dev/null
+++ b/libraries/options/src/android/platform/test/options/DoubleOption.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 android.platform.test.option;
+
+/** A double option for a scenario. */
+public class DoubleOption extends TestOption<Double> {
+ public DoubleOption(String optionName) {
+ super(optionName);
+ }
+
+ @Override
+ protected Double parseValueFromString(String value) {
+ return Double.valueOf(value);
+ }
+}
diff --git a/libraries/options/src/android/platform/test/options/IntegerOption.java b/libraries/options/src/android/platform/test/options/IntegerOption.java
new file mode 100644
index 0000000..63eeaf2
--- /dev/null
+++ b/libraries/options/src/android/platform/test/options/IntegerOption.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 android.platform.test.option;
+
+/** An integer option for a scenario. */
+public class IntegerOption extends TestOption<Integer> {
+ public IntegerOption(String optionName) {
+ super(optionName);
+ }
+
+ @Override
+ protected Integer parseValueFromString(String value) {
+ return Integer.valueOf(value);
+ }
+}
diff --git a/libraries/options/src/android/platform/test/options/LongOption.java b/libraries/options/src/android/platform/test/options/LongOption.java
new file mode 100644
index 0000000..9fc7048
--- /dev/null
+++ b/libraries/options/src/android/platform/test/options/LongOption.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 android.platform.test.option;
+
+/** A long option for a scenario. */
+public class LongOption extends TestOption<Long> {
+ public LongOption(String optionName) {
+ super(optionName);
+ }
+
+ @Override
+ protected Long parseValueFromString(String value) {
+ return Long.valueOf(value);
+ }
+}
diff --git a/libraries/options/src/android/platform/test/options/StringOption.java b/libraries/options/src/android/platform/test/options/StringOption.java
new file mode 100644
index 0000000..5ac6623
--- /dev/null
+++ b/libraries/options/src/android/platform/test/options/StringOption.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 android.platform.test.option;
+
+/** A string option for a scenario. */
+public class StringOption extends TestOption<String> {
+ public StringOption(String optionName) {
+ super(optionName);
+ }
+
+ @Override
+ protected String parseValueFromString(String value) {
+ return value;
+ }
+}
diff --git a/libraries/options/src/android/platform/test/options/TestOption.java b/libraries/options/src/android/platform/test/options/TestOption.java
new file mode 100644
index 0000000..b73264d
--- /dev/null
+++ b/libraries/options/src/android/platform/test/options/TestOption.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 android.platform.test.option;
+
+import android.os.Bundle;
+import androidx.test.InstrumentationRegistry;
+import androidx.annotation.VisibleForTesting;
+
+import org.junit.runner.Description;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
+
+/**
+ * A base class whose implementations encompass options for a scenario test.
+ *
+ * <p>Each option is defined by calling its constructor with its argument string and then optionally
+ * calling a number of setters to set the default value and whether it is required. They need to be
+ * defined as JUnit test rules using the {@code Rule} annotation as this ensures that they are
+ * initialized during test setup.
+ *
+ * <p>Using {@link StringOption} as an example, an option is defined as the following:
+ *
+ * <pre>
+ * @Rule public StringOption sampleOption =
+ * new StringOption("sample-option").setRequired(true).setDefault("sample-value");
+ * </pre>
+ *
+ * <p>To supply value for the above option, use {@code -e sample-option some_value} in the
+ * instrumentation command.
+ */
+public abstract class TestOption<T> implements TestRule {
+ private String mOptionName;
+ private T mDefaultValue;
+ private boolean mIsRequired;
+ private T mValue;
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ // An option with a default value is effectively not required.
+ if (mDefaultValue != null) {
+ mIsRequired = false;
+ }
+ // Populate the option value before the test starts, and throw if the option is
+ // missing when required or illegal.
+ Bundle arguments = getArguments();
+ if (!arguments.containsKey(mOptionName)) {
+ if (mIsRequired) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Missing argument for required option: %s", mOptionName));
+ }
+ mValue = mDefaultValue;
+ } else {
+ // All `am instrument -e` arguments are provided as Strings.
+ try {
+ mValue = parseValueFromString(arguments.getString(mOptionName));
+ } catch (Exception e) {
+ throw new RuntimeException(
+ String.format(
+ "Error parsing option %s for test %s.",
+ TestOption.this, description),
+ e);
+ }
+ }
+
+ // Run the underlying statement which includes the test, if the above pass.
+ base.evaluate();
+ }
+ };
+ }
+
+ /** Creates a required option with the provided name. */
+ public TestOption(String optionName) {
+ mOptionName = optionName;
+ mIsRequired = true;
+ }
+
+ /**
+ * Sets whether the option is required when no default is provided. Options are considered
+ * required by default.
+ */
+ public <S extends TestOption<T>> S setRequired(boolean required) {
+ mIsRequired = required;
+ return (S) this;
+ }
+
+ /** Sets a default value for an option. A null value is not a proper default value. */
+ public <S extends TestOption<T>> S setDefault(T defaultValue) {
+ if (defaultValue == null) {
+ throw new IllegalArgumentException(
+ String.format("Default value for option %s cannot be null.", this));
+ }
+ mDefaultValue = defaultValue;
+ return (S) this;
+ }
+
+ /**
+ * Returns the value of the option which had been initialized during test setup. Can return null
+ * if the option is not set to required.
+ */
+ public T get() {
+ if ((mValue == null) && mIsRequired) {
+ // This should never happen.
+ throw new IllegalStateException(
+ String.format(
+ "Value for required option %s had not been initialized during setup.",
+ mOptionName));
+ }
+ // A non-required option can return null.
+ return mValue;
+ }
+
+ /**
+ * Returns the set value based on registered arguments or the default value if not.
+ *
+ * <p>Note: this should override any defaults already provided by the {@link Bundle}.
+ */
+ protected abstract T parseValueFromString(String value);
+
+ @VisibleForTesting
+ Bundle getArguments() {
+ return InstrumentationRegistry.getArguments();
+ }
+
+ public String toString() {
+ return String.format("%s \"%s\"", this.getClass().getSimpleName(), mOptionName);
+ }
+}
diff --git a/libraries/options/tests/Android.bp b/libraries/options/tests/Android.bp
new file mode 100644
index 0000000..3099de5
--- /dev/null
+++ b/libraries/options/tests/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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.
+
+android_test {
+ name: "PlatformTestOptionsTests",
+ sdk_version: "24",
+ srcs: [ "src/**/*.java" ],
+ static_libs: [
+ "androidx.test.runner",
+ "platform-test-options",
+ "junit",
+ ],
+}
diff --git a/libraries/options/tests/AndroidManifest.xml b/libraries/options/tests/AndroidManifest.xml
new file mode 100644
index 0000000..5d8830f
--- /dev/null
+++ b/libraries/options/tests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.platform.test.options.tests" >
+ <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="24" />
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.platform.test.options.tests"
+ android:label="Tests for Platform Test Options" />
+</manifest>
+
diff --git a/libraries/options/tests/AndroidTest.xml b/libraries/options/tests/AndroidTest.xml
new file mode 100644
index 0000000..59e8a89
--- /dev/null
+++ b/libraries/options/tests/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2018 Google Inc.
+
+ 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.
+-->
+<configuration description="Config for platform test options">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="PlatformTestOptionsTests.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.platform.test.options.tests" />
+ </test>
+</configuration>
diff --git a/libraries/options/tests/src/android/platform/test/options/BooleanOptionTest.java b/libraries/options/tests/src/android/platform/test/options/BooleanOptionTest.java
new file mode 100644
index 0000000..47a8af6
--- /dev/null
+++ b/libraries/options/tests/src/android/platform/test/options/BooleanOptionTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 android.platform.test.option;
+
+import android.os.Bundle;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/** Unit tests for {@link BooleanOption}. */
+public class BooleanOptionTest {
+ private static final String OPTION_NAME = "option";
+
+ private static class TestableBooleanOption extends BooleanOption {
+ private Bundle mArguments = new Bundle();
+ private String mName;
+
+ public TestableBooleanOption(String name) {
+ super(name);
+ mName = name;
+ }
+
+ @Override
+ Bundle getArguments() {
+ return mArguments;
+ }
+
+ public void stubValue(String value) {
+ mArguments.putString(mName, value);
+ }
+ }
+
+ /** Test that the option is parsed correctly for a "true" value. */
+ @Test
+ public void testParsing_true() throws Throwable {
+ TestableBooleanOption option = new TestableBooleanOption(OPTION_NAME);
+ option.stubValue(String.valueOf(true));
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ Assert.assertEquals(true, option.get());
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+
+ /** Test that the option is parsed correctly for a "false" value equivalent. */
+ @Test
+ public void testParsing_false() throws Throwable {
+ TestableBooleanOption option = new TestableBooleanOption(OPTION_NAME);
+ option.stubValue("not true");
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ Assert.assertEquals(false, option.get());
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+}
diff --git a/libraries/options/tests/src/android/platform/test/options/DoubleOptionTest.java b/libraries/options/tests/src/android/platform/test/options/DoubleOptionTest.java
new file mode 100644
index 0000000..0b284af
--- /dev/null
+++ b/libraries/options/tests/src/android/platform/test/options/DoubleOptionTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 android.platform.test.option;
+
+import android.os.Bundle;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/** Unit tests for {@link DoubleOption}. */
+public class DoubleOptionTest {
+ @Rule public ExpectedException mThrown = ExpectedException.none();
+
+ private static final String OPTION_NAME = "option";
+
+ private static class TestableDoubleOption extends DoubleOption {
+ private Bundle mArguments = new Bundle();
+ private String mName;
+
+ public TestableDoubleOption(String name) {
+ super(name);
+ mName = name;
+ }
+
+ @Override
+ Bundle getArguments() {
+ return mArguments;
+ }
+
+ public void stubValue(String value) {
+ mArguments.putString(mName, value);
+ }
+ }
+
+ /** Test that the option is parsed correctly for a valid double value. */
+ @Test
+ public void testParsing_valid() throws Throwable {
+ TestableDoubleOption option = new TestableDoubleOption(OPTION_NAME);
+ // Using boxed value here to avoid ambiguity when calling assertEquals.
+ Double value = 1.1;
+ option.stubValue(String.valueOf(value));
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ Assert.assertEquals(value, option.get());
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+
+ /** Test that the option throws when using an invalid number format. */
+ @Test
+ public void testParsing_invalid() throws Throwable {
+ mThrown.expectMessage("Error parsing");
+
+ TestableDoubleOption option = new TestableDoubleOption(OPTION_NAME);
+ option.stubValue("not a number");
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ option.get();
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+}
diff --git a/libraries/options/tests/src/android/platform/test/options/IntegerOptionTest.java b/libraries/options/tests/src/android/platform/test/options/IntegerOptionTest.java
new file mode 100644
index 0000000..5258be5
--- /dev/null
+++ b/libraries/options/tests/src/android/platform/test/options/IntegerOptionTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 android.platform.test.option;
+
+import android.os.Bundle;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/** Unit tests for {@link IntegerOption}. */
+public class IntegerOptionTest {
+ @Rule public ExpectedException mThrown = ExpectedException.none();
+
+ private static final String OPTION_NAME = "option";
+
+ private static class TestableIntegerOption extends IntegerOption {
+ private Bundle mArguments = new Bundle();
+ private String mName;
+
+ public TestableIntegerOption(String name) {
+ super(name);
+ mName = name;
+ }
+
+ @Override
+ Bundle getArguments() {
+ return mArguments;
+ }
+
+ public void stubValue(String value) {
+ mArguments.putString(mName, value);
+ }
+ }
+
+ /** Test that the option is parsed correctly for a valid integer value. */
+ @Test
+ public void testParsing_valid() throws Throwable {
+ TestableIntegerOption option = new TestableIntegerOption(OPTION_NAME);
+ // Using boxed value here to avoid ambiguity when calling assertEquals.
+ Integer value = 7;
+ option.stubValue(String.valueOf(value));
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ Assert.assertEquals(value, option.get());
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+
+ /** Test that the option throws when using an invalid number format. */
+ @Test
+ public void testParsing_invalid() throws Throwable {
+ mThrown.expectMessage("Error parsing");
+
+ TestableIntegerOption option = new TestableIntegerOption(OPTION_NAME);
+ option.stubValue("not an integer");
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ option.get();
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+}
diff --git a/libraries/options/tests/src/android/platform/test/options/LongOptionTest.java b/libraries/options/tests/src/android/platform/test/options/LongOptionTest.java
new file mode 100644
index 0000000..61df321
--- /dev/null
+++ b/libraries/options/tests/src/android/platform/test/options/LongOptionTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 android.platform.test.option;
+
+import android.os.Bundle;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/** Unit tests for {@link LongOption}. */
+public class LongOptionTest {
+ @Rule public ExpectedException mThrown = ExpectedException.none();
+
+ private static final String OPTION_NAME = "option";
+
+ private static class TestableLongOption extends LongOption {
+ private Bundle mArguments = new Bundle();
+ private String mName;
+
+ public TestableLongOption(String name) {
+ super(name);
+ mName = name;
+ }
+
+ @Override
+ Bundle getArguments() {
+ return mArguments;
+ }
+
+ public void stubValue(String value) {
+ mArguments.putString(mName, value);
+ }
+ }
+
+ /** Test that the option is parsed correctly for a valid long value. */
+ @Test
+ public void testParsing_valid() throws Throwable {
+ TestableLongOption option = new TestableLongOption(OPTION_NAME);
+ // Using boxed value here to avoid ambiguity when calling assertEquals.
+ Long value = 7L;
+ option.stubValue(String.valueOf(value));
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ Assert.assertEquals(value, option.get());
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+
+ /** Test that the option throws when using an invalid number format. */
+ @Test
+ public void testParsing_invalid() throws Throwable {
+ mThrown.expectMessage("Error parsing");
+
+ TestableLongOption option = new TestableLongOption(OPTION_NAME);
+ option.stubValue("not an long");
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ option.get();
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+}
diff --git a/libraries/options/tests/src/android/platform/test/options/StringOptionTest.java b/libraries/options/tests/src/android/platform/test/options/StringOptionTest.java
new file mode 100644
index 0000000..3bdb309
--- /dev/null
+++ b/libraries/options/tests/src/android/platform/test/options/StringOptionTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 android.platform.test.option;
+
+import android.os.Bundle;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/** Unit tests for {@link StringOption}. */
+public class StringOptionTest {
+ private static final String OPTION_NAME = "option";
+
+ private static class TestableStringOption extends StringOption {
+ private Bundle mArguments = new Bundle();
+ private String mName;
+
+ public TestableStringOption(String name) {
+ super(name);
+ mName = name;
+ }
+
+ @Override
+ Bundle getArguments() {
+ return mArguments;
+ }
+
+ public void stubValue(String value) {
+ mArguments.putString(mName, value);
+ }
+ }
+
+ /** Test that the option is retrieved correctly. */
+ @Test
+ public void testRetrieval() throws Throwable {
+ TestableStringOption option = new TestableStringOption(OPTION_NAME);
+ String value = "val";
+ option.stubValue(value);
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ Assert.assertEquals(value, option.get());
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+}
diff --git a/libraries/options/tests/src/android/platform/test/options/TestOptionTest.java b/libraries/options/tests/src/android/platform/test/options/TestOptionTest.java
new file mode 100644
index 0000000..5d1ef5e
--- /dev/null
+++ b/libraries/options/tests/src/android/platform/test/options/TestOptionTest.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 android.platform.test.option;
+
+import android.os.Bundle;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/** Unit tests for {@link TestOption}. */
+public class TestOptionTest {
+ @Rule public ExpectedException mThrown = ExpectedException.none();
+
+ private static final String OPTION_NAME = "option";
+ private static final String VALUE_VALID = "valid";
+ private static final String VALUE_INVALID = "invalid";
+
+ // A testable TestOption class that enables stubbing of the option value.
+ private static class TestableOption extends TestOption<String> {
+ // If stubValue() is not called, the Bundle is empty and thus does not contain the option
+ // value.
+ private Bundle mArguments = new Bundle();
+ private String mName;
+
+ public TestableOption(String name) {
+ super(name);
+ mName = name;
+ }
+
+ @Override
+ public String parseValueFromString(String value) {
+ // Mimick invalid argument behavior.
+ if (value == VALUE_INVALID) {
+ throw new RuntimeException("Invalid argument");
+ }
+
+ return value;
+ }
+
+ @Override
+ Bundle getArguments() {
+ return mArguments;
+ }
+
+ public void stubValue(String value) {
+ mArguments.putString(mName, value);
+ }
+ }
+
+ /** Test that a valid argument is properly accessed. */
+ @Test
+ public void testSuppliedValue_valid() throws Throwable {
+ TestableOption option = new TestableOption(OPTION_NAME);
+ option.stubValue(VALUE_VALID);
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ Assert.assertEquals(VALUE_VALID, option.get());
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+
+ /** Test that an invalid argument is rejected. */
+ @Test
+ public void testSuppliedValue_invalid() throws Throwable {
+ mThrown.expectMessage("Error parsing");
+
+ TestableOption option = new TestableOption(OPTION_NAME);
+ option.stubValue(VALUE_INVALID);
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ Assert.assertEquals(VALUE_VALID, option.get());
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+
+ /** Test that the option throws for a missing argument explicitly set to be required. */
+ @Test
+ public void testRequiredValueAbsent_explicit() throws Throwable {
+ mThrown.expectMessage("Missing argument");
+
+ TestableOption option = new TestableOption(OPTION_NAME).setRequired(true);
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ option.get();
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+
+ /** Test that an option is required by default and throws if absent in instrumentation args. */
+ @Test
+ public void testRequiredValueAbsent_implicit() throws Throwable {
+ mThrown.expectMessage("Missing argument");
+
+ TestableOption option = new TestableOption(OPTION_NAME);
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ option.get();
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+
+ /** Test that an option with a default value will not throw, even if it is required. */
+ @Test
+ public void testRequiredValueAbsent_withDefault() throws Throwable {
+ TestableOption option =
+ new TestableOption(OPTION_NAME).setRequired(true).setDefault(VALUE_VALID);
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ Assert.assertEquals(VALUE_VALID, option.get());
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+
+ /** Test that a non-required option can return null if not provided when accessed in test. */
+ @Test
+ public void testNonRequiredValueAbsent() throws Throwable {
+ TestableOption option = new TestableOption(OPTION_NAME).setRequired(false);
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ Assert.assertNull(option.get());
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ withOption.evaluate();
+ }
+
+ /** Test that an invalid option value will cause the test to be skipped. */
+ @Test
+ public void testOptionErrorSkipsTest_invalidValue() throws Throwable {
+ TestableOption option = new TestableOption(OPTION_NAME);
+ option.stubValue(VALUE_INVALID);
+ // AtomicBoolean is used to allow for modification in the test statement.
+ final AtomicBoolean testReached = new AtomicBoolean(false);
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ testReached.set(true);
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ try {
+ withOption.evaluate();
+ } catch (Throwable e) {
+ // Expected; do nothing.
+ } finally {
+ Assert.assertFalse(testReached.get());
+ }
+ }
+
+ /** Test that a missing required option will cause the test to be skipped. */
+ @Test
+ public void testOptionErrorSkipsTest_requiredMissing() throws Throwable {
+ TestableOption option = new TestableOption(OPTION_NAME).setRequired(true);
+ // AtomicBoolean is used to allow for modification in the test statement.
+ final AtomicBoolean testReached = new AtomicBoolean(false);
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ testReached.set(true);
+ }
+ };
+ Statement withOption = option.apply(testStatement, Description.EMPTY);
+ try {
+ withOption.evaluate();
+ } catch (Throwable e) {
+ // Expected; do nothing.
+ } finally {
+ Assert.assertFalse(testReached.get());
+ }
+ }
+
+ /**
+ * Test that if an option had not been initialized before the test, the test will fail when
+ * accessing the option.
+ *
+ * <p>This should never happen in practice, but tested just in case that custom runners do
+ * something unexpected.
+ */
+ @Test
+ public void testUninitializedOptionThrows() throws Throwable {
+ mThrown.expectMessage("had not been initialized");
+
+ TestableOption option = new TestableOption(OPTION_NAME).setRequired(true);
+ option.stubValue(VALUE_VALID);
+ Statement testStatement =
+ new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ option.get();
+ }
+ };
+ // Run the "test statement" directly without running the option rule, which should throw.
+ testStatement.evaluate();
+ }
+}
diff --git a/tests/scenario/Android.bp b/tests/scenario/Android.bp
index 28abfbf..3afce78 100644
--- a/tests/scenario/Android.bp
+++ b/tests/scenario/Android.bp
@@ -19,6 +19,7 @@
libs: [
"androidx.test.runner",
"junit",
+ "platform-test-options",
"ub-uiautomator",
],
}
diff --git a/tests/scenario/src/android/platform/test/scenario/sleep/Idle.java b/tests/scenario/src/android/platform/test/scenario/sleep/Idle.java
index 0104de9..882523c 100644
--- a/tests/scenario/src/android/platform/test/scenario/sleep/Idle.java
+++ b/tests/scenario/src/android/platform/test/scenario/sleep/Idle.java
@@ -17,10 +17,10 @@
package android.platform.test.scenario.sleep;
import android.os.SystemClock;
+import android.platform.test.option.LongOption;
import android.platform.test.scenario.annotation.Scenario;
-import androidx.test.InstrumentationRegistry;
-import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -31,27 +31,10 @@
@Scenario
@RunWith(JUnit4.class)
public class Idle {
- private static final String DURATION_OPTION = "durationMs";
- private static final String DURATION_DEFAULT = "1000";
-
- private long mDurationMs = 0L;
-
- @Before
- public void setUp() {
- String durationMsString = InstrumentationRegistry.getArguments()
- .getString(DURATION_OPTION, DURATION_DEFAULT);
- try {
- mDurationMs = Long.parseLong(durationMsString);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(
- String.format(
- "Failed to parse option %s: %s", DURATION_OPTION, durationMsString));
- }
-
- }
+ @Rule public final LongOption mDurationMs = new LongOption("durationMs").setDefault(1000L);
@Test
public void testDoingNothing() {
- SystemClock.sleep(mDurationMs);
+ SystemClock.sleep(mDurationMs.get());
}
}
diff --git a/tests/scenario/src/android/platform/test/scenario/system/ScreenOff.java b/tests/scenario/src/android/platform/test/scenario/system/ScreenOff.java
index 997b665..cf6ea9e 100644
--- a/tests/scenario/src/android/platform/test/scenario/system/ScreenOff.java
+++ b/tests/scenario/src/android/platform/test/scenario/system/ScreenOff.java
@@ -18,11 +18,13 @@
import android.os.RemoteException;
import android.os.SystemClock;
+import android.platform.test.option.LongOption;
import android.platform.test.scenario.annotation.Scenario;
import android.support.test.uiautomator.UiDevice;
import androidx.test.InstrumentationRegistry;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -33,30 +35,19 @@
@Scenario
@RunWith(JUnit4.class)
public class ScreenOff {
- private static final String DURATION_OPTION = "screenOffDurationMs";
- private static final String DURATION_DEFAULT = "1000";
+ @Rule
+ public final LongOption mDurationMs = new LongOption("screenOffDurationMs").setDefault(1000L);
- private long mDurationMs = 0L;
private UiDevice mDevice;
@Before
public void setUp() {
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- String durationMsString = InstrumentationRegistry.getArguments()
- .getString(DURATION_OPTION, DURATION_DEFAULT);
- try {
- mDurationMs = Long.parseLong(durationMsString);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(
- String.format(
- "Failed to parse option %s: %s", DURATION_OPTION, durationMsString));
- }
-
}
@Test
public void testScreenOff() throws RemoteException {
mDevice.sleep();
- SystemClock.sleep(mDurationMs);
+ SystemClock.sleep(mDurationMs.get());
}
}
diff --git a/tests/scenario/src/android/platform/test/scenario/system/ScreenOn.java b/tests/scenario/src/android/platform/test/scenario/system/ScreenOn.java
index 103f854..24c1461 100644
--- a/tests/scenario/src/android/platform/test/scenario/system/ScreenOn.java
+++ b/tests/scenario/src/android/platform/test/scenario/system/ScreenOn.java
@@ -18,11 +18,13 @@
import android.os.RemoteException;
import android.os.SystemClock;
+import android.platform.test.option.LongOption;
import android.platform.test.scenario.annotation.Scenario;
import android.support.test.uiautomator.UiDevice;
import androidx.test.InstrumentationRegistry;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -33,30 +35,18 @@
@Scenario
@RunWith(JUnit4.class)
public class ScreenOn {
- private static final String DURATION_OPTION = "screenOnDurationMs";
- private static final String DURATION_DEFAULT = "1000";
+ @Rule public LongOption mDurationMs = new LongOption("screenOnDurationMs").setDefault(1000L);
- private long mDurationMs = 0L;
private UiDevice mDevice;
@Before
public void setUp() {
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- String durationMsString = InstrumentationRegistry.getArguments()
- .getString(DURATION_OPTION, DURATION_DEFAULT);
- try {
- mDurationMs = Long.parseLong(durationMsString);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(
- String.format(
- "Failed to parse option %s: %s", DURATION_OPTION, durationMsString));
- }
-
}
@Test
public void testScreenOn() throws RemoteException {
mDevice.wakeUp();
- SystemClock.sleep(mDurationMs);
+ SystemClock.sleep(mDurationMs.get());
}
}
diff --git a/tests/scenario/tests/Android.bp b/tests/scenario/tests/Android.bp
index 917e64f..a597b92 100644
--- a/tests/scenario/tests/Android.bp
+++ b/tests/scenario/tests/Android.bp
@@ -64,6 +64,7 @@
"longevity-device-lib",
"microbenchmark-device-lib",
"platform-test-composers",
+ "platform-test-options",
"platform-test-rules",
],
srcs: ["src/**/*.java"],