Summary: Convert the last remaining tests to the new direct format: java harness and crashcontext. Remove what is left of the old testing infrastructure. Reviewed By: sblackshear Differential Revision: D3886355 fbshipit-source-id: 5117868master
parent
a2ee69975a
commit
717b61192e
@ -1,10 +1,3 @@
|
|||||||
|
|
||||||
[alias]
|
|
||||||
java = //infer/tests/endtoend:java_endtoend_tests
|
|
||||||
java_libraries = //dependencies/java:java_libraries
|
|
||||||
|
|
||||||
# TODO: this line exists only to support buck integration in infer/tests/build_systems/build_integration_tests.py
|
|
||||||
infer = //infer/tests/endtoend/java/infer:infer
|
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
ignore = .git, .ml, .mli
|
ignore = .git, .ml, .mli
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
export_file(
|
|
||||||
name = 'inferconfig',
|
|
||||||
src = '.inferconfig',
|
|
||||||
out = '.inferconfig',
|
|
||||||
visibility = [
|
|
||||||
'PUBLIC'
|
|
||||||
]
|
|
||||||
)
|
|
@ -1,82 +0,0 @@
|
|||||||
sources = glob(['**/*.java','**/*.json'])
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
'//dependencies/java/android/support/v4:android-support-v4',
|
|
||||||
'//infer/annotations:annotations',
|
|
||||||
'//infer/lib/java/android:android',
|
|
||||||
]
|
|
||||||
|
|
||||||
java_library(
|
|
||||||
name = 'checkers',
|
|
||||||
srcs = sources,
|
|
||||||
deps = dependencies,
|
|
||||||
visibility = [
|
|
||||||
'PUBLIC'
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
out = 'infer-out'
|
|
||||||
inferconfig_file = '$(location //infer/tests/codetoanalyze/java:inferconfig)'
|
|
||||||
copy_inferconfig = ' '.join(['cp', inferconfig_file, '$SRCDIR'])
|
|
||||||
clean_cmd = ' '.join(['rm', '-rf', out])
|
|
||||||
classpath = ':'.join([('$(classpath ' + path + ')') for path in dependencies])
|
|
||||||
|
|
||||||
def mk_infer_cmd(tag, srcs, stacktrace):
|
|
||||||
infer_cmd_main = ' '.join([
|
|
||||||
'infer',
|
|
||||||
'--no-progress-bar',
|
|
||||||
'--absolute-paths',
|
|
||||||
'-a', 'crashcontext',
|
|
||||||
'--stacktrace', stacktrace,
|
|
||||||
'--',
|
|
||||||
'javac',
|
|
||||||
'-cp', classpath,
|
|
||||||
srcs])
|
|
||||||
out_rename = ' '.join(['cp',
|
|
||||||
out + '/crashcontext/crashcontext.json',
|
|
||||||
'$OUT' + "." + tag])
|
|
||||||
return ' && '.join([infer_cmd_main, out_rename])
|
|
||||||
|
|
||||||
infer_cmds = [
|
|
||||||
mk_infer_cmd(
|
|
||||||
"MinimalCrashExample",
|
|
||||||
"MinimalCrashExample.java",
|
|
||||||
"MinimalCrashExample.stacktrace.json"
|
|
||||||
),
|
|
||||||
mk_infer_cmd(
|
|
||||||
"MultiStackFrameCrashExample",
|
|
||||||
"MultiStackFrameCrashExample.java",
|
|
||||||
"MultiStackFrameCrashExample.stacktrace.json"
|
|
||||||
),
|
|
||||||
mk_infer_cmd(
|
|
||||||
"BranchingCallsExample",
|
|
||||||
"BranchingCallsExample.java",
|
|
||||||
"BranchingCallsExample.stacktrace.json"
|
|
||||||
),
|
|
||||||
mk_infer_cmd(
|
|
||||||
"MethodNameClashExample",
|
|
||||||
"MethodNameClashExample.java",
|
|
||||||
"MethodNameClashExample.stacktrace.json"
|
|
||||||
),
|
|
||||||
mk_infer_cmd(
|
|
||||||
"NativeMethodExample",
|
|
||||||
"NativeMethodExample.java",
|
|
||||||
"NativeMethodExample.stacktrace.json"
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
# Copy the last crashcontext.json because buck expects it as the output file.
|
|
||||||
# This will only contain the results for the last run infer_cmd above.
|
|
||||||
copy_cmd = ' '.join(['cp', out + '/crashcontext/crashcontext.json', '$OUT'])
|
|
||||||
command = ' && '.join([clean_cmd, copy_inferconfig, ' && '.join(infer_cmds), copy_cmd])
|
|
||||||
|
|
||||||
genrule(
|
|
||||||
name = 'analyze',
|
|
||||||
srcs = sources,
|
|
||||||
out = 'crashcontext.json',
|
|
||||||
cmd = command,
|
|
||||||
deps = dependencies + [':checkers'],
|
|
||||||
visibility = [
|
|
||||||
'PUBLIC',
|
|
||||||
]
|
|
||||||
)
|
|
@ -0,0 +1 @@
|
|||||||
|
{"stack":[{"method_name":"codetoanalyze.java.crashcontext.BranchingCallsExample.bar():void","location":{"location_type":"call_site","file":"BranchingCallsExample.java","line":24,"blame_range":[{"start_line":22,"end_line":24}]},"callees":[{"method_name":"java.lang.String.toString():java.lang.String","callees":[]}]},{"method_name":"codetoanalyze.java.crashcontext.BranchingCallsExample.foo():void","location":{"location_type":"call_site","file":"BranchingCallsExample.java","line":29,"blame_range":[{"start_line":27,"end_line":30}]},"callees":[{"method_name":"codetoanalyze.java.crashcontext.BranchingCallsExample.bar():void","location":{"location_type":"proc_start","file":"BranchingCallsExample.java","line":22,"blame_range":[{"start_line":22,"end_line":24}]},"callees":[]},{"method_name":"codetoanalyze.java.crashcontext.BranchingCallsExample.pre_bar():void","location":{"location_type":"proc_start","file":"BranchingCallsExample.java","line":14,"blame_range":[{"start_line":14,"end_line":15}]},"callees":[]}]},{"method_name":"codetoanalyze.java.crashcontext.BranchingCallsExample.main(java.lang.String[]):void","location":{"location_type":"call_site","file":"BranchingCallsExample.java","line":34,"blame_range":[{"start_line":33,"end_line":34}]},"callees":[{"method_name":"codetoanalyze.java.crashcontext.BranchingCallsExample.foo():void","location":{"location_type":"proc_start","file":"BranchingCallsExample.java","line":27,"blame_range":[{"start_line":27,"end_line":30}]},"callees":[]}]}]}
|
@ -0,0 +1,42 @@
|
|||||||
|
# Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# This source code is licensed under the BSD style license found in the
|
||||||
|
# LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
# of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
|
include ../Makefile
|
||||||
|
|
||||||
|
|
||||||
|
ANALYZER = crashcontext
|
||||||
|
|
||||||
|
FILES = \
|
||||||
|
BranchingCallsExample \
|
||||||
|
MethodNameClashExample \
|
||||||
|
MinimalCrashExample \
|
||||||
|
MultiStackFrameCrashExample \
|
||||||
|
NativeMethodExample \
|
||||||
|
|
||||||
|
compile:
|
||||||
|
for file in $(FILES) ; do \
|
||||||
|
javac -cp $(CLASSPATH) $$file.java ; \
|
||||||
|
done
|
||||||
|
|
||||||
|
analyze:
|
||||||
|
for file in $(FILES) ; do \
|
||||||
|
$(INFER_BIN) -a $(ANALYZER) --stacktrace $$file.stacktrace.json -- javac -cp $(CLASSPATH) $$file.java >/dev/null 2>/dev/null ; \
|
||||||
|
cp infer-out/crashcontext/crashcontext.json $$file.exp.test ; \
|
||||||
|
done
|
||||||
|
|
||||||
|
# overwrite
|
||||||
|
print:
|
||||||
|
|
||||||
|
# overwrite
|
||||||
|
test: analyze
|
||||||
|
set -e; \
|
||||||
|
for file in $(FILES) ; do \
|
||||||
|
diff -u $$file.exp $$file.exp.test ; \
|
||||||
|
rm $$file.exp.test ; \
|
||||||
|
done
|
||||||
|
make clean
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
{"stack":[{"method_name":"codetoanalyze.java.crashcontext.MethodNameClashExample$A.foo():void","location":{"location_type":"call_site","file":"MethodNameClashExample.java","line":18,"blame_range":[{"start_line":16,"end_line":18}]},"callees":[{"method_name":"java.lang.String.toString():java.lang.String","callees":[]}]},{"method_name":"codetoanalyze.java.crashcontext.MethodNameClashExample$B.foo():void","location":{"location_type":"call_site","file":"MethodNameClashExample.java","line":26,"blame_range":[{"start_line":26,"end_line":26}]},"callees":[{"method_name":"codetoanalyze.java.crashcontext.MethodNameClashExample$A.foo():void","location":{"location_type":"proc_start","file":"MethodNameClashExample.java","line":16,"blame_range":[{"start_line":16,"end_line":18}]},"callees":[]}]},{"method_name":"codetoanalyze.java.crashcontext.MethodNameClashExample.main(java.lang.String[]):void","location":{"location_type":"call_site","file":"MethodNameClashExample.java","line":32,"blame_range":[{"start_line":31,"end_line":32}]},"callees":[{"method_name":"codetoanalyze.java.crashcontext.MethodNameClashExample$B.foo():void","location":{"location_type":"proc_start","file":"MethodNameClashExample.java","line":26,"blame_range":[{"start_line":26,"end_line":26}]},"callees":[]}]}]}
|
@ -0,0 +1 @@
|
|||||||
|
{"stack":[{"method_name":"codetoanalyze.java.crashcontext.MinimalCrashExample.main(java.lang.String[]):void","location":{"location_type":"call_site","file":"MinimalCrashExample.java","line":16,"blame_range":[{"start_line":14,"end_line":16}]},"callees":[{"method_name":"java.lang.String.toString():java.lang.String","callees":[]}]}]}
|
@ -0,0 +1 @@
|
|||||||
|
{"stack":[{"method_name":"codetoanalyze.java.crashcontext.MultiStackFrameCrashExample.bar():void","location":{"location_type":"call_site","file":"MultiStackFrameCrashExample.java","line":16,"blame_range":[{"start_line":14,"end_line":16}]},"callees":[{"method_name":"java.lang.String.toString():java.lang.String","callees":[]}]},{"method_name":"codetoanalyze.java.crashcontext.MultiStackFrameCrashExample.foo():void","location":{"location_type":"call_site","file":"MultiStackFrameCrashExample.java","line":20,"blame_range":[{"start_line":19,"end_line":20}]},"callees":[{"method_name":"codetoanalyze.java.crashcontext.MultiStackFrameCrashExample.bar():void","location":{"location_type":"proc_start","file":"MultiStackFrameCrashExample.java","line":14,"blame_range":[{"start_line":14,"end_line":16}]},"callees":[]}]},{"method_name":"codetoanalyze.java.crashcontext.MultiStackFrameCrashExample.main(java.lang.String[]):void","location":{"location_type":"call_site","file":"MultiStackFrameCrashExample.java","line":24,"blame_range":[{"start_line":23,"end_line":24}]},"callees":[{"method_name":"codetoanalyze.java.crashcontext.MultiStackFrameCrashExample.foo():void","location":{"location_type":"proc_start","file":"MultiStackFrameCrashExample.java","line":19,"blame_range":[{"start_line":19,"end_line":20}]},"callees":[]}]}]}
|
@ -0,0 +1 @@
|
|||||||
|
{"stack":[{"method_name":"codetoanalyze.java.crashcontext.NativeMethodExample.foo():void","location":{"location_type":"call_site","file":"NativeMethodExample.java","line":18,"blame_range":[{"start_line":16,"end_line":18}]},"callees":[{"method_name":"java.lang.String.toString():java.lang.String","callees":[]}]},{"method_name":"sun.reflect.NativeMethodAccessorImpl.invoke0","location":{"location_type":"call_site","file":"Native Method","blame_range":[]},"callees":[]},{"method_name":"sun.reflect.NativeMethodAccessorImpl.invoke","location":{"location_type":"call_site","file":"NativeMethodAccessorImpl.java","line":62,"blame_range":[]},"callees":[]},{"method_name":"sun.reflect.DelegatingMethodAccessorImpl.invoke","location":{"location_type":"call_site","file":"DelegatingMethodAccessorImpl.java","line":43,"blame_range":[]},"callees":[]},{"method_name":"java.lang.reflect.Method.invoke","location":{"location_type":"call_site","file":"Method.java","line":497,"blame_range":[]},"callees":[]},{"method_name":"codetoanalyze.java.crashcontext.NativeMethodExample.main(java.lang.String[]):void","location":{"location_type":"call_site","file":"NativeMethodExample.java","line":27,"blame_range":[{"start_line":21,"end_line":29}]},"callees":[{"method_name":"java.lang.Class.getDeclaredMethod(java.lang.String,java.lang.Class[]):java.lang.reflect.Method","callees":[]},{"method_name":"java.lang.reflect.Method.invoke(java.lang.Object,java.lang.Object[]):java.lang.Object","callees":[]},{"method_name":"__new_array","callees":[]}]}]}
|
@ -0,0 +1,19 @@
|
|||||||
|
# Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# This source code is licensed under the BSD style license found in the
|
||||||
|
# LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
# of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
|
include ../Makefile
|
||||||
|
|
||||||
|
ANALYZER = infer
|
||||||
|
|
||||||
|
FILES = \
|
||||||
|
BasicHarnessActivity.java \
|
||||||
|
|
||||||
|
compile:
|
||||||
|
javac -cp $(CLASSPATH) $(FILES)
|
||||||
|
|
||||||
|
analyze:
|
||||||
|
$(INFER_BIN) -a $(ANALYZER) --android-harness -- javac -cp $(CLASSPATH) $(FILES) >/dev/null 2>/dev/null
|
@ -0,0 +1 @@
|
|||||||
|
BasicHarnessActivity.java, codetoanalyze.java.harness.BasicHarnessActivity.InferGeneratedHarness(), -1, NULL_DEREFERENCE
|
@ -1,24 +0,0 @@
|
|||||||
tests_dependencies = [
|
|
||||||
'//infer/lib/java/android:android',
|
|
||||||
'//dependencies/java/guava:guava',
|
|
||||||
'//dependencies/java/junit:hamcrest',
|
|
||||||
'//dependencies/java/jackson:jackson',
|
|
||||||
'//dependencies/java/jsr-305:jsr-305',
|
|
||||||
'//dependencies/java/junit:junit',
|
|
||||||
'//dependencies/java/opencsv:opencsv',
|
|
||||||
'//infer/tests/utils:utils',
|
|
||||||
'//infer/tests/codetoanalyze/java/crashcontext:crashcontext',
|
|
||||||
'//infer/tests/codetoanalyze/java/infer:infer',
|
|
||||||
]
|
|
||||||
|
|
||||||
# ############### Java endtoend tests ########################
|
|
||||||
java_test(
|
|
||||||
name='java_endtoend_tests',
|
|
||||||
deps=[
|
|
||||||
'//infer/tests/endtoend/java/crashcontext:crashcontext',
|
|
||||||
'//infer/tests/endtoend/java/harness:harness',
|
|
||||||
],
|
|
||||||
visibility=[
|
|
||||||
'PUBLIC',
|
|
||||||
],
|
|
||||||
)
|
|
@ -1,16 +0,0 @@
|
|||||||
java_test(
|
|
||||||
name='crashcontext',
|
|
||||||
srcs=glob(['*.java']),
|
|
||||||
deps=[
|
|
||||||
'//dependencies/java/guava:guava',
|
|
||||||
'//dependencies/java/junit:hamcrest',
|
|
||||||
'//dependencies/java/junit:junit',
|
|
||||||
'//infer/tests/utils:utils',
|
|
||||||
],
|
|
||||||
resources=[
|
|
||||||
'//infer/tests/codetoanalyze/java/crashcontext:analyze',
|
|
||||||
],
|
|
||||||
visibility=[
|
|
||||||
'PUBLIC',
|
|
||||||
],
|
|
||||||
)
|
|
@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package endtoend.java.crashcontext;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import utils.CrashContextResults;
|
|
||||||
|
|
||||||
public class BranchingCallsTest {
|
|
||||||
|
|
||||||
public static final String TAG = "BranchingCallsExample";
|
|
||||||
public static final String FILENAME = "BranchingCallsExample.java";
|
|
||||||
|
|
||||||
public static final String MAIN_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.BranchingCallsExample.main(java.lang.String[]):void";
|
|
||||||
public static final int MAIN_METHOD_LOC_START = 33;
|
|
||||||
public static final int MAIN_METHOD_LOC_LINE = 34;
|
|
||||||
public static final int MAIN_METHOD_LOC_END = 34;
|
|
||||||
|
|
||||||
public static final String FOO_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.BranchingCallsExample.foo():void";
|
|
||||||
public static final int FOO_METHOD_LOC_START = 27;
|
|
||||||
public static final int FOO_METHOD_LOC_LINE = 27;
|
|
||||||
public static final int FOO_METHOD_LOC_END = 30;
|
|
||||||
|
|
||||||
public static final String PRE_BAR_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.BranchingCallsExample.pre_bar():void";
|
|
||||||
public static final int PRE_BAR_METHOD_LOC_START = 14;
|
|
||||||
public static final int PRE_BAR_METHOD_LOC_LINE = 14;
|
|
||||||
public static final int PRE_BAR_METHOD_LOC_END = 15;
|
|
||||||
|
|
||||||
public static final String BAR_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.BranchingCallsExample.bar():void";
|
|
||||||
public static final int BAR_METHOD_LOC_START = 22;
|
|
||||||
public static final int BAR_METHOD_LOC_LINE = 24;
|
|
||||||
public static final int BAR_METHOD_LOC_END = 24;
|
|
||||||
|
|
||||||
public static final String POST_BAR_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.BranchingCallsExample.post_bar():void";
|
|
||||||
|
|
||||||
public static final String TO_STRING_METHOD =
|
|
||||||
"java.lang.String.toString():java.lang.String";
|
|
||||||
|
|
||||||
private static CrashContextResults crashcontext;
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void loadResults() throws IOException {
|
|
||||||
crashcontext =
|
|
||||||
CrashContextResults.loadJSONResults(TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shapeOfTheStack() {
|
|
||||||
assertThat("The stack trace should contain " + BAR_METHOD,
|
|
||||||
crashcontext.hasStackFrame(BAR_METHOD, 0));
|
|
||||||
assertThat("The stack trace should contain " + FOO_METHOD,
|
|
||||||
crashcontext.hasStackFrame(FOO_METHOD, 1));
|
|
||||||
assertThat("The stack trace should contain " + MAIN_METHOD,
|
|
||||||
crashcontext.hasStackFrame(MAIN_METHOD, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void toStringMethodIsFound() {
|
|
||||||
assertThat("Method " + TO_STRING_METHOD + " should be part of the context",
|
|
||||||
crashcontext.hasMethod(TO_STRING_METHOD));
|
|
||||||
assertThat("Method " + TO_STRING_METHOD + " should be reachable in the " +
|
|
||||||
"context tree from " + BAR_METHOD,
|
|
||||||
crashcontext.hasPath(BAR_METHOD, TO_STRING_METHOD));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void preBarMethodIsFound() {
|
|
||||||
assertThat("Method " + PRE_BAR_METHOD + " should be part of the context",
|
|
||||||
crashcontext.hasMethod(PRE_BAR_METHOD));
|
|
||||||
assertThat("Method " + PRE_BAR_METHOD + " should be reachable in the " +
|
|
||||||
"context tree from " + FOO_METHOD,
|
|
||||||
crashcontext.hasPath(FOO_METHOD, PRE_BAR_METHOD));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void postBarMethodIsOmitted() {
|
|
||||||
assertThat("Method " + POST_BAR_METHOD + " shouldn't be part of the context",
|
|
||||||
crashcontext.hasNotMethod(POST_BAR_METHOD));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void sourceFileLocations() {
|
|
||||||
assertThat("Method " + MAIN_METHOD + " should have the following " +
|
|
||||||
"location information: {file: " + FILENAME +
|
|
||||||
", critical line: " + MAIN_METHOD_LOC_LINE +
|
|
||||||
", range start: " + MAIN_METHOD_LOC_START +
|
|
||||||
", range end: " + MAIN_METHOD_LOC_END + "}",
|
|
||||||
crashcontext.hasMethodWithLocation(MAIN_METHOD,
|
|
||||||
FILENAME,
|
|
||||||
MAIN_METHOD_LOC_LINE,
|
|
||||||
MAIN_METHOD_LOC_START,
|
|
||||||
MAIN_METHOD_LOC_END));
|
|
||||||
assertThat("Method " + FOO_METHOD + " should have the following " +
|
|
||||||
"location information: {file: " + FILENAME +
|
|
||||||
", critical line: " + FOO_METHOD_LOC_LINE +
|
|
||||||
", range start: " + FOO_METHOD_LOC_START +
|
|
||||||
", range end: " + FOO_METHOD_LOC_END + "}",
|
|
||||||
crashcontext.hasMethodWithLocation(FOO_METHOD,
|
|
||||||
FILENAME,
|
|
||||||
FOO_METHOD_LOC_LINE,
|
|
||||||
FOO_METHOD_LOC_START,
|
|
||||||
FOO_METHOD_LOC_END));
|
|
||||||
assertThat("Method " + BAR_METHOD + " should have the following " +
|
|
||||||
"location information: {file: " + FILENAME +
|
|
||||||
", critical line: " + BAR_METHOD_LOC_LINE +
|
|
||||||
", range start: " + BAR_METHOD_LOC_START +
|
|
||||||
", range end: " + BAR_METHOD_LOC_END + "}",
|
|
||||||
crashcontext.hasMethodWithLocation(BAR_METHOD,
|
|
||||||
FILENAME,
|
|
||||||
BAR_METHOD_LOC_LINE,
|
|
||||||
BAR_METHOD_LOC_START,
|
|
||||||
BAR_METHOD_LOC_END));
|
|
||||||
assertThat("Method " + PRE_BAR_METHOD + " should have the following " +
|
|
||||||
"location information: {file: " + FILENAME +
|
|
||||||
", critical line: " + PRE_BAR_METHOD_LOC_LINE +
|
|
||||||
", range start: " + PRE_BAR_METHOD_LOC_START +
|
|
||||||
", range end: " + PRE_BAR_METHOD_LOC_END + "}",
|
|
||||||
crashcontext.hasMethodWithLocation(PRE_BAR_METHOD,
|
|
||||||
FILENAME,
|
|
||||||
PRE_BAR_METHOD_LOC_LINE,
|
|
||||||
PRE_BAR_METHOD_LOC_START,
|
|
||||||
PRE_BAR_METHOD_LOC_END));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package endtoend.java.crashcontext;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import utils.CrashContextResults;
|
|
||||||
|
|
||||||
public class MethodNameClashTest {
|
|
||||||
|
|
||||||
public static final String TAG = "MethodNameClashExample";
|
|
||||||
|
|
||||||
public static final String MAIN_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.MethodNameClashExample.main(java.lang.String[]):void";
|
|
||||||
|
|
||||||
public static final String A_FOO_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.MethodNameClashExample$A.foo():void";
|
|
||||||
|
|
||||||
public static final String B_FOO_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.MethodNameClashExample$B.foo():void";
|
|
||||||
|
|
||||||
private static CrashContextResults crashcontext;
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void loadResults() throws IOException {
|
|
||||||
crashcontext =
|
|
||||||
CrashContextResults.loadJSONResults(TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shapeOfTheStack() {
|
|
||||||
assertThat("The stack trace should contain " + A_FOO_METHOD,
|
|
||||||
crashcontext.hasStackFrame(A_FOO_METHOD, 0));
|
|
||||||
assertThat("The stack trace should contain " + B_FOO_METHOD,
|
|
||||||
crashcontext.hasStackFrame(B_FOO_METHOD, 1));
|
|
||||||
assertThat("The stack trace should contain " + MAIN_METHOD,
|
|
||||||
crashcontext.hasStackFrame(MAIN_METHOD, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package endtoend.java.crashcontext;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import utils.CrashContextResults;
|
|
||||||
|
|
||||||
public class MinimalCrashTest {
|
|
||||||
|
|
||||||
public static final String TAG = "MinimalCrashExample";
|
|
||||||
|
|
||||||
public static final String MAIN_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.MinimalCrashExample.main(java.lang.String[]):void";
|
|
||||||
|
|
||||||
public static final String TO_STRING_METHOD =
|
|
||||||
"java.lang.String.toString():java.lang.String";
|
|
||||||
|
|
||||||
private static CrashContextResults crashcontext;
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void loadResults() throws IOException {
|
|
||||||
crashcontext =
|
|
||||||
CrashContextResults.loadJSONResults(TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shapeOfTheStack() {
|
|
||||||
assertThat("The stack trace should contain " + MAIN_METHOD,
|
|
||||||
crashcontext.hasStackFrame(MAIN_METHOD, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void toStringMethodIsDetected() {
|
|
||||||
assertThat("Method " + TO_STRING_METHOD + " should be part of the context",
|
|
||||||
crashcontext.hasMethod(TO_STRING_METHOD));
|
|
||||||
assertThat("Method " + TO_STRING_METHOD + " should be reachable in the " +
|
|
||||||
"context tree from " + MAIN_METHOD,
|
|
||||||
crashcontext.hasPath(MAIN_METHOD, TO_STRING_METHOD));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package endtoend.java.crashcontext;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import utils.CrashContextResults;
|
|
||||||
|
|
||||||
public class MultiStackFrameCrashTest {
|
|
||||||
|
|
||||||
public static final String TAG = "MultiStackFrameCrashExample";
|
|
||||||
|
|
||||||
public static final String MAIN_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.MultiStackFrameCrashExample.main(java.lang.String[]):void";
|
|
||||||
|
|
||||||
public static final String FOO_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.MultiStackFrameCrashExample.foo():void";
|
|
||||||
|
|
||||||
public static final String BAR_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.MultiStackFrameCrashExample.bar():void";
|
|
||||||
|
|
||||||
public static final String TO_STRING_METHOD =
|
|
||||||
"java.lang.String.toString():java.lang.String";
|
|
||||||
|
|
||||||
private static CrashContextResults crashcontext;
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void loadResults() throws IOException {
|
|
||||||
crashcontext =
|
|
||||||
CrashContextResults.loadJSONResults(TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shapeOfTheStack() {
|
|
||||||
assertThat("The stack trace should contain " + BAR_METHOD,
|
|
||||||
crashcontext.hasStackFrame(BAR_METHOD, 0));
|
|
||||||
assertThat("The stack trace should contain " + FOO_METHOD,
|
|
||||||
crashcontext.hasStackFrame(FOO_METHOD, 1));
|
|
||||||
assertThat("The stack trace should contain " + MAIN_METHOD,
|
|
||||||
crashcontext.hasStackFrame(MAIN_METHOD, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void toStringMethodIsFound() {
|
|
||||||
assertThat("Method " + TO_STRING_METHOD + " should be part of the context",
|
|
||||||
crashcontext.hasMethod(TO_STRING_METHOD));
|
|
||||||
assertThat("Method " + TO_STRING_METHOD + " should be reachable in the " +
|
|
||||||
"context tree from " + BAR_METHOD,
|
|
||||||
crashcontext.hasPath(BAR_METHOD, TO_STRING_METHOD));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package endtoend.java.crashcontext;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import utils.CrashContextResults;
|
|
||||||
|
|
||||||
public class NativeMethodTest {
|
|
||||||
|
|
||||||
public static final String TAG = "NativeMethodExample";
|
|
||||||
|
|
||||||
public static final String MAIN_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.NativeMethodExample.main(java.lang.String[]):void";
|
|
||||||
|
|
||||||
// Currently, native methods are missing their arguments lists.
|
|
||||||
public static final String REFLECTION_INVOKE_METHOD =
|
|
||||||
"sun.reflect.NativeMethodAccessorImpl.invoke0";
|
|
||||||
|
|
||||||
public static final String FOO_METHOD =
|
|
||||||
"codetoanalyze.java.crashcontext.NativeMethodExample.foo():void";
|
|
||||||
|
|
||||||
private static CrashContextResults crashcontext;
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void loadResults() throws IOException {
|
|
||||||
crashcontext =
|
|
||||||
CrashContextResults.loadJSONResults(TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shapeOfTheStack() {
|
|
||||||
assertThat("The stack trace should contain " + FOO_METHOD,
|
|
||||||
crashcontext.hasStackFrame(FOO_METHOD));
|
|
||||||
assertThat("The trace should contain at least one native method ",
|
|
||||||
crashcontext.hasNativeMethodOnStack());
|
|
||||||
assertThat("The stack trace should contain " + REFLECTION_INVOKE_METHOD,
|
|
||||||
crashcontext.hasStackFrame(REFLECTION_INVOKE_METHOD));
|
|
||||||
assertThat("The stack trace should contain " + MAIN_METHOD,
|
|
||||||
crashcontext.hasStackFrame(MAIN_METHOD));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
java_test(
|
|
||||||
name='harness',
|
|
||||||
srcs=glob(['*.java']),
|
|
||||||
deps=[
|
|
||||||
'//dependencies/java/guava:guava',
|
|
||||||
'//dependencies/java/junit:hamcrest',
|
|
||||||
'//dependencies/java/junit:junit',
|
|
||||||
'//infer/tests/utils:utils',
|
|
||||||
],
|
|
||||||
visibility=[
|
|
||||||
'PUBLIC',
|
|
||||||
],
|
|
||||||
)
|
|
@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package endtoend.java.harness;
|
|
||||||
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static utils.matchers.ResultContainsErrorNoFilename.contains;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.ClassRule;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import utils.DebuggableTemporaryFolder;
|
|
||||||
import utils.InferException;
|
|
||||||
import utils.InferResults;
|
|
||||||
import utils.InferRunner;
|
|
||||||
|
|
||||||
public class InhabitTest {
|
|
||||||
|
|
||||||
public static final String TrickyParamsActivity =
|
|
||||||
"infer/tests/codetoanalyze/java/harness/TrickyParamsActivity.java";
|
|
||||||
|
|
||||||
public static final String NULL_DEREFERENCE = "NULL_DEREFERENCE";
|
|
||||||
|
|
||||||
@ClassRule
|
|
||||||
public static DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder();
|
|
||||||
|
|
||||||
private static ImmutableList<String> inferCmd;
|
|
||||||
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void runInfer() throws IOException {
|
|
||||||
inferCmd = InferRunner.createJavaInferHarnessCommand(folder, TrickyParamsActivity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void canInhabitTrickyParams()
|
|
||||||
throws InterruptedException, IOException, InferException {
|
|
||||||
InferResults inferResults = InferRunner.runInferJava(inferCmd);
|
|
||||||
assertThat(
|
|
||||||
"Results should contain NPE",
|
|
||||||
inferResults,
|
|
||||||
contains(
|
|
||||||
NULL_DEREFERENCE,
|
|
||||||
"java.harness.TrickyParamsActivity.InferGeneratedHarness"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package endtoend.java.harness;
|
|
||||||
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static utils.matchers.ResultContainsErrorNoFilename.contains;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.ClassRule;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import utils.DebuggableTemporaryFolder;
|
|
||||||
import utils.InferException;
|
|
||||||
import utils.InferResults;
|
|
||||||
import utils.InferRunner;
|
|
||||||
|
|
||||||
public class LifecycleTest {
|
|
||||||
|
|
||||||
public static final String BasicHarnessActivity =
|
|
||||||
"infer/tests/codetoanalyze/java/harness/BasicHarnessActivity.java";
|
|
||||||
|
|
||||||
public static final String NULL_DEREFERENCE = "NULL_DEREFERENCE";
|
|
||||||
|
|
||||||
@ClassRule
|
|
||||||
public static DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder();
|
|
||||||
|
|
||||||
private static ImmutableList<String> inferCmd;
|
|
||||||
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void runInfer() throws IOException {
|
|
||||||
inferCmd = InferRunner.createJavaInferHarnessCommand(folder, BasicHarnessActivity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void harnessRevealsNpe()
|
|
||||||
throws InterruptedException, IOException, InferException {
|
|
||||||
InferResults inferResults = InferRunner.runInferJava(inferCmd);
|
|
||||||
assertThat(
|
|
||||||
"Results should contain NPE",
|
|
||||||
inferResults,
|
|
||||||
contains(
|
|
||||||
NULL_DEREFERENCE,
|
|
||||||
"java.harness.BasicHarnessActivity.InferGeneratedHarness"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
# TODO: this file exists only to support buck integration in infer/tests/build_systems/build_integration_tests.py
|
|
||||||
java_test(
|
|
||||||
name='infer',
|
|
||||||
srcs=glob(['*.java']),
|
|
||||||
deps=[
|
|
||||||
'//dependencies/java/guava:guava',
|
|
||||||
'//dependencies/java/junit:hamcrest',
|
|
||||||
'//dependencies/java/junit:junit',
|
|
||||||
'//infer/tests/utils:utils',
|
|
||||||
],
|
|
||||||
resources=[
|
|
||||||
'//infer/tests/codetoanalyze/java/infer:analyze',
|
|
||||||
],
|
|
||||||
visibility=[
|
|
||||||
'PUBLIC',
|
|
||||||
],
|
|
||||||
)
|
|
@ -1,35 +0,0 @@
|
|||||||
tests_dependencies = [
|
|
||||||
'//infer/lib/java/android:android',
|
|
||||||
'//dependencies/java/guava:guava',
|
|
||||||
'//dependencies/java/junit:hamcrest',
|
|
||||||
'//dependencies/java/jackson:jackson',
|
|
||||||
'//dependencies/java/jsr-305:jsr-305',
|
|
||||||
'//dependencies/java/junit:junit',
|
|
||||||
'//dependencies/java/opencsv:opencsv',
|
|
||||||
'//infer/tests/utils:utils',
|
|
||||||
]
|
|
||||||
|
|
||||||
objcpp_infer_test_sources = glob(['*.java'])
|
|
||||||
objcpp_infer_test_deps = []
|
|
||||||
for test_source in objcpp_infer_test_sources:
|
|
||||||
target_name = test_source.replace("/", "_")[:-len(".java")]
|
|
||||||
objcpp_infer_test_deps.append(target_name)
|
|
||||||
|
|
||||||
java_test(
|
|
||||||
name=target_name,
|
|
||||||
srcs=[test_source],
|
|
||||||
deps=tests_dependencies,
|
|
||||||
visibility=[
|
|
||||||
'PUBLIC',
|
|
||||||
],
|
|
||||||
source='7',
|
|
||||||
target='7',
|
|
||||||
)
|
|
||||||
|
|
||||||
java_test(
|
|
||||||
name='infer',
|
|
||||||
deps=[':' + x for x in objcpp_infer_test_deps],
|
|
||||||
visibility=[
|
|
||||||
'PUBLIC',
|
|
||||||
],
|
|
||||||
)
|
|
@ -1,18 +0,0 @@
|
|||||||
java_library(
|
|
||||||
name='utils',
|
|
||||||
srcs=glob(['**/*.java']),
|
|
||||||
deps=[
|
|
||||||
'//infer/lib/java/android:android',
|
|
||||||
'//dependencies/java/guava:guava',
|
|
||||||
'//dependencies/java/junit:hamcrest',
|
|
||||||
'//dependencies/java/jackson:jackson',
|
|
||||||
'//dependencies/java/jsr-305:jsr-305',
|
|
||||||
'//dependencies/java/junit:junit',
|
|
||||||
'//dependencies/java/opencsv:opencsv'
|
|
||||||
],
|
|
||||||
visibility = [
|
|
||||||
'PUBLIC',
|
|
||||||
],
|
|
||||||
source='7',
|
|
||||||
target='7',
|
|
||||||
)
|
|
@ -1,129 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils;
|
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
import com.google.common.io.ByteStreams;
|
|
||||||
|
|
||||||
public class CrashContextResults {
|
|
||||||
|
|
||||||
private static final String CRASHCONTEXT_JSON =
|
|
||||||
"/buck-out/gen/infer/tests/codetoanalyze/java/crashcontext/analyze/crashcontext.json";
|
|
||||||
|
|
||||||
private JsonNode json;
|
|
||||||
private String filename;
|
|
||||||
|
|
||||||
private CrashContextResults(String tag) throws IOException {
|
|
||||||
String path =
|
|
||||||
System.getProperty("user.dir") + CRASHCONTEXT_JSON + "." + tag;
|
|
||||||
byte[] jsonData = ByteStreams.toByteArray(new FileInputStream(path));
|
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
json = objectMapper.readTree(jsonData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasStackFrame(String methodSignature, int pos) {
|
|
||||||
return methodSignature.equals(
|
|
||||||
json.path("stack").get(pos).path("method_name").asText());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasStackFrame(String methodSignature) {
|
|
||||||
for (JsonNode frame : json.path("stack")) {
|
|
||||||
if (methodSignature.equals(frame.path("method_name").asText())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasLocationOnStack(String filename, int line) {
|
|
||||||
for (JsonNode frame : json.path("stack")) {
|
|
||||||
if (filename.equals(frame.path("location").path("file").asText()) &&
|
|
||||||
line == frame.path("location").path("line").asInt()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNativeMethodOnStack() {
|
|
||||||
for (JsonNode frame : json.path("stack")) {
|
|
||||||
if (frame.path("location").path("file").asText()
|
|
||||||
.equals("Native Method")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<JsonNode> findNodesForMethod(JsonNode node,
|
|
||||||
String methodSignature,
|
|
||||||
List<JsonNode> accumulator) {
|
|
||||||
if (methodSignature.equals(node.path("method_name").asText())) {
|
|
||||||
accumulator.add(node);
|
|
||||||
}
|
|
||||||
for (JsonNode callee : node.path("callees")) {
|
|
||||||
findNodesForMethod(callee, methodSignature, accumulator);
|
|
||||||
}
|
|
||||||
return accumulator;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<JsonNode> findNodesForMethod(String methodSignature) {
|
|
||||||
List<JsonNode> accumulator = new ArrayList<JsonNode>();
|
|
||||||
for (JsonNode frame : json.path("stack")) {
|
|
||||||
findNodesForMethod(frame, methodSignature, accumulator);
|
|
||||||
}
|
|
||||||
return accumulator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasMethod(String methodSignature) {
|
|
||||||
return !findNodesForMethod(methodSignature).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNotMethod(String methodSignature) {
|
|
||||||
return findNodesForMethod(methodSignature).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasPath(String methodFrom, String methodTo) {
|
|
||||||
for (JsonNode from : findNodesForMethod(methodFrom)) {
|
|
||||||
if (!findNodesForMethod(from, methodTo, new ArrayList()).isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasMethodWithLocation(String methodSignature, String filename,
|
|
||||||
int line, int start, int end) {
|
|
||||||
for (JsonNode frame : findNodesForMethod(methodSignature)) {
|
|
||||||
if (frame.path("location").path("file").asText().endsWith(filename) &&
|
|
||||||
line == frame.path("location").path("line").asInt()) {
|
|
||||||
for (JsonNode blameRange : frame.path("location").path("blame_range")) {
|
|
||||||
if (blameRange.path("start_line").asInt() == start &&
|
|
||||||
blameRange.path("end_line").asInt() == end) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CrashContextResults loadJSONResults(String tag) throws IOException {
|
|
||||||
return new CrashContextResults(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-present Facebook, Inc.
|
|
||||||
*
|
|
||||||
* 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 utils;
|
|
||||||
|
|
||||||
import org.junit.rules.TemporaryFolder;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
|
|
||||||
public class DebuggableTemporaryFolder extends TemporaryFolder {
|
|
||||||
|
|
||||||
private
|
|
||||||
@Nullable
|
|
||||||
String name;
|
|
||||||
private boolean doNotDeleteOnExit;
|
|
||||||
|
|
||||||
public DebuggableTemporaryFolder() {
|
|
||||||
Map<String, String> env = System.getenv();
|
|
||||||
if (env.get("INFER_KEEP_FOLDER") != null) {
|
|
||||||
doNotDeleteOnExit = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If invoked, the directory created by this {@link org.junit.rules.TemporaryFolder} will not be
|
|
||||||
* deleted when the test finishes.
|
|
||||||
*
|
|
||||||
* @return {@code this}
|
|
||||||
*/
|
|
||||||
public DebuggableTemporaryFolder doNotDeleteOnExit() {
|
|
||||||
this.doNotDeleteOnExit = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name to use to identify this {@link org.junit.rules.TemporaryFolder} when writing log messages
|
|
||||||
* to stdout.
|
|
||||||
*
|
|
||||||
* @return {@code this}
|
|
||||||
*/
|
|
||||||
public DebuggableTemporaryFolder setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void after() {
|
|
||||||
if (doNotDeleteOnExit) {
|
|
||||||
String name = this.name == null ? "TemporaryFolder" : this.name;
|
|
||||||
System.out.printf("%s available at %s.\n", name, getRoot());
|
|
||||||
} else {
|
|
||||||
super.after();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class InferError {
|
|
||||||
|
|
||||||
private String errorType;
|
|
||||||
private Path errorFile;
|
|
||||||
private String errorMethod;
|
|
||||||
private int errorLine;
|
|
||||||
|
|
||||||
public InferError(String errorType, Path errorFile, String errorMethod, int errorLine) {
|
|
||||||
this.errorType = errorType;
|
|
||||||
this.errorMethod = errorMethod;
|
|
||||||
this.errorLine = errorLine;
|
|
||||||
try {
|
|
||||||
this.errorFile = errorFile.toRealPath();
|
|
||||||
} catch (IOException e) {
|
|
||||||
this.errorFile = errorFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public InferError(String errorType, Path errorFile, String errorMethod) {
|
|
||||||
this.errorType = errorType;
|
|
||||||
this.errorFile = errorFile;
|
|
||||||
this.errorMethod = errorMethod;
|
|
||||||
this.errorLine = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InferError inferError(String errorMethod, Path errorFile, String errorType) {
|
|
||||||
return new InferError(errorMethod, errorFile, errorType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getErrorType() {
|
|
||||||
return errorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getErrorMethod() {
|
|
||||||
return errorMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getErrorFile() {
|
|
||||||
return errorFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getErrorLine() {
|
|
||||||
return errorLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toStringNoLine() {
|
|
||||||
return errorType + " at " + errorFile + ", method " + errorMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
if (errorLine > 0)
|
|
||||||
return toStringNoLine() + " (line " + errorLine + ")";
|
|
||||||
else return toStringNoLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toStringFileMethod() {
|
|
||||||
return errorFile + ", method " + errorMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toStringErrorTypeMethod() {
|
|
||||||
return errorType + " at " + errorMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean matchType(String type) {
|
|
||||||
return this.errorType.equals(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean matchFile(Path file) {
|
|
||||||
Path realFile;
|
|
||||||
try {
|
|
||||||
realFile = file.toRealPath();
|
|
||||||
} catch (IOException e) {
|
|
||||||
realFile = file;
|
|
||||||
}
|
|
||||||
return this.errorFile.equals(realFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean matchMethod(String method) {
|
|
||||||
return this.errorMethod.equals(method);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean matchLine(int line) {
|
|
||||||
return this.errorLine < 0 || line < 0
|
|
||||||
|| (this.errorLine == line);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils;
|
|
||||||
|
|
||||||
|
|
||||||
public class InferException extends RuntimeException {
|
|
||||||
|
|
||||||
public InferException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized Throwable fillInStackTrace() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,202 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils;
|
|
||||||
|
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Vector;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import au.com.bytecode.opencsv.CSVReader;
|
|
||||||
|
|
||||||
public class InferResults {
|
|
||||||
|
|
||||||
private ImmutableList<String> inferCmd;
|
|
||||||
|
|
||||||
public static final Pattern JAVA_METHOD_NAME = Pattern.compile("(\\.)(.*)(\\()");
|
|
||||||
public static final Pattern C_FUNCTION_NAME = Pattern.compile("(\")(.*)(\")");
|
|
||||||
public static final Pattern OBJC_FUNCTION_NAME = Pattern.compile("(.*)_(.*)");
|
|
||||||
|
|
||||||
private Vector<InferError> errors = new Vector<InferError>();
|
|
||||||
|
|
||||||
InferResults() {
|
|
||||||
this.inferCmd = ImmutableList.of("");
|
|
||||||
}
|
|
||||||
|
|
||||||
InferResults(ImmutableList<String> inferCmd) {
|
|
||||||
this.inferCmd = inferCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void parseInferResultsFromString(Pattern pattern, String errorString)
|
|
||||||
throws IOException, InferException {
|
|
||||||
|
|
||||||
try (CSVReader reader = new CSVReader(new StringReader(errorString))) {
|
|
||||||
List<String[]> lines = reader.readAll();
|
|
||||||
Path root = Paths.get(System.getProperty("user.dir"));
|
|
||||||
|
|
||||||
for (String[] items : lines) {
|
|
||||||
String errorKind = items[1].trim();
|
|
||||||
String errorType = items[2].trim();
|
|
||||||
if (errorKind.equals("ERROR") ||
|
|
||||||
errorType.equals("ASSIGN_POINTER_WARNING") ||
|
|
||||||
errorType.equals("STRONG_DELEGATE_WARNING") ||
|
|
||||||
errorType.equals("DIRECT_ATOMIC_PROPERTY_ACCESS") ||
|
|
||||||
errorType.equals("CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK") ||
|
|
||||||
errorType.equals("REGISTERED_OBSERVER_BEING_DEALLOCATED") ||
|
|
||||||
errorType.equals("GLOBAL_VARIABLE_INITIALIZED_WITH_FUNCTION_OR_METHOD_CALL") ||
|
|
||||||
errorType.equals("IMMUTABLE_CAST") ||
|
|
||||||
errorType.equals("PARAMETER_NOT_NULL_CHECKED") ||
|
|
||||||
errorType.equals("DANGLING_POINTER_DEREFERENCE") ||
|
|
||||||
errorType.equals("IVAR_NOT_NULL_CHECKED") ||
|
|
||||||
errorType.equals("BAD_POINTER_COMPARISON") ||
|
|
||||||
errorType.equals("Bad_footprint") ||
|
|
||||||
errorType.equals("MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE")) {
|
|
||||||
Integer errorLine = Integer.parseInt(items[5].trim());
|
|
||||||
String procedure = items[6];
|
|
||||||
Path path = Paths.get(items[8]);
|
|
||||||
if (path.isAbsolute()) {
|
|
||||||
path = root.relativize(Paths.get(items[8]));
|
|
||||||
}
|
|
||||||
Matcher methodMatcher = pattern.matcher(procedure);
|
|
||||||
boolean matching = methodMatcher.find();
|
|
||||||
if (matching) {
|
|
||||||
procedure = methodMatcher.group(2);
|
|
||||||
if (procedure == null) {
|
|
||||||
throw new InferException("Unexpected method name structure.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
procedure = procedure.trim();
|
|
||||||
InferError error = new InferError(errorType, path, procedure, errorLine);
|
|
||||||
errors.add(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void parseJavaInferResultsFromString(String errorString)
|
|
||||||
throws IOException, InferException {
|
|
||||||
parseInferResultsFromString(JAVA_METHOD_NAME, errorString);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void parseCInferResultsFromString(String errorString)
|
|
||||||
throws IOException, InferException {
|
|
||||||
parseInferResultsFromString(C_FUNCTION_NAME, errorString);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void parseObjCInferResultsFromString(String errorString)
|
|
||||||
throws IOException, InferException {
|
|
||||||
parseInferResultsFromString(OBJC_FUNCTION_NAME, errorString);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector<InferError> getErrors() {
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String inferCmdToString() {
|
|
||||||
return "Infer command: " + Joiner.on(' ').join(inferCmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
String s = "";
|
|
||||||
for (InferError e : errors) {
|
|
||||||
s = s + "\n" + e.toString();
|
|
||||||
}
|
|
||||||
if (s.length() == 0) return "No results.";
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void filter(String filename) {
|
|
||||||
Vector<InferError> filtered_errors = new Vector<InferError>();
|
|
||||||
for (InferError error : errors) {
|
|
||||||
if (error.getErrorFile().endsWith(filename)) {
|
|
||||||
filtered_errors.add(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
errors = filtered_errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InferResults loadResultsFromReader(
|
|
||||||
BufferedReader reader,
|
|
||||||
String sourceFile,
|
|
||||||
Pattern pattern) {
|
|
||||||
InferResults inferResults = new InferResults();
|
|
||||||
String resultString = "";
|
|
||||||
try {
|
|
||||||
String line = reader.readLine();
|
|
||||||
while (line != null) {
|
|
||||||
resultString += line + "\n";
|
|
||||||
line = reader.readLine();
|
|
||||||
}
|
|
||||||
inferResults.parseInferResultsFromString(
|
|
||||||
pattern,
|
|
||||||
resultString);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e.toString());
|
|
||||||
}
|
|
||||||
inferResults.filter(sourceFile);
|
|
||||||
return inferResults;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static InferResults loadResultsFromPath(Class currentClass, String sourceFile,
|
|
||||||
String csvPath, Pattern procnamePattern) {
|
|
||||||
BufferedReader reader =
|
|
||||||
new BufferedReader(
|
|
||||||
new InputStreamReader(
|
|
||||||
currentClass.getResourceAsStream(csvPath)));
|
|
||||||
return loadResultsFromReader(
|
|
||||||
Preconditions.checkNotNull(reader),
|
|
||||||
sourceFile,
|
|
||||||
procnamePattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InferResults loadInferResults(Class currentClass, String sourceFile) {
|
|
||||||
return loadResultsFromPath(
|
|
||||||
currentClass,
|
|
||||||
sourceFile,
|
|
||||||
"/infer/tests/codetoanalyze/java/infer/report.csv",
|
|
||||||
InferResults.JAVA_METHOD_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InferResults loadTracingResults(Class currentClass, String sourceFile) {
|
|
||||||
return loadResultsFromPath(
|
|
||||||
currentClass,
|
|
||||||
sourceFile,
|
|
||||||
"/infer/tests/codetoanalyze/java/tracing/report.csv",
|
|
||||||
InferResults.JAVA_METHOD_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InferResults loadTracingComparisonResults(Class currentClass, String sourceFile) {
|
|
||||||
return loadResultsFromPath(
|
|
||||||
currentClass,
|
|
||||||
sourceFile,
|
|
||||||
"/infer/tests/codetoanalyze/java/infer/comparison_report.csv",
|
|
||||||
InferResults.JAVA_METHOD_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InferResults loadCInferResults(Class currentClass, String sourceFile) {
|
|
||||||
return loadResultsFromPath(
|
|
||||||
currentClass,
|
|
||||||
sourceFile,
|
|
||||||
"/infer/tests/codetoanalyze/c/errors/report.csv",
|
|
||||||
InferResults.C_FUNCTION_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,306 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils;
|
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
|
|
||||||
import org.junit.rules.TemporaryFolder;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
public class InferRunner {
|
|
||||||
|
|
||||||
public static final String BUGS_FILE_NAME = "report.csv";
|
|
||||||
|
|
||||||
public static final String DOT_FILE_NAME = "icfg.dot";
|
|
||||||
|
|
||||||
public static final String CAPTURED_FOLDER = "captured";
|
|
||||||
|
|
||||||
private static File bugsFile;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static File dotFile;
|
|
||||||
|
|
||||||
private static File resultsDir;
|
|
||||||
|
|
||||||
private static final ImmutableList<String> EMPTY_ARGS = ImmutableList.of();
|
|
||||||
|
|
||||||
private static final String ANDROID =
|
|
||||||
"/infer/lib/java/android/android-19.jar";
|
|
||||||
|
|
||||||
private static final String[] LIBRARIES = {
|
|
||||||
"/infer/lib/java/models.jar",
|
|
||||||
"/infer/annotations/annotations.jar",
|
|
||||||
"/dependencies/java/guava/guava-10.0.1-fork.jar",
|
|
||||||
"/dependencies/java/jackson/jackson-2.2.3.jar",
|
|
||||||
};
|
|
||||||
|
|
||||||
private static HashMap<String, InferResults> inferResultsMap =
|
|
||||||
new HashMap<String, InferResults>();
|
|
||||||
|
|
||||||
private static String getXcodeRoot() throws IOException, InterruptedException {
|
|
||||||
ProcessBuilder pb = new ProcessBuilder("xcode-select", "-p");
|
|
||||||
Process process = pb.start();
|
|
||||||
InputStream is = process.getInputStream();
|
|
||||||
InputStreamReader isr = new InputStreamReader(is);
|
|
||||||
BufferedReader br = new BufferedReader(isr);
|
|
||||||
String line = br.readLine();
|
|
||||||
process.waitFor();
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getXCodeVersion() throws IOException, InterruptedException {
|
|
||||||
ProcessBuilder pb = new ProcessBuilder("xcodebuild", "-version");
|
|
||||||
Process process = pb.start();
|
|
||||||
InputStream is = process.getInputStream();
|
|
||||||
InputStreamReader isr = new InputStreamReader(is);
|
|
||||||
BufferedReader br = new BufferedReader(isr);
|
|
||||||
String line = br.readLine();
|
|
||||||
process.waitFor();
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ImmutableList<String> createInferJavaCommand(
|
|
||||||
TemporaryFolder folder,
|
|
||||||
ImmutableList<String> sourceFiles,
|
|
||||||
String analyzer,
|
|
||||||
ImmutableList<String> args) {
|
|
||||||
try {
|
|
||||||
File resultsDir = createResultsDir(folder);
|
|
||||||
String resultsDirName = resultsDir.getAbsolutePath();
|
|
||||||
InferRunner.bugsFile = new File(resultsDir, BUGS_FILE_NAME);
|
|
||||||
|
|
||||||
ImmutableList<String> javacCmd = createJavacCommand(
|
|
||||||
folder,
|
|
||||||
sourceFiles);
|
|
||||||
|
|
||||||
return new ImmutableList.Builder<String>()
|
|
||||||
.add("infer")
|
|
||||||
.add("--no-progress-bar")
|
|
||||||
.add("--no-filtering")
|
|
||||||
.addAll(args)
|
|
||||||
.add("-o")
|
|
||||||
.add(resultsDirName)
|
|
||||||
.add("-a")
|
|
||||||
.add(analyzer)
|
|
||||||
.add("--")
|
|
||||||
.addAll(javacCmd)
|
|
||||||
.build();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
return ImmutableList.of(); // unreachable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ImmutableList<String> createJavacCommand(
|
|
||||||
TemporaryFolder folder,
|
|
||||||
ImmutableList<String> sourceFiles)
|
|
||||||
throws IOException {
|
|
||||||
File classesDir = folder.newFolder("classes_out");
|
|
||||||
String classesDirName = classesDir.getAbsolutePath();
|
|
||||||
|
|
||||||
ImmutableList<String> javacCmd = new ImmutableList.Builder<String>()
|
|
||||||
.add("javac")
|
|
||||||
.add("-classpath")
|
|
||||||
.add(getClasspath())
|
|
||||||
.add("-bootclasspath")
|
|
||||||
.add(getBootClasspath())
|
|
||||||
.add("-d")
|
|
||||||
.add(classesDirName)
|
|
||||||
.addAll(sourceFiles).build();
|
|
||||||
return javacCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ImmutableList<String> createJavaInferHarnessCommand(
|
|
||||||
TemporaryFolder folder,
|
|
||||||
ImmutableList<String> sourceFiles) {
|
|
||||||
ImmutableList<String> args = new ImmutableList.Builder<String>()
|
|
||||||
.add("--android-harness")
|
|
||||||
.build();
|
|
||||||
return createInferJavaCommand(folder, sourceFiles, "infer", args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ImmutableList<String> createJavaInferHarnessCommand(
|
|
||||||
TemporaryFolder folder,
|
|
||||||
String sourceFile) {
|
|
||||||
return createJavaInferHarnessCommand(folder, ImmutableList.of(sourceFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ImmutableList<String> createJavaInferAngelicHarnessCommand(
|
|
||||||
TemporaryFolder folder,
|
|
||||||
ImmutableList<String> sourceFiles) {
|
|
||||||
ImmutableList<String> args = (new ImmutableList.Builder<String>())
|
|
||||||
.add("--android-harness")
|
|
||||||
.build();
|
|
||||||
return createInferJavaCommand(folder, sourceFiles, "infer", args);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static InferResults runInfer(
|
|
||||||
ImmutableList<String> inferCmd,
|
|
||||||
Language lang)
|
|
||||||
throws IOException, InterruptedException, InferException {
|
|
||||||
String inferCmdString = Joiner.on(' ').join(inferCmd);
|
|
||||||
InferResults results = inferResultsMap.get(inferCmdString);
|
|
||||||
if (results == null) {
|
|
||||||
if (lang == Language.Java) checkLibraries();
|
|
||||||
|
|
||||||
runCommand(inferCmd, TestType.END_TO_END);
|
|
||||||
String errorString = getErrors(bugsFile);
|
|
||||||
results = new InferResults(inferCmd);
|
|
||||||
if (lang == Language.Java)
|
|
||||||
results.parseJavaInferResultsFromString(errorString);
|
|
||||||
else if (lang == Language.C || lang == Language.CPP || lang == Language.ObjCPP)
|
|
||||||
results.parseCInferResultsFromString(errorString);
|
|
||||||
else if (lang == Language.ObjC)
|
|
||||||
results.parseObjCInferResultsFromString(errorString);
|
|
||||||
inferResultsMap.put(inferCmdString, results);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InferResults runInferJava(ImmutableList<String> inferCmd)
|
|
||||||
throws IOException, InterruptedException, InferException {
|
|
||||||
return runInfer(inferCmd, Language.Java);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InferResults runInferC(ImmutableList<String> inferCmd)
|
|
||||||
throws IOException, InterruptedException, InferException {
|
|
||||||
return runInfer(inferCmd, Language.C);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InferResults runInferCPP(ImmutableList<String> inferCmd)
|
|
||||||
throws IOException, InterruptedException, InferException {
|
|
||||||
return runInfer(inferCmd, Language.CPP);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InferResults runInferObjC(ImmutableList<String> inferCmd)
|
|
||||||
throws IOException, InterruptedException, InferException {
|
|
||||||
return runInfer(inferCmd, Language.ObjC);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InferResults runInferObjCPP(ImmutableList<String> inferCmd)
|
|
||||||
throws IOException, InterruptedException, InferException {
|
|
||||||
return runInfer(inferCmd, Language.ObjCPP);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static void runCommand(
|
|
||||||
ImmutableList<String> inferCmd,
|
|
||||||
TestType testType)
|
|
||||||
throws IOException, InterruptedException, InferException {
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(inferCmd);
|
|
||||||
|
|
||||||
Map<String, String> env = pb.environment();
|
|
||||||
env.put("INFER_REPORT_CUSTOM_ERROR", "1");
|
|
||||||
|
|
||||||
Process process = pb.start();
|
|
||||||
StringBuilder stderr = new StringBuilder();
|
|
||||||
try (BufferedReader bufferedReader =
|
|
||||||
new BufferedReader(
|
|
||||||
new InputStreamReader(
|
|
||||||
process.getErrorStream()))) {
|
|
||||||
String line = null;
|
|
||||||
while ((line = bufferedReader.readLine()) != null) {
|
|
||||||
stderr.append(line + "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
process.waitFor();
|
|
||||||
|
|
||||||
File file = null;
|
|
||||||
if (testType == TestType.END_TO_END) {
|
|
||||||
file = bugsFile;
|
|
||||||
} else if (testType == TestType.FRONTEND) {
|
|
||||||
getDotFile();
|
|
||||||
file = dotFile;
|
|
||||||
}
|
|
||||||
if (file == null || !file.exists()) {
|
|
||||||
String fileNotFoundMessage = file == null ?
|
|
||||||
"" : "\n\nFile " + file + " not found.";
|
|
||||||
throw new InferException(
|
|
||||||
"There was an error while calling Infer." +
|
|
||||||
"\n\nCommand output:\n" + stderr +
|
|
||||||
"\nCommand: " + Joiner.on(' ').join(inferCmd) +
|
|
||||||
fileNotFoundMessage +
|
|
||||||
"\n==========================================================================");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static String getErrors(File file) throws IOException {
|
|
||||||
String s = "";
|
|
||||||
String line = "";
|
|
||||||
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
|
|
||||||
br.readLine();
|
|
||||||
while ((line = br.readLine()) != null) {
|
|
||||||
s += line + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getBootClasspath() {
|
|
||||||
String current_dir = System.getProperty("user.dir");
|
|
||||||
String bootclasspath = current_dir + ANDROID;
|
|
||||||
return bootclasspath;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getClasspath() {
|
|
||||||
String current_dir = System.getProperty("user.dir");
|
|
||||||
StringBuilder classpath = new StringBuilder();
|
|
||||||
for (String library : LIBRARIES) {
|
|
||||||
classpath.append(current_dir);
|
|
||||||
classpath.append(library);
|
|
||||||
classpath.append(":");
|
|
||||||
}
|
|
||||||
classpath.deleteCharAt(classpath.length() - 1);
|
|
||||||
return classpath.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void checkLibraries() throws InferException {
|
|
||||||
String current_dir = System.getProperty("user.dir");
|
|
||||||
for (String lib_file : LIBRARIES) {
|
|
||||||
File lib = new File(current_dir + lib_file);
|
|
||||||
if (!lib.exists()) {
|
|
||||||
throw new InferException("File " + lib_file + " not found.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static File createResultsDir(TemporaryFolder folder) {
|
|
||||||
try {
|
|
||||||
resultsDir = folder.newFolder("infer_out");
|
|
||||||
return resultsDir;
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
return null; // unreachable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void getDotFile() {
|
|
||||||
File captured = new File(resultsDir, CAPTURED_FOLDER);
|
|
||||||
if (captured.exists()) {
|
|
||||||
File f = new File(captured, captured.list()[0]);
|
|
||||||
dotFile = new File(f, DOT_FILE_NAME);
|
|
||||||
} else {
|
|
||||||
dotFile = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Reader;
|
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown=true)
|
|
||||||
public class InferStats {
|
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown=true)
|
|
||||||
private static class IntFields {
|
|
||||||
@JsonProperty(value = "files")
|
|
||||||
int numFiles;
|
|
||||||
|
|
||||||
@JsonProperty(value = "procedures")
|
|
||||||
int numProcedures;
|
|
||||||
|
|
||||||
@JsonProperty(value = "lines")
|
|
||||||
int numLines;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class FloatFields {
|
|
||||||
@JsonProperty(value = "reporting_time")
|
|
||||||
float reportingTime;
|
|
||||||
|
|
||||||
@JsonProperty(value = "capture_time")
|
|
||||||
float captureTime;
|
|
||||||
|
|
||||||
@JsonProperty(value = "analysis_time")
|
|
||||||
float analysisTime;
|
|
||||||
|
|
||||||
@JsonProperty(value = "makefile_generation_time")
|
|
||||||
float makefileGenerationTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonProperty(value = "int")
|
|
||||||
private IntFields intFields;
|
|
||||||
|
|
||||||
@JsonProperty(value = "float")
|
|
||||||
private FloatFields floatFields;
|
|
||||||
|
|
||||||
private static InferStats parseInferStatsFromJson(Reader reader) throws IOException {
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
InferStats user = mapper.readValue(reader, InferStats.class);
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InferStats loadInferStats(Class currentClass, String sourceDir) throws IOException {
|
|
||||||
BufferedReader reader =
|
|
||||||
new BufferedReader(
|
|
||||||
new InputStreamReader(
|
|
||||||
currentClass.getResourceAsStream(sourceDir + "stats.json")));
|
|
||||||
return parseInferStatsFromJson(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumFiles() {
|
|
||||||
return intFields.numFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumProcedures() {
|
|
||||||
return intFields.numProcedures;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumLines() {
|
|
||||||
return intFields.numLines;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getReportingTime() {
|
|
||||||
return floatFields.reportingTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getCaptureTime() {
|
|
||||||
return floatFields.captureTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getAnalysisTime() {
|
|
||||||
return floatFields.analysisTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getMakefileGenerationTime() {
|
|
||||||
return floatFields.makefileGenerationTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils;
|
|
||||||
|
|
||||||
public enum Language {
|
|
||||||
Java, C, ObjC, CPP, ObjCPP
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils;
|
|
||||||
|
|
||||||
public enum TestType {
|
|
||||||
END_TO_END, FRONTEND;
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class DotFilesEqual extends BaseMatcher<File> {
|
|
||||||
|
|
||||||
String dotFile;
|
|
||||||
|
|
||||||
public DotFilesEqual(String dotFile) {
|
|
||||||
this.dotFile = dotFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
private StringBuilder diffOutput = new StringBuilder();
|
|
||||||
private String diffCommand = "";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Object o) {
|
|
||||||
File newDotFile = (File) o;
|
|
||||||
Map<String, String> env = System.getenv();
|
|
||||||
if (env.get("INFER_DOT_REPLACE") != null) {
|
|
||||||
diffCommand = "cp " + newDotFile.getAbsolutePath() + " " + dotFile;
|
|
||||||
} else {
|
|
||||||
diffCommand = "diff -u " + dotFile + " " + newDotFile.getAbsolutePath();
|
|
||||||
}
|
|
||||||
Process diff_process = null;
|
|
||||||
try {
|
|
||||||
diff_process = Runtime.getRuntime().exec(diffCommand);
|
|
||||||
try (BufferedReader inputReader =
|
|
||||||
new BufferedReader(new InputStreamReader(diff_process.getInputStream()));
|
|
||||||
BufferedReader errorReader =
|
|
||||||
new BufferedReader(new InputStreamReader(diff_process.getErrorStream()))) {
|
|
||||||
|
|
||||||
String line = inputReader.readLine();
|
|
||||||
while (line != null) {
|
|
||||||
diffOutput = diffOutput.append(line + "\n");
|
|
||||||
line = inputReader.readLine();
|
|
||||||
}
|
|
||||||
String errorLine = errorReader.readLine();
|
|
||||||
while (errorLine != null) {
|
|
||||||
diffOutput = diffOutput.append(errorLine + "\n");
|
|
||||||
errorLine = errorReader.readLine();
|
|
||||||
}
|
|
||||||
diff_process.waitFor();
|
|
||||||
return "".equals(diffOutput.toString());
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
} finally {
|
|
||||||
if (diff_process != null) diff_process.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText("Dot file equal to " + dotFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeMismatch(Object item, Description description) {
|
|
||||||
String outputDesc = "The command:\n\n " + diffCommand
|
|
||||||
+ "\n\nfailed with output:\n" + diffOutput.toString() + "\n";
|
|
||||||
description.appendText(outputDesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<File> dotFileEqualTo(String dotFile) {
|
|
||||||
return new DotFilesEqual(dotFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import utils.InferError;
|
|
||||||
|
|
||||||
public class ErrorPattern {
|
|
||||||
|
|
||||||
private final String errorType;
|
|
||||||
|
|
||||||
private final Path errorFile;
|
|
||||||
|
|
||||||
private final String errorMethod;
|
|
||||||
|
|
||||||
public ErrorPattern(String type, String file, String method) {
|
|
||||||
errorType = type;
|
|
||||||
errorFile = Paths.get(file);
|
|
||||||
errorMethod = method;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getErrorType() {
|
|
||||||
return errorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
Path getErrorFile() {
|
|
||||||
return errorFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getErrorMethod() {
|
|
||||||
return errorMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean match(InferError error) {
|
|
||||||
return error.matchType(errorType)
|
|
||||||
&& error.matchMethod(errorMethod)
|
|
||||||
&& error.matchFile(errorFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<ErrorPattern> createPatterns(String type, String file, String[] methods) {
|
|
||||||
List<ErrorPattern> patterns = new ArrayList<>();
|
|
||||||
for (String method : methods) {
|
|
||||||
patterns.add(new ErrorPattern(type, file, method));
|
|
||||||
}
|
|
||||||
return patterns;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getErrorType() + " in file: " + getErrorFile() + ", method: " + getErrorMethod();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
|
|
||||||
import utils.InferError;
|
|
||||||
import utils.InferStats;
|
|
||||||
|
|
||||||
public class NumberOfFilesAnalyzed extends BaseMatcher<InferStats> {
|
|
||||||
|
|
||||||
private int expectedNumFiles;
|
|
||||||
private int actualNumFiles;
|
|
||||||
|
|
||||||
public NumberOfFilesAnalyzed(int expectedNumFiles) {
|
|
||||||
this.expectedNumFiles = expectedNumFiles;
|
|
||||||
this.actualNumFiles = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Object o) {
|
|
||||||
InferStats stats = (InferStats) o;
|
|
||||||
actualNumFiles = stats.getNumFiles();
|
|
||||||
return actualNumFiles == expectedNumFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText(expectedNumFiles + " files analyzed by Infer.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeMismatch(Object item, Description description) {
|
|
||||||
InferStats stats = (InferStats) item;
|
|
||||||
description.appendText("found " + actualNumFiles + " files analyzed by Infer.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferStats> numberOfFilesAnalyzed(
|
|
||||||
int expectedNumFiles) {
|
|
||||||
return new NumberOfFilesAnalyzed(expectedNumFiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
|
|
||||||
import utils.InferError;
|
|
||||||
import utils.InferStats;
|
|
||||||
|
|
||||||
public class NumberOfProceduresAnalyzed extends BaseMatcher<InferStats> {
|
|
||||||
|
|
||||||
private int expectedNumProcedures;
|
|
||||||
private int actualNumProcedures;
|
|
||||||
|
|
||||||
public NumberOfProceduresAnalyzed(int expectedNumProcedures) {
|
|
||||||
this.expectedNumProcedures = expectedNumProcedures;
|
|
||||||
this.actualNumProcedures = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Object o) {
|
|
||||||
InferStats stats = (InferStats) o;
|
|
||||||
actualNumProcedures = stats.getNumProcedures();
|
|
||||||
return actualNumProcedures == expectedNumProcedures;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText(expectedNumProcedures + " procedures analyzed by Infer.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeMismatch(Object item, Description description) {
|
|
||||||
InferStats stats = (InferStats) item;
|
|
||||||
description.appendText("found " + actualNumProcedures + " procedures analyzed by Infer.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferStats> numberOfProceduresAnalyzed(
|
|
||||||
int expectedNumProcedures) {
|
|
||||||
return new NumberOfProceduresAnalyzed(expectedNumProcedures);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
import utils.InferError;
|
|
||||||
import utils.InferResults;
|
|
||||||
|
|
||||||
public class ResultContainsErrorInMethod extends BaseMatcher<InferResults> {
|
|
||||||
|
|
||||||
private String errorType;
|
|
||||||
private Path errorFile;
|
|
||||||
private String errorMethod;
|
|
||||||
|
|
||||||
public ResultContainsErrorInMethod(String type, String file, String method) {
|
|
||||||
this.errorType = type;
|
|
||||||
this.errorFile = Paths.get(file);
|
|
||||||
this.errorMethod = method;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Object o) {
|
|
||||||
InferResults results = (InferResults) o;
|
|
||||||
for (InferError foundError : results.getErrors()) {
|
|
||||||
if (foundError.matchType(this.errorType)
|
|
||||||
&& foundError.matchMethod(this.errorMethod)
|
|
||||||
&& foundError.matchFile(this.errorFile)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText(
|
|
||||||
this.errorType + " error in file: " + this.errorFile
|
|
||||||
+ ", method: " + this.errorMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeMismatch(Object item, Description description) {
|
|
||||||
InferResults results = (InferResults) item;
|
|
||||||
String resultsString = "";
|
|
||||||
for (InferError error : results.getErrors()) {
|
|
||||||
resultsString = resultsString + "\n\t" + error;
|
|
||||||
}
|
|
||||||
description.appendText(
|
|
||||||
"Found errors: \n" + resultsString
|
|
||||||
+ "\nwith:\n" + results.inferCmdToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> contains(String type, String file, String method) {
|
|
||||||
return new ResultContainsErrorInMethod(type, file, method);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
|
|
||||||
import utils.InferError;
|
|
||||||
import utils.InferResults;
|
|
||||||
|
|
||||||
public class ResultContainsErrorNoFilename extends BaseMatcher<InferResults> {
|
|
||||||
|
|
||||||
private String errorType;
|
|
||||||
private String errorMethod;
|
|
||||||
|
|
||||||
public ResultContainsErrorNoFilename(String type, String method) {
|
|
||||||
this.errorType = type;
|
|
||||||
this.errorMethod = method;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Object o) {
|
|
||||||
InferResults results = (InferResults) o;
|
|
||||||
for (InferError foundError : results.getErrors()) {
|
|
||||||
if (foundError.matchType(this.errorType)
|
|
||||||
&& foundError.matchMethod(this.errorMethod)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText(
|
|
||||||
this.errorType + " error in " + this.errorMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeMismatch(Object item, Description description) {
|
|
||||||
InferResults results = (InferResults) item;
|
|
||||||
String resultsString = "";
|
|
||||||
for (InferError error : results.getErrors()) {
|
|
||||||
resultsString = resultsString + "\n\t" + error;
|
|
||||||
}
|
|
||||||
description.appendText(
|
|
||||||
"Found errors: \n" + resultsString
|
|
||||||
+ "\nwith:\n" + results.inferCmdToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> contains(String type, String method) {
|
|
||||||
return new ResultContainsErrorNoFilename(type, method);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import utils.InferResults;
|
|
||||||
|
|
||||||
public class ResultContainsExactly extends BaseMatcher<InferResults> {
|
|
||||||
|
|
||||||
Matcher<InferResults> containsAll;
|
|
||||||
Matcher<InferResults> containsOnly;
|
|
||||||
|
|
||||||
private ResultContainsExactly(List<ErrorPattern> patterns) {
|
|
||||||
containsAll = ResultContainsTheseErrors.contains(patterns);
|
|
||||||
containsOnly = ResultContainsOnlyTheseErrors.containsOnly(patterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Object o) {
|
|
||||||
return containsAll.matches(o) && containsOnly.matches(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
containsAll.describeTo(description);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeMismatch(Object item, Description description) {
|
|
||||||
if (!containsAll.matches(item)) {
|
|
||||||
containsAll.describeMismatch(item, description);
|
|
||||||
}
|
|
||||||
if (!containsOnly.matches(item)) {
|
|
||||||
containsOnly.describeMismatch(item, description);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> containsExactly(List<ErrorPattern> patterns) {
|
|
||||||
return new ResultContainsExactly(patterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> containsExactly(
|
|
||||||
String type,
|
|
||||||
String file,
|
|
||||||
String[] methods) {
|
|
||||||
ArrayList<ErrorPattern> patterns = new ArrayList<>();
|
|
||||||
for (String method : methods) {
|
|
||||||
patterns.add(new ErrorPattern(type, file, method));
|
|
||||||
}
|
|
||||||
return new ResultContainsExactly(patterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import com.google.common.base.Optional;
|
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import utils.InferError;
|
|
||||||
import utils.InferResults;
|
|
||||||
|
|
||||||
public class ResultContainsLineNumbers extends BaseMatcher<InferResults> {
|
|
||||||
|
|
||||||
private int[] lines;
|
|
||||||
private boolean strict;
|
|
||||||
private Optional<String> bugType;
|
|
||||||
|
|
||||||
public ResultContainsLineNumbers(
|
|
||||||
int[] lines,
|
|
||||||
boolean strict,
|
|
||||||
Optional<String> bugType) {
|
|
||||||
this.lines = lines;
|
|
||||||
this.strict = strict;
|
|
||||||
this.bugType = bugType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Object o) {
|
|
||||||
Vector<InferError> errors = ((InferResults) o).getErrors();
|
|
||||||
if (strict && lines.length != errors.size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
boolean allContained = true;
|
|
||||||
for (int line : lines) {
|
|
||||||
boolean isContained = false;
|
|
||||||
for (InferError error : errors) {
|
|
||||||
String bugType = this.bugType.or(error.getErrorType());
|
|
||||||
boolean isSameErrType = bugType.equals(error.getErrorType());
|
|
||||||
isContained = isContained || (line == error.getErrorLine() && isSameErrType);
|
|
||||||
}
|
|
||||||
allContained = allContained && isContained;
|
|
||||||
}
|
|
||||||
return allContained;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText("Correct line numbers in the error report.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeMismatch(Object item, Description description) {
|
|
||||||
InferResults results = (InferResults) item;
|
|
||||||
String linesString = Arrays.toString(lines);
|
|
||||||
String reportedLinesString = Arrays.toString(findLineNumbersInReport(results));
|
|
||||||
description.appendText(
|
|
||||||
"Infer did not report an error in the following lines: " + linesString +
|
|
||||||
". \n \t Reported lines are: " + reportedLinesString +
|
|
||||||
"\n" + results.inferCmdToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> containsLines(int[] lines) {
|
|
||||||
return new ResultContainsLineNumbers(lines, false, Optional.<String>absent());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> containsOnlyLines(int[] lines) {
|
|
||||||
return new ResultContainsLineNumbers(lines, true, Optional.<String>absent());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> containsLinesOfError(int[] lines, String bugType) {
|
|
||||||
return new ResultContainsLineNumbers(lines, false, Optional.of(bugType));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> containsOnlyLinesOfError(int[] lines, String bugType) {
|
|
||||||
return new ResultContainsLineNumbers(lines, true, Optional.of(bugType));
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] findLineNumbersInReport(InferResults results) {
|
|
||||||
Vector<InferError> errors = results.getErrors();
|
|
||||||
int nErrors = errors.size();
|
|
||||||
int[] lines = new int[nErrors];
|
|
||||||
for (int i = 0; i < nErrors; i++) {
|
|
||||||
lines[i] = errors.get(i).getErrorLine();
|
|
||||||
}
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
|
|
||||||
import utils.InferError;
|
|
||||||
import utils.InferResults;
|
|
||||||
|
|
||||||
public class ResultContainsNoErrorInMethod extends BaseMatcher<InferResults> {
|
|
||||||
|
|
||||||
ErrorPattern pattern;
|
|
||||||
|
|
||||||
public ResultContainsNoErrorInMethod(String type, String file, String method) {
|
|
||||||
pattern = new ErrorPattern(type, file, method);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Object o) {
|
|
||||||
InferResults results = (InferResults) o;
|
|
||||||
for (InferError foundError : results.getErrors()) {
|
|
||||||
if (pattern.match(foundError)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText(
|
|
||||||
"No " + pattern.getErrorType() + " error in " + pattern.getErrorMethod());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeMismatch(Object item, Description description) {
|
|
||||||
InferResults results = (InferResults) item;
|
|
||||||
description.appendText(
|
|
||||||
pattern.getErrorType() + " error found in " +
|
|
||||||
pattern.getErrorMethod() + " in the results of Infer.\n" +
|
|
||||||
results.inferCmdToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> doesNotContain(String type, String file, String method) {
|
|
||||||
return new ResultContainsNoErrorInMethod(type, file, method);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
|
|
||||||
import utils.InferError;
|
|
||||||
import utils.InferResults;
|
|
||||||
|
|
||||||
public class ResultContainsNumberOfErrorsInMethod extends BaseMatcher<InferResults> {
|
|
||||||
|
|
||||||
private final ErrorPattern pattern;
|
|
||||||
private final int numberOfErrors;
|
|
||||||
int actualNumberErrors;
|
|
||||||
|
|
||||||
public ResultContainsNumberOfErrorsInMethod(
|
|
||||||
String type,
|
|
||||||
String file,
|
|
||||||
String method,
|
|
||||||
int numberOfErrors) {
|
|
||||||
this.pattern = new ErrorPattern(type, file, method);
|
|
||||||
this.numberOfErrors = numberOfErrors;
|
|
||||||
this.actualNumberErrors = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Object o) {
|
|
||||||
InferResults results = (InferResults) o;
|
|
||||||
for (InferError error : results.getErrors()) {
|
|
||||||
if (pattern.match(error)) {
|
|
||||||
actualNumberErrors++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (actualNumberErrors == numberOfErrors);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText(
|
|
||||||
numberOfErrors + " " + pattern.getErrorType()
|
|
||||||
+ " errors in file: " + pattern.getErrorFile()
|
|
||||||
+ ", method: " + pattern.getErrorMethod());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeMismatch(Object item, Description description) {
|
|
||||||
InferResults results = (InferResults) item;
|
|
||||||
description.appendText(
|
|
||||||
actualNumberErrors + " " + pattern.getErrorType() +
|
|
||||||
" errors found in " + pattern.getErrorMethod() + " in the results of Infer." +
|
|
||||||
"\n" + results.inferCmdToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> containsNumberOfErrors(
|
|
||||||
String type,
|
|
||||||
String file,
|
|
||||||
String method,
|
|
||||||
int numberOfErrors) {
|
|
||||||
return new ResultContainsNumberOfErrorsInMethod(type, file, method, numberOfErrors);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import utils.InferError;
|
|
||||||
import utils.InferResults;
|
|
||||||
|
|
||||||
public class ResultContainsOnlyTheseErrors extends BaseMatcher<InferResults> {
|
|
||||||
|
|
||||||
private List<ErrorPattern> patterns;
|
|
||||||
|
|
||||||
public ResultContainsOnlyTheseErrors(List<ErrorPattern> patterns) {
|
|
||||||
this.patterns = patterns;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean mathTypeAndAnyMethod(InferError e) {
|
|
||||||
for (ErrorPattern pattern : patterns) {
|
|
||||||
if (pattern.match(e)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Object o) {
|
|
||||||
InferResults results = (InferResults) o;
|
|
||||||
for (InferError error : results.getErrors()) {
|
|
||||||
if (!mathTypeAndAnyMethod(error)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
String errorsString = "";
|
|
||||||
for (ErrorPattern pattern : patterns) {
|
|
||||||
errorsString =
|
|
||||||
errorsString + "\t" + pattern.toString() + "\n";
|
|
||||||
}
|
|
||||||
description.appendText("Only these errors: \n" + errorsString);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeMismatch(Object item, Description description) {
|
|
||||||
InferResults results = (InferResults) item;
|
|
||||||
String unexpectedErrors = "";
|
|
||||||
|
|
||||||
for (InferError error : results.getErrors()) {
|
|
||||||
if (!mathTypeAndAnyMethod(error)) {
|
|
||||||
unexpectedErrors = unexpectedErrors + "\t" + error + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
description.appendText(
|
|
||||||
"Infer reported the following unexpected errors: \n" +
|
|
||||||
unexpectedErrors + "\n" + results.inferCmdToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> containsOnly(String type, String file, String[] methods) {
|
|
||||||
ArrayList<ErrorPattern> patterns = new ArrayList<>();
|
|
||||||
for (String method : methods) {
|
|
||||||
patterns.add(new ErrorPattern(type, file, method));
|
|
||||||
}
|
|
||||||
return new ResultContainsOnlyTheseErrors(patterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> containsOnly(List<ErrorPattern> patterns) {
|
|
||||||
return new ResultContainsOnlyTheseErrors(patterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import utils.InferError;
|
|
||||||
import utils.InferResults;
|
|
||||||
|
|
||||||
public class ResultContainsTheseErrors extends BaseMatcher<InferResults> {
|
|
||||||
|
|
||||||
private List<ErrorPattern> patterns;
|
|
||||||
|
|
||||||
private ResultContainsTheseErrors(List<ErrorPattern> patterns) {
|
|
||||||
this.patterns = patterns;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean patternFound(ErrorPattern pattern, InferResults results) {
|
|
||||||
for (InferError error : results.getErrors()) {
|
|
||||||
if (pattern.match(error)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Object o) {
|
|
||||||
InferResults results = (InferResults) o;
|
|
||||||
for (ErrorPattern pattern : patterns) {
|
|
||||||
if (!patternFound(pattern, results)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
String errorsString = "";
|
|
||||||
for (ErrorPattern pattern : patterns) {
|
|
||||||
errorsString += "\t" + pattern.toString() + "\n";
|
|
||||||
}
|
|
||||||
description.appendText("Expecting these errors: \n" + errorsString);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeMismatch(Object item, Description description) {
|
|
||||||
|
|
||||||
InferResults results = (InferResults) item;
|
|
||||||
String expectedErrors = "";
|
|
||||||
|
|
||||||
for (ErrorPattern pattern : patterns) {
|
|
||||||
if (!patternFound(pattern, results)) {
|
|
||||||
expectedErrors += "\t" + pattern.toString() + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
description.appendText(
|
|
||||||
"The following errors were not reported: \n" + expectedErrors + "\n" + "but found: " +
|
|
||||||
results.toString() + "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> contains(List<ErrorPattern> patterns) {
|
|
||||||
return new ResultContainsTheseErrors(patterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> contains(String type, String file, String[] methods) {
|
|
||||||
ArrayList<ErrorPattern> patterns = new ArrayList<>();
|
|
||||||
for (String method : methods) {
|
|
||||||
patterns.add(new ErrorPattern(type, file, method));
|
|
||||||
}
|
|
||||||
return new ResultContainsTheseErrors(patterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - present Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package utils.matchers;
|
|
||||||
|
|
||||||
import org.hamcrest.BaseMatcher;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
|
|
||||||
import utils.InferError;
|
|
||||||
import utils.InferResults;
|
|
||||||
|
|
||||||
public class ResultContainsZeroErrorsInMethod extends BaseMatcher<InferResults> {
|
|
||||||
|
|
||||||
String fileName;
|
|
||||||
String methodName;
|
|
||||||
int actualNumberErrors;
|
|
||||||
|
|
||||||
public ResultContainsZeroErrorsInMethod(String fileName, String methodName) {
|
|
||||||
this.fileName = fileName;
|
|
||||||
this.methodName = methodName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Object o) {
|
|
||||||
InferResults results = (InferResults) o;
|
|
||||||
for (InferError error : results.getErrors()) {
|
|
||||||
if (fileName.equals(error.getErrorFile()) &&
|
|
||||||
methodName.equals(error.getErrorMethod())) {
|
|
||||||
actualNumberErrors++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return actualNumberErrors == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText(actualNumberErrors + " errors found in method." + methodName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeMismatch(Object item, Description description) {
|
|
||||||
InferResults results = (InferResults) item;
|
|
||||||
description.appendText(
|
|
||||||
actualNumberErrors + " errors found in " + methodName +
|
|
||||||
" in the results of Infer, but expected 0." + "\n" + results.inferCmdToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Matcher<InferResults> containsZeroErrors(String fileName, String methodName) {
|
|
||||||
return new ResultContainsZeroErrorsInMethod(fileName, methodName);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in new issue