< Summary - Neospec Coverage

Information
Line coverage
82%
Covered lines: 29
Uncovered lines: 6
Coverable lines: 35
Total lines: 74
Line coverage: 82.8%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Download0%0082.86%

File(s)

/home/runner/work/neospec/neospec/internal/adapters/neovim/downloader.go

#LineLine coverage
 1package neovim
 2
 3import (
 4  "context"
 5  "fmt"
 6  "io"
 7  "net/http"
 8  "os"
 9  "path/filepath"
 10
 11  "github.com/jedi-knights/neospec/internal/domain"
 12)
 13
 14// githubReleaseBase is the base URL for Neovim's GitHub releases.
 15const githubReleaseBase = "https://github.com/neovim/neovim/releases/download"
 16
 17// Downloader fetches Neovim release archives from GitHub.
 18type Downloader struct {
 19  client *http.Client
 20}
 21
 22// NewDownloader creates a Downloader with the default HTTP client.
 23func NewDownloader() *Downloader {
 24  return &Downloader{client: &http.Client{}}
 25}
 26
 27// Download fetches the release archive for version+platform and writes it to
 28// destPath, creating parent directories as needed.
 1029func (d *Downloader) Download(ctx context.Context, v domain.Version, p domain.Platform, destPath string) (retErr error) 
 1030  assetName := v.AssetName(p)
 131  if assetName == "" {
 132    return fmt.Errorf("no asset defined for platform %s", p)
 133  }
 34
 935  url := fmt.Sprintf("%s/%s/%s", githubReleaseBase, v.Tag, assetName)
 936
 137  if err := os.MkdirAll(filepath.Dir(destPath), 0o755); err != nil {
 138    return fmt.Errorf("creating download dir: %w", err)
 139  }
 40
 41  // This error branch is structurally unreachable: http.NewRequestWithContext
 42  // only fails when the method or URL is malformed. Both are constructed from
 43  // the compile-time constant http.MethodGet and a well-formed URL built from
 44  // the fixed githubReleaseBase prefix. No user-supplied input reaches here.
 845  req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
 046  if err != nil {
 047    return fmt.Errorf("creating request: %w", err)
 048  }
 49
 850  resp, err := d.client.Do(req)
 151  if err != nil {
 152    return fmt.Errorf("fetching %s: %w", url, err)
 153  }
 754  defer resp.Body.Close()
 755
 256  if resp.StatusCode != http.StatusOK {
 257    return fmt.Errorf("unexpected HTTP %d fetching %s", resp.StatusCode, url)
 258  }
 59
 560  f, err := os.Create(destPath)
 161  if err != nil {
 162    return fmt.Errorf("creating archive file: %w", err)
 163  }
 464  defer func() {
 065    if cerr := f.Close(); cerr != nil && retErr == nil {
 066      retErr = cerr
 067    }
 68  }()
 69
 170  if _, err := io.Copy(f, resp.Body); err != nil {
 171    return fmt.Errorf("writing archive: %w", err)
 172  }
 373  return nil
 74}

Methods/Properties

Download