Skip to content

Commit ec2b1f5

Browse files
authored
tests: Add tests (#75)
* tests: Add tests * fix: Vet * tests: Add more tests * fix: Sonar code smells * tests: improve coverage * tests: Increase test coverage * tests: Increase coverage * bypass nilcontext * fix: io.Reader scanner bugs
1 parent da7518d commit ec2b1f5

30 files changed

+862
-13
lines changed

cmd/aoc-cli/handlers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func notFound(ctx context.Context) cli.CommandNotFoundFunc {
6868
}
6969
func menu(ctx context.Context) cli.ActionFunc {
7070
return func(c *cli.Context) error {
71-
ctx = command.ContextWithOptions(ctx, optionsFromCli(c))
71+
ctx = command.ContextWithOptions(ctx, optionsFromCli(c)...)
7272
ctx = command.ContextWithSession(ctx, sessionFromCli(c))
7373

7474
years := puzzles.GetYears()

internal/command/command_test.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package command_test
2+
3+
import (
4+
"context"
5+
"errors"
6+
"io"
7+
"net/http"
8+
"strings"
9+
"testing"
10+
11+
"github.com/stretchr/testify/assert"
12+
13+
"github.com/obalunenko/advent-of-code/internal/command"
14+
"github.com/obalunenko/advent-of-code/internal/puzzles"
15+
"github.com/obalunenko/advent-of-code/internal/puzzles/input"
16+
)
17+
18+
// Custom type that allows setting the func that our Mock Do func will run instead
19+
type dofunc func(req *http.Request) (*http.Response, error)
20+
21+
// MockClient is the mock client
22+
type mockHTTPClient struct {
23+
MockDo dofunc
24+
}
25+
26+
// Overriding what the Do function should "do" in our MockClient
27+
func (m *mockHTTPClient) Do(req *http.Request) (*http.Response, error) {
28+
return m.MockDo(req)
29+
}
30+
31+
type mockSolver struct {
32+
year string
33+
name string
34+
}
35+
36+
func (m mockSolver) Year() string {
37+
return m.year
38+
}
39+
40+
func (m mockSolver) Day() string {
41+
return m.name
42+
}
43+
44+
func (m mockSolver) Part1(in io.Reader) (string, error) {
45+
split, err := read(in)
46+
if err != nil {
47+
return "", err
48+
}
49+
50+
return split[1], nil
51+
}
52+
53+
func (m mockSolver) Part2(in io.Reader) (string, error) {
54+
split, err := read(in)
55+
if err != nil {
56+
return "", err
57+
}
58+
59+
return split[2], nil
60+
}
61+
62+
func read(in io.Reader) ([]string, error) {
63+
all, err := io.ReadAll(in)
64+
if err != nil {
65+
return nil, err
66+
}
67+
68+
split := strings.Split(string(all), ",")
69+
70+
if len(split) != 3 {
71+
return nil, errors.New("wrong parts")
72+
}
73+
74+
return split, nil
75+
}
76+
77+
func TestRun(t *testing.T) {
78+
ctx := context.Background()
79+
80+
year := "1992"
81+
day := "31"
82+
83+
puzzles.Register(mockSolver{
84+
year: year,
85+
name: day,
86+
})
87+
88+
t.Cleanup(func() {
89+
puzzles.UnregisterAllSolvers(t)
90+
})
91+
92+
r := io.NopCloser(strings.NewReader("1,2,3"))
93+
94+
input.Client = &mockHTTPClient{
95+
MockDo: func(req *http.Request) (*http.Response, error) {
96+
return &http.Response{
97+
Status: http.StatusText(http.StatusOK),
98+
StatusCode: http.StatusOK,
99+
Proto: "HTTP/1.0",
100+
ProtoMajor: 1,
101+
ProtoMinor: 0,
102+
Header: nil,
103+
Body: r,
104+
ContentLength: 0,
105+
TransferEncoding: nil,
106+
Close: false,
107+
Uncompressed: false,
108+
Trailer: nil,
109+
Request: nil,
110+
TLS: nil,
111+
}, nil
112+
},
113+
}
114+
115+
got, err := command.Run(ctx, year, day)
116+
assert.NoError(t, err)
117+
118+
assert.Equal(t, puzzles.Result{
119+
Year: "1992",
120+
Name: "31",
121+
Part1: "2",
122+
Part2: "3",
123+
}, got)
124+
}

internal/command/context.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func SessionFromContext(ctx context.Context) string {
3636
type optsCtxKey struct{}
3737

3838
// ContextWithOptions adds options to context.
39-
func ContextWithOptions(ctx context.Context, opts []puzzles.RunOption) context.Context {
39+
func ContextWithOptions(ctx context.Context, opts ...puzzles.RunOption) context.Context {
4040
if len(opts) == 0 {
4141
return ctx
4242
}

internal/command/context_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package command_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
9+
"github.com/obalunenko/advent-of-code/internal/command"
10+
"github.com/obalunenko/advent-of-code/internal/puzzles"
11+
)
12+
13+
func nilContext() context.Context {
14+
return nil
15+
}
16+
17+
func TestContext(t *testing.T) {
18+
sess := "test_session"
19+
20+
ctx := command.ContextWithSession(context.Background(), sess)
21+
22+
got := command.SessionFromContext(ctx)
23+
assert.Equal(t, sess, got)
24+
25+
got = command.SessionFromContext(nilContext())
26+
assert.Equal(t, "", got)
27+
28+
got = command.SessionFromContext(context.Background())
29+
assert.Equal(t, "", got)
30+
31+
opt := puzzles.WithElapsed()
32+
33+
ctx = command.ContextWithOptions(ctx, opt)
34+
35+
gotopts := command.OptionsFromContext(ctx)
36+
assert.Equal(t, []puzzles.RunOption{opt}, gotopts)
37+
38+
gotopts = command.OptionsFromContext(nilContext())
39+
assert.Equal(t, []puzzles.RunOption{}, gotopts)
40+
41+
gotopts = command.OptionsFromContext(context.Background())
42+
assert.Equal(t, []puzzles.RunOption{}, gotopts)
43+
}

internal/puzzles/input/content.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,21 @@ func (d Date) String() string {
3131
return path.Join(d.Year, d.Day)
3232
}
3333

34+
// ClientDo provides the interface for custom HTTP client implementations.
35+
type ClientDo interface {
36+
Do(*http.Request) (*http.Response, error)
37+
}
38+
39+
// Client is the default Client and is used by Get, Head, and Post.
40+
var Client ClientDo = http.DefaultClient
41+
3442
// Get returns puzzle input.
3543
func Get(ctx context.Context, d Date, session string) ([]byte, error) {
3644
req, err := createInputReq(ctx, d, session)
3745
if err != nil {
3846
return nil, fmt.Errorf("create input request: %w", err)
3947
}
4048

41-
client := http.DefaultClient
42-
4349
const (
4450
timeoutSecs = 5
4551
)
@@ -49,7 +55,7 @@ func Get(ctx context.Context, d Date, session string) ([]byte, error) {
4955

5056
req = req.Clone(ctx)
5157

52-
resp, err := client.Do(req)
58+
resp, err := Client.Do(req)
5359
if err != nil {
5460
return nil, fmt.Errorf("send request: %w", err)
5561
}

0 commit comments

Comments
 (0)