1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.compatibility.common.util;
18 
19 import static org.junit.Assert.fail;
20 
21 import android.graphics.Color;
22 
23 import androidx.annotation.NonNull;
24 import androidx.annotation.Nullable;
25 
26 import java.util.function.Function;
27 import java.util.function.IntUnaryOperator;
28 
29 public class ColorUtils {
verifyColor(int expected, int observed)30     public static void verifyColor(int expected, int observed) {
31         verifyColor(expected, observed, 0);
32     }
33 
verifyColor(int expected, int observed, int tolerance)34     public static void verifyColor(int expected, int observed, int tolerance) {
35         verifyColor("", expected, observed, tolerance);
36     }
37 
38     /**
39      * Verify that two colors match within a per-channel tolerance.
40      *
41      * @param s String with extra information about the test with an error.
42      * @param expected Expected color.
43      * @param observed Observed color.
44      * @param tolerance Per-channel tolerance by which the color can mismatch.
45      */
verifyColor(@onNull String s, int expected, int observed, int tolerance)46     public static void verifyColor(@NonNull String s, int expected, int observed, int tolerance) {
47         s += " expected 0x" + Integer.toHexString(expected)
48             + ", observed 0x" + Integer.toHexString(observed)
49             + ", tolerated channel error 0x" + tolerance;
50         String red = verifyChannel("red", expected, observed, tolerance, (i) -> Color.red(i));
51         String green = verifyChannel("green", expected, observed, tolerance, (i) -> Color.green(i));
52         String blue = verifyChannel("blue", expected, observed, tolerance, (i) -> Color.blue(i));
53         String alpha = verifyChannel("alpha", expected, observed, tolerance, (i) -> Color.alpha(i));
54 
55         buildErrorString(s, red, green, blue, alpha);
56     }
57 
buildErrorString(@onNull String s, @Nullable String red, @Nullable String green, @Nullable String blue, @Nullable String alpha)58     private static void buildErrorString(@NonNull String s, @Nullable String red,
59             @Nullable String green, @Nullable String blue, @Nullable String alpha) {
60         String err = null;
61         for (String channel : new String[]{red, green, blue, alpha}) {
62             if (channel == null) continue;
63             if (err == null) err = s;
64             err += "\n\t\t" + channel;
65         }
66         if (err != null) {
67             fail(err);
68         }
69     }
70 
verifyChannel(String channelName, int expected, int observed, int tolerance, IntUnaryOperator f)71     private static String verifyChannel(String channelName, int expected, int observed,
72             int tolerance, IntUnaryOperator f) {
73         int e = f.applyAsInt(expected);
74         int o = f.applyAsInt(observed);
75         if (Math.abs(e - o) <= tolerance) {
76             return null;
77         }
78         return "Channel " + channelName + " mismatch: expected<0x" + Integer.toHexString(e)
79             + ">, observed: <0x" + Integer.toHexString(o) + ">";
80     }
81 
82     /**
83      * Verify that two colors match within a per-channel tolerance.
84      *
85      * @param msg String with extra information about the test with an error.
86      * @param expected Expected color.
87      * @param observed Observed color.
88      * @param tolerance Per-channel tolerance by which the color can mismatch.
89      */
verifyColor(@onNull String msg, Color expected, Color observed, float tolerance)90     public static void verifyColor(@NonNull String msg, Color expected, Color observed,
91             float tolerance) {
92         if (!expected.getColorSpace().equals(observed.getColorSpace())) {
93             fail("Cannot compare Colors with different color spaces! expected: " + expected
94                     + "\tobserved: " + observed);
95         }
96         msg += " expected " + expected + ", observed " + observed + ", tolerated channel error "
97             + tolerance;
98         String red = verifyChannel("red", expected, observed, tolerance, (c) -> c.red());
99         String green = verifyChannel("green", expected, observed, tolerance, (c) -> c.green());
100         String blue = verifyChannel("blue", expected, observed, tolerance, (c) -> c.blue());
101         String alpha = verifyChannel("alpha", expected, observed, tolerance, (c) -> c.alpha());
102 
103         buildErrorString(msg, red, green, blue, alpha);
104     }
105 
verifyChannel(String channelName, Color expected, Color observed, float tolerance, Function<Color, Float> f)106     private static String verifyChannel(String channelName, Color expected, Color observed,
107             float tolerance, Function<Color, Float> f) {
108         float e = f.apply(expected);
109         float o = f.apply(observed);
110         float diff = Math.abs(e - o);
111         if (diff <= tolerance) {
112             return null;
113         }
114         return "Channel " + channelName + " mismatch: expected<" + e + ">, observed: <" + o
115             + ">, difference: <" + diff + ">";
116     }
117 }
118