content: package org.aion.avm.embed;
  
  import avm.Address;
  import org.aion.avm.tooling.abi.ABICompiler;
  import org.aion.avm.tooling.deploy.JarOptimizer;
  import org.aion.avm.userlib.CodeAndArguments;
  import org.aion.avm.utilities.JarBuilder;
  import org.aion.avm.utilities.Utilities;
  import org.junit.Assert;
  import org.junit.ClassRule;
  import org.junit.Test;
  import org.objectweb.asm.ClassWriter;
  import org.objectweb.asm.Label;
  import org.objectweb.asm.MethodVisitor;
  
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.math.BigInteger;
  import java.util.Collections;
  import java.util.HashSet;
  import java.util.Set;
  import java.util.jar.Attributes;
  import java.util.jar.JarEntry;
  import java.util.jar.JarOutputStream;
  import java.util.jar.Manifest;
  
  import static org.objectweb.asm.Opcodes.*;
  
  public class UserlibCollisionTest {
      @ClassRule
      public static AvmRule avmRule = new AvmRule(false);
  
      @Test
      public void testJavaLangPackageContract() {
          boolean correctExceptionThrown = false;
          try {
              // having a package starting with .java fails during class loading
              SingleLoader loader = new SingleLoader();
              loader.loadClassFromByteCode("java.lang.MyClass", getJavaLangPackageClassBytes());
          } catch (SecurityException e) {
              correctExceptionThrown = true;
          }
  
          Assert.assertTrue(correctExceptionThrown);
      }
  
      @Test
      public void testJavaLangPackageContractDuringDeployment() {
  
          byte[] jar = buildJarForClassNameAndBytecode("java.lang.MyClass", getJavaLangPackageClassBytes());
  
          JarOptimizer jarOptimizer = new JarOptimizer(false);
          ABICompiler compiler = ABICompiler.compileJarBytes(jar);
          byte[] optimizedDappBytes = jarOptimizer.optimize(compiler.getJarFileBytes());
          byte[] txData = new CodeAndArguments(optimizedDappBytes, null).encodeToBytes();
  
          Address from = avmRule.getPreminedAccount();
  
          AvmRule.ResultWrapper resultWrapper = avmRule.deploy(from, BigInteger.ZERO, txData);
          Assert.assertTrue(resultWrapper.getReceiptStatus().isFailed());
      }
  
      @Test
      public void testAvmPackageContract() {
          ;
          JarOptimizer jarOptimizer = new JarOptimizer(false);
          byte[] jar = JarBuilder.buildJarForExplicitClassNamesAndBytecode("avm.Main", getAvmPackageClassBytes(), Collections.emptyMap());
          ABICompiler compiler = ABICompiler.compileJarBytes(jar);
          byte[] optimizedDappBytes = jarOptimizer.optimize(compiler.getJarFileBytes());
          byte[] txData = new CodeAndArguments(optimizedDappBytes, null).encodeToBytes();
  
          Address from = avmRule.getPreminedAccount();
  
          AvmRule.ResultWrapper resultWrapper = avmRule.deploy(from, BigInteger.ZERO, txData);
          Assert.assertTrue(resultWrapper.getReceiptStatus().isFailed());
      }
  
      private static byte[] getJavaLangPackageClassBytes() {
  
          ClassWriter classWriter = new ClassWriter(0);
          MethodVisitor methodVisitor;
  
          classWriter.visit(V10, ACC_PUBLIC | ACC_SUPER, "java/lang/MyClass", null, "java/lang/Object", null);
  
          classWriter.visitSource("MyClass.java", null);
          {
              methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
              methodVisitor.visitCode();
              Label label0 = new Label();
              methodVisitor.visitLabel(label0);
              methodVisitor.visitLineNumber(3, label0);
              methodVisitor.visitVarInsn(ALOAD, 0);
              methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
              methodVisitor.visitInsn(RETURN);
              methodVisitor.visitMaxs(1, 1);
              methodVisitor.visitEnd();
          }
          classWriter.visitEnd();
  
          return classWriter.toByteArray();
      }
  
      private static byte[] getAvmPackageClassBytes() {
  
          ClassWriter classWriter = new ClassWriter(0);
          MethodVisitor methodVisitor;
  
          classWriter.visit(V10, ACC_PUBLIC | ACC_SUPER, "avm/Main", null, "java/lang/Object", null);
  
          classWriter.visitSource("Main.java", null);
          {
              methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
              methodVisitor.visitCode();
              Label label0 = new Label();
              methodVisitor.visitLabel(label0);
              methodVisitor.visitLineNumber(3, label0);
              methodVisitor.visitVarInsn(ALOAD, 0);
              methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
              methodVisitor.visitInsn(RETURN);
              methodVisitor.visitMaxs(1, 1);
              methodVisitor.visitEnd();
          }
          classWriter.visitEnd();
  
          return classWriter.toByteArray();
      }
  
      public static byte[] buildJarForClassNameAndBytecode(String mainClassName, byte[] mainClassBytes) {
          Manifest manifest = new Manifest();
          Attributes mainAttributes = manifest.getMainAttributes();
  
          mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
          mainAttributes.put(Attributes.Name.MAIN_CLASS, mainClassName);
  
          ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
          JarOutputStream stream = null;
          try {
              stream = new JarOutputStream(byteStream, manifest);
          } catch (IOException e) {
              throw unexpected(e);
          }
          JarOutputStream jarStream = stream;
          Set<String> entriesInJar = new HashSet<>();
  
          try {
              String internalName = Utilities.fulllyQualifiedNameToInternalName(mainClassName);
              assertTrue(!entriesInJar.contains(internalName));
              JarEntry entry = new JarEntry(internalName + ".class");
              jarStream.putNextEntry(entry);
              jarStream.write(mainClassBytes);
              jarStream.closeEntry();
              entriesInJar.add(internalName);
  
              jarStream.finish();
              jarStream.close();
              byteStream.close();
          } catch (IOException e) {
              throw unexpected(e);
          }
  
          return byteStream.toByteArray();
      }
  
      private static void assertTrue(boolean flag) {
          // We use a private helper to manage the assertions since the JDK default disables them.
          if (!flag) {
              throw new AssertionError("Case must be true");
          }
      }
  
      private static AssertionError unexpected(IOException e) throws AssertionError {
          throw new AssertionError("Unexpected exception", e);
      }
  
  
      public class SingleLoader extends ClassLoader {
          public Class<?> loadClassFromByteCode(String name, byte[] bytecode) {
              Class<?> clazz = this.defineClass(name, bytecode, 0, bytecode.length);
              Assert.assertNotNull(clazz);
              Assert.assertEquals(this, clazz.getClassLoader());
              return clazz;
          }
      }
  }
  