Path: blob/master/test/jdk/java/nio/file/Files/Mismatch.java
41153 views
/*1* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import org.testng.Assert;24import org.testng.annotations.AfterClass;25import org.testng.annotations.BeforeClass;26import org.testng.annotations.DataProvider;27import org.testng.annotations.Test;2829import java.io.File;30import java.io.IOException;31import java.nio.charset.StandardCharsets;32import java.nio.file.FileSystem;33import java.nio.file.Files;34import java.nio.file.Path;35import java.nio.file.Paths;36import java.nio.file.spi.FileSystemProvider;37import java.util.Map;3839import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;4041/* @test42* @bug 820228543* @build Mismatch44* @run testng Mismatch45* @summary Unit test for the Files.mismatch method.46*/47public class Mismatch {48// the standard buffer size49final static int BUFFER_SIZE = 8192;5051private static final int MISMATCH_NO = -1;5253// Map to be used for creating a ZIP archive54private static final Map<String, String> ZIPFS_MAP = Map.of("create", "true");5556// temporary test directory where all test files will be created57Path testDir;5859@BeforeClass60void setup() throws IOException {61testDir = Files.createTempDirectory("testMismatch");62}6364@AfterClass65void cleanup() throws IOException {66// clean up files created under the test directory67Files.walk(testDir).map(Path::toFile).forEach(File::delete);68Files.deleteIfExists(testDir);69}7071/*72* DataProvider for mismatch test. Provides the following fields:73* path1 -- the path to a file74* path2 -- the path to another file75* expected -- expected result of the mismatch method76* note -- a note about the test77*/78@DataProvider(name = "testMismatch")79public Object[][] getDataForMismatch() throws IOException {80// an non-existent file81Path foo = Paths.get("nonexistentfile");8283/**84* File path naming convention:85* "test" + file size + [abm] [+ position of a modified char] + [ab]86* where:87* a or b -- is used to differentiate two files of the same size.88* m -- indicates the file is modified at the position specified after it89*/9091// create empty files92int size = 0;93Path test0a = createASCIIFile(testDir, "test0a", 0, -1, ' ');94Path test0b = createASCIIFile(testDir, "test0b", 0, -1, ' ');9596/**97* Since the Impl uses a standard buffer of 8192, the test files are created98* with sizes <= and > 8192, either multiples of the buffer size, or random.99* The files are then altered at the begining (0), end (size), and a random100* position.101*/102size = 147;103Path test147a = createASCIIFile(testDir, "test147a", size, -1, ' ');104Path test147b = createASCIIFile(testDir, "test147b", size, -1, ' ');105Path test147m0 = createASCIIFile(testDir, "test147m0", size, 0, '!');106Path test147m70 = createASCIIFile(testDir, "test147m70", size, 70, '@');107Path test147m146 = createASCIIFile(testDir, "test147m146", size, size - 1, '$');108109size = 1024;110Path test1024a = createASCIIFile(testDir, "test1024a", size, -1, ' ');111Path test1024b = createASCIIFile(testDir, "test1024b", size, -1, ' ');112Path test1024m512 = createASCIIFile(testDir, "test1024m512", size, size >> 1, '@');113Path test1024m1023 = createASCIIFile(testDir, "test1024m1023", size, size - 1, '$');114115size = BUFFER_SIZE;116Path test8192a = createASCIIFile(testDir, "test8192a", size, -1, ' ');117Path test8192b = createASCIIFile(testDir, "test8192b", size, -1, ' ');118Path test8192m4096 = createASCIIFile(testDir, "test8192m4096", size, size >> 1, '%');119Path test8192m8191 = createASCIIFile(testDir, "test8192m8191", size, size - 1, '$');120121122// create files with size several times > BUFFER_SIZE to be used for tests that verify123// the situations where they are read into full buffers a few times124size = BUFFER_SIZE << 3;125Path test65536a = createASCIIFile(testDir, "test65536a", size, -1, ' ');126Path test65536b = createASCIIFile(testDir, "test65536b", size, -1, ' ');127Path test65536m0 = createASCIIFile(testDir, "test65536m0", size, 0, '!');128Path test65536m32768 = createASCIIFile(testDir, "test65536m32768", size, size >> 1, '%');129Path test65536m65535 = createASCIIFile(testDir, "test65536m65535", size, size - 1, '$');130131// create files with sizes that will be iterated several times with full buffers, and132// then a partial one at the last133size = 70025;134Path test70025a = createASCIIFile(testDir, "test70025a", size, -1, ' ');135Path test70025b = createASCIIFile(testDir, "test70025b", size, -1, ' ');136Path test70025m8400 = createASCIIFile(testDir, "test70025m8400", size, 8400, '@');137Path test70025m35000 = createASCIIFile(testDir, "test70025m35000", size, 35000, '%');138Path test70025m70024 = createASCIIFile(testDir, "test70025m70024", size, 70024, '$');139140// create larger files with >= 1048576. The mismatching will be similar. These are just141// tests to exercise the process with larger files142size = 1048576;143Path test1048576a = createASCIIFile(testDir, "test1048576a", size, -1, ' ');144145size = 1065000;146Path test1065000m532500 = createASCIIFile(testDir, "test1065000m532500", size, size >> 1, '%');147Path test1065000m1064999 = createASCIIFile(testDir, "test1065000m1064999", size, 1064999, '$');148149return new Object[][]{150// Spec Case 1: the two paths locate the same file , even if one does not exist151{foo, foo, MISMATCH_NO, "Same file, no mismatch"},152{test1024a, test1024a, MISMATCH_NO, "Same file, no mismatch"},153154// Spec Case 2: The two files are the same size, and every byte in the first file155// is identical to the corresponding byte in the second file.156{test0a, test0b, MISMATCH_NO, "Sizes == 0, no mismatch"},157{test147a, test147b, MISMATCH_NO, "size = 147 < buffer = 8192, no mismatch"},158{test1024a, test1024b, MISMATCH_NO, "size = 1024 < buffer = 8192, no mismatch"},159{test8192a, test8192b, MISMATCH_NO, "size = 8192 = buffer = 8192, no mismatch"},160{test65536a, test65536b, MISMATCH_NO, "read 8 * full buffer, no mismatch"},161{test70025a, test70025b, MISMATCH_NO, "read 8 * full buffer plus a partial buffer, no mismatch"},162163164/**165* Spec Case 3: the value returned is the position of the first mismatched byte166* Impl: the impl uses a buffer 8192. The testcases below covers a range of files167* with sizes <= and > the buffer size. The last buffer is either full or partially full.168*/169170// edge case, one of the file sizes is zero171// also covers Spec Case 4 and 6172{test147a, test147m0, 0, "mismatch = 0 (at the beginning)"},173{test65536m0, test65536a, 0, "mismatch = 0 (at the beginning)"},174175/**176* Compares files of equal sizes177*/178// small files179{test147a, test147m70, 70, "read one partial buffer, mismatch = 70"},180{test147a, test147m146, 146, "read one partial buffer, mismatch = 146 (end)"},181{test1024a, test1024m512, 512, "read one partial buffer, mismatch = 512"},182{test1024a, test1024m1023, 1023, "read one partial buffer, mismatch = 1023 (end)"},183184// file size >= Impl's Buffer Size185{test8192a, test8192m4096, 4096, "read one buffer, mismatch = 4096 "},186{test8192a, test8192m8191, 8191, "read one buffer, mismatch = 8191 (at the end)"},187188// file size = n * Impl's Buffer Size189{test65536a, test65536m32768, 32768, "read through half of the file, mismatch = 32768"},190{test65536a, test65536m65535, 65535, "read through the whole file, mismatch = 65535 (at the end)"},191192// file size = n * Impl's Buffer Size + x193{test70025a, test70025m8400, 8400, "mismatch in the 2nd buffer, mismatch = 8400"},194{test70025a, test70025m35000, 35000, "read about half of the file, mismatch = 35000"},195{test70025a, test70025m70024, 70024, "read through the whole file, mismatch = 70024 (at the end)"},196197/**198* Compares files of unequal sizes199*/200{test8192m8191, test70025m35000, 8191, "mismatch at the end of the 1st file/buffer, mismatch = 8191"},201{test65536m32768, test70025m8400, 8400, "mismatch in the 2nd buffer, mismatch = 8400"},202{test70025m70024, test1065000m532500, 70024, "mismatch at the end of the 1st file, mismatch = 70024"},203204/**205* Spec Case 4: returns the size of the smaller file (in bytes) when the files are206* different sizes and every byte of the smaller file is identical to the corresponding207* byte of the larger file.208* Impl: similar to case 3, covers a range of file sizes209*/210{test147a, test1024a, 147, "mismatch is the length of the smaller file: 147"},211{test1024a, test8192a, 1024, "mismatch is the length of the smaller file: 1024"},212{test1024a, test65536a, 1024, "mismatch is the length of the smaller file: 1024"},213{test8192a, test65536a, 8192, "mismatch is the length of the smaller file: 8192"},214{test70025a, test65536a, 65536, "mismatch is the length of the smaller file: 65536"},215{test1048576a, test1065000m1064999, 1048576, "mismatch is the length of the smaller file: 1048576"},216217// Spec Case 5: This method is always reflexive (for Path f , mismatch(f,f) returns -1L)218// See tests for Spec Case 1.219220// Spec Case 6: If the file system and files remain static, then this method is symmetric221// (for two Paths f and g, mismatch(f,g) will return the same value as mismatch(g,f)).222// The following tests are selected from tests for Spec Case 3 with the order of223// file paths switched, the returned values are the same as those for Case 3:224{test147m70, test147a, 70, "read one partial buffer, mismatch = 70"},225{test147m146, test147a, 146, "read one partial buffer, mismatch = 146 (end)"},226{test1024m512, test1024a, 512, "read one partial buffer, mismatch = 512"},227{test1024m1023, test1024a, 1023, "read one partial buffer, mismatch = 1023 (end)"},228229{test70025m35000, test8192m8191, 8191, "mismatch at the end of the 1st file/buffer, mismatch = 8191"},230{test70025m8400, test65536m32768, 8400, "mismatch in the 2nd buffer, mismatch = 8400"},231{test1065000m532500, test70025m70024, 70024, "mismatch at the end of the 1st file, mismatch = 70024"},232};233}234235/*236* DataProvider for mismatch tests involving ZipFS using a few test cases selected237* from those of the original mismatch tests.238*/239@DataProvider(name = "testMismatchZipfs")240public Object[][] getDataForMismatchZipfs() throws IOException {241Path test1200 = createASCIIFile(testDir, "test1200", 1200, -1, ' ');242Path test9500 = createASCIIFile(testDir, "test9500", 9500, -1, ' ');243Path test9500m4200 = createASCIIFile(testDir, "test9500m4200", 9500, 4200, '!');244Path test80025 = createASCIIFile(testDir, "test80025", 80025, -1, ' ');245Path test1028500 = createASCIIFile(testDir, "test1028500", 1028500, -1, ' ');246return new Object[][]{247{test1200, test1200, MISMATCH_NO, "Compares the file and its copy in zip, no mismatch"},248{test9500, test9500m4200, 4200,249"Compares a copy of test9500m4200 in zip with test9500, shall return 4200"},250{test80025, test1028500, 80025, "mismatch is the length of the smaller file: 80025"},251};252}253254/*255* DataProvider for verifying null handling.256*/257@DataProvider(name = "testFileNull")258public Object[][] getDataForNull() throws IOException {259Path test = createASCIIFile(testDir, "testNonNull", 2200, -1, ' ');260return new Object[][]{261{(Path)null, (Path)null},262{(Path)null, test},263{test, (Path)null},264};265}266267/*268* DataProvider for verifying how the mismatch method handles the situation269* when one or both files do not exist.270*/271@DataProvider(name = "testFileNotExist")272public Object[][] getDataForFileNotExist() throws IOException {273Path test = createASCIIFile(testDir, "testFileNotExist", 3200, -1, ' ');274return new Object[][]{275{Paths.get("foo"), Paths.get("bar")},276{Paths.get("foo"), test},277{test, Paths.get("bar")},278};279}280281/**282* Tests the mismatch method. Refer to the dataProvider testMismatch for more283* details about the cases.284* @param path the path to a file285* @param path2 the path to another file286* @param expected the expected result287* @param msg the message about the test288* @throws IOException if the test fails289*/290@Test(dataProvider = "testMismatch", priority = 0)291public void testMismatch(Path path, Path path2, long expected, String msg)292throws IOException {293Assert.assertEquals(Files.mismatch(path, path2), expected, msg);294}295296/**297* Tests the mismatch method by comparing files with those in a ZIP file.298* @param path the path to a file299* @param path2 the path to another file to be added into a ZIP file300* @param expected the expected result301* @param msg the message about the test302* @throws IOException if the test fails303*/304@Test(dataProvider = "testMismatchZipfs", priority = 1)305public void testMismatchZipfs(Path path, Path path2, long expected, String msg)306throws IOException {307Path zipPath = Paths.get(testDir.toString(), "TestWithFSZip.zip");308try (FileSystem fs = getZipFSProvider().newFileSystem(zipPath, ZIPFS_MAP)) {309Path copy = fs.getPath(path.getFileName().toString());310Files.copy(path, copy, REPLACE_EXISTING);311312if (path2 == null) {313Assert.assertEquals(Files.mismatch(copy, path), expected, msg);314} else {315Assert.assertEquals(Files.mismatch(copy, path2), expected, msg);316}317}318}319320/**321* Verifies that NullPointerException is thrown when one or both files are null.322* @param path the path to a file323* @param path2 the path to another file324* @throws NullPointerException as expected325*/326@Test(dataProvider = "testFileNull", priority = 2, expectedExceptions = NullPointerException.class)327public void testMismatchNull(Path path, Path path2) throws Exception {328long result = Files.mismatch(path, path2);329}330331/**332* Verifies that IOException is thrown when one or both files do not exist.333* @param path the path to a file334* @param path2 the path to another file335* @throws IOException as expected336*/337@Test(dataProvider = "testFileNotExist", priority = 2, expectedExceptions = IOException.class)338public void testMismatchNotExist(Path path, Path path2) throws IOException {339long result = Files.mismatch(path, path2);340}341342/**343* Creates a file with ASCII content with one character altered344* at the specified position.345*346* Note: Files.mismatch method does a byte-by-byte comparison. ASCII files347* are sufficient for verifying the feature.348*349* @param dir the directory in which the file is to be created350* @param purpose the purpose of the file351* @param size the size of the file352* @param pos the position where the alternative char is to be added. If it353* is smaller than zero, no alternation shall be made.354* @param c the character355* @return path of the created file356* @throws IOException357*/358private static Path createASCIIFile(Path dir, String purpose, int size, int pos,359char c) throws IOException {360Path path = Files.createFile(Paths.get(dir.toString(), purpose + ".txt"));361if (size > 0) {362writeASCIIFile(path, size, pos, c);363}364return path;365}366367private static void writeASCIIFile(Path path, int size, int pos, char c)368throws IOException {369byte[] a = createASCIIArray(size);370if (pos >= 0) a[pos] = (byte)(c & 0xFF); // US_ASCII char only, may cast directly371Files.write(path, a);372}373374private static byte[] createASCIIArray(int length) {375byte[] bytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 \n"376.getBytes(StandardCharsets.US_ASCII);377byte[] a = new byte[length];378fillArray(bytes, a);379return a;380}381382private static FileSystemProvider getZipFSProvider() {383for (FileSystemProvider provider : FileSystemProvider.installedProviders()) {384if ("jar".equals(provider.getScheme())) {385return provider;386}387}388return null;389}390391/**392* Fills the destination array by copying the source array repeatedly until393* it is completely filled.394*395* @param src the source array396* @param dest the destination array397*/398public static void fillArray(byte[] src, byte[] dest) {399int bLen = src.length;400int space = dest.length;401int iteration = 0;402403while (space > 0) {404if (space >= bLen) {405System.arraycopy(src, 0, dest, iteration++ * bLen, bLen);406space -= bLen;407} else {408System.arraycopy(src, 0, dest, iteration++ * bLen, space);409break;410}411}412}413}414415416