1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.build.lint 18 19 import com.android.tools.lint.checks.infrastructure.ProjectDescription 20 import org.junit.Test 21 import org.junit.runner.RunWith 22 import org.junit.runners.JUnit4 23 24 @RunWith(JUnit4::class) 25 class AutoValueNullnessOverrideTest : 26 AbstractLintDetectorTest( 27 useDetector = AutoValueNullnessOverride(), 28 useIssues = listOf(AutoValueNullnessOverride.ISSUE), 29 stubs = arrayOf(autovalueStub, jspecifyNonNullStub, jspecifyNullableStub) 30 ) { 31 @Test No superclassnull32 fun `No superclass`() { 33 val input = 34 java( 35 """ 36 package test.pkg; 37 import com.google.auto.value.AutoValue; 38 import org.jspecify.annotations.Nullable; 39 @AutoValue 40 public abstract class Foo { 41 public abstract @Nullable String getString(); 42 } 43 """ 44 .trimIndent() 45 ) 46 check(input).expectClean() 47 } 48 49 @Test Superclass in same librarynull50 fun `Superclass in same library`() { 51 val input = 52 arrayOf( 53 java( 54 """ 55 package test.pkg; 56 import com.google.auto.value.AutoValue; 57 @AutoValue 58 public abstract class Foo extends ParentClass { 59 } 60 """ 61 .trimIndent() 62 ), 63 java( 64 """ 65 package test.pkg; 66 import org.jspecify.annotations.Nullable; 67 public abstract class ParentClass { 68 public abstract @Nullable String getString(); 69 } 70 """ 71 .trimIndent() 72 ) 73 ) 74 check(*input).expectClean() 75 } 76 77 @Test Superclass in different librarynull78 fun `Superclass in different library`() { 79 // Files needs to be set up in project structure for the lint to understand they are from 80 // different libraries 81 val jspecify = 82 project() 83 .files(jspecifyNonNullStub, jspecifyNullableStub) 84 .type(ProjectDescription.Type.LIBRARY) 85 86 val autovalue = project().files(autovalueStub).type(ProjectDescription.Type.LIBRARY) 87 88 val parentLibrary = 89 project() 90 .files( 91 java( 92 """ 93 package androidx.example; 94 import org.jspecify.annotations.NonNull; 95 import org.jspecify.annotations.Nullable; 96 public abstract class SuperClass { 97 public abstract @Nullable String getNullableStringNotOverridden(); 98 public abstract @NonNull String getNonNullStringNotOverridden(); 99 public abstract String getUnannotatedStringNotOverridden(); 100 101 public abstract @Nullable String getNullableStringOverridden(); 102 103 public abstract @Nullable String getNullableStringOverrideNotAbstract(); 104 } 105 """ 106 .trimIndent(), 107 ), 108 gradle( 109 """ 110 apply plugin: 'com.android.library' 111 group=androidx.example 112 """ 113 ) 114 ) 115 .dependsOn(jspecify) 116 .type(ProjectDescription.Type.LIBRARY) 117 118 val sourceProject = 119 project() 120 .files( 121 java( 122 """ 123 package test.pkg; 124 import com.google.auto.value.AutoValue; 125 import androidx.example.SuperClass; 126 @AutoValue 127 public abstract class Foo extends SuperClass { 128 @Override 129 public abstract @Nullable String getNullableStringOverridden(); 130 131 @Override 132 public abstract @Nullable String getNullableStringOverrideNotAbstract() { 133 return null; 134 } 135 } 136 """ 137 .trimIndent(), 138 ), 139 gradle( 140 """ 141 apply plugin: 'com.android.library' 142 group=test.pkg 143 """ 144 ) 145 ) 146 .dependsOn(jspecify) 147 .dependsOn(autovalue) 148 .dependsOn(parentLibrary) 149 150 val expected = 151 """ 152 src/main/java/test/pkg/Foo.java:5: Error: Methods need @Nullable overrides for AutoValue: getNullableStringNotOverridden() [AutoValueNullnessOverride] 153 public abstract class Foo extends SuperClass { 154 ~~~ 155 1 errors, 0 warnings 156 """ 157 .trimIndent() 158 val expectedFixDiffs = 159 """ 160 Fix for src/main/java/test/pkg/Foo.java line 5: Replace with ...: 161 @@ -6 +6 162 + @Override 163 + public abstract @Nullable String getNullableStringNotOverridden(); 164 """ 165 .trimIndent() 166 167 lint().projects(sourceProject).run().expect(expected).expectFixDiffs(expectedFixDiffs) 168 } 169 170 companion object { 171 private val autovalueStub = 172 kotlin( 173 """ 174 package com.google.auto.value 175 annotation class AutoValue 176 """ 177 .trimIndent() 178 ) 179 private val jspecifyNullableStub = 180 kotlin( 181 """ 182 package org.jspecify.annotations 183 @Target(AnnotationTarget.TYPE) 184 annotation class Nullable 185 """ 186 .trimIndent() 187 ) 188 private val jspecifyNonNullStub = 189 kotlin( 190 """ 191 package org.jspecify.annotations 192 @Target(AnnotationTarget.TYPE) 193 annotation class NonNull 194 """ 195 .trimIndent() 196 ) 197 } 198 } 199