[tests] Convert java harness and crashcontext tests to new direct format.

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: 5117868
master
Cristiano Calcagno 8 years ago committed by Facebook Github Bot 9
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

@ -9,18 +9,17 @@ ROOT_DIR = .
include $(ROOT_DIR)/Makefile.config include $(ROOT_DIR)/Makefile.config
DIRECT_TESTS= DIRECT_TESTS=
TARGETS_TO_TEST=
ifeq ($(BUILD_C_ANALYZERS),yes) ifeq ($(BUILD_C_ANALYZERS),yes)
DIRECT_TESTS += c_infer_test c_frontend_test cpp_infer_test cpp_frontend_test DIRECT_TESTS += c_infer_test c_frontend_test cpp_infer_test cpp_frontend_test
endif endif
ifeq ($(BUILD_JAVA_ANALYZERS),yes) ifeq ($(BUILD_JAVA_ANALYZERS),yes)
TARGETS_TO_TEST += java DIRECT_TESTS += \
DIRECT_TESTS += java_checkers_test java_eradicate_test java_infer_test java_tracing_test java_quandary_test java_checkers_test java_eradicate_test java_infer_test java_tracing_test \
java_quandary_test java_crashcontext_test java_harness_test
endif endif
ifneq ($(XCODE_SELECT),no) ifneq ($(XCODE_SELECT),no)
DIRECT_TESTS += objc_frontend_test objc_infer_test objc_linters objcpp_frontend_test objcpp_linters DIRECT_TESTS += objc_frontend_test objc_infer_test objc_linters objcpp_frontend_test objcpp_linters
endif endif
TARGETS_TO_TEST := $(shell echo $(TARGETS_TO_TEST))
all: infer inferTraceBugs all: infer inferTraceBugs
@ -120,9 +119,15 @@ cpp_infer_test:
java_checkers_test: java_checkers_test:
make -C ./infer/tests/codetoanalyze/java/checkers test make -C ./infer/tests/codetoanalyze/java/checkers test
java_crashcontext_test:
make -C ./infer/tests/codetoanalyze/java/crashcontext test
java_eradicate_test: java_eradicate_test:
make -C ./infer/tests/codetoanalyze/java/eradicate test make -C ./infer/tests/codetoanalyze/java/eradicate test
java_harness_test:
make -C ./infer/tests/codetoanalyze/java/harness test
java_infer_test: java_infer_test:
make -C ./infer/tests/codetoanalyze/java/infer test make -C ./infer/tests/codetoanalyze/java/infer test
@ -154,18 +159,15 @@ objcpp_linters:
make -C ./infer/tests/codetoanalyze/objcpp/linters test make -C ./infer/tests/codetoanalyze/objcpp/linters test
direct_tests: direct_tests:
make $(DIRECT_TESTS) time make -j $(NCPU) -l $(NCPU) $(DIRECT_TESTS)
buck_test: infer buck_test: infer
make direct_tests make direct_tests
NO_BUCKD=1 buck clean
MAKEFLAGS= NO_BUCKD=1 buck test -j $(NCPU) -L $(NCPU) $(TARGETS_TO_TEST)
NO_BUCKD=1 ./infer/tests/build_systems/build_integration_tests.py NO_BUCKD=1 ./infer/tests/build_systems/build_integration_tests.py
buck_test_xml: infer buck_test_xml: infer
make direct_tests make direct_tests
NO_BUCKD=1 buck clean buck test --xml test.xml # TODO: generate test.xml with test results
NO_BUCKD=1 buck test -j $(NCPU) -L $(NCPU) --xml test.xml $(TARGETS_TO_TEST)
NO_BUCKD=1 ./infer/tests/build_systems/build_integration_tests.py NO_BUCKD=1 ./infer/tests/build_systems/build_integration_tests.py
inferTraceBugs_test: infer inferTraceBugs_test: infer

@ -344,9 +344,10 @@ class BuildIntegrationTest(unittest.TestCase):
env=env) env=env)
def test_buck_integration(self): def test_buck_integration(self):
target = '//infer/tests/codetoanalyze/java/infer:analyze'
test('buck', 'Buck', test('buck', 'Buck',
ROOT_DIR, ROOT_DIR,
[{'compile': ['buck', 'build', 'infer']}], [{'compile': ['buck', 'build', target]}],
clean_commands=[['buck', 'clean']], clean_commands=[['buck', 'clean']],
available=lambda: is_tool_available(['buck', '--version'])) available=lambda: is_tool_available(['buck', '--version']))

@ -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

@ -19,8 +19,6 @@ java_library(
def analysis_cmd(analyzer): def analysis_cmd(analyzer):
out = 'out' out = 'out'
inferconfig_file = '$(location //infer/tests/codetoanalyze/java:inferconfig)'
copy_inferconfig = ' '.join(['cp', inferconfig_file, '$SRCDIR'])
clean_cmd = ' '.join(['rm', '-rf', out]) clean_cmd = ' '.join(['rm', '-rf', out])
classpath = ':'.join([('$(classpath ' + path + ')') for path in dependencies]) classpath = ':'.join([('$(classpath ' + path + ')') for path in dependencies])
infer_cmd = ' '.join([ infer_cmd = ' '.join([
@ -36,7 +34,7 @@ def analysis_cmd(analyzer):
'$SRCS', '$SRCS',
]) ])
copy_cmd = ' '.join(['cp', out + '/report.csv', '$OUT']) copy_cmd = ' '.join(['cp', out + '/report.csv', '$OUT'])
return ' && '.join([clean_cmd, copy_inferconfig, infer_cmd, copy_cmd]) return ' && '.join([clean_cmd, infer_cmd, copy_cmd])
genrule( genrule(
name = 'analyze', name = 'analyze',

@ -12,7 +12,7 @@ OPTIONS = -x objective-c -fobjc-arc -c
ANALYZER = linters ANALYZER = linters
FILES = \ FILES = \
**.m \ *.m \
*/*.m \ */*.m \
compile: compile:

@ -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…
Cancel
Save