1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 /* 3 * Copyright (C) 2019 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package tests.util; 19 20 import static org.junit.Assert.fail; 21 22 import java.io.ByteArrayOutputStream; 23 import java.io.PrintStream; 24 import java.security.Provider; 25 import java.security.Security; 26 import java.util.Arrays; 27 import java.util.Collection; 28 import java.util.HashSet; 29 import java.util.LinkedHashSet; 30 import java.util.Set; 31 32 /** 33 * A utility for testing all the implementations of a particular service (such as MessageDigest or 34 * KeyGenerator). 35 * <p> 36 * An instance of this class may only be used to run one test. 37 * @hide This class is not part of the Android public SDK API 38 */ 39 public final class ServiceTester { 40 41 /** 42 * @hide This class is not part of the Android public SDK API 43 */ 44 public interface Test { 45 /** 46 * Run the test for the given provider and algorithm. This method should throw an exception 47 * if the test fails or do nothing if it passes. 48 */ test(Provider p, String algorithm)49 void test(Provider p, String algorithm) throws Exception; 50 } 51 52 private static final String SEPARATOR = "||"; 53 private final String service; 54 private final Set<Provider> providers = new LinkedHashSet<>(); 55 private final Set<Provider> skipProviders = new HashSet<>(); 56 private final Set<String> algorithms = new LinkedHashSet<>(); 57 private final Set<String> skipAlgorithms = new HashSet<>(); 58 private final Set<String> skipCombinations = new HashSet<>(); 59 ServiceTester(String service)60 private ServiceTester(String service) { 61 this.service = service; 62 } 63 64 /** 65 * Create a new ServiceTester for the given service. 66 */ test(String service)67 public static ServiceTester test(String service) { 68 if (service.equalsIgnoreCase("Cipher")) { 69 // Cipher is complicated because the parameterized transformations mean that you have 70 // to check for a lot of combinations (eg, a test for AES/CBC/NoPadding might be satisfied by 71 // a provider providing AES, AES/CBC, AES//NoPadding, or AES/CBC/NoPadding). We don't 72 // really need it, so we haven't implemented it. 73 throw new IllegalArgumentException("ServiceTester doesn't support Cipher"); 74 } 75 return new ServiceTester(service); 76 } 77 78 /** 79 * Specifies the list of providers to test. If this method is called multiple times, the 80 * collections are combined. If this method is never called, this will test all installed 81 * providers. 82 * 83 * @throws IllegalArgumentException if a named provider is not installed 84 */ withProviders(Collection<String> providers)85 public ServiceTester withProviders(Collection<String> providers) { 86 for (String name : providers) { 87 Provider p = Security.getProvider(name); 88 if (p == null) { 89 throw new IllegalArgumentException("No such provider: " + name); 90 } 91 this.providers.add(p); 92 } 93 return this; 94 } 95 96 /** 97 * Causes the given provider to be omitted from this instance's testing. If the given provider 98 * is not installed, does nothing. 99 */ skipProvider(String provider)100 public ServiceTester skipProvider(String provider) { 101 Provider p = Security.getProvider(provider); 102 if (p != null) { 103 skipProviders.add(p); 104 } 105 return this; 106 } 107 108 /** 109 * Specifies the algorithm to test. If this method and/or {@link #withAlgorithms(Collection)}} 110 * are called multiple times, all values are combined. If neither method is called, this will 111 * test all algorithms supported by any tested provider. 112 */ withAlgorithm(String algorithm)113 public ServiceTester withAlgorithm(String algorithm) { 114 this.algorithms.add(algorithm); 115 return this; 116 } 117 118 /** 119 * Specifies the algorithms to test. If this method and/or {@link #withAlgorithm(String)}} 120 * are called multiple times, all values are combined. If neither method is called, this will 121 * test all algorithms supported by any tested provider. 122 */ withAlgorithms(Collection<String> algorithms)123 public ServiceTester withAlgorithms(Collection<String> algorithms) { 124 this.algorithms.addAll(algorithms); 125 return this; 126 } 127 128 /** 129 * Causes the given algorithm to be omitted from this instance's testing. If no tested provider 130 * provides the given algorithm, does nothing. 131 */ skipAlgorithm(String algorithm)132 public ServiceTester skipAlgorithm(String algorithm) { 133 skipAlgorithms.add(algorithm); 134 return this; 135 } 136 137 /** 138 * Causes the given combination of provider and algorithm to be omitted from this instance's 139 * testing. If no tested provider provides the given algorithm, does nothing. 140 */ skipCombination(String provider, String algorithm)141 public ServiceTester skipCombination(String provider, String algorithm) { 142 Provider p = Security.getProvider(provider); 143 if (p != null) { 144 skipCombinations.add(makeCombination(provider, algorithm)); 145 } 146 return this; 147 } 148 149 /** 150 * Runs the given test against the configured combination of providers and algorithms. Continues 151 * running all combinations even if some fail. If any of the test runs fail, this throws 152 * an exception with the details of the failure(s). 153 */ run(Test test)154 public void run(Test test) { 155 if (providers.isEmpty()) { 156 providers.addAll(Arrays.asList(Security.getProviders())); 157 } 158 providers.removeAll(skipProviders); 159 final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream(); 160 PrintStream errors = new PrintStream(errBuffer); 161 for (Provider p : providers) { 162 if (algorithms.isEmpty()) { 163 for (Provider.Service s : p.getServices()) { 164 if (s.getType().equals(service) && !skipAlgorithms.contains(s.getAlgorithm()) 165 && !shouldSkipCombination(p.getName(), s.getAlgorithm())) { 166 doTest(test, p, s.getAlgorithm(), errors); 167 } 168 } 169 } else { 170 algorithms.removeAll(skipAlgorithms); 171 for (String algorithm : algorithms) { 172 if (p.getService(service, algorithm) != null 173 && !shouldSkipCombination(p.getName(), algorithm)) { 174 doTest(test, p, algorithm, errors); 175 } 176 } 177 } 178 } 179 errors.flush(); 180 if (errBuffer.size() > 0) { 181 fail("Tests failed:\n\n" + errBuffer.toString()); 182 } 183 } 184 makeCombination(String provider, String algorithm)185 private String makeCombination(String provider, String algorithm) { 186 return provider + SEPARATOR + algorithm; 187 } 188 shouldSkipCombination(String provider, String algorithm)189 private boolean shouldSkipCombination(String provider, String algorithm) { 190 return skipCombinations.contains(makeCombination(provider, algorithm)); 191 } 192 doTest(Test test, Provider p, String algorithm, PrintStream errors)193 private void doTest(Test test, Provider p, String algorithm, PrintStream errors) { 194 try { 195 test.test(p, algorithm); 196 } catch (Exception | AssertionError e) { 197 errors.append("Failure testing " + service + ":" + algorithm + " from provider " 198 + p.getName() + ":\n"); 199 e.printStackTrace(errors); 200 } 201 } 202 203 } 204