blob: 48e4ad11f9bff7432600ffbd915157ab4e2ad6c7 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* 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.android;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import com.google.errorprone.CompilationTestHelper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class EfficientStringsCheckerTest {
private CompilationTestHelper compilationHelper;
@Before
public void setUp() {
compilationHelper = CompilationTestHelper.newInstance(
EfficientStringsChecker.class, getClass());
}
@Test
public void testSimple() {
assertTrue(EfficientStringsChecker.isSimple(""));
assertTrue(EfficientStringsChecker.isSimple("%s"));
assertTrue(EfficientStringsChecker.isSimple("String %s%s and %%%% number %d%d together"));
assertTrue(EfficientStringsChecker.isSimple("%04d"));
assertTrue(EfficientStringsChecker.isSimple("%02x:%02x:%02x"));
assertTrue(EfficientStringsChecker.isSimple("%10d"));
assertFalse(EfficientStringsChecker.isSimple("%0.4f"));
assertFalse(EfficientStringsChecker.isSimple("%t"));
assertFalse(EfficientStringsChecker.isSimple("%1$s"));
}
@Test
public void testFormat() {
compilationHelper
.addSourceLines("Example.java",
"import java.util.Locale;",
"public class Example {",
" public void example(String str) {",
" String.format(str, str);",
" // BUG: Diagnostic contains:",
" String.format(\"foo %s bar\", str);",
" // BUG: Diagnostic contains:",
" String.format(\"foo %d bar\", 42);",
" // BUG: Diagnostic contains:",
" String.format(\"foo %04d bar\", 42);",
" }",
" public void exampleLocale(String str) {",
" String.format(Locale.US, str, str);",
" // BUG: Diagnostic contains:",
" String.format(Locale.US, \"foo %s bar\", str);",
" // BUG: Diagnostic contains:",
" String.format(Locale.US, \"foo %d bar\", 42);",
" // BUG: Diagnostic contains:",
" String.format(Locale.US, \"foo %04d bar\", 42);",
" }",
"}")
.doTest();
}
@Test
public void testPreconditions() {
compilationHelper
.addSourceFile("/android/util/Preconditions.java")
.addSourceLines("Example.java",
"import android.util.Preconditions;",
"import java.util.Objects;",
"public class Example {",
" String str;",
" public void checkState(boolean val) {",
" Preconditions.checkState(val);",
" Preconditions.checkState(val, str);",
" Preconditions.checkState(val, \"foo\");",
" Preconditions.checkState(val, \"foo\" + \"bar\");",
" // BUG: Diagnostic contains:",
" Preconditions.checkState(val, \"foo \" + val);",
" }",
" public void checkArgument(boolean val) {",
" Preconditions.checkArgument(val);",
" Preconditions.checkArgument(val, str);",
" Preconditions.checkArgument(val, \"foo\");",
" Preconditions.checkArgument(val, \"foo\" + \"bar\");",
" // BUG: Diagnostic contains:",
" Preconditions.checkArgument(val, \"foo \" + val);",
" }",
" public void checkNotNull(Object val) {",
" Preconditions.checkNotNull(val);",
" Preconditions.checkNotNull(val, str);",
" Preconditions.checkNotNull(val, \"foo\");",
" Preconditions.checkNotNull(val, \"foo\" + \"bar\");",
" // BUG: Diagnostic contains:",
" Preconditions.checkNotNull(val, \"foo \" + val);",
" }",
" public void requireNonNull(Object val) {",
" Objects.requireNonNull(val);",
" Objects.requireNonNull(val, str);",
" Objects.requireNonNull(val, \"foo\");",
" Objects.requireNonNull(val, \"foo\" + \"bar\");",
" // BUG: Diagnostic contains:",
" Objects.requireNonNull(val, \"foo \" + val);",
" }",
"}")
.doTest();
}
@Test
public void testPreconditions_Complex() {
compilationHelper
.addSourceFile("/android/util/Preconditions.java")
.addSourceLines("Example.java",
"import android.util.Preconditions;",
"public class Example {",
" String[] classArray = new String[] { null };",
" String classVar;",
" static final String CONST_VAR = \"baz\";",
" public String classMethod() { return \"baz\"; }",
" public static final String CONST_METHOD() { return \"baz\"; }",
" public void checkNotNull(Example example, Object val) {",
" String methodVar = \"baz\";",
" Preconditions.checkNotNull(val, \"foo\");",
" Preconditions.checkNotNull(val, (\"foo\"));",
" Preconditions.checkNotNull(val, classArray[0]);",
" Preconditions.checkNotNull(val, classVar);",
" Preconditions.checkNotNull(val, CONST_VAR);",
" Preconditions.checkNotNull(val, example.classVar);",
" Preconditions.checkNotNull(val, Example.CONST_VAR);",
" Preconditions.checkNotNull(val, methodVar);",
" Preconditions.checkNotNull(val, classMethod());",
" Preconditions.checkNotNull(val, CONST_METHOD());",
" Preconditions.checkNotNull(val, \"foo\" + \"bar\");",
" Preconditions.checkNotNull(val, (\"foo\" + \"bar\"));",
" // BUG: Diagnostic contains:",
" Preconditions.checkNotNull(val, \"foo\" + classArray[0]);",
" // BUG: Diagnostic contains:",
" Preconditions.checkNotNull(val, \"foo\" + classVar);",
" Preconditions.checkNotNull(val, \"foo\" + CONST_VAR);",
" // BUG: Diagnostic contains:",
" Preconditions.checkNotNull(val, \"foo\" + methodVar);",
" // BUG: Diagnostic contains:",
" Preconditions.checkNotNull(val, \"foo\" + classMethod());",
" // BUG: Diagnostic contains:",
" Preconditions.checkNotNull(val, \"foo\" + CONST_METHOD());",
" }",
"}")
.doTest();
}
@Test
public void testStringBuffer() {
compilationHelper
.addSourceLines("Example.java",
"public class Example {",
" public void example() {",
" // BUG: Diagnostic contains:",
" StringBuffer sb = new StringBuffer();",
" }",
"}")
.doTest();
}
@Test
public void testStringBuilder() {
compilationHelper
.addSourceLines("Example.java",
"public class Example {",
" StringBuilder sb = new StringBuilder();",
" String[] classArray = new String[] { null };",
" String classVar;",
" static final String CONST_VAR = \"baz\";",
" public String classMethod() { return \"baz\"; }",
" public static final String CONST_METHOD() { return \"baz\"; }",
" public void generic(Example example) {",
" sb.append(\"foo\");",
" sb.append(\"foo\" + \"bar\");",
" sb.append(classArray[0]);",
" sb.append(example.classArray[0]);",
" sb.append(classVar);",
" sb.append(CONST_VAR);",
" sb.append(example.classVar);",
" sb.append(Example.CONST_VAR);",
" sb.append(classMethod());",
" sb.append(CONST_METHOD());",
" }",
" public void string(String val) {",
" sb.append(\"foo\").append(val);",
" sb.append(\"foo\").append(val != null ? \"bar\" : \"baz\");",
" // BUG: Diagnostic contains:",
" sb.append(\"foo\" + val);",
" }",
" public void number(int val) {",
" sb.append(\"foo\").append(val);",
" sb.append(\"foo\").append(val + val);",
" sb.append(\"foo\").append(val > 0 ? \"bar\" : \"baz\");",
" // BUG: Diagnostic contains:",
" sb.append(\"foo\" + val);",
" // BUG: Diagnostic contains:",
" sb.append(\"foo\" + String.valueOf(val));",
" // BUG: Diagnostic contains:",
" sb.append(\"foo\" + Integer.toString(val));",
" }",
"}")
.doTest();
}
@Test
public void testPlusAssignment() {
compilationHelper
.addSourceLines("Example.java",
"public class Example {",
" public void string(String val) {",
" String s = \"foo\";",
" // BUG: Diagnostic contains:",
" s += \"bar\";",
" // BUG: Diagnostic contains:",
" s += val;",
" // BUG: Diagnostic contains:",
" s += (\"bar\" + \"baz\");",
" }",
" public void number(int val) {",
" int other = 42;",
" other += 24;",
" other += val;",
" }",
"}")
.doTest();
}
}