1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.incubator.jpackage.internal; 26 27 import java.io.*; 28 import java.nio.charset.StandardCharsets; 29 import java.nio.file.Files; 30 import java.nio.file.Path; 31 import java.util.HashMap; 32 import java.util.Iterator; 33 import java.util.List; 34 import java.util.Map; 35 import jdk.incubator.jpackage.internal.resources.ResourceLocator; 36 import static org.hamcrest.CoreMatchers.is; 37 import static org.hamcrest.CoreMatchers.not; 38 import static org.junit.Assert.*; 39 import org.junit.Rule; 40 import org.junit.Test; 41 import org.junit.rules.TemporaryFolder; 42 43 public class OverridableResourceTest { 44 45 @Rule 46 public final TemporaryFolder tempFolder = new TemporaryFolder(); 47 48 @Test 49 public void testDefault() throws IOException { 50 byte[] actualBytes = saveToFile(new OverridableResource(DEFAULT_NAME)); 51 52 try (InputStream is = ResourceLocator.class.getResourceAsStream( 53 DEFAULT_NAME)) { 54 assertArrayEquals(is.readAllBytes(), actualBytes); 55 } 56 } 57 58 @Test 59 public void testDefaultWithSubstitution() throws IOException { 60 OverridableResource resource = new OverridableResource(DEFAULT_NAME); 61 62 List<String> linesBeforeSubstitution = convertToStringList(saveToFile( 63 resource)); 64 65 if (SUBSTITUTION_DATA.size() != 1) { 66 // Test setup issue 67 throw new IllegalArgumentException( 68 "Substitution map should contain only a single entry"); 69 } 70 71 resource.setSubstitutionData(SUBSTITUTION_DATA); 72 List<String> linesAfterSubstitution = convertToStringList(saveToFile( 73 resource)); 74 75 assertEquals(linesBeforeSubstitution.size(), linesAfterSubstitution.size()); 76 77 Iterator<String> beforeIt = linesBeforeSubstitution.iterator(); 78 Iterator<String> afterIt = linesAfterSubstitution.iterator(); 79 80 var substitutionEntry = SUBSTITUTION_DATA.entrySet().iterator().next(); 81 82 boolean linesMismatch = false; 83 while (beforeIt.hasNext()) { 84 String beforeStr = beforeIt.next(); 85 String afterStr = afterIt.next(); 86 87 if (beforeStr.equals(afterStr)) { 88 assertFalse(beforeStr.contains(substitutionEntry.getKey())); 89 } else { 90 linesMismatch = true; 91 assertTrue(beforeStr.contains(substitutionEntry.getKey())); 92 assertTrue(afterStr.contains(substitutionEntry.getValue())); 93 assertFalse(afterStr.contains(substitutionEntry.getKey())); 94 } 95 } 96 97 assertTrue(linesMismatch); 98 } 99 100 @Test 101 public void testCustom() throws IOException { 102 testCustom(DEFAULT_NAME); 103 } 104 105 @Test 106 public void testCustomNoDefault() throws IOException { 107 testCustom(null); 108 } 109 110 private void testCustom(String defaultName) throws IOException { 111 List<String> expectedResourceData = List.of("A", "B", "C"); 112 113 Path customFile = createCustomFile("foo", expectedResourceData); 114 115 List<String> actualResourceData = convertToStringList(saveToFile( 116 new OverridableResource(defaultName) 117 .setPublicName(customFile.getFileName()) 118 .setResourceDir(customFile.getParent()))); 119 120 assertArrayEquals(expectedResourceData.toArray(String[]::new), 121 actualResourceData.toArray(String[]::new)); 122 } 123 124 @Test 125 public void testCustomtWithSubstitution() throws IOException { 126 testCustomtWithSubstitution(DEFAULT_NAME); 127 } 128 129 @Test 130 public void testCustomtWithSubstitutionNoDefault() throws IOException { 131 testCustomtWithSubstitution(null); 132 } 133 134 private void testCustomtWithSubstitution(String defaultName) throws IOException { 135 final List<String> resourceData = List.of("A", "[BB]", "C", "Foo", 136 "GoodbyeHello"); 137 final Path customFile = createCustomFile("foo", resourceData); 138 139 final Map<String, String> substitutionData = new HashMap(Map.of("B", 140 "Bar", "Foo", "B")); 141 substitutionData.put("Hello", null); 142 143 final List<String> expectedResourceData = List.of("A", "[BarBar]", "C", 144 "B", "Goodbye"); 145 146 final List<String> actualResourceData = convertToStringList(saveToFile( 147 new OverridableResource(defaultName) 148 .setPublicName(customFile.getFileName()) 149 .setSubstitutionData(substitutionData) 150 .setResourceDir(customFile.getParent()))); 151 assertArrayEquals(expectedResourceData.toArray(String[]::new), 152 actualResourceData.toArray(String[]::new)); 153 154 // Don't call setPublicName() 155 final Path dstFile = tempFolder.newFolder().toPath().resolve(customFile.getFileName()); 156 new OverridableResource(defaultName) 157 .setSubstitutionData(substitutionData) 158 .setResourceDir(customFile.getParent()) 159 .saveToFile(dstFile); 160 assertArrayEquals(expectedResourceData.toArray(String[]::new), 161 convertToStringList(Files.readAllBytes(dstFile)).toArray( 162 String[]::new)); 163 164 // Verify setSubstitutionData() stores a copy of passed in data 165 Map<String, String> substitutionData2 = new HashMap(substitutionData); 166 var resource = new OverridableResource(defaultName) 167 .setResourceDir(customFile.getParent()); 168 169 resource.setSubstitutionData(substitutionData2); 170 substitutionData2.clear(); 171 Files.delete(dstFile); 172 resource.saveToFile(dstFile); 173 assertArrayEquals(expectedResourceData.toArray(String[]::new), 174 convertToStringList(Files.readAllBytes(dstFile)).toArray( 175 String[]::new)); 176 } 177 178 @Test 179 public void testNoDefault() throws IOException { 180 Path dstFolder = tempFolder.newFolder().toPath(); 181 Path dstFile = dstFolder.resolve(Path.of("foo", "bar")); 182 183 new OverridableResource(null).saveToFile(dstFile); 184 185 assertFalse(dstFile.toFile().exists()); 186 } 187 188 private final static String DEFAULT_NAME; 189 private final static Map<String, String> SUBSTITUTION_DATA; 190 static { 191 if (Platform.isWindows()) { 192 DEFAULT_NAME = "WinLauncher.template"; 193 SUBSTITUTION_DATA = Map.of("COMPANY_NAME", "Foo9090345"); 194 } else if (Platform.isLinux()) { 195 DEFAULT_NAME = "template.control"; 196 SUBSTITUTION_DATA = Map.of("APPLICATION_PACKAGE", "Package1967"); 197 } else if (Platform.isMac()) { 198 DEFAULT_NAME = "Info-lite.plist.template"; 199 SUBSTITUTION_DATA = Map.of("DEPLOY_BUNDLE_IDENTIFIER", "12345"); 200 } else { 201 throw Platform.throwUnknownPlatformError(); 202 } 203 } 204 205 private byte[] saveToFile(OverridableResource resource) throws IOException { 206 Path dstFile = tempFolder.newFile().toPath(); 207 resource.saveToFile(dstFile); 208 assertThat(0, is(not(dstFile.toFile().length()))); 209 210 return Files.readAllBytes(dstFile); 211 } 212 213 private Path createCustomFile(String publicName, List<String> data) throws 214 IOException { 215 Path resourceFolder = tempFolder.newFolder().toPath(); 216 Path customFile = resourceFolder.resolve(publicName); 217 218 Files.write(customFile, data); 219 220 return customFile; 221 } 222 223 private static List<String> convertToStringList(byte[] data) { 224 return List.of(new String(data, StandardCharsets.UTF_8).split("\\R")); 225 } 226 }