mirror of
https://github.com/github/codeql.git
synced 2025-12-25 05:06:34 +01:00
107 lines
3.7 KiB
Plaintext
107 lines
3.7 KiB
Plaintext
/**
|
|
* Test-case generator for flow summaries. See the accompanying `GenerateFlowTestCase.py` for full
|
|
* documentation and usage information.
|
|
*/
|
|
|
|
import java
|
|
private import semmle.code.java.dataflow.internal.DataFlowUtil
|
|
private import semmle.code.java.dataflow.ExternalFlow
|
|
private import semmle.code.java.dataflow.FlowSummary
|
|
private import semmle.code.java.dataflow.internal.FlowSummaryImpl
|
|
import FlowTestCase
|
|
private import FlowTestCaseSupportMethods
|
|
private import FlowTestCaseUtils
|
|
|
|
/**
|
|
* Gets a CSV row for which a test has been requested, and `SummaryModelCsv.row` does hold, but
|
|
* nonetheless we can't generate a test case for it, indicating we cannot resolve either the callable
|
|
* spec or an input or output spec.
|
|
*/
|
|
query string getAParseFailure(string reason) {
|
|
any(TargetSummaryModelCsv target).row(result) and
|
|
any(SummaryModelCsv model).row(result) and
|
|
(
|
|
not summaryModel(_, _, _, _, _, _, _, _, _, _, result) and
|
|
reason = "row could not be parsed"
|
|
or
|
|
exists(
|
|
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
|
|
|
|
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, result) and
|
|
not interpretElement(namespace, type, subtypes, name, signature, ext) instanceof Callable and
|
|
reason = "callable could not be resolved"
|
|
)
|
|
or
|
|
exists(string inputSpec |
|
|
summaryModel(_, _, _, _, _, _, inputSpec, _, _, _, result) and
|
|
not Private::External::interpretSpec(inputSpec, _) and
|
|
reason = "input spec could not be parsed"
|
|
)
|
|
or
|
|
exists(string outputSpec |
|
|
summaryModel(_, _, _, _, _, _, _, outputSpec, _, _, result) and
|
|
not Private::External::interpretSpec(outputSpec, _) and
|
|
reason = "output spec could not be parsed"
|
|
)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Gets a CSV row for which a test was requested and was correctly parsed,
|
|
* but for which no test case could be generated due to a limitation of the query.
|
|
*/
|
|
query string noTestCaseGenerated() {
|
|
any(TargetSummaryModelCsv target).row(result) and
|
|
any(SummaryModelCsv model).row(result) and
|
|
not exists(getAParseFailure(_)) and
|
|
not exists(any(TestCase tc).getATestSnippetForRow(result))
|
|
}
|
|
|
|
/**
|
|
* Gets a valid test case, i.e. one that has a test snippet.
|
|
*/
|
|
TestCase getAValidTestCase() { exists(result.getATestSnippetForRow(_)) }
|
|
|
|
/**
|
|
* Returns an import statement to include in the test case header.
|
|
*/
|
|
string getAnImportStatement() {
|
|
exists(RefType t |
|
|
t = getAValidTestCase().getADesiredImport() and
|
|
isImportable(t) and
|
|
t.getPackage().getName() != "java.lang"
|
|
|
|
|
result = "import " + t.getPackage().getName() + "." + t.getName() + ";"
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Returns a support method to include in the generated test class.
|
|
*/
|
|
SupportMethod getASupportMethod() {
|
|
result instanceof SourceMethod or
|
|
result instanceof SinkMethod or
|
|
result = getAValidTestCase().getASupportMethod()
|
|
}
|
|
|
|
/**
|
|
* Returns a CSV specification of the taint-/value-propagation behavior of a test support method (`get` or `newWith` method).
|
|
*/
|
|
query string getASupportMethodModel() { result = getASupportMethod().getCsvModel() }
|
|
|
|
/**
|
|
* Gets a Java file body testing all requested CSV rows against whatever classes and methods they resolve against.
|
|
*/
|
|
query string getTestCase() {
|
|
result =
|
|
"package generatedtest;\n\n" + concat(getAnImportStatement() + "\n") +
|
|
"\n// Test case generated by GenerateFlowTestCase.ql\npublic class Test {\n\n" +
|
|
concat("\t" + getASupportMethod().getDefinition() + "\n") +
|
|
"\n\tpublic void test() throws Exception {\n\n" +
|
|
concat(string row, string snippet |
|
|
snippet = any(TestCase tc).getATestSnippetForRow(row)
|
|
|
|
|
snippet order by row
|
|
) + "\n\t}\n\n}"
|
|
}
|