blob: e3ccd3a9f616d91317e8c997859089dd3da80d74 [file] [log] [blame]
/*
* Copyright (C) 2021 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 com.android.car.ui.uxr;
import static org.junit.Assert.assertNotNull;
import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.car.ui.TestActivity;
import com.android.car.ui.test.R;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@RunWith(Parameterized.class)
public class DrawableStateViewTest {
private static final List<Class<? extends DrawableStateView>> ALL_DRAWABLE_STATE_VIEWS =
Collections.unmodifiableList(Arrays.asList(
DrawableStateButton.class,
DrawableStateConstraintLayout.class,
DrawableStateFrameLayout.class,
DrawableStateImageView.class,
DrawableStateLinearLayout.class,
DrawableStateRelativeLayout.class,
DrawableStateSwitch.class,
DrawableStateTextView.class,
DrawableStateToggleButton.class));
@Parameterized.Parameters
public static Object[] data() {
return ALL_DRAWABLE_STATE_VIEWS.toArray();
}
private final Class<? extends DrawableStateView> mClassToTest;
public DrawableStateViewTest(Class<? extends DrawableStateView> classToTest) {
mClassToTest = classToTest;
}
@Rule
public final ActivityScenarioRule<TestActivity> mScenarioRule =
new ActivityScenarioRule<>(TestActivity.class);
@Test
public void test_drawablestateview_methods_work() throws ReflectiveOperationException {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
DrawableStateView button = mClassToTest.getDeclaredConstructor(Context.class)
.newInstance(context);
int[] drawableState = runOnUiThread(((View) button)::getDrawableState);
assertDrawableArrays(
drawableState,
new int[] { android.R.attr.state_enabled },
null);
drawableState = runOnUiThread(() -> {
((View) button).setEnabled(false);
return ((View) button).getDrawableState();
});
assertDrawableArrays(
drawableState,
null,
new int[] { android.R.attr.state_enabled });
drawableState = runOnUiThread(() -> {
((View) button).setEnabled(true);
button.setExtraDrawableState(new int[] { R.attr.state_ux_restricted }, null);
return ((View) button).getDrawableState();
});
assertDrawableArrays(
drawableState,
new int[] {
android.R.attr.state_enabled,
R.attr.state_ux_restricted
},
null);
drawableState = runOnUiThread(() -> {
((View) button).setEnabled(true);
button.setExtraDrawableState(
new int[] { R.attr.state_ux_restricted },
new int[] { android.R.attr.state_enabled });
return ((View) button).getDrawableState();
});
assertDrawableArrays(
drawableState,
new int[] { R.attr.state_ux_restricted },
new int[] { android.R.attr.state_enabled });
}
@Test
public void test_setExtraDrawableState_calledFirst() throws ReflectiveOperationException {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
DrawableStateView button = mClassToTest.getDeclaredConstructor(Context.class)
.newInstance(context);
int[] drawableState = runOnUiThread(() -> {
button.setExtraDrawableState(new int[] { R.attr.state_ux_restricted }, null);
return ((View) button).getDrawableState();
});
assertDrawableArrays(
drawableState,
new int[] { android.R.attr.state_enabled, R.attr.state_ux_restricted },
null);
}
@Test
public void test_emptyStateToRemove_works() throws ReflectiveOperationException {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
DrawableStateView button = mClassToTest.getDeclaredConstructor(Context.class)
.newInstance(context);
int[] drawableState = runOnUiThread(() -> {
button.setExtraDrawableState(null, new int[] {});
return ((View) button).getDrawableState();
});
assertDrawableArrays(
drawableState,
new int[] { android.R.attr.state_enabled },
new int[] { R.attr.state_ux_restricted });
}
@Test
public void test_constructors_work() throws ReflectiveOperationException {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
assertNotNull(mClassToTest
.getDeclaredConstructor(Context.class)
.newInstance(context));
assertNotNull(mClassToTest
.getDeclaredConstructor(Context.class, AttributeSet.class)
.newInstance(context, null));
assertNotNull(mClassToTest
.getDeclaredConstructor(Context.class, AttributeSet.class, int.class)
.newInstance(context, null, 0));
}
private int[] runOnUiThread(Supplier<int[]> runnable) {
int[][] result = new int[][] {null};
mScenarioRule.getScenario().onActivity(activity -> result[0] = runnable.get());
return result[0];
}
/**
* Checks that a drawable array has some attributes and doesn't have others.
*
* @param drawableArr The drawable array to check
* @param contains An array of attributes that the drawable array must contain.
* @param doesntContain An array of attributes the drawable array must not contain.
*/
private static void assertDrawableArrays(
int[] drawableArr, int[] contains, int[] doesntContain) {
if (contains != null) {
for (int contain : contains) {
boolean found = false;
for (int attr : drawableArr) {
if (attr == contain) {
found = true;
break;
}
}
if (!found) {
Assert.fail("Drawable array " + drawableArrayToString(drawableArr)
+ " did not contain required attribute "
+ getResourceName(contain));
}
}
}
if (doesntContain != null) {
for (int notContained : doesntContain) {
for (int attr : drawableArr) {
if (attr == notContained) {
Assert.fail("Drawable array " + drawableArrayToString(drawableArr)
+ " contained prohibited attribute "
+ getResourceName(notContained));
}
}
}
}
}
@NonNull
private static String drawableArrayToString(@Nullable int[] arr) {
if (arr == null) {
return "null";
}
return "[" + Arrays.stream(arr)
.mapToObj(DrawableStateViewTest::getResourceName)
.collect(Collectors.joining(", ")) + "]";
}
private static String getResourceName(int resource) {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
try {
return context.getResources().getResourceName(resource);
} catch (Resources.NotFoundException e) {
return String.valueOf(resource);
}
}
}