/* * Copyright 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.errorprone.bugpatterns.nullness; import com.google.errorprone.CompilationTestHelper; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** @author kmb@google.com (Kevin Bierhoff) */ @RunWith(JUnit4.class) public class ReturnMissingNullableTest { @Test public void testLiteralNullReturn() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/LiteralNullReturnTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public class LiteralNullReturnTest {", " public String getMessage() {", " // BUG: Diagnostic contains: @Nullable", " return null;", " }", "}") .doTest(); } @Test public void testDefiniteNullReturn() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/LiteralNullReturnTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public class LiteralNullReturnTest {", " public String getMessage(String message) {", " // BUG: Diagnostic contains: @Nullable", " return message != null ? null : message;", " }", "}") .doTest(); } @Test public void testMaybeNullReturn() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/LiteralNullReturnTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public class LiteralNullReturnTest {", " public String getMessage(int x) {", " // BUG: Diagnostic contains: @Nullable", " return x >= 0 ? null : \"negative\";", " }", "}") .doTest(); } @Test public void testNullableMethodCall() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/NullableMethodCallTest.java", "package com.google.errorprone.bugpatterns.nullness;", "import javax.annotation.Nullable;", "public class NullableMethodCallTest {", " public String getMessage(int x) {", " // BUG: Diagnostic contains: @Nullable", " return toSignString(x);", " }", "", " @Nullable", " private String toSignString(int x) {", " return x < 0 ? \"negative\" : \"positive\";", " }", "}") .doTest(); } @Test public void testNullableMethodCall_alternativeAnnotation() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/anno/my/Nullable.java", "package com.google.anno.my;", "public @interface Nullable {}") .addSourceLines( "com/google/errorprone/bugpatterns/nullness/NullableMethodCallTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public class NullableMethodCallTest {", " public String getMessage(int x) {", " // BUG: Diagnostic contains: @Nullable", " return toSignString(x);", " }", "", " @com.google.anno.my.Nullable", " private String toSignString(int x) {", " return x < 0 ? \"negative\" : \"positive\";", " }", "}") .doTest(); } @Test public void testNullableField() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/NullableFieldTest.java", "package com.google.errorprone.bugpatterns.nullness;", "import javax.annotation.Nullable;", "public class NullableFieldTest {", " @Nullable private String message;", " public String getMessage() {", " // BUG: Diagnostic contains: @Nullable", " return message;", " }", "}") .doTest(); } @Test public void testNullableParameter() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/NullableParameterTest.java", "package com.google.errorprone.bugpatterns.nullness;", "import javax.annotation.Nullable;", "public class NullableParameterTest {", " public String apply(@Nullable String message) {", " // BUG: Diagnostic contains: @Nullable", " return message;", " }", "}") .doTest(); } @Test public void testNegativeCases_alreadyAnnotated() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/LiteralNullReturnTest.java", "package com.google.errorprone.bugpatterns.nullness;", "import javax.annotation.Nullable;", "public class LiteralNullReturnTest {", " @Nullable", " public String getMessage() {", " return null;", " }", "}") .doTest(); } @Test public void testNegativeCases_nonNullLiteral() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/LiteralNullReturnTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public class LiteralNullReturnTest {", " public String getMessage() {", " return \"hello\";", " }", "}") .doTest(); } @Test public void testNegativeCases_nonNullMethod() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/NonNullMethodTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public class NonNullMethodTest {", " public String getMessage(int x) {", " return String.valueOf(x);", " }", "}") .doTest(); } @Test public void testNegativeCases_nonNullField() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/NonNullFieldTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public class NonNullFieldTest {", " private String message;", " public String getMessage() {", " return message;", " }", "}") .doTest(); } @Test public void testNegativeCases_nonNullParameter() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/NonNullParameterTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public class NonNullParameterTest {", " public String apply(String message) {", " return message;", " }", "}") .doTest(); } @Test public void testNegativeCases_this() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/ThisTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public class ThisTest {", " private String message;", " public ThisTest setMessage(String message) {", " this.message = message;", " return this;", " }", "}") .doTest(); } @Test public void testNegativeCases_capturedLocal() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/CapturedLocalTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public abstract class CapturedLocalTest {", " public abstract String getMessage();", " public CapturedLocalTest withMessage(final String message) {", " return new CapturedLocalTest() {", " public String getMessage() {", " return message;", " }", " };", " }", "}") .doTest(); } /** * Makes sure the check never flags methods returning a primitive. Returning null from them is a * bug, of course, but we're not trying to find those bugs in this check. */ @Test public void testNegativeCases_primitiveReturnType() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/PrimitiveReturnTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public class PrimitiveReturnTest {", " public int getCount() {", " return (Integer) null;", " }", "}") .doTest(); } @Test public void testNegativeCases_voidMethod() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/VoidMethodTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public class VoidMethodTest {", " public void run(int iterations) {", " if (iterations <= 0) { return; }", " run(iterations - 1);", " }", "}") .doTest(); } @Test public void testNegativeCases_voidTypedMethod() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/VoidTypeTest.java", "package com.google.errorprone.bugpatterns.nullness;", "public class VoidTypeTest {", " public Void run(int iterations) {", " if (iterations <= 0) { return null; }", " run(iterations - 1);", " return null;", " }", "}") .doTest(); } @Test public void testNegativeCases_nullableReturnInLambda() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/MissingNullableReturnTest.java", "package com.google.errorprone.bugpatterns.nullness;", "import javax.annotation.Nullable;", "public class MissingNullableReturnTest {", " public static final java.util.function.Function<String, String> IDENTITY =", " (s -> { return s != null ? s : null; });", "}") .doTest(); } @Test public void testNegativeCases_returnLambda() throws Exception { createCompilationTestHelper() .addSourceLines( "com/google/errorprone/bugpatterns/nullness/MissingNullableReturnTest.java", "package com.google.errorprone.bugpatterns.nullness;", "import javax.annotation.Nullable;", "public class MissingNullableReturnTest {", " public static java.util.function.Function<String, String> identity() {", " return (s -> s);", " }", "}") .doTest(); } private CompilationTestHelper createCompilationTestHelper() { return CompilationTestHelper.newInstance(ReturnMissingNullable.class, getClass()); } }