Reviewed By: sblackshear Differential Revision: D3619339 fbshipit-source-id: 46f3cc1master
parent
33b417c280
commit
9a79e74380
@ -0,0 +1,73 @@
|
||||
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 = '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',
|
||||
'-o', out,
|
||||
'-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"
|
||||
)
|
||||
]
|
||||
|
||||
# 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',
|
||||
]
|
||||
)
|
@ -1 +1 @@
|
||||
{"exception_type": "java.lang.NullPointerException", "stack_trace": ["at endtoend.java.crashcontext.MinimalCrashExample.main(MinimalCrashExample.java:16)",""], "exception_message": "", "normvector_stack": ["endtoend.java.crashcontext.MinimalCrashExample.main"]}
|
||||
{"exception_type": "java.lang.NullPointerException", "stack_trace": ["at codetoanalyze.java.crashcontext.MinimalCrashExample.main(MinimalCrashExample.java:16)",""], "exception_message": "", "normvector_stack": ["codetoanalyze.java.crashcontext.MinimalCrashExample.main"]}
|
||||
|
@ -0,0 +1,16 @@
|
||||
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',
|
||||
],
|
||||
)
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 MAIN_METHOD =
|
||||
"codetoanalyze.java.crashcontext.BranchingCallsExample.main(java.lang.String[]):void";
|
||||
|
||||
public static final String FOO_METHOD =
|
||||
"codetoanalyze.java.crashcontext.BranchingCallsExample.foo():void";
|
||||
|
||||
public static final String PRE_BAR_METHOD =
|
||||
"codetoanalyze.java.crashcontext.BranchingCallsExample.pre_bar():void";
|
||||
|
||||
public static final String BAR_METHOD =
|
||||
"codetoanalyze.java.crashcontext.BranchingCallsExample.bar():void";
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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").asText());
|
||||
}
|
||||
|
||||
public boolean hasStackFrame(String methodSignature) {
|
||||
for (JsonNode frame : json.path("stack")) {
|
||||
if(methodSignature.equals(frame.path("method").asText())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<JsonNode> findNodesForMethod(JsonNode node,
|
||||
String methodSignature,
|
||||
List<JsonNode> accumulator) {
|
||||
if(methodSignature.equals(node.path("method").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 static CrashContextResults loadJSONResults(String tag) throws IOException {
|
||||
return new CrashContextResults(tag);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in new issue