Skip to content

Commit

Permalink
additional unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
sagerb committed Dec 19, 2024
1 parent 2af2ace commit d77b562
Show file tree
Hide file tree
Showing 5 changed files with 385 additions and 32 deletions.
112 changes: 99 additions & 13 deletions internal/initialize/initialize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
"github.com/stretchr/testify/suite"
)

// TODO = initialize not currently testing R project

type InitializeSuite struct {
utiltest.Suite
cwd util.AbsolutePath
Expand Down Expand Up @@ -59,14 +61,63 @@ func (s *InitializeSuite) TestInitEmpty() {
s.Equal("My App", cfg.Title)
}

func (s *InitializeSuite) createAppPy() {
func (s *InitializeSuite) createAppPy() util.AbsolutePath {
appPath := s.cwd.Join("app.py")
err := appPath.WriteFile([]byte(`
from flask import Flask
app = Flask(__name__)
app.run()
`), 0666)
s.NoError(err)
return appPath
}

func (s *InitializeSuite) createAppR() util.AbsolutePath {
appPath := s.cwd.Join("app.R")
err := appPath.WriteFile([]byte(`
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
# Run the application
shinyApp(ui = ui, server = server)
`), 0666)
s.NoError(err)
return appPath
}

func (s *InitializeSuite) createHTML() {
Expand Down Expand Up @@ -98,10 +149,26 @@ func makeMockPythonInspector(util.AbsolutePath, util.Path, logging.Logger) inspe
return pyInspector
}

var expectedRConfig = &config.R{
Version: "1.2.3",
PackageManager: "renv",
PackageFile: "renv.lock",
}

func setupMockRInspector(requiredRReturnValue bool, requiredRError error) func(util.AbsolutePath, util.Path, logging.Logger) (inspect.RInspector, error) {
return func(util.AbsolutePath, util.Path, logging.Logger) (inspect.RInspector, error) {
rInspector := inspect.NewMockRInspector()
rInspector.On("InspectR").Return(expectedRConfig, nil)
rInspector.On("RequiresR").Return(requiredRReturnValue, requiredRError)
return rInspector, nil
}
}

func (s *InitializeSuite) TestInitInferredType() {
log := logging.New()
s.createAppPy()
PythonInspectorFactory = makeMockPythonInspector
RInspectorFactory = setupMockRInspector(false, nil)
configName := ""
cfg, err := Init(s.cwd, configName, util.Path{}, util.Path{}, log)
s.NoError(err)
Expand All @@ -118,6 +185,7 @@ func (s *InitializeSuite) TestInitRequirementsFile() {
s.createHTML()
s.createRequirementsFile()
PythonInspectorFactory = makeMockPythonInspector
RInspectorFactory = setupMockRInspector(false, nil)
configName := ""
cfg, err := Init(s.cwd, configName, util.Path{}, util.Path{}, log)
s.NoError(err)
Expand All @@ -133,6 +201,7 @@ func (s *InitializeSuite) TestInitIfNeededWhenNeeded() {
log := logging.New()
s.createAppPy()
PythonInspectorFactory = makeMockPythonInspector
RInspectorFactory = setupMockRInspector(false, nil)
configName := ""
err := InitIfNeeded(s.cwd, configName, log)
s.NoError(err)
Expand Down Expand Up @@ -160,6 +229,9 @@ func (s *InitializeSuite) TestInitIfNeededWhenNotNeeded() {
PythonInspectorFactory = func(util.AbsolutePath, util.Path, logging.Logger) inspect.PythonInspector {
return &inspect.MockPythonInspector{}
}
RInspectorFactory = func(util.AbsolutePath, util.Path, logging.Logger) (inspect.RInspector, error) {
return &inspect.MockRInspector{}, nil
}
err := InitIfNeeded(s.cwd, configName, log)
s.NoError(err)
newConfig, err := config.FromFile(configPath)
Expand All @@ -169,25 +241,39 @@ func (s *InitializeSuite) TestInitIfNeededWhenNotNeeded() {

func (s *InitializeSuite) TestGetPossibleConfigs() {
log := logging.New()
s.createAppPy()
appPy := s.createAppPy()
exist, err := appPy.Exists()
s.NoError(err)
s.Equal(true, exist)
appR := s.createAppR()
exist, err = appR.Exists()
s.NoError(err)
s.Equal(true, exist)

err := s.cwd.Join("index.html").WriteFile([]byte(`<html></html>`), 0666)
err = s.cwd.Join("index.html").WriteFile([]byte(`<html></html>`), 0666)
s.NoError(err)

PythonInspectorFactory = makeMockPythonInspector
RInspectorFactory = setupMockRInspector(true, nil)

configs, err := GetPossibleConfigs(s.cwd, util.Path{}, util.Path{}, util.RelativePath{}, log)
s.NoError(err)

s.Len(configs, 2)
s.Equal(config.ContentTypePythonFlask, configs[0].Type)
s.Equal("app.py", configs[0].Entrypoint)
s.Equal([]string{"/app.py", "/requirements.txt"}, configs[0].Files)
s.Equal(expectedPyConfig, configs[0].Python)

s.Equal(config.ContentTypeHTML, configs[1].Type)
s.Equal("index.html", configs[1].Entrypoint)
s.Equal([]string{"/index.html"}, configs[1].Files)
s.Nil(configs[1].Python)
s.Len(configs, 3)
s.Equal(config.ContentTypeRShiny, configs[0].Type)
s.Equal("app.R", configs[0].Entrypoint)
s.Equal([]string{"/app.R", "/renv.lock"}, configs[0].Files)
s.Equal(expectedRConfig, configs[0].R)

s.Equal(config.ContentTypePythonFlask, configs[1].Type)
s.Equal("app.py", configs[1].Entrypoint)
s.Equal([]string{"/app.py", "/requirements.txt", "/renv.lock"}, configs[1].Files)
s.Equal(expectedPyConfig, configs[1].Python)

s.Equal(config.ContentTypeHTML, configs[2].Type)
s.Equal("index.html", configs[2].Entrypoint)
s.Equal([]string{"/index.html", "/renv.lock"}, configs[2].Files)
s.Nil(configs[2].Python)
}

func (s *InitializeSuite) TestGetPossibleConfigsEmpty() {
Expand Down
141 changes: 133 additions & 8 deletions internal/inspect/r_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ package inspect
// Copyright (C) 2023 by Posit Software, PBC.

import (
"errors"
"testing"

"github.com/posit-dev/publisher/internal/config"
"github.com/posit-dev/publisher/internal/interpreters"
"github.com/posit-dev/publisher/internal/logging"
"github.com/posit-dev/publisher/internal/types"
"github.com/posit-dev/publisher/internal/util"
"github.com/posit-dev/publisher/internal/util/utiltest"
"github.com/spf13/afero"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
)

Expand All @@ -29,19 +31,19 @@ func (s *RSuite) SetupTest() {
s.cwd = cwd
err = cwd.MkdirAll(0700)
s.NoError(err)
}

func (s *RSuite) TestNewRInspector() {
log := logging.New()
rPath := util.NewPath("/usr/bin/R", nil)

interpreters.NewRInterpreter = func(baseDir util.AbsolutePath, rExec util.Path, log logging.Logger) interpreters.RInterpreter {
i := interpreters.NewMockRInterpreter()
i.On("Init").Return(nil)
i.On("RequiresR", mock.Anything).Return(false, nil)
i.On("GetLockFilePath").Return(util.RelativePath{}, false, nil)
// i.On("RequiresR", mock.Anything).Return(false, nil)
// i.On("GetLockFilePath").Return(util.RelativePath{}, false, nil)
return i
}
}

func (s *RSuite) TestNewRInspector() {
log := logging.New()
rPath := util.NewPath("/usr/bin/R", nil)

i, err := NewRInspector(s.cwd, rPath, log)
s.NoError(err)
Expand All @@ -50,3 +52,126 @@ func (s *RSuite) TestNewRInspector() {
s.Equal(s.cwd, inspector.base)
s.Equal(log, inspector.log)
}

func (s *RSuite) TestInspectWithRFound() {
var relPath util.RelativePath

interpreters.NewRInterpreter = func(baseDir util.AbsolutePath, rExec util.Path, log logging.Logger) interpreters.RInterpreter {
i := interpreters.NewMockRInterpreter()
i.On("Init").Return(nil)
i.On("GetRExecutable").Return(util.NewAbsolutePath("R", baseDir.Fs()), nil)
i.On("GetRVersion").Return("1.2.3", nil)
relPath = util.NewRelativePath(baseDir.Join("renv.lock").String(), baseDir.Fs())
i.On("GetLockFilePath").Return(relPath, true, nil)
return i
}
log := logging.New()
i, err := NewRInspector(s.cwd, util.Path{}, log)
s.NoError(err)

inspect, err := i.InspectR()
s.NoError(err)
s.Equal("renv", inspect.PackageManager)
s.Equal("1.2.3", inspect.Version)
s.Equal(relPath.String(), inspect.PackageFile)
}

func (s *RSuite) TestInspectWithNoRFound() {
interpreters.NewRInterpreter = func(baseDir util.AbsolutePath, rExec util.Path, log logging.Logger) interpreters.RInterpreter {
i := interpreters.NewMockRInterpreter()
rExecNotFoundError := types.NewAgentError(types.ErrorRExecNotFound, errors.New("info"), nil)
i.On("Init").Return(nil)
i.On("GetRExecutable").Return(util.AbsolutePath{}, nil)
i.On("GetRVersion").Return("", rExecNotFoundError)
// i.On("RequiresR", mock.Anything).Return(false, nil)
relPath := util.NewRelativePath(baseDir.Join("renv_2222.lock").String(), baseDir.Fs())
i.On("GetLockFilePath").Return(relPath, false, nil)
return i
}
log := logging.New()
i, err := NewRInspector(s.cwd, util.Path{}, log)
s.NoError(err)

inspect, err := i.InspectR()
s.NoError(err)
s.Equal("renv", inspect.PackageManager)
s.Equal("", inspect.Version)
s.Equal(s.cwd.Join("renv_2222.lock").String(), inspect.PackageFile)
}

func (s *RSuite) TestRequiresRWithEmptyCfgAndLockfileExists() {
interpreters.NewRInterpreter = func(baseDir util.AbsolutePath, rExec util.Path, log logging.Logger) interpreters.RInterpreter {
i := interpreters.NewMockRInterpreter()
relPath := util.NewRelativePath(s.cwd.Join("renv.lock").String(), s.cwd.Fs())
i.On("GetLockFilePath").Return(relPath, true, nil)
return i
}

log := logging.New()
i, err := NewRInspector(s.cwd, util.Path{}, log)
s.NoError(err)

cfg := &config.Config{}

require, err := i.RequiresR(cfg)
s.NoError(err)
s.Equal(true, require)
}

func (s *RSuite) TestRequiresRWithEmptyCfgAndLockfileDoesNotExists() {
interpreters.NewRInterpreter = func(baseDir util.AbsolutePath, rExec util.Path, log logging.Logger) interpreters.RInterpreter {
i := interpreters.NewMockRInterpreter()
relPath := util.NewRelativePath(s.cwd.Join("renv.lock").String(), s.cwd.Fs())
i.On("GetLockFilePath").Return(relPath, false, nil)
return i
}

log := logging.New()
i, err := NewRInspector(s.cwd, util.Path{}, log)
s.NoError(err)

cfg := &config.Config{}

require, err := i.RequiresR(cfg)
s.NoError(err)
s.Equal(false, require)
}

func (s *RSuite) TestRequiresRWithRCfg() {
log := logging.New()
i, err := NewRInspector(s.cwd, util.Path{}, log)
s.NoError(err)

cfg := &config.Config{
R: &config.R{},
}
require, err := i.RequiresR(cfg)
s.NoError(err)
s.Equal(true, require)
}

func (s *RSuite) TestRequiresRNoRButWithTypeAsPython() {
log := logging.New()
i, err := NewRInspector(s.cwd, util.Path{}, log)
s.NoError(err)

cfg := &config.Config{
Type: config.ContentTypePythonFastAPI,
}
require, err := i.RequiresR(cfg)
s.NoError(err)
s.Equal(false, require)
}

func (s *RSuite) TestRequiresRNoRButWithTypeEqualContentTypeHTML() {
log := logging.New()
i, err := NewRInspector(s.cwd, util.Path{}, log)
s.NoError(err)

cfg := &config.Config{
Type: config.ContentTypeHTML,
}
require, err := i.RequiresR(cfg)
s.NoError(err)
s.Equal(false, require)
}
12 changes: 8 additions & 4 deletions internal/interpreters/r.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,10 +364,14 @@ func (i *defaultRInterpreter) CreateLockfile(lockfilePath util.AbsolutePath) err
if err != nil {
return err
}

escaped := strings.ReplaceAll(lockfilePath.String(), `\`, `\\`)
code := fmt.Sprintf(`renv::snapshot(lockfile="%s")`, escaped)
args := []string{"-s", "-e", code}
var cmd string
if lockfilePath.String() == "" {
cmd = "renv::snapshot()"
} else {
escaped := strings.ReplaceAll(lockfilePath.String(), `\`, `\\`)
cmd = fmt.Sprintf(`renv::snapshot(lockfile="%s")`, escaped)
}
args := []string{"-s", "-e", cmd}
stdout, stderr, err := i.executor.RunCommand(rExecutable.String(), args, i.base, i.log)
i.log.Debug("renv::snapshot()", "out", string(stdout), "err", string(stderr))
return err
Expand Down
Loading

0 comments on commit d77b562

Please sign in to comment.