Skip to content

Commit 53403a1

Browse files
committed
Eliminate global state and co-locate integration tests
1 parent 9d584c7 commit 53403a1

18 files changed

Lines changed: 356 additions & 342 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ To run the unit tests, run:
119119
just test
120120
```
121121

122-
This will run all unit tests alongside the source code in `internal/`.
122+
This will run all unit tests alongside the source code in `cmd/` and `internal/`.
123123

124124
To generate a test coverage report, run:
125125

@@ -172,4 +172,4 @@ The `pkgstats` project is structured as follows:
172172
- `system/`: Gathers system information like CPU architecture.
173173
- `main.go`: The main entry point of the application.
174174
- `justfile`: Contains the `just` commands for development and testing.
175-
- `tests/`: Contains the integration tests.
175+
- `tests/`: Contains the integration test Dockerfile.

cmd/architecture.go

Lines changed: 64 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8,70 +8,75 @@ import (
88
"github.com/spf13/cobra"
99
)
1010

11-
var architectureCmd = &cobra.Command{
12-
Use: "architecture",
13-
Aliases: []string{"arch"},
14-
Short: "Shows information about CPU and OS architecture",
15-
Hidden: true,
16-
Args: cobra.NoArgs,
17-
RunE: func(cmd *cobra.Command, args []string) error {
18-
s := system.NewSystem()
19-
20-
osArchitecture, err := s.GetArchitecture()
21-
if err != nil {
22-
return fmt.Errorf("could not get OS architecture: %w", err)
23-
}
24-
25-
systemArchitecture, err := s.GetCpuArchitecture()
26-
if err != nil {
27-
return fmt.Errorf("could not get CPU architecture: %w", err)
28-
}
29-
30-
fmt.Fprintf(cmd.OutOrStdout(), "You are using a %s CPU on a %s OS\n", systemArchitecture, osArchitecture)
31-
32-
return nil
33-
},
11+
func newArchitectureCmd() *cobra.Command {
12+
architectureCmd := &cobra.Command{
13+
Use: "architecture",
14+
Aliases: []string{"arch"},
15+
Short: "Shows information about CPU and OS architecture",
16+
Hidden: true,
17+
Args: cobra.NoArgs,
18+
RunE: func(cmd *cobra.Command, args []string) error {
19+
s := system.NewSystem()
20+
21+
osArchitecture, err := s.GetArchitecture()
22+
if err != nil {
23+
return fmt.Errorf("could not get OS architecture: %w", err)
24+
}
25+
26+
systemArchitecture, err := s.GetCpuArchitecture()
27+
if err != nil {
28+
return fmt.Errorf("could not get CPU architecture: %w", err)
29+
}
30+
31+
fmt.Fprintf(cmd.OutOrStdout(), "You are using a %s CPU on a %s OS\n", systemArchitecture, osArchitecture)
32+
33+
return nil
34+
},
35+
}
36+
37+
architectureCmd.AddCommand(newOsArchitectureCmd())
38+
architectureCmd.AddCommand(newSystemArchitectureCmd())
39+
40+
return architectureCmd
3441
}
3542

36-
var osArchitectureCommand = &cobra.Command{
37-
Use: "os",
38-
Short: "Shows OS architecture",
39-
Args: cobra.NoArgs,
40-
RunE: func(cmd *cobra.Command, args []string) error {
41-
s := system.NewSystem()
43+
func newOsArchitectureCmd() *cobra.Command {
44+
return &cobra.Command{
45+
Use: "os",
46+
Short: "Shows OS architecture",
47+
Args: cobra.NoArgs,
48+
RunE: func(cmd *cobra.Command, args []string) error {
49+
s := system.NewSystem()
4250

43-
osArchitecture, err := s.GetArchitecture()
44-
if err != nil {
45-
return fmt.Errorf("could not get OS architecture: %w", err)
46-
}
51+
osArchitecture, err := s.GetArchitecture()
52+
if err != nil {
53+
return fmt.Errorf("could not get OS architecture: %w", err)
54+
}
4755

48-
fmt.Fprintln(cmd.OutOrStdout(), osArchitecture)
56+
fmt.Fprintln(cmd.OutOrStdout(), osArchitecture)
4957

50-
return nil
51-
},
58+
return nil
59+
},
60+
}
5261
}
5362

54-
var systemArchitectureCommand = &cobra.Command{
55-
Use: "system",
56-
Aliases: []string{"cpu"},
57-
Short: "Shows CPU architecture",
58-
Args: cobra.NoArgs,
59-
RunE: func(cmd *cobra.Command, args []string) error {
60-
s := system.NewSystem()
61-
62-
systemArchitecture, err := s.GetCpuArchitecture()
63-
if err != nil {
64-
return fmt.Errorf("could not get CPU architecture: %w", err)
65-
}
66-
67-
fmt.Fprintln(cmd.OutOrStdout(), systemArchitecture)
68-
69-
return nil
70-
},
71-
}
72-
73-
func init() {
74-
rootCmd.AddCommand(architectureCmd)
75-
architectureCmd.AddCommand(osArchitectureCommand)
76-
architectureCmd.AddCommand(systemArchitectureCommand)
63+
func newSystemArchitectureCmd() *cobra.Command {
64+
return &cobra.Command{
65+
Use: "system",
66+
Aliases: []string{"cpu"},
67+
Short: "Shows CPU architecture",
68+
Args: cobra.NoArgs,
69+
RunE: func(cmd *cobra.Command, args []string) error {
70+
s := system.NewSystem()
71+
72+
systemArchitecture, err := s.GetCpuArchitecture()
73+
if err != nil {
74+
return fmt.Errorf("could not get CPU architecture: %w", err)
75+
}
76+
77+
fmt.Fprintln(cmd.OutOrStdout(), systemArchitecture)
78+
79+
return nil
80+
},
81+
}
7782
}

cmd/architecture_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package cmd_test
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"pkgstats-cli/internal/system"
8+
)
9+
10+
func TestShowArchitecture(t *testing.T) {
11+
output, err := pkgstats(t, []string{"architecture"})
12+
if err != nil {
13+
t.Fatalf("Failed to run command: %v", err)
14+
}
15+
16+
s := system.NewSystem()
17+
osArchitecture, err := s.GetArchitecture()
18+
if err != nil {
19+
t.Fatal(err)
20+
}
21+
cpuArchitecture, err := s.GetCpuArchitecture()
22+
if err != nil {
23+
t.Fatal(err)
24+
}
25+
26+
if !strings.Contains(output, osArchitecture) || !strings.Contains(output, cpuArchitecture) {
27+
t.Fatalf("Expected OS and CPU architecture %s and %s, but got %s", osArchitecture, cpuArchitecture, strings.TrimSpace(output))
28+
}
29+
}
30+
31+
func TestShowOsArchitecture(t *testing.T) {
32+
output, err := pkgstats(t, []string{"architecture", "os"})
33+
if err != nil {
34+
t.Fatalf("Failed to run command: %v", err)
35+
}
36+
37+
s := system.NewSystem()
38+
osArchitecture, err := s.GetArchitecture()
39+
if err != nil {
40+
t.Fatal(err)
41+
}
42+
43+
if strings.TrimSpace(output) != osArchitecture {
44+
t.Fatalf("Expected OS architecture %s, but got %s", osArchitecture, strings.TrimSpace(output))
45+
}
46+
}
47+
48+
func TestShowSystemArchitecture(t *testing.T) {
49+
output, err := pkgstats(t, []string{"architecture", "system"})
50+
if err != nil {
51+
t.Fatalf("Failed to run command: %v", err)
52+
}
53+
54+
s := system.NewSystem()
55+
cpuArchitecture, err := s.GetCpuArchitecture()
56+
if err != nil {
57+
t.Fatal(err)
58+
}
59+
60+
if strings.TrimSpace(output) != cpuArchitecture {
61+
t.Fatalf("Expected CPU architecture %s, but got %s", cpuArchitecture, strings.TrimSpace(output))
62+
}
63+
}

cmd/root.go

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package cmd
22

33
import (
4-
"fmt"
54
"os"
65

76
"pkgstats-cli/internal/build"
@@ -15,46 +14,42 @@ const (
1514
pkgstatsConfParam = "pkgstats-conf"
1615
)
1716

18-
var (
19-
baseURL = "https://pkgstats.archlinux.de"
20-
pacmanConf = "/etc/pacman.conf"
21-
pkgstatsConf = ""
22-
rootCmd = &cobra.Command{
17+
func Execute() {
18+
if err := NewRootCmd().Execute(); err != nil {
19+
os.Exit(1)
20+
}
21+
}
22+
23+
func NewRootCmd() *cobra.Command {
24+
var (
25+
baseURL = "https://pkgstats.archlinux.de"
26+
pacmanConf = "/etc/pacman.conf"
27+
pkgstatsConf = ""
28+
)
29+
30+
rootCmd := &cobra.Command{
2331
Use: "pkgstats",
2432
Short: "pkgstats client",
2533
Version: build.Version,
2634
SilenceUsage: true,
2735
}
28-
)
29-
30-
func Execute() {
31-
if err := rootCmd.Execute(); err != nil {
32-
os.Exit(1)
33-
}
34-
}
3536

36-
func init() {
3737
rootCmd.PersistentFlags().StringVar(&baseURL, baseUrlParam, baseURL, "base url of the pkgstats server")
38-
if err := rootCmd.PersistentFlags().MarkHidden(baseUrlParam); err != nil {
39-
fmt.Fprintln(rootCmd.ErrOrStderr(), err)
40-
os.Exit(1)
41-
}
38+
_ = rootCmd.PersistentFlags().MarkHidden(baseUrlParam)
4239

4340
rootCmd.PersistentFlags().StringVar(&pacmanConf, pacmanConfParam, pacmanConf, "path to pacman.conf")
44-
if err := rootCmd.PersistentFlags().MarkHidden(pacmanConfParam); err != nil {
45-
fmt.Fprintln(rootCmd.ErrOrStderr(), err)
46-
os.Exit(1)
47-
}
41+
_ = rootCmd.PersistentFlags().MarkHidden(pacmanConfParam)
4842

4943
rootCmd.PersistentFlags().StringVarP(&pkgstatsConf, pkgstatsConfParam, "c", pkgstatsConf, "path to pkgstats config file")
50-
if err := rootCmd.PersistentFlags().MarkHidden(pkgstatsConfParam); err != nil {
51-
fmt.Fprintln(rootCmd.ErrOrStderr(), err)
52-
os.Exit(1)
53-
}
44+
_ = rootCmd.PersistentFlags().MarkHidden(pkgstatsConfParam)
5445

5546
rootCmd.CompletionOptions.HiddenDefaultCmd = true
56-
}
5747

58-
func GetRootCmd() *cobra.Command {
48+
rootCmd.AddCommand(newSubmitCmd(&baseURL, &pacmanConf, &pkgstatsConf))
49+
rootCmd.AddCommand(newSearchCmd(&baseURL))
50+
rootCmd.AddCommand(newShowCmd(&baseURL))
51+
rootCmd.AddCommand(newArchitectureCmd())
52+
rootCmd.AddCommand(newVersionCmd())
53+
5954
return rootCmd
6055
}

cmd/root_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package cmd_test
2+
3+
import (
4+
"strings"
5+
"testing"
6+
)
7+
8+
func TestShowHelp(t *testing.T) {
9+
output, err := pkgstats(t, []string{"help"})
10+
if err != nil {
11+
t.Fatalf("Failed to run command: %v", err)
12+
}
13+
if !strings.Contains(output, "Usage:") {
14+
t.Errorf("Expected help output to contain 'Usage:', got %s", output)
15+
}
16+
}

cmd/search.go

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,36 +13,37 @@ const (
1313
maxLimit = 10000
1414
)
1515

16-
var limit = 10
17-
18-
var searchCmd = &cobra.Command{
19-
Use: "search",
20-
Short: "Search packages and list their popularity",
21-
Args: cobra.ExactArgs(1),
22-
RunE: func(cmd *cobra.Command, args []string) error {
23-
if limit < minLimit || limit > maxLimit {
24-
return fmt.Errorf("valid limit needs to be between %d and %d", minLimit, maxLimit)
25-
}
26-
if err := request.ValidatePackageName(args[0]); err != nil {
27-
return err
28-
}
29-
30-
client := request.NewClient(baseURL)
31-
32-
ppl, err := client.SearchPackages(args[0], limit)
33-
if err != nil {
34-
return err
35-
}
36-
37-
request.PrintPackagePopularities(cmd.OutOrStdout(), ppl)
38-
fmt.Fprintln(cmd.OutOrStdout())
39-
request.PrintSearchURL(cmd.OutOrStdout(), baseURL, args[0])
40-
41-
return nil
42-
},
43-
}
16+
func newSearchCmd(baseURL *string) *cobra.Command {
17+
limit := 10
18+
19+
searchCmd := &cobra.Command{
20+
Use: "search",
21+
Short: "Search packages and list their popularity",
22+
Args: cobra.ExactArgs(1),
23+
RunE: func(cmd *cobra.Command, args []string) error {
24+
if limit < minLimit || limit > maxLimit {
25+
return fmt.Errorf("valid limit needs to be between %d and %d", minLimit, maxLimit)
26+
}
27+
if err := request.ValidatePackageName(args[0]); err != nil {
28+
return err
29+
}
30+
31+
client := request.NewClient(*baseURL)
32+
33+
ppl, err := client.SearchPackages(args[0], limit)
34+
if err != nil {
35+
return err
36+
}
37+
38+
request.PrintPackagePopularities(cmd.OutOrStdout(), ppl)
39+
fmt.Fprintln(cmd.OutOrStdout())
40+
request.PrintSearchURL(cmd.OutOrStdout(), *baseURL, args[0])
41+
42+
return nil
43+
},
44+
}
4445

45-
func init() {
46-
rootCmd.AddCommand(searchCmd)
4746
searchCmd.Flags().IntVarP(&limit, "limit", "l", limit, fmt.Sprintf("Limit the results from %d to %d entries", minLimit, maxLimit))
47+
48+
return searchCmd
4849
}

0 commit comments

Comments
 (0)