1 /*
   2  * Copyright (c) 2015, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * Asm plugin testing.
  26  * @test
  27  * @summary Test visitors.
  28  * @author Andrei Eremeev
  29  * @modules java.base/jdk.internal.org.objectweb.asm
  30  *          jdk.jlink/jdk.tools.jlink.internal
  31  *          jdk.jlink/jdk.tools.jlink.internal.plugins.asm
  32  * @build AsmPluginTestBase
  33  * @run main VisitorTest
  34  */
  35 
  36 import java.io.IOException;
  37 import java.util.Collection;
  38 import java.util.function.Function;
  39 
  40 import jdk.internal.org.objectweb.asm.ClassReader;
  41 import jdk.internal.org.objectweb.asm.ClassVisitor;
  42 import jdk.internal.org.objectweb.asm.ClassWriter;
  43 import jdk.internal.org.objectweb.asm.Opcodes;
  44 import jdk.tools.jlink.internal.plugins.asm.AsmPool;
  45 import jdk.tools.jlink.internal.plugins.asm.AsmPool.ClassReaderVisitor;
  46 import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile;
  47 import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFileVisitor;
  48 import jdk.tools.jlink.internal.plugins.asm.AsmPools;
  49 import jdk.tools.jlink.plugin.ModuleEntry;
  50 import jdk.tools.jlink.plugin.ModulePool;
  51 
  52 public class VisitorTest extends AsmPluginTestBase {
  53 
  54     public static void main(String[] args) throws Exception {
  55         if (!isImageBuild()) {
  56             System.err.println("Test not run. Not image build.");
  57             return;
  58         }
  59         new VisitorTest().test();
  60     }
  61 
  62     @Override
  63     public void test() throws Exception {
  64         TestPlugin[] plugins = new TestPlugin[] {
  65                 new ClassVisitorPlugin("Class-global-pool", AsmPools::getGlobalPool),
  66                 new ClassVisitorPlugin("Class-module-pool", pools -> pools.getModulePool("java.base")),
  67                 new ResourceVisitorPlugin("Resource-global-pool", AsmPools::getGlobalPool),
  68                 new ResourceVisitorPlugin("Resource-module-pool", pools -> pools.getModulePool("java.base"))
  69         };
  70         for (TestPlugin p : plugins) {
  71             System.err.println("Testing: " + p.getName());
  72             ModulePool out = p.visit(getPool());
  73             p.test(getPool(), out);
  74         }
  75     }
  76 
  77     private static class CustomClassReaderVisitor implements ClassReaderVisitor {
  78         private int amount = 0;
  79         private int changed = 0;
  80 
  81         @Override
  82         public ClassWriter visit(ClassReader reader) {
  83             if ((amount++ % 2) == 0) {
  84                 String className = reader.getClassName();
  85                 if (className.endsWith("module-info")) {
  86                     return null;
  87                 }
  88                 ClassWriter cw = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
  89                 reader.accept(new ClassVisitor(Opcodes.ASM5, cw) {
  90                     @Override
  91                     public void visit(int i, int i1, String s, String s1, String s2, String[] strings) {
  92                         super.visit(i, i1, s + "Changed", s1, s2, strings);
  93                     }
  94                 }, ClassReader.EXPAND_FRAMES);
  95                 ++changed;
  96                 return cw;
  97             } else {
  98                 return null;
  99             }
 100         }
 101 
 102         public int getAmount() {
 103             return amount;
 104         }
 105 
 106         public int getNumberOfChanged() {
 107             return changed;
 108         }
 109     }
 110 
 111     private static class CustomResourceFileVisitor implements ResourceFileVisitor {
 112         private int amount = 0;
 113         private int changed = 0;
 114 
 115         @Override
 116         public ResourceFile visit(ResourceFile resourceFile) {
 117             if ((amount++ % 2) == 0) {
 118                 ++changed;
 119                 return new ResourceFile(resourceFile.getPath() + "Changed", resourceFile.getContent());
 120             } else {
 121                 return null;
 122             }
 123         }
 124 
 125         public int getAmount() {
 126             return amount;
 127         }
 128 
 129         public int getNumberOfChanged() {
 130             return changed;
 131         }
 132     }
 133 
 134     public class ClassVisitorPlugin extends TestPlugin {
 135 
 136         private final String name;
 137         private final Function<AsmPools, AsmPool> getPool;
 138         private final CustomClassReaderVisitor classReaderVisitor = new CustomClassReaderVisitor();
 139 
 140         public ClassVisitorPlugin(String name, Function<AsmPools, AsmPool> getPool) {
 141             this.name = name;
 142             this.getPool = getPool;
 143         }
 144 
 145         @Override
 146         public void visit() {
 147             AsmPool pool = getPool.apply(getPools());
 148             pool.visitClassReaders(classReaderVisitor);
 149         }
 150 
 151         @Override
 152         public void test(ModulePool in, ModulePool out) throws Exception {
 153             Collection<ModuleEntry> inClasses = getPool.apply(getPools()).getClasses();
 154             if (inClasses.size() != classReaderVisitor.getAmount()) {
 155                 throw new AssertionError("Testing " + name + ". Number of visited classes. Expected: " +
 156                         inClasses.size() + ", got: " + classReaderVisitor.getAmount());
 157             }
 158             Collection<ModuleEntry> outClasses = extractClasses(out);
 159             int changedClasses = 0;
 160             for (ModuleEntry r : outClasses) {
 161                 if (r.getPath().endsWith("Changed.class")) {
 162                     ++changedClasses;
 163                 }
 164             }
 165             if (changedClasses != classReaderVisitor.getNumberOfChanged()) {
 166                 throw new AssertionError("Testing " + name + ". Changed classes. Expected: " + changedClasses +
 167                         ", got: " + classReaderVisitor.getNumberOfChanged());
 168             }
 169         }
 170 
 171         @Override
 172         public String getName() {
 173             return name;
 174         }
 175     }
 176 
 177     public class ResourceVisitorPlugin extends TestPlugin {
 178 
 179         private final String name;
 180         private final Function<AsmPools, AsmPool> getPool;
 181         private final CustomResourceFileVisitor resourceFileVisitor = new CustomResourceFileVisitor();
 182 
 183         public ResourceVisitorPlugin(String name, Function<AsmPools, AsmPool> getPool) {
 184             this.name = name;
 185             this.getPool = getPool;
 186         }
 187 
 188         @Override
 189         public void visit() {
 190             AsmPool pool = getPool.apply(getPools());
 191             pool.visitResourceFiles(resourceFileVisitor);
 192         }
 193 
 194         @Override
 195         public void test(ModulePool in, ModulePool out) throws Exception {
 196             Collection<ModuleEntry> inResources = getPool.apply(getPools()).getResourceFiles();
 197             if (inResources.size() != resourceFileVisitor.getAmount()) {
 198                 throw new AssertionError("Testing " + name + ". Number of visited resources. Expected: " +
 199                         inResources.size() + ", got: " + resourceFileVisitor.getAmount());
 200             }
 201             Collection<ModuleEntry> outResources = extractResources(out);
 202             int changedClasses = 0;
 203             for (ModuleEntry r : outResources) {
 204                 if (r.getPath().endsWith("Changed")) {
 205                     ++changedClasses;
 206                 }
 207             }
 208             if (changedClasses != resourceFileVisitor.getNumberOfChanged()) {
 209                 throw new AssertionError("Testing " + name + ". Changed classes. Expected: " + changedClasses +
 210                         ", got: " + resourceFileVisitor.getNumberOfChanged());
 211             }
 212         }
 213 
 214         @Override
 215         public String getName() {
 216             return name;
 217         }
 218     }
 219 }