Skip to content

Commit

Permalink
test: cmd package
Browse files Browse the repository at this point in the history
  • Loading branch information
hedhyw committed Oct 5, 2024
1 parent c3abe87 commit 4e5a0f8
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 53 deletions.
74 changes: 53 additions & 21 deletions cmd/jlv/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package main

import (
"context"
"errors"
"flag"
"fmt"
"io"
"io/fs"
"os"
"path"

Expand All @@ -25,48 +28,80 @@ func main() {
printVersion := flag.Bool("version", false, "Print version")
flag.Parse()

if *printVersion {
err := runApp(applicationArguments{
Stdout: os.Stdout,
Stdin: os.Stdin,

ConfigPath: *configPath,
PrintVersion: *printVersion,
Args: flag.Args(),

RunProgram: func(p *tea.Program) (tea.Model, error) {
return p.Run()
},
})
if err != nil {
fmt.Fprintln(os.Stderr, "Error: "+err.Error())
os.Exit(1)
}
}

type applicationArguments struct {
Stdout io.Writer
Stdin fs.File

ConfigPath string
PrintVersion bool
Args []string

RunProgram func(*tea.Program) (tea.Model, error)
}

func runApp(args applicationArguments) (err error) {
if args.PrintVersion {
// nolint: forbidigo // Version command.
print("github.com/hedhyw/json-log-viewer@" + version + "\n")
fmt.Fprintln(args.Stdout, "github.com/hedhyw/json-log-viewer@"+version)

return
return nil
}

cfg, err := readConfig(*configPath)
cfg, err := readConfig(args.ConfigPath)
if err != nil {
fatalf("Error reading config: %s\n", err)
return fmt.Errorf("reading config: %w", err)
}

fileName := ""
var inputSource *source.Source

switch flag.NArg() {
switch len(args.Args) {
case 0:
// Tee stdin to a temp file, so that we can
// lazy load the log entries using random access.
fileName = "-"

stdIn, err := getStdinReader(os.Stdin)
stdin, err := getStdinReader(args.Stdin)
if err != nil {
fatalf("Stdin: %s\n", err)
return fmt.Errorf("getting stdin: %w", err)
}

inputSource, err = source.Reader(stdIn, cfg)
inputSource, err = source.Reader(stdin, cfg)
if err != nil {
fatalf("Could not create temp flie: %s\n", err)
return fmt.Errorf("creating a temporary file: %w", err)
}
defer inputSource.Close()

defer func() { err = errors.Join(err, inputSource.Close()) }()
case 1:
fileName = flag.Arg(0)
fileName = args.Args[0]

inputSource, err = source.File(fileName, cfg)
if err != nil {
fatalf("Could not create temp flie: %s\n", err)
return fmt.Errorf("reading file: %w", err)
}
defer inputSource.Close()

defer func() { err = errors.Join(err, inputSource.Close()) }()
default:
fatalf("Invalid arguments, usage: %s file.log\n", os.Args[0])
// nolint: err113 // One time case.
return fmt.Errorf("invalid arguments, usage: %s file.log", os.Args[0])
}

appModel := app.NewModel(fileName, cfg, version)
Expand All @@ -80,14 +115,11 @@ func main() {
}
})

if _, err := program.Run(); err != nil {
fatalf("Error running program: %s\n", err)
if _, err := args.RunProgram(program); err != nil {
return fmt.Errorf("running program: %w", err)
}
}

func fatalf(message string, args ...any) {
fmt.Fprintf(os.Stderr, message, args...)
os.Exit(1)
return nil
}

// readConfig tries to read config from working directory or home directory.
Expand Down
140 changes: 140 additions & 0 deletions cmd/jlv/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,150 @@ import (
"os"
"testing"

"github.com/hedhyw/json-log-viewer/internal/app"
"github.com/hedhyw/json-log-viewer/internal/pkg/config"
"github.com/hedhyw/json-log-viewer/internal/pkg/tests"

tea "github.com/charmbracelet/bubbletea"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestRunAppVersion(t *testing.T) {
t.Parallel()

var outputBuf bytes.Buffer

err := runApp(applicationArguments{
Stdout: &outputBuf,
PrintVersion: true,
})
require.NoError(t, err)

assert.Contains(t, outputBuf.String(), version)
}

func TestRunAppRunProgramFailed(t *testing.T) {
t.Parallel()

fileName := tests.RequireCreateFile(t, []byte(t.Name()))

err := runApp(applicationArguments{
Args: []string{fileName},
RunProgram: func(*tea.Program) (tea.Model, error) {
return nil, tests.ErrTest
},
})
require.ErrorIs(t, err, tests.ErrTest)
}

func TestRunAppRunProgramReadConfigInvalid(t *testing.T) {
t.Parallel()

configPath := tests.RequireCreateFile(t, []byte("invalid config"))

err := runApp(applicationArguments{
ConfigPath: configPath,
RunProgram: func(*tea.Program) (tea.Model, error) {
t.Fatal("Should not run")

return app.NewModel("", config.GetDefaultConfig(), version), nil
},
})
require.Error(t, err)
}

func TestRunAppUnexpectedNumberOfArgs(t *testing.T) {
t.Parallel()

err := runApp(applicationArguments{
Args: []string{"1", "2", "3"},
})
require.Error(t, err)
}

func TestRunAppReadFileSuccess(t *testing.T) {
t.Parallel()

fileName := tests.RequireCreateFile(t, []byte(t.Name()))

var isStarted bool

err := runApp(applicationArguments{
Args: []string{fileName},
RunProgram: func(p *tea.Program) (tea.Model, error) {
assert.NotNil(t, p)
isStarted = true

return app.NewModel("", config.GetDefaultConfig(), version), nil
},
})
require.NoError(t, err)

assert.True(t, isStarted)
}

func TestRunAppReadFileNotFound(t *testing.T) {
t.Parallel()

err := runApp(applicationArguments{
Args: []string{t.Name() + "not found"},
RunProgram: func(*tea.Program) (tea.Model, error) {
t.Fatal("Should not run")

return app.NewModel("", config.GetDefaultConfig(), version), nil
},
})
require.Error(t, err)
}

func TestRunAppReadStdinSuccess(t *testing.T) {
t.Parallel()

fakeStdin := fakeFile{
Reader: bytes.NewReader([]byte(t.Name())),
StatFileInfo: fakeFileInfo{
FileMode: os.ModeNamedPipe,
},
}

var isStarted bool

err := runApp(applicationArguments{
Args: []string{},
Stdin: fakeStdin,
RunProgram: func(p *tea.Program) (tea.Model, error) {
assert.NotNil(t, p)
isStarted = true

return app.NewModel("", config.GetDefaultConfig(), version), nil
},
})
require.NoError(t, err)

assert.True(t, isStarted)
}

func TestRunAppReadStdinStatFailed(t *testing.T) {
t.Parallel()

fakeStdin := fakeFile{
Reader: bytes.NewReader([]byte(t.Name())),
ErrStat: tests.ErrTest,
}

err := runApp(applicationArguments{
Args: []string{},
Stdin: fakeStdin,
RunProgram: func(*tea.Program) (tea.Model, error) {
t.Fatal("Should not run")

return app.NewModel("", config.GetDefaultConfig(), version), nil
},
})
require.ErrorIs(t, err, tests.ErrTest)
}

func TestGetStdinSource(t *testing.T) {
t.Parallel()

Expand Down
30 changes: 0 additions & 30 deletions cmd/jlv/stdin_reader_mock.go

This file was deleted.

2 changes: 0 additions & 2 deletions cmd/jlv/stdin_reader.go → cmd/jlv/stdinreader.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:build !mock_stdin

package main

import (
Expand Down

0 comments on commit 4e5a0f8

Please sign in to comment.