1 // Copyright 2016 The Bazel Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package com.google.devtools.build.android.desugar; 15 16 import static com.google.common.truth.Truth.assertThat; 17 import static org.junit.Assert.fail; 18 import static org.objectweb.asm.Opcodes.INVOKESTATIC; 19 20 import com.google.devtools.build.android.desugar.testdata.ClassCallingRequireNonNull; 21 import java.io.IOException; 22 import java.util.concurrent.atomic.AtomicInteger; 23 import org.junit.Test; 24 import org.junit.runner.RunWith; 25 import org.junit.runners.JUnit4; 26 import org.objectweb.asm.ClassReader; 27 import org.objectweb.asm.ClassVisitor; 28 import org.objectweb.asm.MethodVisitor; 29 import org.objectweb.asm.Opcodes; 30 31 /** 32 * This test case tests the desugaring feature for Objects.requireNonNull. This feature replaces any 33 * call to this method with o.getClass() to check whether 'o' is null. 34 */ 35 @RunWith(JUnit4.class) 36 public class DesugarObjectsRequireNonNullTest { 37 38 @Test 39 public void testClassCallingRequireNonNullHasNoReferenceToRequiresNonNull() { 40 try { 41 ClassReader reader = new ClassReader(ClassCallingRequireNonNull.class.getName()); 42 43 AtomicInteger counterForSingleArgument = new AtomicInteger(0); 44 AtomicInteger counterForString = new AtomicInteger(0); 45 AtomicInteger counterForSupplier = new AtomicInteger(0); 46 47 reader.accept( 48 new ClassVisitor(Opcodes.ASM5) { 49 @Override 50 public MethodVisitor visitMethod( 51 int access, String name, String desc, String signature, String[] exceptions) { 52 return new MethodVisitor(api) { 53 @Override 54 public void visitMethodInsn( 55 int opcode, String owner, String name, String desc, boolean itf) { 56 if (opcode == INVOKESTATIC 57 && owner.equals("java/util/Objects") 58 && name.equals("requireNonNull")) { 59 switch (desc) { 60 case "(Ljava/lang/Object;)Ljava/lang/Object;": 61 counterForSingleArgument.incrementAndGet(); 62 break; 63 case "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;": 64 counterForString.incrementAndGet(); 65 break; 66 case "(Ljava/lang/Object;Ljava/util/function/Supplier;)Ljava/lang/Object;": 67 counterForSupplier.incrementAndGet(); 68 break; 69 default: 70 fail("Unknown overloaded requireNonNull is found: " + desc); 71 } 72 } 73 } 74 }; 75 } 76 }, 77 0); 78 assertThat(counterForSingleArgument.get()).isEqualTo(0); 79 // we do not desugar requireNonNull(Object, String) or requireNonNull(Object, Supplier) 80 assertThat(counterForString.get()).isEqualTo(1); 81 assertThat(counterForSupplier.get()).isEqualTo(1); 82 } catch (IOException e) { 83 fail(); 84 } 85 } 86 87 @Test 88 public void testInliningImplicitCallToObjectsRequireNonNull() { 89 try { 90 ClassCallingRequireNonNull.getStringLengthWithMethodReference(null); 91 fail ("NullPointerException expected"); 92 } catch (NullPointerException e) { 93 // Expected 94 } 95 96 assertThat(ClassCallingRequireNonNull.getStringLengthWithMethodReference("")).isEqualTo(0); 97 assertThat(ClassCallingRequireNonNull.getStringLengthWithMethodReference("1")).isEqualTo(1); 98 99 try { 100 ClassCallingRequireNonNull.getStringLengthWithLambdaAndExplicitCallToRequireNonNull(null); 101 fail ("NullPointerException expected"); 102 } catch (NullPointerException e) { 103 // Expected 104 } 105 106 assertThat( 107 ClassCallingRequireNonNull.getStringLengthWithLambdaAndExplicitCallToRequireNonNull("")) 108 .isEqualTo(0); 109 assertThat( 110 ClassCallingRequireNonNull.getStringLengthWithLambdaAndExplicitCallToRequireNonNull( 111 "1")) 112 .isEqualTo(1); 113 } 114 115 @Test 116 public void testInliningExplicitCallToObjectsRequireNonNull() { 117 try { 118 ClassCallingRequireNonNull.getFirstCharVersionOne(null); 119 fail ("NullPointerException expected"); 120 } catch (NullPointerException e) { 121 // Expected 122 } 123 124 try { 125 ClassCallingRequireNonNull.getFirstCharVersionTwo(null); 126 fail ("NullPointerException expected"); 127 } catch (NullPointerException e) { 128 // Expected 129 } 130 131 try { 132 ClassCallingRequireNonNull.callRequireNonNullWithArgumentString(null); 133 fail ("NullPointerException expected"); 134 } catch (NullPointerException e) { 135 // Expected 136 } 137 138 try { 139 ClassCallingRequireNonNull.callRequireNonNullWithArgumentSupplier(null); 140 fail ("NullPointerException expected"); 141 } catch (NullPointerException e) { 142 // Expected 143 } 144 145 assertThat(ClassCallingRequireNonNull.getFirstCharVersionOne("hello")).isEqualTo('h'); 146 assertThat(ClassCallingRequireNonNull.getFirstCharVersionTwo("hello")).isEqualTo('h'); 147 148 assertThat(ClassCallingRequireNonNull.callRequireNonNullWithArgumentString("hello")) 149 .isEqualTo('h'); 150 assertThat(ClassCallingRequireNonNull.callRequireNonNullWithArgumentSupplier("hello")) 151 .isEqualTo('h'); 152 } 153 } 154