Skip to content

Commit

Permalink
tests: add tests on suggested fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
ldez committed Jan 16, 2025
1 parent 2046ce8 commit c156c33
Show file tree
Hide file tree
Showing 2 changed files with 258 additions and 5 deletions.
12 changes: 7 additions & 5 deletions pkg/analyzer/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ func TestAnalyzer(t *testing.T) {
desc: "no func decl",
dir: "no_structpointer",
},
{
desc: "no func decl",
dir: "cgo",
},
{
desc: "func decl",
dir: "common",
Expand Down Expand Up @@ -55,7 +51,13 @@ func TestAnalyzer(t *testing.T) {
}
}

analysistest.Run(t, analysistest.TestData(), a, test.dir)
analysistest.RunWithSuggestedFixes(t, analysistest.TestData(), a, test.dir)
})
}
}

func TestAnalyzer_cgo(t *testing.T) {
a := analyzer.NewAnalyzer()

analysistest.Run(t, analysistest.TestData(), a, "cgo")
}
251 changes: 251 additions & 0 deletions pkg/analyzer/testdata/src/common/example.go.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
package common

import (
"context"
"testing"
)

func example() {
ctx := context.Background()

for i := 0; i < 10; i++ {
ctx := context.WithValue(ctx, "key", i)
ctx = context.WithValue(ctx, "other", "val")
}

for i := 0; i < 10; i++ {
ctx := context.WithValue(ctx, "key", i) // want "nested context in loop"
ctx = context.WithValue(ctx, "other", "val")
}

for item := range []string{"one", "two", "three"} {
ctx := wrapContext(ctx) // want "nested context in loop"
ctx := context.WithValue(ctx, "key", item)
ctx = wrapContext(ctx)
}

for {
ctx := wrapContext(ctx) // want "nested context in loop"
break
}

// not fooled by shadowing in nested blocks
for {
err := doSomething()
if err != nil {
ctx := wrapContext(ctx)
ctx = wrapContext(ctx)
}

switch err {
case nil:
ctx := wrapContext(ctx)
ctx = wrapContext(ctx)
default:
ctx := wrapContext(ctx)
ctx = wrapContext(ctx)
}

{
ctx := wrapContext(ctx)
ctx = wrapContext(ctx)
}

select {
case <-ctx.Done():
ctx := wrapContext(ctx)
ctx = wrapContext(ctx)
default:
}

ctx := wrapContext(ctx) // want "nested context in loop"

break
}

// detects contexts wrapped in function literals (this is risky as function literals can be called multiple times)
_ = func() {
ctx := wrapContext(ctx) // want "nested context in function literal"
}

// this is fine because the context is created in the loop
for {
if ctx := context.Background(); doSomething() != nil {
ctx = wrapContext(ctx)
}
}

for {
ctx2 := context.Background()
ctx := wrapContext(ctx) // want "nested context in loop"
if doSomething() != nil {
ctx2 = wrapContext(ctx2)
}
}
}

func wrapContext(ctx context.Context) context.Context {
return context.WithoutCancel(ctx)
}

func doSomething() error {
return nil
}

// storing contexts in a struct isn't recommended, but local copies of a non-pointer struct should act like local copies of a context.
func inStructs(ctx context.Context) {
for i := 0; i < 10; i++ {
c := struct{ Ctx context.Context }{ctx}
c.Ctx = context.WithValue(c.Ctx, "key", i)
c.Ctx = context.WithValue(c.Ctx, "other", "val")
}

for i := 0; i < 10; i++ {
c := []struct{ Ctx context.Context }{{ctx}}
c[0].Ctx = context.WithValue(c[0].Ctx, "key", i)
c[0].Ctx = context.WithValue(c[0].Ctx, "other", "val")
}

c := struct{ Ctx context.Context }{ctx}
for i := 0; i < 10; i++ {
c := c
c.Ctx = context.WithValue(c.Ctx, "key", i)
c.Ctx = context.WithValue(c.Ctx, "other", "val")
}

pc := &struct{ Ctx context.Context }{ctx}
for i := 0; i < 10; i++ {
c := pc
c.Ctx := context.WithValue(c.Ctx, "key", i) // want "nested context in loop"
c.Ctx = context.WithValue(c.Ctx, "other", "val")
}

r := []struct{ Ctx context.Context }{{ctx}}
for i := 0; i < 10; i++ {
r[0].Ctx := context.WithValue(r[0].Ctx, "key", i) // want "nested context in loop"
r[0].Ctx = context.WithValue(r[0].Ctx, "other", "val")
}

rp := []*struct{ Ctx context.Context }{{ctx}}
for i := 0; i < 10; i++ {
rp[0].Ctx := context.WithValue(rp[0].Ctx, "key", i) // want "nested context in loop"
rp[0].Ctx = context.WithValue(rp[0].Ctx, "other", "val")
}
}

func inVariousNestedBlocks(ctx context.Context) {
for {
err := doSomething()
if err != nil {
ctx := wrapContext(ctx) // want "nested context in loop"
}

break
}

for {
err := doSomething()
if err != nil {
if true {
ctx := wrapContext(ctx) // want "nested context in loop"
}
}

break
}

for {
err := doSomething()
switch err {
case nil:
ctx := wrapContext(ctx) // want "nested context in loop"
}

break
}

for {
err := doSomething()
switch err {
default:
ctx := wrapContext(ctx) // want "nested context in loop"
}

break
}

for {
ctx := wrapContext(ctx)

err := doSomething()
if err != nil {
ctx = wrapContext(ctx)
}

break
}

for {
{
ctx := wrapContext(ctx) // want "nested context in loop"
}

break
}

for {
select {
case <-ctx.Done():
ctx := wrapContext(ctx) // want "nested context in loop"
default:
}

break
}
}

// this middleware could run on every request, bloating the request parameter level context and causing a memory leak
func badMiddleware(ctx context.Context) func() error {
return func() error {
ctx := wrapContext(ctx) // want "nested context in function literal"
return doSomethingWithCtx(ctx)
}
}

// this middleware is fine, as it doesn't modify the context of parent function
func okMiddleware(ctx context.Context) func() error {
return func() error {
ctx := wrapContext(ctx)
return doSomethingWithCtx(ctx)
}
}

// this middleware is fine, as it only modifies the context passed to it
func okMiddleware2(ctx context.Context) func(ctx context.Context) error {
return func(ctx context.Context) error {
ctx = wrapContext(ctx)
return doSomethingWithCtx(ctx)
}
}

func doSomethingWithCtx(ctx context.Context) error {
return nil
}

func testCasesInit(t *testing.T) {
cases := []struct {
ctx context.Context
}{
{},
{
ctx: context.WithValue(context.Background(), "key", "value"),
},
}
for _, tc := range cases {
t.Run("some test", func(t *testing.T) {
if tc.ctx == nil {
tc.ctx = context.Background()
}
})
}
}

0 comments on commit c156c33

Please # to comment.