/*
* 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 FieldMissingNullableTest {
@Test
public void testLiteralNullAssignment() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/FieldMissingNullTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"public class FieldMissingNullTest {",
" private String message = \"hello\";",
" public void reset() {",
" // BUG: Diagnostic contains: @Nullable",
" message = null;",
" }",
"}")
.doTest();
}
@Test
public void testDefiniteNullAssignment() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/FieldMissingNullTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"public class FieldMissingNullTest {",
" private String message = \"hello\";",
" public void setMessage(String message) {",
" // BUG: Diagnostic contains: @Nullable",
" this.message = message != null ? null : message;",
" }",
"}")
.doTest();
}
@Test
public void testMaybeNullAssignment() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/FieldMissingNullTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"public class FieldMissingNullTest {",
" private String message = \"hello\";",
" public void setMessage(int x) {",
" // BUG: Diagnostic contains: @Nullable",
" message = x >= 0 ? null : \"negative\";",
" }",
"}")
.doTest();
}
@Test
public void testAssignNullableMethodResult() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/NullableMethodCallTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"import javax.annotation.Nullable;",
"public class NullableMethodCallTest {",
" private String message = \"hello\";",
" public void setMessage(int x) {",
" // BUG: Diagnostic contains: @Nullable",
" message = toSignString(x);",
" }",
"",
" @Nullable",
" private String toSignString(int x) {",
" return x < 0 ? \"negative\" : \"positive\";",
" }",
"}")
.doTest();
}
@Test
public void testAssignNullableMethodCall_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 {",
" private String message = \"hello\";",
" public void setMessage(int x) {",
" // BUG: Diagnostic contains: @Nullable",
" message = toSignString(x);",
" }",
"",
" @com.google.anno.my.Nullable",
" private String toSignString(int x) {",
" return x < 0 ? \"negative\" : \"positive\";",
" }",
"}")
.doTest();
}
@Test
public void testAssignNullableField() 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;",
" private String previous = \"\";",
" public void setMessage(String message) {",
" // BUG: Diagnostic contains: @Nullable",
" previous = this.message;",
" this.message = message;",
" }",
"}")
.doTest();
}
@Test
public void testAssignNullableParameter() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/NullableParameterTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"import javax.annotation.Nullable;",
"public class NullableParameterTest {",
" private String message = \"hello\";",
" public void apply(@Nullable String message) {",
" // BUG: Diagnostic contains: @Nullable",
" this.message = message;",
" }",
"}")
.doTest();
}
@Test
public void testInitializeWithNullableParameter() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/NullableParameterTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"import javax.annotation.Nullable;",
"public class NullableParameterTest {",
" private final String message;",
" public NullableParameterTest(@Nullable String message) {",
" // BUG: Diagnostic contains: @Nullable",
" this.message = message;",
" }",
"}")
.doTest();
}
@Test
public void testNullInitializer() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/NullableParameterTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"import javax.annotation.Nullable;",
"public class NullableParameterTest {",
" // BUG: Diagnostic contains: @Nullable",
" public static final String MESSAGE = null;",
"}")
.doTest();
}
@Test
public void testMaybeNullAssignmentInLambda() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/NullableParameterTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"import javax.annotation.Nullable;",
"public class NullableParameterTest {",
" private String message = \"hello\";",
" public void setMessageIfPresent(java.util.Optional<String> message) {",
// Note this code is bogus: s is guaranteed non-null...
" // BUG: Diagnostic contains: @Nullable",
" message.ifPresent(s -> { this.message = s != null ? s : null; });",
" }",
"}")
.doTest();
}
@Test
public void testNegativeCases_alreadyAnnotated() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/FieldMissingNullTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"import javax.annotation.Nullable;",
"public class FieldMissingNullTest {",
" @Nullable String message;",
" public void reset() {",
" this.message = null;",
" }",
"}")
.doTest();
}
@Test
public void testNegativeCases_initializeWithNonNullLiteral() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/FieldMissingNullTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"public class FieldMissingNullTest {",
" private final String message;",
" public FieldMissingNullTest() {",
" message = \"hello\";",
" }",
"}")
.doTest();
}
@Test
public void testNegativeCases_nonNullInitializer() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/FieldMissingNullTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"public class FieldMissingNullTest {",
" private String message = \"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 {",
" private String message = \"hello\";",
" public void setMessage(int x) {",
" message = 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 = \"hello\";",
" private String previous = \"\";",
" public void save() {",
" previous = 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 {",
" private String message = \"hello\";",
" public void setMessage(String message) {",
" this.message = 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 static ThisTest theInstance = new ThisTest();",
" public void makeDefault() {",
" this.theInstance = this;",
" }",
"}")
.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_primitiveFieldType() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/PrimitiveReturnTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"public class PrimitiveReturnTest {",
" private int count = (Integer) null;",
"}")
.doTest();
}
@Test
public void testNegativeCases_initializeWithLambda() throws Exception {
createCompilationTestHelper()
.addSourceLines(
"com/google/errorprone/bugpatterns/nullness/NullableParameterTest.java",
"package com.google.errorprone.bugpatterns.nullness;",
"import javax.annotation.Nullable;",
"public class NullableParameterTest {",
" private String message = \"hello\";",
" public void setMessageIfPresent(java.util.Optional<String> message) {",
" message.ifPresent(s -> { this.message = s; });",
" }",
"}")
.doTest();
}
private CompilationTestHelper createCompilationTestHelper() {
return CompilationTestHelper.newInstance(FieldMissingNullable.class, getClass());
}
}