1244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov/*
2244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov * Copyright (C) 2015 The Android Open Source Project
3244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov *
4244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov * Licensed under the Apache License, Version 2.0 (the "License");
5244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov * you may not use this file except in compliance with the License.
6244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov * You may obtain a copy of the License at
7244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov *
8244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov *      http://www.apache.org/licenses/LICENSE-2.0
9244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov *
10244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov * Unless required by applicable law or agreed to in writing, software
11244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov * distributed under the License is distributed on an "AS IS" BASIS,
12244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov * See the License for the specific language governing permissions and
14244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov * limitations under the License.
15244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov */
16244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.appcompat.testutils;
18244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov
191d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikovimport android.database.sqlite.SQLiteCursor;
201d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikovimport android.graphics.Bitmap;
21244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikovimport android.graphics.drawable.Drawable;
22244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikovimport android.support.test.espresso.matcher.BoundedMatcher;
231d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikovimport android.text.TextUtils;
24244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikovimport android.view.View;
251d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikovimport android.view.ViewGroup;
262d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikovimport android.widget.CheckedTextView;
27244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikovimport android.widget.ImageView;
2827644c071b7fc0e1e4f91194f2a08b4aa2cf1465Aurimas Liutikas
293de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikasimport androidx.annotation.ColorInt;
303de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikasimport androidx.core.view.TintableBackgroundView;
313de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikas
32244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikovimport org.hamcrest.Description;
33244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikovimport org.hamcrest.Matcher;
34ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikovimport org.hamcrest.TypeSafeMatcher;
35244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov
3621f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikovimport java.util.List;
3721f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
38244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikovpublic class TestUtilsMatchers {
39244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov    /**
40244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov     * Returns a matcher that matches <code>ImageView</code>s which have drawable flat-filled
41244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov     * with the specific color.
42244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov     */
43244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov    public static Matcher drawable(@ColorInt final int color) {
44244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov        return new BoundedMatcher<View, ImageView>(ImageView.class) {
45244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov            private String failedComparisonDescription;
46244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov
47244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov            @Override
48244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov            public void describeTo(final Description description) {
49244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                description.appendText("with drawable of color: ");
50244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov
51244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                description.appendText(failedComparisonDescription);
52244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov            }
53244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov
54244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov            @Override
55244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov            public boolean matchesSafely(final ImageView view) {
56244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                Drawable drawable = view.getDrawable();
57244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                if (drawable == null) {
58244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                    return false;
59244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                }
60244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov
61244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                // One option is to check if we have a ColorDrawable and then call getColor
62244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                // but that API is v11+. Instead, we call our helper method that checks whether
63244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                // all pixels in a Drawable are of the same specified color.
64244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                try {
65244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                    TestUtils.assertAllPixelsOfColor("", drawable, view.getWidth(),
661b81f288853d60e25e870fd522c927fd72f2efb5Kirill Grouchnikov                            view.getHeight(), true, color, 0, true);
67244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                    // If we are here, the color comparison has passed.
68244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                    failedComparisonDescription = null;
69244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                    return true;
70244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                } catch (Throwable t) {
71244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                    // If we are here, the color comparison has failed.
72244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                    failedComparisonDescription = t.getMessage();
73244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                    return false;
74244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov                }
75244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov            }
76244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov        };
77244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov    }
782d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov
792d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov    /**
801d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov     * Returns a matcher that matches <code>View</code>s which have background flat-filled
811d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov     * with the specific color.
821d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov     */
831d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov    public static Matcher isBackground(@ColorInt final int color) {
841cd642752286e1fba44d8ec87e9793f116a22240Chris Banes        return isBackground(color, false);
851cd642752286e1fba44d8ec87e9793f116a22240Chris Banes    }
861cd642752286e1fba44d8ec87e9793f116a22240Chris Banes
871cd642752286e1fba44d8ec87e9793f116a22240Chris Banes    /**
881cd642752286e1fba44d8ec87e9793f116a22240Chris Banes     * Returns a matcher that matches <code>View</code>s which have background flat-filled
891cd642752286e1fba44d8ec87e9793f116a22240Chris Banes     * with the specific color.
901cd642752286e1fba44d8ec87e9793f116a22240Chris Banes     */
911cd642752286e1fba44d8ec87e9793f116a22240Chris Banes    public static Matcher isBackground(@ColorInt final int color, final boolean onlyTestCenter) {
921d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov        return new BoundedMatcher<View, View>(View.class) {
931d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            private String failedComparisonDescription;
941d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov
951d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            @Override
961d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            public void describeTo(final Description description) {
971d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                description.appendText("with background of color: ");
981d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov
991d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                description.appendText(failedComparisonDescription);
1001d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            }
1011d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov
1021d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            @Override
1031d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            public boolean matchesSafely(final View view) {
1041d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                Drawable drawable = view.getBackground();
1051d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                if (drawable == null) {
1061d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    return false;
1071d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                }
1081d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                try {
1091cd642752286e1fba44d8ec87e9793f116a22240Chris Banes                    if (onlyTestCenter) {
1101cd642752286e1fba44d8ec87e9793f116a22240Chris Banes                        TestUtils.assertCenterPixelOfColor("", drawable, view.getWidth(),
1111cd642752286e1fba44d8ec87e9793f116a22240Chris Banes                                view.getHeight(), false, color, 0, true);
1121cd642752286e1fba44d8ec87e9793f116a22240Chris Banes                    } else {
1131cd642752286e1fba44d8ec87e9793f116a22240Chris Banes                        TestUtils.assertAllPixelsOfColor("", drawable, view.getWidth(),
1141cd642752286e1fba44d8ec87e9793f116a22240Chris Banes                                view.getHeight(), false, color, 0, true);
1151cd642752286e1fba44d8ec87e9793f116a22240Chris Banes                    }
1161d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    // If we are here, the color comparison has passed.
1171d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    failedComparisonDescription = null;
1181d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    return true;
1191d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                } catch (Throwable t) {
1201d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    // If we are here, the color comparison has failed.
1211d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    failedComparisonDescription = t.getMessage();
1221d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    return false;
1231d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                }
1241d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            }
1251d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov        };
1261d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov    }
1271d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov
1281d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov    /**
1291d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov     * Returns a matcher that matches <code>View</code>s whose combined background starting
1301d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov     * from the view and up its ancestor chain matches the specified color.
1311d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov     */
1323ab41277a085b829e15eca69442cfe45cae58a8cKirill Grouchnikov    public static Matcher isCombinedBackground(@ColorInt final int color,
1333ab41277a085b829e15eca69442cfe45cae58a8cKirill Grouchnikov            final boolean onlyTestCenterPixel) {
1341d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov        return new BoundedMatcher<View, View>(View.class) {
1351d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            private String failedComparisonDescription;
1361d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov
1371d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            @Override
1381d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            public void describeTo(final Description description) {
1391d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                description.appendText("with ascendant background of color: ");
1401d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov
1411d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                description.appendText(failedComparisonDescription);
1421d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            }
1431d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov
1441d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            @Override
1451d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            public boolean matchesSafely(View view) {
1461d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                // Create a bitmap with combined backgrounds of the view and its ancestors.
1471d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                Bitmap combinedBackgroundBitmap = TestUtils.getCombinedBackgroundBitmap(view);
1481d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                try {
1493ab41277a085b829e15eca69442cfe45cae58a8cKirill Grouchnikov                    if (onlyTestCenterPixel) {
1503ab41277a085b829e15eca69442cfe45cae58a8cKirill Grouchnikov                        TestUtils.assertCenterPixelOfColor("", combinedBackgroundBitmap,
1513ab41277a085b829e15eca69442cfe45cae58a8cKirill Grouchnikov                                color, 0, true);
1523ab41277a085b829e15eca69442cfe45cae58a8cKirill Grouchnikov                    } else {
1533ab41277a085b829e15eca69442cfe45cae58a8cKirill Grouchnikov                        TestUtils.assertAllPixelsOfColor("", combinedBackgroundBitmap,
1543ab41277a085b829e15eca69442cfe45cae58a8cKirill Grouchnikov                                combinedBackgroundBitmap.getWidth(),
1553ab41277a085b829e15eca69442cfe45cae58a8cKirill Grouchnikov                                combinedBackgroundBitmap.getHeight(), color, 0, true);
1563ab41277a085b829e15eca69442cfe45cae58a8cKirill Grouchnikov                    }
1571d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    // If we are here, the color comparison has passed.
1581d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    failedComparisonDescription = null;
1591d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    return true;
1601d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                } catch (Throwable t) {
1611d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    failedComparisonDescription = t.getMessage();
1621d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    return false;
1631d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                } finally {
1641d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    combinedBackgroundBitmap.recycle();
1651d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                }
1661d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            }
1671d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov        };
1681d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov    }
1691d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov
1701d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov    /**
1712d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov     * Returns a matcher that matches <code>CheckedTextView</code>s which are in checked state.
1722d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov     */
1732d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov    public static Matcher isCheckedTextView() {
1742d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov        return new BoundedMatcher<View, CheckedTextView>(CheckedTextView.class) {
1752d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            private String failedDescription;
1762d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov
1772d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            @Override
1782d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            public void describeTo(final Description description) {
1792d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                description.appendText("checked text view: ");
1802d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov
1812d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                description.appendText(failedDescription);
1822d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            }
1832d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov
1842d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            @Override
1852d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            public boolean matchesSafely(final CheckedTextView view) {
1862d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                if (view.isChecked()) {
1872d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                    return true;
1882d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                }
1892d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov
1902d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                failedDescription = "not checked";
1912d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                return false;
1922d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            }
1932d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov        };
1942d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov    }
1952d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov
1962d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov    /**
1972d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov     * Returns a matcher that matches <code>CheckedTextView</code>s which are in checked state.
1982d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov     */
1992d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov    public static Matcher isNonCheckedTextView() {
2002d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov        return new BoundedMatcher<View, CheckedTextView>(CheckedTextView.class) {
2012d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            private String failedDescription;
2022d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov
2032d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            @Override
2042d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            public void describeTo(final Description description) {
2052d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                description.appendText("non checked text view: ");
2062d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov
2072d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                description.appendText(failedDescription);
2082d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            }
2092d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov
2102d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            @Override
2112d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            public boolean matchesSafely(final CheckedTextView view) {
2122d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                if (!view.isChecked()) {
2132d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                    return true;
2142d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                }
2152d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov
2162d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                failedDescription = "checked";
2172d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov                return false;
2182d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov            }
2192d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov        };
2202d18d3a4b92369971ed446cf54d98fb0fc55646aKirill Grouchnikov    }
2211d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov
2221d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov    /**
2231d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov     * Returns a matcher that matches data entry in <code>SQLiteCursor</code> that has
2241d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov     * the specified text in the specified column.
2251d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov     */
2261d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov    public static Matcher<Object> withCursorItemContent(final String columnName,
2271d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov            final String expectedText) {
2281d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov        return new BoundedMatcher<Object, SQLiteCursor>(SQLiteCursor.class) {
2291d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov            @Override
2301d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov            public void describeTo(Description description) {
2311d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov                description.appendText("doesn't match " + expectedText);
2321d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov            }
2331d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov
2341d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov            @Override
2351d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov            protected boolean matchesSafely(SQLiteCursor cursor) {
2361d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov                return TextUtils.equals(expectedText,
2371d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov                        cursor.getString(cursor.getColumnIndex(columnName)));
2381d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov            }
2391d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov        };
2401d8515a3b783e9b091bea2891606b466515b4fddKirill Grouchnikov    }
241ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov
242ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov    /**
243ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov     * Returns a matcher that matches Views which implement TintableBackgroundView.
244ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov     */
245ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov    public static Matcher<View> isTintableBackgroundView() {
246ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov        return new TypeSafeMatcher<View>() {
247ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov            @Override
248ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov            public void describeTo(Description description) {
249ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov                description.appendText("is TintableBackgroundView");
250ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov            }
251ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov
252ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov            @Override
253ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov            public boolean matchesSafely(View view) {
254ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov                return TintableBackgroundView.class.isAssignableFrom(view.getClass());
255ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov            }
256ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov        };
257ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov    }
258ee9519c17254b5e992164ff278173c4b2c7c5fceKirill Grouchnikov
25921f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov    /**
26021f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov     * Returns a matcher that matches lists of float values that fall into the specified range.
26121f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov     */
26221f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov    public static Matcher<List<Float>> inRange(final float from, final float to) {
26321f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov        return new TypeSafeMatcher<List<Float>>() {
26421f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            private String mFailedDescription;
26521f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
26621f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            @Override
26721f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            public void describeTo(Description description) {
26821f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                description.appendText(mFailedDescription);
26921f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            }
27021f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
27121f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            @Override
27221f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            protected boolean matchesSafely(List<Float> item) {
27321f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                int itemCount = item.size();
27421f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
27521f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                for (int i = 0; i < itemCount; i++) {
27621f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                    float curr = item.get(i);
27721f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
27821f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                    if ((curr < from) || (curr > to)) {
27921f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                        mFailedDescription = "Value #" + i + ":" + curr + " should be between " +
28021f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                                from + " and " + to;
28121f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                        return false;
28221f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                    }
28321f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                }
28421f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
28521f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                return true;
28621f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            }
28721f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov        };
28821f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov    }
28921f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
29021f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov    /**
29121f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov     * Returns a matcher that matches lists of float values that are in ascending order.
29221f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov     */
29321f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov    public static Matcher<List<Float>> inAscendingOrder() {
29421f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov        return new TypeSafeMatcher<List<Float>>() {
29521f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            private String mFailedDescription;
29621f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
29721f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            @Override
29821f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            public void describeTo(Description description) {
29921f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                description.appendText(mFailedDescription);
30021f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            }
30121f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
30221f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            @Override
30321f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            protected boolean matchesSafely(List<Float> item) {
30421f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                int itemCount = item.size();
30521f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
30621f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                if (itemCount >= 2) {
30721f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                    for (int i = 0; i < itemCount - 1; i++) {
30821f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                        float curr = item.get(i);
30921f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                        float next = item.get(i + 1);
31021f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
31121f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                        if (curr > next) {
31221f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                            mFailedDescription = "Values should increase between #" + i +
31321f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                                    ":" + curr + " and #" + (i + 1) + ":" + next;
31421f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                            return false;
31521f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                        }
31621f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                    }
31721f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                }
31821f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
31921f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                return true;
32021f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            }
32121f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov        };
32221f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov    }
32321f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
32421f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov    /**
32521f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov     * Returns a matcher that matches lists of float values that are in descending order.
32621f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov     */
32721f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov    public static Matcher<List<Float>> inDescendingOrder() {
32821f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov        return new TypeSafeMatcher<List<Float>>() {
32921f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            private String mFailedDescription;
33021f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
33121f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            @Override
33221f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            public void describeTo(Description description) {
33321f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                description.appendText(mFailedDescription);
33421f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            }
33521f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
33621f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            @Override
33721f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            protected boolean matchesSafely(List<Float> item) {
33821f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                int itemCount = item.size();
33921f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
34021f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                if (itemCount >= 2) {
34121f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                    for (int i = 0; i < itemCount - 1; i++) {
34221f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                        float curr = item.get(i);
34321f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                        float next = item.get(i + 1);
34421f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
34521f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                        if (curr < next) {
34621f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                            mFailedDescription = "Values should decrease between #" + i +
34721f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                                    ":" + curr + " and #" + (i + 1) + ":" + next;
34821f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                            return false;
34921f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                        }
35021f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                    }
35121f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                }
35221f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov
35321f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov                return true;
35421f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov            }
35521f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov        };
35621f78eb90b3217aa5cf69c3ffd359506468b55f4Kirill Grouchnikov    }
3571d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov
3581d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov
3591d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov    /**
3601d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov     * Returns a matcher that matches {@link View}s based on the given child type.
3611d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov     *
3621d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov     * @param childMatcher the type of the child to match on
3631d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov     */
3641d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov    public static Matcher<ViewGroup> hasChild(final Matcher<View> childMatcher) {
3651d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov        return new TypeSafeMatcher<ViewGroup>() {
3661d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            @Override
3671d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            public void describeTo(Description description) {
3681d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                description.appendText("has child: ");
3691d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                childMatcher.describeTo(description);
3701d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            }
3711d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov
3721d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            @Override
3731d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            public boolean matchesSafely(ViewGroup view) {
3741d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                final int childCount = view.getChildCount();
3751d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                for (int i = 0; i < childCount; i++) {
3761d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    if (childMatcher.matches(view.getChildAt(i))) {
3771d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                        return true;
3781d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                    }
3791d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                }
3801d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov                return false;
3811d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov            }
3821d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov        };
3831d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov    }
3841d6e3840486930e276d142861afb6c7e72d5ce72Kirill Grouchnikov
385244abf1fee3fe4fab72a1d8925407e29219940beKirill Grouchnikov}
386