Skip to content
This repository was archived by the owner on Jan 5, 2023. It is now read-only.

Commit cf8eff5

Browse files
authored
Merge pull request #94 from max-schaefer/more-testing-frameworks
Recognise more testing frameworks
2 parents 43309b9 + d344687 commit cf8eff5

9 files changed

Lines changed: 98 additions & 6 deletions

File tree

change-notes/1.24/analysis-go.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
* Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`).
66
* Analysis of flow through fields has been improved.
7-
* More sources of untrusted input as well as vulnerable sinks are modelled, which may lead to more results from the security queries.
7+
* Detection of test code has been improved. LGTM will not show alerts in test code by default.
88
* Go 1.14 library changes have been modeled.
9+
* More sources of untrusted input as well as vulnerable sinks are modelled, which may lead to more results from the security queries.
910

1011
## New queries
1112

ql/src/Security/CWE-295/DisabledCertificateCheck.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,5 @@ where
115115
becomesPartOf*(base, init)
116116
) and
117117
// exclude results in test code
118-
exists(File fl | fl = w.getFile() | not fl = any(TestCase tc).getFile())
118+
exists(File fl | fl = w.getFile() | not fl instanceof TestFile)
119119
select w, "InsecureSkipVerify should not be used in production code."

ql/src/filters/ClassifyFiles.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ string generatorCommentRegex() {
2121

2222
predicate classify(File f, string category) {
2323
// tests
24-
f = any(TestCase tc).getFile() and
24+
f instanceof TestFile and
2525
category = "test"
2626
or
2727
// vendored code

ql/src/semmle/go/frameworks/Testing.qll

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,59 @@ module TestCase {
2727
/** A `go test` style test (including benchmarks and examples). */
2828
private class GoTestFunction extends Range, FuncDef {
2929
GoTestFunction() {
30-
getName().regexpMatch("Test[^a-z].*") and
30+
getName().regexpMatch("Test(?![a-z]).*") and
3131
getNumParameter() = 1 and
3232
getParameter(0).getType().(PointerType).getBaseType().hasQualifiedName("testing", "T")
3333
or
34-
getName().regexpMatch("Benchmark[^a-z].*") and
34+
getName().regexpMatch("Benchmark(?![a-z]).*") and
3535
getNumParameter() = 1 and
3636
getParameter(0).getType().(PointerType).getBaseType().hasQualifiedName("testing", "B")
3737
or
38-
getName().regexpMatch("Example[^a-z].*") and
38+
getName().regexpMatch("Example(?![a-z]).*") and
3939
getNumParameter() = 0
4040
}
4141
}
4242
}
43+
44+
/**
45+
* A file that contains test cases or is otherwise used for testing.
46+
*
47+
* Extend this class to refine existing models of testing frameworks. If you want to model new
48+
* frameworks, extend `TestFile::Range` instead.
49+
*/
50+
class TestFile extends File {
51+
TestFile::Range self;
52+
53+
TestFile() { this = self }
54+
}
55+
56+
/** Provides classes for working with test files. */
57+
module TestFile {
58+
/**
59+
* A file that contains test cases or is otherwise used for testing.
60+
*
61+
* Extend this class to model new testing frameworks. If you want to refine existing models,
62+
* extend `TestFile` instead.
63+
*/
64+
abstract class Range extends File { }
65+
66+
/** A file containing at least one test case. */
67+
private class FileContainingTestCases extends Range {
68+
FileContainingTestCases() { this = any(TestCase tc).getFile() }
69+
}
70+
71+
/** A file that imports a well-known testing framework. */
72+
private class FileImportingTestingFramework extends Range {
73+
FileImportingTestingFramework() {
74+
exists(string pkg, ImportSpec is |
75+
is.getPath() = pkg and
76+
is.getFile() = this
77+
|
78+
pkg = "net/http/httptest" or
79+
pkg = "gen/thrifttest" or
80+
pkg = "github.com/onsi/ginkgo" or
81+
pkg = "github.com/onsi/gomega"
82+
)
83+
}
84+
}
85+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
| hello2.go:0:0:0:0 | hello2.go | generated |
22
| hello.go:0:0:0:0 | hello.go | generated |
3+
| httptest.go:0:0:0:0 | httptest.go | test |
4+
| test1.go:0:0:0:0 | test1.go | test |
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| test1.go:5:1:5:26 | function declaration |
2+
| test1.go:7:1:7:27 | function declaration |
3+
| test1.go:15:1:15:31 | function declaration |
4+
| test1.go:17:1:17:32 | function declaration |
5+
| test1.go:25:1:25:17 | function declaration |
6+
| test1.go:27:1:27:18 | function declaration |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import go
2+
3+
from TestCase tc
4+
select tc
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package main
2+
3+
import "net/http/httptest"
4+
5+
func setup(server *httptest.Server) {}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package main
2+
3+
import "testing"
4+
5+
func Test(t *testing.T) {} // test case
6+
7+
func Test2(t *testing.T) {} // test case
8+
9+
func TestMustHaveSingleParameter(t *testing.T, b bool) {} // not a test case
10+
11+
func TestParameterMustHaveCorrectType(b *testing.B) {} // not a test case
12+
13+
func TestsDoNotLookLikeThis(t *testing.T) {} // not a test case
14+
15+
func Benchmark(b *testing.B) {} // test case
16+
17+
func Benchmark2(b *testing.B) {} // test case
18+
19+
func BenchmarkMustHaveSingleParameter(b *testing.B, flag bool) {} // not a test case
20+
21+
func BenchmarkParameterMustHaveCorrectType(t *testing.T) {} // not a test case
22+
23+
func BenchmarksDoNotLookLikeThis(b *testing.B) {} // not a test case
24+
25+
func Example() {} // test case
26+
27+
func Example2() {} // test case
28+
29+
func ExampleMustNotHaveParameter(t *testing.T) {} // not a test case
30+
31+
func ExamplesDoNotLookLikeThis() {} // not a test case

0 commit comments

Comments
 (0)