From 48b0af54ccabf715f1ead0a5c281984bbdc04237 Mon Sep 17 00:00:00 2001 From: Benoit Lamarche Date: Thu, 4 Jun 2015 16:29:21 +0200 Subject: Adapt ResourceTests to support CaseInsesitiveFS Bug: 21486756 Change-Id: I3f0e0b7d6a2511b08129bff4bc34a0ba54aead4e (cherry picked from commit 973a373d8fc030c0ea3e8f6113caa29be3776454) --- .../com/android/jack/classpath/ClasspathTests.java | 2 +- .../com/android/jack/resource/ResourceTests.java | 234 ++++++++++++--------- .../com/android/jack/resource/test003/jack/A.txt | 11 - .../rsc/com/android/jack/resource/test003/jack/A | 11 + .../com/android/jack/resource/test003/jack/A.txt | 11 + 5 files changed, 159 insertions(+), 110 deletions(-) delete mode 100644 jack-tests/tests/com/android/jack/resource/test003/jack/A.txt create mode 100644 jack-tests/tests/com/android/jack/resource/test003/jack/rsc/com/android/jack/resource/test003/jack/A create mode 100644 jack-tests/tests/com/android/jack/resource/test003/jack/rsc/com/android/jack/resource/test003/jack/A.txt (limited to 'jack-tests/tests') diff --git a/jack-tests/tests/com/android/jack/classpath/ClasspathTests.java b/jack-tests/tests/com/android/jack/classpath/ClasspathTests.java index e570611..c69991d 100644 --- a/jack-tests/tests/com/android/jack/classpath/ClasspathTests.java +++ b/jack-tests/tests/com/android/jack/classpath/ClasspathTests.java @@ -128,7 +128,7 @@ public class ClasspathTests { { // delete unused inner in classpath and check we can still compile with it - InputJackLibrary lib = AbstractTestTools.getInputJackLibraryFromDir(libOut); + InputJackLibrary lib = AbstractTestTools.getInputJackLibrary(libOut); lib.getFile(FileType.JAYCE, new VPath("com/android/jack/classpath/test003/lib/HasInnersClasses$InnerToDelete", '/')) .delete(); diff --git a/jack-tests/tests/com/android/jack/resource/ResourceTests.java b/jack-tests/tests/com/android/jack/resource/ResourceTests.java index d0e8220..7098d91 100644 --- a/jack-tests/tests/com/android/jack/resource/ResourceTests.java +++ b/jack-tests/tests/com/android/jack/resource/ResourceTests.java @@ -17,23 +17,24 @@ package com.android.jack.resource; import com.android.jack.library.FileType; +import com.android.jack.library.FileTypeDoesNotExistException; +import com.android.jack.library.InputJackLibrary; import com.android.jack.shrob.obfuscation.NameProviderFactory; import com.android.jack.test.category.KnownBugs; import com.android.jack.test.toolchain.AbstractTestTools; import com.android.jack.test.toolchain.JackBasedToolchain; -import com.android.sched.util.stream.ByteStreamSucker; +import com.android.sched.vfs.InputVFile; +import com.android.sched.vfs.VPath; import junit.framework.Assert; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -85,10 +86,10 @@ public class ResourceTests { toolchain.libToExe(jackAr, dexDir, /* zipFile = */ false); // check that resources are contained in dex dir - checkResourceContentFromDir(dexDir, RESOURCE1_SHORTPATH, "Res1", /*isLib*/ false); - checkResourceContentFromDir(dexDir, RESOURCE2_SHORTPATH, "Res2", /*isLib*/ false); - checkResourceContentFromDir(dexDir, RESOURCE3_SHORTPATH, "Res3", /*isLib*/ false); - checkResourceContentFromDir(dexDir, RESOURCE4_SHORTPATH, "Res4", /*isLib*/ false); + checkResourceContentFromDir(dexDir, RESOURCE1_SHORTPATH, "Res1"); + checkResourceContentFromDir(dexDir, RESOURCE2_SHORTPATH, "Res2"); + checkResourceContentFromDir(dexDir, RESOURCE3_SHORTPATH, "Res3"); + checkResourceContentFromDir(dexDir, RESOURCE4_SHORTPATH, "Res4"); } @Test @@ -103,10 +104,10 @@ public class ResourceTests { // check that resources are contained in dex archive ZipFile zipFile = new ZipFile(dexAr); - checkResourceContentFromZip(zipFile, RESOURCE1_SHORTPATH, "Res1", /*isLib*/ false); - checkResourceContentFromZip(zipFile, RESOURCE2_SHORTPATH, "Res2", /*isLib*/ false); - checkResourceContentFromZip(zipFile, RESOURCE3_SHORTPATH, "Res3", /*isLib*/ false); - checkResourceContentFromZip(zipFile, RESOURCE4_SHORTPATH, "Res4", /*isLib*/ false); + checkResourceContentFromZip(zipFile, RESOURCE1_SHORTPATH, "Res1"); + checkResourceContentFromZip(zipFile, RESOURCE2_SHORTPATH, "Res2"); + checkResourceContentFromZip(zipFile, RESOURCE3_SHORTPATH, "Res3"); + checkResourceContentFromZip(zipFile, RESOURCE4_SHORTPATH, "Res4"); } @Test @@ -128,10 +129,10 @@ public class ResourceTests { // check that resources are contained in dex archive ZipFile zipFile = new ZipFile(dexAr); - checkResourceContentFromZip(zipFile, RESOURCE1_SHORTPATH, "Res1", /*isLib*/ false); - checkResourceContentFromZip(zipFile, RESOURCE2_SHORTPATH, "Res2", /*isLib*/ false); - checkResourceContentFromZip(zipFile, RESOURCE3_SHORTPATH, "Res3", /*isLib*/ false); - checkResourceContentFromZip(zipFile, RESOURCE4_SHORTPATH, "Res4", /*isLib*/ false); + checkResourceContentFromZip(zipFile, RESOURCE1_SHORTPATH, "Res1"); + checkResourceContentFromZip(zipFile, RESOURCE2_SHORTPATH, "Res2"); + checkResourceContentFromZip(zipFile, RESOURCE3_SHORTPATH, "Res3"); + checkResourceContentFromZip(zipFile, RESOURCE4_SHORTPATH, "Res4"); } @Test @@ -148,11 +149,18 @@ public class ResourceTests { toolchain.libToLib(jackAr, shrobbedJackAr, /* zipFiles = */ true); // check that resources are contained in dex archive - ZipFile zipFile = new ZipFile(shrobbedJackAr); - checkResourceContentFromZip(zipFile, RESOURCE1_SHORTPATH, "Res1", /*isLib*/ true); - checkResourceContentFromZip(zipFile, RESOURCE2_SHORTPATH, "Res2", /*isLib*/ true); - checkResourceContentFromZip(zipFile, RESOURCE3_SHORTPATH, "Res3", /*isLib*/ true); - checkResourceContentFromZip(zipFile, RESOURCE4_SHORTPATH, "Res4", /*isLib*/ true); + InputJackLibrary shrobbedLib = null; + try { + shrobbedLib = AbstractTestTools.getInputJackLibrary(shrobbedJackAr); + checkResourceContentFromLib(shrobbedLib, RESOURCE1_SHORTPATH, "Res1"); + checkResourceContentFromLib(shrobbedLib, RESOURCE2_SHORTPATH, "Res2"); + checkResourceContentFromLib(shrobbedLib, RESOURCE3_SHORTPATH, "Res3"); + checkResourceContentFromLib(shrobbedLib, RESOURCE4_SHORTPATH, "Res4"); + } finally { + if (shrobbedLib != null) { + shrobbedLib.close(); + } + } } @Test @@ -176,15 +184,21 @@ public class ResourceTests { toolchain.libToLib(jackFolder, shrobbedJackAr, /* zipFiles = */ true); // check that resources are contained in Jack archive - ZipFile zipFile = new ZipFile(shrobbedJackAr); - checkResourceContentFromZip(zipFile, RESOURCE1_SHORTPATH, "Res1", /*isLib*/ true); - checkResourceContentFromZip(zipFile, RESOURCE2_SHORTPATH, "Res2", /*isLib*/ true); - checkResourceContentFromZip(zipFile, RESOURCE3_SHORTPATH, "Res3", /*isLib*/ true); - checkResourceContentFromZip(zipFile, RESOURCE4_SHORTPATH, "Res4", /*isLib*/ true); + InputJackLibrary shrobbedLib = null; + try { + shrobbedLib = AbstractTestTools.getInputJackLibrary(shrobbedJackAr); + checkResourceContentFromLib(shrobbedLib, RESOURCE1_SHORTPATH, "Res1"); + checkResourceContentFromLib(shrobbedLib, RESOURCE2_SHORTPATH, "Res2"); + checkResourceContentFromLib(shrobbedLib, RESOURCE3_SHORTPATH, "Res3"); + checkResourceContentFromLib(shrobbedLib, RESOURCE4_SHORTPATH, "Res4"); + } finally { + if (shrobbedLib != null) { + shrobbedLib.close(); + } + } } @Test - @Ignore public void testJackArchiveToJackDir() throws Exception { // compile source file to a Jack archive and add resources File jackAr = createJackArchiveWithResources(); @@ -197,15 +211,21 @@ public class ResourceTests { toolchain.libToLib(jackAr, shrobbedJackDir, /* zipFiles = */ false); // check that resources are contained in Jack dir - checkResourceContentFromDir(shrobbedJackDir, RESOURCE1_SHORTPATH, "Res1", /*isLib*/ true); - checkResourceContentFromDir(shrobbedJackDir, RESOURCE2_SHORTPATH, "Res2", /*isLib*/ true); - checkResourceContentFromDir(shrobbedJackDir, RESOURCE3_SHORTPATH, "Res3", /*isLib*/ true); - checkResourceContentFromDir(shrobbedJackDir, RESOURCE4_SHORTPATH, "Res4", /*isLib*/ true); - + InputJackLibrary shrobbedLib = null; + try { + shrobbedLib = AbstractTestTools.getInputJackLibrary(shrobbedJackDir); + checkResourceContentFromLib(shrobbedLib, RESOURCE1_SHORTPATH, "Res1"); + checkResourceContentFromLib(shrobbedLib, RESOURCE2_SHORTPATH, "Res2"); + checkResourceContentFromLib(shrobbedLib, RESOURCE3_SHORTPATH, "Res3"); + checkResourceContentFromLib(shrobbedLib, RESOURCE4_SHORTPATH, "Res4"); + } finally { + if (shrobbedLib != null) { + shrobbedLib.close(); + } + } } @Test - @Ignore public void testJackDirToJackDir() throws Exception { // compile source file to a Jack dir File jackFolder = AbstractTestTools.createTempDir(); @@ -225,10 +245,18 @@ public class ResourceTests { toolchain.libToLib(jackFolder, shrobbedJackDir, /* zipFiles = */ false); // check that resources are contained in Jack dir - checkResourceContentFromDir(shrobbedJackDir, RESOURCE1_SHORTPATH, "Res1", /*isLib*/ true); - checkResourceContentFromDir(shrobbedJackDir, RESOURCE2_SHORTPATH, "Res2", /*isLib*/ true); - checkResourceContentFromDir(shrobbedJackDir, RESOURCE3_SHORTPATH, "Res3", /*isLib*/ true); - checkResourceContentFromDir(shrobbedJackDir, RESOURCE4_SHORTPATH, "Res4", /*isLib*/ true); + InputJackLibrary shrobbedLib = null; + try { + shrobbedLib = AbstractTestTools.getInputJackLibrary(shrobbedJackDir); + checkResourceContentFromLib(shrobbedLib, RESOURCE1_SHORTPATH, "Res1"); + checkResourceContentFromLib(shrobbedLib, RESOURCE2_SHORTPATH, "Res2"); + checkResourceContentFromLib(shrobbedLib, RESOURCE3_SHORTPATH, "Res3"); + checkResourceContentFromLib(shrobbedLib, RESOURCE4_SHORTPATH, "Res4"); + } finally { + if (shrobbedLib != null) { + shrobbedLib.close(); + } + } } @Test @@ -249,10 +277,10 @@ public class ResourceTests { toolchain.libToExe(jackFolder, dexDir, /* zipFile = */ false); // check that resources are contained in dex dir - checkResourceContentFromDir(dexDir, RESOURCE1_SHORTPATH, "Res1", /*isLib*/ false); - checkResourceContentFromDir(dexDir, RESOURCE2_SHORTPATH, "Res2", /*isLib*/ false); - checkResourceContentFromDir(dexDir, RESOURCE3_SHORTPATH, "Res3", /*isLib*/ false); - checkResourceContentFromDir(dexDir, RESOURCE4_SHORTPATH, "Res4", /*isLib*/ false); + checkResourceContentFromDir(dexDir, RESOURCE1_SHORTPATH, "Res1"); + checkResourceContentFromDir(dexDir, RESOURCE2_SHORTPATH, "Res2"); + checkResourceContentFromDir(dexDir, RESOURCE3_SHORTPATH, "Res3"); + checkResourceContentFromDir(dexDir, RESOURCE4_SHORTPATH, "Res4"); } @Test @@ -273,10 +301,10 @@ public class ResourceTests { .libToExe(jackFolder, dexDir, /* zipFile = */ false); // check that resources are contained in dex dir - checkResourceContentFromDir(dexDir, RESOURCE1_SHORTPATH, "Res1", /*isLib*/ false); - checkResourceContentFromDir(dexDir, RESOURCE2_SHORTPATH, "Res2", /*isLib*/ false); - checkResourceContentFromDir(dexDir, RESOURCE3_SHORTPATH, "Res3", /*isLib*/ false); - checkResourceContentFromDir(dexDir, RESOURCE4_SHORTPATH, "Res4", /*isLib*/ false); + checkResourceContentFromDir(dexDir, RESOURCE1_SHORTPATH, "Res1"); + checkResourceContentFromDir(dexDir, RESOURCE2_SHORTPATH, "Res2"); + checkResourceContentFromDir(dexDir, RESOURCE3_SHORTPATH, "Res3"); + checkResourceContentFromDir(dexDir, RESOURCE4_SHORTPATH, "Res4"); } @Test @@ -286,20 +314,32 @@ public class ResourceTests { File jackOutputFolder = AbstractTestTools.createTempDir(); //String testName = "resource/test003"; File testFolder = AbstractTestTools.getTestRootDir("com.android.jack.resource.test003"); - File jackTestFolder = AbstractTestTools.getTestRootDir("com.android.jack.resource.test003.jack"); - JackBasedToolchain toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class); - toolchain.addToClasspath(toolchain.getDefaultBootClasspath()) + File jackTestFolder = + AbstractTestTools.getTestRootDir("com.android.jack.resource.test003.jack"); + File rscFolder = new File(jackTestFolder, "rsc"); + String resource1LongPath = "com/android/jack/resource/test003/jack/A"; + String resource2LongPath = "com/android/jack/resource/test003/jack/A.txt"; + JackBasedToolchain toolchain = + AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class); + toolchain.addResource(rscFolder).addToClasspath(toolchain.getDefaultBootClasspath()) .srcToLib( jackOutputFolder, /* zipFiles = */ false, testFolder); - String resource1LongPath = "com/android/jack/resource/test003/jack/A"; - String resource2LongPath = "com/android/jack/resource/test003/jack/A.txt"; - - // add resources to Jack dir - copyFileToDir(new File(jackTestFolder, "A.txt"), resource1LongPath, jackOutputFolder); - copyFileToDir(new File(jackTestFolder, "A.txt"), resource2LongPath, jackOutputFolder); + // check that resources are contained in Jack dir and check their contents + InputJackLibrary lib = null; + try { + lib = AbstractTestTools.getInputJackLibrary(jackOutputFolder); + InputVFile candidateFile1 = lib.getFile(FileType.RSC, new VPath(resource1LongPath, '/')); + InputVFile candidateFile2 = lib.getFile(FileType.RSC, new VPath(resource2LongPath, '/')); + checkResourceContent(candidateFile1, new File(rscFolder, resource1LongPath)); + checkResourceContent(candidateFile2, new File(rscFolder, resource2LongPath)); + } finally { + if (lib != null) { + lib.close(); + } + } toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class); toolchain.addProperty(NameProviderFactory.NAMEPROVIDER.getName(), "rot13"); @@ -308,11 +348,21 @@ public class ResourceTests { toolchain.libToLib(jackOutputFolder, shrobbedJackDir, /* zipFiles = */ false); // check that resources are contained in Jack dir and check their contents - File referenceFileContent = new File(testFolder, "refs/A.txt"); - checkResourceContent(new File(shrobbedJackDir, "pcz/nbqfcvq/wnpx/frgcifpr/hrgh003/wnpx/A"), - referenceFileContent); - checkResourceContent(new File(shrobbedJackDir, "pcz/nbqfcvq/wnpx/frgcifpr/hrgh003/wnpx/N.txt"), - referenceFileContent); + InputJackLibrary shrobbedLib = null; + try { + shrobbedLib = AbstractTestTools.getInputJackLibrary(shrobbedJackDir); + File referenceFile = new File(testFolder, "refs/A.txt"); + InputVFile candidateFile1 = shrobbedLib.getFile(FileType.RSC, + new VPath("pcz/nbqfcvq/wnpx/frgcifpr/hrgh003/wnpx/A", '/')); + InputVFile candidateFile2 = shrobbedLib.getFile(FileType.RSC, + new VPath("pcz/nbqfcvq/wnpx/frgcifpr/hrgh003/wnpx/N.txt", '/')); + checkResourceContent(candidateFile1, referenceFile); + checkResourceContent(candidateFile2, referenceFile); + } finally { + if (shrobbedLib != null) { + shrobbedLib.close(); + } + } } @Nonnull @@ -331,8 +381,8 @@ public class ResourceTests { } private void checkResourceContentFromZip(@Nonnull ZipFile zipFile, @Nonnull String entryName, - @Nonnull String expectedContent, boolean isLib) throws IOException { - ZipEntry entry = zipFile.getEntry((isLib ? FileType.RSC.getPrefix() + '/' : "") + entryName); + @Nonnull String expectedContent) throws IOException { + ZipEntry entry = zipFile.getEntry(entryName); Assert.assertNotNull(entry); BufferedReader candidateReader = null; BufferedReader referenceReader = null; @@ -351,10 +401,29 @@ public class ResourceTests { } } + private void checkResourceContentFromLib(@Nonnull InputJackLibrary lib, @Nonnull String path, + @Nonnull String expectedContent) throws IOException, FileTypeDoesNotExistException { + InputVFile rescFile = lib.getFile(FileType.RSC, new VPath(path, '/')); + BufferedReader candidateReader = null; + BufferedReader referenceReader = null; + try { + candidateReader = new BufferedReader(new InputStreamReader(rescFile.getInputStream())); + referenceReader = new BufferedReader(new StringReader(expectedContent)); + compareReadLines(referenceReader, candidateReader); + } finally { + if (candidateReader != null) { + candidateReader.close(); + } + if (referenceReader != null) { + referenceReader.close(); + } + } + } + private void checkResourceContentFromDir(@Nonnull File dir, @Nonnull String path, - @Nonnull String expectedContent, boolean isLib) throws IOException { + @Nonnull String expectedContent) throws IOException { assert dir.isDirectory(); - File file = new File(isLib ? new File(dir, FileType.RSC.getPrefix()) : dir, path); + File file = new File(dir, path); Assert.assertTrue(file.exists()); BufferedReader candidateReader = null; BufferedReader referenceReader = null; @@ -374,14 +443,14 @@ public class ResourceTests { } - private void checkResourceContent(@Nonnull File candidateFileContent, - @Nonnull File referenceFileContent) throws IOException { - Assert.assertTrue(candidateFileContent.exists()); + private void checkResourceContent(@Nonnull InputVFile candidateFile, + @Nonnull File referenceFile) throws IOException { BufferedReader candidateReader = null; BufferedReader referenceReader = null; try { - candidateReader = new BufferedReader(new InputStreamReader(new FileInputStream(candidateFileContent))); - referenceReader = new BufferedReader(new InputStreamReader(new FileInputStream(referenceFileContent))); + candidateReader = new BufferedReader(new InputStreamReader(candidateFile.getInputStream())); + referenceReader = + new BufferedReader(new InputStreamReader(new FileInputStream(referenceFile))); compareReadLines(referenceReader, candidateReader); } finally { if (candidateReader != null) { @@ -403,35 +472,4 @@ public class ResourceTests { } Assert.assertNull(candidateReader.readLine()); } - - private void copyFileToDir(@Nonnull File fileToCopy, @Nonnull String relativePath, - @Nonnull File dir) throws IOException { - FileOutputStream fos = null; - FileInputStream fis = null; - try { - fis = new FileInputStream(fileToCopy); - File copiedFile = new File(dir, relativePath); - File parentDir = copiedFile.getParentFile(); - if (!parentDir.exists()) { - boolean res = parentDir.mkdirs(); - if (!res) { - throw new AssertionError(); - } - } - try { - fos = new FileOutputStream(copiedFile); - ByteStreamSucker sucker = new ByteStreamSucker(fis, fos); - sucker.suck(); - } finally { - if (fos != null) { - fos.close(); - } - } - } finally { - if (fis != null) { - fis.close(); - } - } - } - } diff --git a/jack-tests/tests/com/android/jack/resource/test003/jack/A.txt b/jack-tests/tests/com/android/jack/resource/test003/jack/A.txt deleted file mode 100644 index a6beffa..0000000 --- a/jack-tests/tests/com/android/jack/resource/test003/jack/A.txt +++ /dev/null @@ -1,11 +0,0 @@ -com.android.jack.resource.test003.jack.A -Lcom.android.jack.resource.test003.jack.A; -com/android/jack/resource/test003/jack/A -Lcom/android/jack/resource/test003/jack/A; -A -fddfcom.android.jack.resource.test003.jack.A -fgjgLcom.android.jack.resource.test003.jack.A; -sddtcom/android/jack/resource/test003/jack/A -fdhdhLcom/android/jack/resource/test003/jack/A; -estsrtA - com.android.jack.resource.test003.jack.A Lcom.android.jack.resource.test003.jack.A; com/android/jack/resource/test003/jack/A Lcom/android/jack/resource/test003/jack/A; A \ No newline at end of file diff --git a/jack-tests/tests/com/android/jack/resource/test003/jack/rsc/com/android/jack/resource/test003/jack/A b/jack-tests/tests/com/android/jack/resource/test003/jack/rsc/com/android/jack/resource/test003/jack/A new file mode 100644 index 0000000..a6beffa --- /dev/null +++ b/jack-tests/tests/com/android/jack/resource/test003/jack/rsc/com/android/jack/resource/test003/jack/A @@ -0,0 +1,11 @@ +com.android.jack.resource.test003.jack.A +Lcom.android.jack.resource.test003.jack.A; +com/android/jack/resource/test003/jack/A +Lcom/android/jack/resource/test003/jack/A; +A +fddfcom.android.jack.resource.test003.jack.A +fgjgLcom.android.jack.resource.test003.jack.A; +sddtcom/android/jack/resource/test003/jack/A +fdhdhLcom/android/jack/resource/test003/jack/A; +estsrtA + com.android.jack.resource.test003.jack.A Lcom.android.jack.resource.test003.jack.A; com/android/jack/resource/test003/jack/A Lcom/android/jack/resource/test003/jack/A; A \ No newline at end of file diff --git a/jack-tests/tests/com/android/jack/resource/test003/jack/rsc/com/android/jack/resource/test003/jack/A.txt b/jack-tests/tests/com/android/jack/resource/test003/jack/rsc/com/android/jack/resource/test003/jack/A.txt new file mode 100644 index 0000000..a6beffa --- /dev/null +++ b/jack-tests/tests/com/android/jack/resource/test003/jack/rsc/com/android/jack/resource/test003/jack/A.txt @@ -0,0 +1,11 @@ +com.android.jack.resource.test003.jack.A +Lcom.android.jack.resource.test003.jack.A; +com/android/jack/resource/test003/jack/A +Lcom/android/jack/resource/test003/jack/A; +A +fddfcom.android.jack.resource.test003.jack.A +fgjgLcom.android.jack.resource.test003.jack.A; +sddtcom/android/jack/resource/test003/jack/A +fdhdhLcom/android/jack/resource/test003/jack/A; +estsrtA + com.android.jack.resource.test003.jack.A Lcom.android.jack.resource.test003.jack.A; com/android/jack/resource/test003/jack/A Lcom/android/jack/resource/test003/jack/A; A \ No newline at end of file -- cgit v1.1