2017-03-16 02:15:27 +02:00
package task_test
import (
2017-05-17 19:37:11 +02:00
"bytes"
2019-02-09 14:16:13 +02:00
"context"
2017-07-12 11:30:28 +02:00
"fmt"
2021-12-04 17:37:52 +02:00
"io"
2024-10-06 02:40:22 +02:00
"io/fs"
2024-10-18 18:13:25 +02:00
rand "math/rand/v2"
2024-10-06 02:40:22 +02:00
"net/http"
"net/http/httptest"
2017-03-16 02:15:27 +02:00
"os"
"path/filepath"
2024-01-12 01:33:36 +02:00
"regexp"
2019-09-02 03:26:53 +02:00
"runtime"
2017-03-25 15:51:30 +02:00
"strings"
2024-03-10 19:21:50 +02:00
"sync"
2017-03-16 02:15:27 +02:00
"testing"
2024-10-06 02:40:22 +02:00
"time"
2017-06-16 16:24:01 +02:00
2023-02-08 12:21:43 +02:00
"github.com/Masterminds/semver/v3"
2021-01-07 16:48:33 +02:00
"github.com/stretchr/testify/assert"
2023-04-06 12:18:41 +02:00
"github.com/stretchr/testify/require"
2021-01-07 16:48:33 +02:00
2020-08-16 20:48:19 +02:00
"github.com/go-task/task/v3"
2023-04-15 22:22:25 +02:00
"github.com/go-task/task/v3/errors"
2024-07-17 00:44:34 +02:00
"github.com/go-task/task/v3/internal/experiments"
2022-08-06 23:19:07 +02:00
"github.com/go-task/task/v3/internal/filepathext"
2024-10-06 02:40:22 +02:00
"github.com/go-task/task/v3/internal/logger"
2023-12-29 22:32:03 +02:00
"github.com/go-task/task/v3/taskfile/ast"
2017-03-16 02:15:27 +02:00
)
2021-05-31 03:48:48 +02:00
func init ( ) {
_ = os . Setenv ( "NO_COLOR" , "1" )
}
2024-03-10 19:21:50 +02:00
// SyncBuffer is a threadsafe buffer for testing.
// Some times replace stdout/stderr with a buffer to capture output.
// stdout and stderr are threadsafe, but a regular bytes.Buffer is not.
// Using this instead helps prevents race conditions with output.
type SyncBuffer struct {
buf bytes . Buffer
mu sync . Mutex
}
func ( sb * SyncBuffer ) Write ( p [ ] byte ) ( n int , err error ) {
sb . mu . Lock ( )
defer sb . mu . Unlock ( )
return sb . buf . Write ( p )
}
2017-07-20 09:05:37 +02:00
// fileContentTest provides a basic reusable test-case for running a Taskfile
// and inspect generated files.
type fileContentTest struct {
2021-12-04 17:37:52 +02:00
Dir string
Entrypoint string
Target string
TrimSpace bool
Files map [ string ] string
2017-07-20 09:05:37 +02:00
}
func ( fct fileContentTest ) name ( file string ) string {
return fmt . Sprintf ( "target=%q,file=%q" , fct . Target , file )
}
func ( fct fileContentTest ) Run ( t * testing . T ) {
for f := range fct . Files {
2022-08-06 23:19:07 +02:00
_ = os . Remove ( filepathext . SmartJoin ( fct . Dir , f ) )
2017-07-20 09:05:37 +02:00
}
e := & task . Executor {
2024-06-28 18:01:11 +02:00
Dir : fct . Dir ,
TempDir : task . TempDir {
Remote : filepathext . SmartJoin ( fct . Dir , ".task" ) ,
Fingerprint : filepathext . SmartJoin ( fct . Dir , ".task" ) ,
} ,
2021-12-04 17:37:52 +02:00
Entrypoint : fct . Entrypoint ,
Stdout : io . Discard ,
Stderr : io . Discard ,
2017-07-20 09:05:37 +02:00
}
2024-07-17 00:44:34 +02:00
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) , "e.Setup()" )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : fct . Target } ) , "e.Run(target)" )
2017-07-20 09:05:37 +02:00
for name , expectContent := range fct . Files {
t . Run ( fct . name ( name ) , func ( t * testing . T ) {
2024-02-13 03:07:00 +02:00
path := filepathext . SmartJoin ( e . Dir , name )
2022-07-26 00:10:16 +02:00
b , err := os . ReadFile ( path )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err , "Error reading file" )
2017-07-20 09:05:37 +02:00
s := string ( b )
if fct . TrimSpace {
s = strings . TrimSpace ( s )
}
2022-07-26 00:10:16 +02:00
assert . Equal ( t , expectContent , s , "unexpected file content in %s" , path )
2017-07-20 09:05:37 +02:00
} )
}
}
2020-10-13 02:03:13 +02:00
func TestEmptyTask ( t * testing . T ) {
e := & task . Executor {
Dir : "testdata/empty_task" ,
2021-12-04 17:37:52 +02:00
Stdout : io . Discard ,
Stderr : io . Discard ,
2020-10-13 02:03:13 +02:00
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) , "e.Setup()" )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "default" } ) )
2020-10-13 02:03:13 +02:00
}
2024-05-12 21:25:54 +02:00
func TestEmptyTaskfile ( t * testing . T ) {
e := & task . Executor {
Dir : "testdata/empty_taskfile" ,
Stdout : io . Discard ,
Stderr : io . Discard ,
}
require . Error ( t , e . Setup ( ) , "e.Setup()" )
}
2017-08-16 13:04:58 +02:00
func TestEnv ( t * testing . T ) {
2024-07-17 00:44:34 +02:00
t . Setenv ( "QUX" , "from_os" )
2017-08-16 13:04:58 +02:00
tt := fileContentTest {
Dir : "testdata/env" ,
Target : "default" ,
TrimSpace : false ,
Files : map [ string ] string {
2024-11-07 18:25:59 +02:00
"local.txt" : "GOOS='linux' GOARCH='amd64' CGO_ENABLED='0'\n" ,
"global.txt" : "FOO='foo' BAR='overridden' BAZ='baz'\n" ,
"multiple_type.txt" : "FOO='1' BAR='true' BAZ='1.1'\n" ,
"not-overridden.txt" : "QUX='from_os'\n" ,
2017-08-16 13:04:58 +02:00
} ,
}
tt . Run ( t )
2024-07-17 00:44:34 +02:00
t . Setenv ( "TASK_X_ENV_PRECEDENCE" , "1" )
experiments . EnvPrecedence = experiments . New ( "ENV_PRECEDENCE" )
ttt := fileContentTest {
Dir : "testdata/env" ,
2024-11-07 18:25:59 +02:00
Target : "overridden" ,
2024-07-17 00:44:34 +02:00
TrimSpace : false ,
Files : map [ string ] string {
2024-11-07 18:25:59 +02:00
"overridden.txt" : "QUX='from_taskfile'\n" ,
2024-07-17 00:44:34 +02:00
} ,
}
ttt . Run ( t )
2017-08-16 13:04:58 +02:00
}
2023-12-29 22:26:02 +02:00
func TestVars ( t * testing . T ) {
2017-09-03 12:48:06 +02:00
tt := fileContentTest {
2023-12-29 22:26:02 +02:00
Dir : "testdata/vars" ,
2020-05-16 20:45:41 +02:00
Target : "default" ,
Files : map [ string ] string {
"missing-var.txt" : "\n" ,
"var-order.txt" : "ABCDEF\n" ,
"dependent-sh.txt" : "123456\n" ,
"with-call.txt" : "Hi, ABC123!\n" ,
2021-01-12 16:09:46 +02:00
"from-dot-env.txt" : "From .env file\n" ,
2020-05-16 20:45:41 +02:00
} ,
}
tt . Run ( t )
}
2024-10-18 18:16:57 +02:00
func TestRequires ( t * testing . T ) {
const dir = "testdata/requires"
var buff bytes . Buffer
e := & task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
require . NoError ( t , e . Setup ( ) )
require . ErrorContains ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "missing-var" } ) , "task: Task \"missing-var\" cancelled because it is missing required variables: foo" )
buff . Reset ( )
require . NoError ( t , e . Setup ( ) )
vars := & ast . Vars { }
vars . Set ( "foo" , ast . Var { Value : "bar" } )
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call {
Task : "missing-var" ,
Vars : vars ,
} ) )
buff . Reset ( )
require . NoError ( t , e . Setup ( ) )
require . ErrorContains ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "validation-var" , Vars : vars } ) , "task: Task \"validation-var\" cancelled because it is missing required variables:\n - foo has an invalid value : 'bar' (allowed values : [one two])" )
buff . Reset ( )
require . NoError ( t , e . Setup ( ) )
vars . Set ( "foo" , ast . Var { Value : "one" } )
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "validation-var" , Vars : vars } ) )
buff . Reset ( )
}
2022-09-03 23:14:54 +02:00
func TestSpecialVars ( t * testing . T ) {
const dir = "testdata/special_vars"
2024-03-04 13:34:44 +02:00
const subdir = "testdata/special_vars/subdir"
2022-09-03 23:14:54 +02:00
toAbs := func ( rel string ) string {
abs , err := filepath . Abs ( rel )
2023-09-06 01:26:25 +02:00
assert . NoError ( t , err )
2022-09-03 23:14:54 +02:00
return abs
}
2023-09-06 01:26:25 +02:00
tests := [ ] struct {
target string
expected string
} {
// Root
{ target : "print-task" , expected : "print-task" } ,
{ target : "print-root-dir" , expected : toAbs ( dir ) } ,
2024-03-04 13:34:44 +02:00
{ target : "print-taskfile" , expected : toAbs ( dir ) + "/Taskfile.yml" } ,
2023-09-06 01:26:25 +02:00
{ target : "print-taskfile-dir" , expected : toAbs ( dir ) } ,
{ target : "print-task-version" , expected : "unknown" } ,
// Included
{ target : "included:print-task" , expected : "included:print-task" } ,
{ target : "included:print-root-dir" , expected : toAbs ( dir ) } ,
2024-03-04 13:34:44 +02:00
{ target : "included:print-taskfile" , expected : toAbs ( dir ) + "/included/Taskfile.yml" } ,
2023-09-06 01:26:25 +02:00
{ target : "included:print-taskfile-dir" , expected : toAbs ( dir ) + "/included" } ,
{ target : "included:print-task-version" , expected : "unknown" } ,
}
2022-09-03 23:14:54 +02:00
2024-03-04 13:34:44 +02:00
for _ , dir := range [ ] string { dir , subdir } {
for _ , test := range tests {
t . Run ( test . target , func ( t * testing . T ) {
var buff bytes . Buffer
e := & task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
require . NoError ( t , e . Setup ( ) )
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : test . target } ) )
assert . Equal ( t , test . expected + "\n" , buff . String ( ) )
} )
}
2023-09-06 01:26:25 +02:00
}
2022-09-03 23:14:54 +02:00
}
2020-06-12 20:09:53 +02:00
func TestConcurrency ( t * testing . T ) {
const (
dir = "testdata/concurrency"
target = "default"
)
e := & task . Executor {
Dir : dir ,
2021-12-04 17:37:52 +02:00
Stdout : io . Discard ,
Stderr : io . Discard ,
2020-06-12 20:09:53 +02:00
Concurrency : 1 ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) , "e.Setup()" )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : target } ) , "e.Run(target)" )
2020-06-12 20:09:53 +02:00
}
2017-07-20 09:05:37 +02:00
func TestParams ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/params" ,
Target : "default" ,
TrimSpace : false ,
Files : map [ string ] string {
"hello.txt" : "Hello\n" ,
"world.txt" : "World\n" ,
"exclamation.txt" : "!\n" ,
"dep1.txt" : "Dependence1\n" ,
"dep2.txt" : "Dependence2\n" ,
"spanish.txt" : "¡Holla mundo!\n" ,
"spanish-dep.txt" : "¡Holla dependencia!\n" ,
"portuguese.txt" : "Olá, mundo!\n" ,
"portuguese2.txt" : "Olá, mundo!\n" ,
"german.txt" : "Welt!\n" ,
} ,
}
tt . Run ( t )
}
2017-03-16 02:15:27 +02:00
func TestDeps ( t * testing . T ) {
const dir = "testdata/deps"
files := [ ] string {
"d1.txt" ,
"d2.txt" ,
"d3.txt" ,
"d11.txt" ,
"d12.txt" ,
"d13.txt" ,
"d21.txt" ,
"d22.txt" ,
"d23.txt" ,
"d31.txt" ,
"d32.txt" ,
"d33.txt" ,
}
for _ , f := range files {
2022-08-06 23:19:07 +02:00
_ = os . Remove ( filepathext . SmartJoin ( dir , f ) )
2017-03-16 02:15:27 +02:00
}
2017-06-16 16:24:01 +02:00
e := & task . Executor {
2017-07-01 20:32:13 +02:00
Dir : dir ,
2021-12-04 17:37:52 +02:00
Stdout : io . Discard ,
Stderr : io . Discard ,
2017-03-16 02:15:27 +02:00
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "default" } ) )
2017-03-16 02:15:27 +02:00
for _ , f := range files {
2022-08-06 23:19:07 +02:00
f = filepathext . SmartJoin ( dir , f )
2017-03-16 02:15:27 +02:00
if _ , err := os . Stat ( f ) ; err != nil {
2019-06-04 08:08:25 +02:00
t . Errorf ( "File %s should exist" , f )
2017-03-16 02:15:27 +02:00
}
}
}
2017-03-25 15:51:30 +02:00
2017-05-17 19:37:11 +02:00
func TestStatus ( t * testing . T ) {
const dir = "testdata/status"
2021-04-20 15:04:21 +02:00
files := [ ] string {
"foo.txt" ,
"bar.txt" ,
2023-04-06 03:18:58 +02:00
"baz.txt" ,
2021-04-20 15:04:21 +02:00
}
2017-05-17 19:37:11 +02:00
2021-04-20 15:04:21 +02:00
for _ , f := range files {
2022-08-06 23:19:07 +02:00
path := filepathext . SmartJoin ( dir , f )
2021-04-20 15:04:21 +02:00
_ = os . Remove ( path )
if _ , err := os . Stat ( path ) ; err == nil {
t . Errorf ( "File should not exist: %v" , err )
}
2017-05-17 19:37:11 +02:00
}
2017-07-01 20:32:13 +02:00
2018-02-17 20:12:41 +02:00
var buff bytes . Buffer
2017-07-01 20:32:13 +02:00
e := & task . Executor {
2024-06-28 18:01:11 +02:00
Dir : dir ,
TempDir : task . TempDir {
Remote : filepathext . SmartJoin ( dir , ".task" ) ,
Fingerprint : filepathext . SmartJoin ( dir , ".task" ) ,
} ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
2017-05-17 19:37:11 +02:00
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2023-04-06 03:18:58 +02:00
// gen-foo creates foo.txt, and will always fail it's status check.
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-foo" } ) )
2023-04-06 03:18:58 +02:00
// gen-foo creates bar.txt, and will pass its status-check the 3. time it
// is run. It creates bar.txt, but also lists it as its source. So, the checksum
// for the file won't match before after the second run as we the file
// only exists after the first run.
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-bar" } ) )
2023-04-06 03:18:58 +02:00
// gen-silent-baz is marked as being silent, and should only produce output
// if e.Verbose is set to true.
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-silent-baz" } ) )
2017-07-01 20:32:13 +02:00
2021-04-20 15:04:21 +02:00
for _ , f := range files {
2022-08-06 23:19:07 +02:00
if _ , err := os . Stat ( filepathext . SmartJoin ( dir , f ) ) ; err != nil {
2021-04-20 15:04:21 +02:00
t . Errorf ( "File should exist: %v" , err )
}
2017-05-17 19:37:11 +02:00
}
2023-04-06 03:18:58 +02:00
// Run gen-bar a second time to produce a checksum file that matches bar.txt
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-bar" } ) )
2023-04-06 03:18:58 +02:00
// Run gen-bar a third time, to make sure we've triggered the status check.
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-bar" } ) )
2023-04-06 03:18:58 +02:00
// We're silent, so no output should have been produced.
assert . Empty ( t , buff . String ( ) )
// Now, let's remove source file, and run the task again to to prepare
// for the next test.
err := os . Remove ( filepathext . SmartJoin ( dir , "bar.txt" ) )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-bar" } ) )
2023-04-06 03:18:58 +02:00
buff . Reset ( )
// Global silence switched of, so we should see output unless the task itself
// is silent.
2018-02-17 20:12:41 +02:00
e . Silent = false
2017-07-01 20:32:13 +02:00
2021-04-20 15:04:21 +02:00
// all: not up-to-date
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-foo" } ) )
2021-04-20 15:04:21 +02:00
assert . Equal ( t , "task: [gen-foo] touch foo.txt" , strings . TrimSpace ( buff . String ( ) ) )
buff . Reset ( )
// status: not up-to-date
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-foo" } ) )
2021-04-20 15:04:21 +02:00
assert . Equal ( t , "task: [gen-foo] touch foo.txt" , strings . TrimSpace ( buff . String ( ) ) )
buff . Reset ( )
2017-07-01 20:32:13 +02:00
2021-04-20 15:04:21 +02:00
// sources: not up-to-date
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-bar" } ) )
2021-04-20 15:04:21 +02:00
assert . Equal ( t , "task: [gen-bar] touch bar.txt" , strings . TrimSpace ( buff . String ( ) ) )
buff . Reset ( )
// all: up-to-date
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-bar" } ) )
2021-04-20 15:04:21 +02:00
assert . Equal ( t , ` task: Task "gen-bar" is up to date ` , strings . TrimSpace ( buff . String ( ) ) )
buff . Reset ( )
2023-04-06 03:18:58 +02:00
// sources: not up-to-date, no output produced.
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-silent-baz" } ) )
2023-04-06 03:18:58 +02:00
assert . Empty ( t , buff . String ( ) )
// up-to-date, no output produced
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-silent-baz" } ) )
2023-04-06 03:18:58 +02:00
assert . Empty ( t , buff . String ( ) )
e . Verbose = true
// up-to-date, output produced due to Verbose mode.
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "gen-silent-baz" } ) )
2023-04-06 03:18:58 +02:00
assert . Equal ( t , ` task: Task "gen-silent-baz" is up to date ` , strings . TrimSpace ( buff . String ( ) ) )
buff . Reset ( )
2017-05-17 19:37:11 +02:00
}
2017-05-17 20:38:46 +02:00
2019-05-17 22:13:47 +02:00
func TestPrecondition ( t * testing . T ) {
const dir = "testdata/precondition"
var buff bytes . Buffer
e := & task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
// A precondition that has been met
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "foo" } ) )
2019-05-17 22:13:47 +02:00
if buff . String ( ) != "" {
t . Errorf ( "Got Output when none was expected: %s" , buff . String ( ) )
}
// A precondition that was not met
2024-01-26 16:34:18 +02:00
require . Error ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "impossible" } ) )
2019-05-17 22:13:47 +02:00
2019-06-11 21:20:56 +02:00
if buff . String ( ) != "task: 1 != 0 obviously!\n" {
2019-05-17 22:13:47 +02:00
t . Errorf ( "Wrong output message: %s" , buff . String ( ) )
}
buff . Reset ( )
// Calling a task with a precondition in a dependency fails the task
2024-01-26 16:34:18 +02:00
require . Error ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "depends_on_impossible" } ) )
2019-05-28 22:02:59 +02:00
2019-06-11 21:20:56 +02:00
if buff . String ( ) != "task: 1 != 0 obviously!\n" {
2019-05-17 22:13:47 +02:00
t . Errorf ( "Wrong output message: %s" , buff . String ( ) )
}
buff . Reset ( )
// Calling a task with a precondition in a cmd fails the task
2024-01-26 16:34:18 +02:00
require . Error ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "executes_failing_task_as_cmd" } ) )
2019-06-11 21:20:56 +02:00
if buff . String ( ) != "task: 1 != 0 obviously!\n" {
2019-05-17 22:13:47 +02:00
t . Errorf ( "Wrong output message: %s" , buff . String ( ) )
}
buff . Reset ( )
}
2017-07-12 11:30:28 +02:00
func TestGenerates ( t * testing . T ) {
2021-01-07 16:17:38 +02:00
const dir = "testdata/generates"
2019-02-22 01:52:27 +02:00
const (
srcTask = "sub/src.txt"
relTask = "rel.txt"
2021-01-09 17:09:23 +02:00
absTask = "abs.txt"
2019-02-22 01:52:27 +02:00
fileWithSpaces = "my text file.txt"
)
2017-07-12 11:30:28 +02:00
2023-03-31 21:13:29 +02:00
srcFile := filepathext . SmartJoin ( dir , srcTask )
2017-07-12 11:30:28 +02:00
2019-02-22 01:52:27 +02:00
for _ , task := range [ ] string { srcTask , relTask , absTask , fileWithSpaces } {
2022-08-06 23:19:07 +02:00
path := filepathext . SmartJoin ( dir , task )
2017-07-12 11:30:28 +02:00
_ = os . Remove ( path )
if _ , err := os . Stat ( path ) ; err == nil {
2019-06-04 08:08:25 +02:00
t . Errorf ( "File should not exist: %v" , err )
2017-07-12 11:30:28 +02:00
}
}
buff := bytes . NewBuffer ( nil )
e := & task . Executor {
Dir : dir ,
Stdout : buff ,
Stderr : buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2017-07-12 11:30:28 +02:00
2019-02-22 01:52:27 +02:00
for _ , theTask := range [ ] string { relTask , absTask , fileWithSpaces } {
2023-03-31 21:13:29 +02:00
destFile := filepathext . SmartJoin ( dir , theTask )
upToDate := fmt . Sprintf ( "task: Task \"%s\" is up to date\n" , srcTask ) +
2017-09-07 18:57:06 +02:00
fmt . Sprintf ( "task: Task \"%s\" is up to date\n" , theTask )
2017-07-12 11:30:28 +02:00
// Run task for the first time.
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : theTask } ) )
2017-07-12 11:30:28 +02:00
if _ , err := os . Stat ( srcFile ) ; err != nil {
2019-06-04 08:08:25 +02:00
t . Errorf ( "File should exist: %v" , err )
2017-07-12 11:30:28 +02:00
}
if _ , err := os . Stat ( destFile ) ; err != nil {
2019-06-04 08:08:25 +02:00
t . Errorf ( "File should exist: %v" , err )
2017-07-12 11:30:28 +02:00
}
// Ensure task was not incorrectly found to be up-to-date on first run.
if buff . String ( ) == upToDate {
t . Errorf ( "Wrong output message: %s" , buff . String ( ) )
}
buff . Reset ( )
// Re-run task to ensure it's now found to be up-to-date.
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : theTask } ) )
2017-07-12 11:30:28 +02:00
if buff . String ( ) != upToDate {
t . Errorf ( "Wrong output message: %s" , buff . String ( ) )
}
buff . Reset ( )
}
}
2017-09-16 16:44:13 +02:00
func TestStatusChecksum ( t * testing . T ) {
const dir = "testdata/checksum"
2023-03-06 08:16:41 +02:00
tests := [ ] struct {
files [ ] string
task string
} {
{ [ ] string { "generated.txt" , ".task/checksum/build" } , "build" } ,
{ [ ] string { "generated.txt" , ".task/checksum/build-with-status" } , "build-with-status" } ,
2017-09-16 16:44:13 +02:00
}
2023-03-06 08:16:41 +02:00
for _ , test := range tests {
t . Run ( test . task , func ( t * testing . T ) {
for _ , f := range test . files {
_ = os . Remove ( filepathext . SmartJoin ( dir , f ) )
2017-09-16 16:44:13 +02:00
2023-03-06 08:16:41 +02:00
_ , err := os . Stat ( filepathext . SmartJoin ( dir , f ) )
2023-04-06 12:18:41 +02:00
require . Error ( t , err )
2023-03-06 08:16:41 +02:00
}
2017-09-16 16:44:13 +02:00
2023-03-06 08:16:41 +02:00
var buff bytes . Buffer
2024-06-28 18:01:11 +02:00
tempdir := task . TempDir {
Remote : filepathext . SmartJoin ( dir , ".task" ) ,
Fingerprint : filepathext . SmartJoin ( dir , ".task" ) ,
}
2023-03-06 08:16:41 +02:00
e := task . Executor {
Dir : dir ,
2023-06-04 00:20:08 +02:00
TempDir : tempdir ,
2023-03-06 08:16:41 +02:00
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2017-09-16 16:44:13 +02:00
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : test . task } ) )
2023-03-06 08:16:41 +02:00
for _ , f := range test . files {
_ , err := os . Stat ( filepathext . SmartJoin ( dir , f ) )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2023-03-06 08:16:41 +02:00
}
2017-09-16 16:44:13 +02:00
2023-06-04 00:20:08 +02:00
// Capture the modification time, so we can ensure the checksum file
// is not regenerated when the hash hasn't changed.
2024-06-28 18:01:11 +02:00
s , err := os . Stat ( filepathext . SmartJoin ( tempdir . Fingerprint , "checksum/" + test . task ) )
2023-06-04 00:20:08 +02:00
require . NoError ( t , err )
time := s . ModTime ( )
2023-03-06 08:16:41 +02:00
buff . Reset ( )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : test . task } ) )
2023-03-06 08:16:41 +02:00
assert . Equal ( t , ` task: Task " ` + test . task + ` " is up to date ` + "\n" , buff . String ( ) )
2023-06-04 00:20:08 +02:00
2024-06-28 18:01:11 +02:00
s , err = os . Stat ( filepathext . SmartJoin ( tempdir . Fingerprint , "checksum/" + test . task ) )
2023-06-04 00:20:08 +02:00
require . NoError ( t , err )
assert . Equal ( t , time , s . ModTime ( ) )
2023-03-06 08:16:41 +02:00
} )
}
2019-09-14 22:54:41 +02:00
}
2019-06-11 20:49:37 +02:00
2022-10-02 00:39:44 +02:00
func TestAlias ( t * testing . T ) {
const dir = "testdata/alias"
data , err := os . ReadFile ( filepathext . SmartJoin ( dir , "alias.txt" ) )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2022-10-02 00:39:44 +02:00
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "f" } ) )
2022-10-02 00:39:44 +02:00
assert . Equal ( t , string ( data ) , buff . String ( ) )
}
func TestDuplicateAlias ( t * testing . T ) {
const dir = "testdata/alias"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . Error ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "x" } ) )
2022-11-02 16:38:26 +02:00
assert . Equal ( t , "" , buff . String ( ) )
2022-10-02 00:39:44 +02:00
}
func TestAliasSummary ( t * testing . T ) {
const dir = "testdata/alias"
data , err := os . ReadFile ( filepathext . SmartJoin ( dir , "alias-summary.txt" ) )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2022-10-02 00:39:44 +02:00
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Summary : true ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "f" } ) )
2022-10-02 00:39:44 +02:00
assert . Equal ( t , string ( data ) , buff . String ( ) )
}
2020-06-14 11:02:25 +02:00
func TestLabelUpToDate ( t * testing . T ) {
const dir = "testdata/label_uptodate"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "foo" } ) )
2020-06-14 11:02:25 +02:00
assert . Contains ( t , buff . String ( ) , "foobar" )
}
func TestLabelSummary ( t * testing . T ) {
const dir = "testdata/label_summary"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Summary : true ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "foo" } ) )
2020-06-14 11:02:25 +02:00
assert . Contains ( t , buff . String ( ) , "foobar" )
}
func TestLabelInStatus ( t * testing . T ) {
const dir = "testdata/label_status"
e := task . Executor {
Dir : dir ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
err := e . Status ( context . Background ( ) , & ast . Call { Task : "foo" } )
2023-04-06 12:18:41 +02:00
assert . ErrorContains ( t , err , "foobar" )
2020-06-14 11:02:25 +02:00
}
func TestLabelWithVariableExpansion ( t * testing . T ) {
const dir = "testdata/label_var"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "foo" } ) )
2020-06-14 11:02:25 +02:00
assert . Contains ( t , buff . String ( ) , "foobaz" )
}
func TestLabelInSummary ( t * testing . T ) {
const dir = "testdata/label_summary"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "foo" } ) )
2020-06-14 11:02:25 +02:00
assert . Contains ( t , buff . String ( ) , "foobar" )
}
2023-06-04 03:33:00 +02:00
func TestPromptInSummary ( t * testing . T ) {
const dir = "testdata/prompt"
tests := [ ] struct {
name string
input string
wantError bool
} {
{ "test short approval" , "y\n" , false } ,
{ "test long approval" , "yes\n" , false } ,
{ "test uppercase approval" , "Y\n" , false } ,
{ "test stops task" , "n\n" , true } ,
{ "test junk value stops task" , "foobar\n" , true } ,
{ "test Enter stops task" , "\n" , true } ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var inBuff bytes . Buffer
var outBuff bytes . Buffer
2023-09-12 23:42:54 +02:00
var errBuff bytes . Buffer
2023-06-04 03:33:00 +02:00
inBuff . Write ( [ ] byte ( test . input ) )
e := task . Executor {
2023-10-07 23:55:43 +02:00
Dir : dir ,
Stdin : & inBuff ,
Stdout : & outBuff ,
Stderr : & errBuff ,
AssumeTerm : true ,
2023-06-04 03:33:00 +02:00
}
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : "foo" } )
2023-06-04 03:33:00 +02:00
if test . wantError {
require . Error ( t , err )
2023-06-04 03:33:22 +02:00
} else {
require . NoError ( t , err )
2023-06-04 03:33:00 +02:00
}
} )
}
}
func TestPromptWithIndirectTask ( t * testing . T ) {
const dir = "testdata/prompt"
var inBuff bytes . Buffer
var outBuff bytes . Buffer
2023-09-12 23:42:54 +02:00
var errBuff bytes . Buffer
2023-06-04 03:33:00 +02:00
inBuff . Write ( [ ] byte ( "y\n" ) )
e := task . Executor {
2023-10-07 23:55:43 +02:00
Dir : dir ,
Stdin : & inBuff ,
Stdout : & outBuff ,
Stderr : & errBuff ,
AssumeTerm : true ,
2023-06-04 03:33:00 +02:00
}
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : "bar" } )
2023-06-04 03:33:00 +02:00
assert . Contains ( t , outBuff . String ( ) , "show-prompt" )
require . NoError ( t , err )
}
func TestPromptAssumeYes ( t * testing . T ) {
const dir = "testdata/prompt"
tests := [ ] struct {
name string
assumeYes bool
} {
{ "--yes flag should skip prompt" , true } ,
{ "task should raise errors.TaskCancelledError" , false } ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var inBuff bytes . Buffer
var outBuff bytes . Buffer
2023-09-12 23:42:54 +02:00
var errBuff bytes . Buffer
2023-06-04 03:33:00 +02:00
// always cancel the prompt so we can require.Error
inBuff . Write ( [ ] byte ( "\n" ) )
e := task . Executor {
Dir : dir ,
Stdin : & inBuff ,
Stdout : & outBuff ,
2023-09-12 23:42:54 +02:00
Stderr : & errBuff ,
2023-06-04 03:33:00 +02:00
AssumeYes : test . assumeYes ,
}
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : "foo" } )
2023-06-04 03:33:00 +02:00
if ! test . assumeYes {
require . Error ( t , err )
return
}
} )
}
}
2022-09-30 17:17:04 +02:00
func TestNoLabelInList ( t * testing . T ) {
2020-06-14 11:02:25 +02:00
const dir = "testdata/label_list"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2022-12-17 15:31:00 +02:00
if _ , err := e . ListTasks ( task . ListOptions { ListOnlyTasksWithDescriptions : true } ) ; err != nil {
t . Error ( err )
}
2022-09-30 17:17:04 +02:00
assert . Contains ( t , buff . String ( ) , "foo" )
2020-06-14 11:02:25 +02:00
}
2020-11-13 23:24:34 +02:00
// task -al case 1: listAll list all tasks
func TestListAllShowsNoDesc ( t * testing . T ) {
const dir = "testdata/list_mixed_desc"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2020-11-13 23:24:34 +02:00
var title string
2022-12-17 15:31:00 +02:00
if _ , err := e . ListTasks ( task . ListOptions { ListAllTasks : true } ) ; err != nil {
t . Error ( err )
}
2020-11-13 23:24:34 +02:00
for _ , title = range [ ] string {
"foo" ,
"voo" ,
"doo" ,
} {
assert . Contains ( t , buff . String ( ) , title )
}
}
// task -al case 2: !listAll list some tasks (only those with desc)
func TestListCanListDescOnly ( t * testing . T ) {
const dir = "testdata/list_mixed_desc"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2022-12-17 15:31:00 +02:00
if _ , err := e . ListTasks ( task . ListOptions { ListOnlyTasksWithDescriptions : true } ) ; err != nil {
t . Error ( err )
}
2020-11-13 23:24:34 +02:00
var title string
assert . Contains ( t , buff . String ( ) , "foo" )
for _ , title = range [ ] string {
"voo" ,
"doo" ,
} {
assert . NotContains ( t , buff . String ( ) , title )
}
}
2023-10-07 23:57:14 +02:00
func TestListDescInterpolation ( t * testing . T ) {
const dir = "testdata/list_desc_interpolation"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
require . NoError ( t , e . Setup ( ) )
if _ , err := e . ListTasks ( task . ListOptions { ListOnlyTasksWithDescriptions : true } ) ; err != nil {
t . Error ( err )
}
2024-08-14 15:37:05 +02:00
assert . Contains ( t , buff . String ( ) , "foo-var" )
assert . Contains ( t , buff . String ( ) , "bar-var" )
2023-10-07 23:57:14 +02:00
}
2019-09-14 22:54:41 +02:00
func TestStatusVariables ( t * testing . T ) {
2019-09-14 23:04:41 +02:00
const dir = "testdata/status_vars"
2019-09-14 22:54:41 +02:00
2022-08-06 23:19:07 +02:00
_ = os . RemoveAll ( filepathext . SmartJoin ( dir , ".task" ) )
_ = os . Remove ( filepathext . SmartJoin ( dir , "generated.txt" ) )
2019-09-14 23:04:41 +02:00
var buff bytes . Buffer
e := task . Executor {
2024-06-28 18:01:11 +02:00
Dir : dir ,
TempDir : task . TempDir {
Remote : filepathext . SmartJoin ( dir , ".task" ) ,
Fingerprint : filepathext . SmartJoin ( dir , ".task" ) ,
} ,
2019-09-14 23:04:41 +02:00
Stdout : & buff ,
Stderr : & buff ,
Silent : false ,
Verbose : true ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "build" } ) )
2019-09-14 23:04:41 +02:00
2023-09-14 02:26:48 +02:00
assert . Contains ( t , buff . String ( ) , "3e464c4b03f4b65d740e1e130d4d108a" )
2019-09-14 23:04:41 +02:00
2022-08-06 23:19:07 +02:00
inf , err := os . Stat ( filepathext . SmartJoin ( dir , "source.txt" ) )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2019-09-14 23:04:41 +02:00
ts := fmt . Sprintf ( "%d" , inf . ModTime ( ) . Unix ( ) )
2022-05-15 02:00:15 +02:00
tf := inf . ModTime ( ) . String ( )
2019-09-14 23:04:41 +02:00
assert . Contains ( t , buff . String ( ) , ts )
assert . Contains ( t , buff . String ( ) , tf )
2017-09-16 16:44:13 +02:00
}
2017-05-17 20:38:46 +02:00
func TestInit ( t * testing . T ) {
const dir = "testdata/init"
2023-03-31 21:13:29 +02:00
file := filepathext . SmartJoin ( dir , "Taskfile.yml" )
2017-05-17 20:38:46 +02:00
_ = os . Remove ( file )
if _ , err := os . Stat ( file ) ; err == nil {
2023-03-17 02:53:01 +02:00
t . Errorf ( "Taskfile.yml should not exist" )
2017-05-17 20:38:46 +02:00
}
2021-12-04 17:37:52 +02:00
if err := task . InitTaskfile ( io . Discard , dir ) ; err != nil {
2017-05-17 20:38:46 +02:00
t . Error ( err )
}
2017-07-01 20:32:13 +02:00
2017-05-17 20:38:46 +02:00
if _ , err := os . Stat ( file ) ; err != nil {
2023-03-17 02:53:01 +02:00
t . Errorf ( "Taskfile.yml should exist" )
2017-05-17 20:38:46 +02:00
}
2021-12-04 17:37:52 +02:00
_ = os . Remove ( file )
2017-05-17 20:38:46 +02:00
}
2017-07-02 20:30:50 +02:00
2017-07-08 18:33:55 +02:00
func TestCyclicDep ( t * testing . T ) {
const dir = "testdata/cyclic"
e := task . Executor {
Dir : dir ,
2021-12-04 17:37:52 +02:00
Stdout : io . Discard ,
Stderr : io . Discard ,
2017-07-08 18:33:55 +02:00
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
assert . IsType ( t , & errors . TaskCalledTooManyTimesError { } , e . Run ( context . Background ( ) , & ast . Call { Task : "task-1" } ) )
2017-07-08 18:33:55 +02:00
}
2017-12-29 22:27:32 +02:00
func TestTaskVersion ( t * testing . T ) {
tests := [ ] struct {
Dir string
2023-02-08 12:21:43 +02:00
Version * semver . Version
2023-12-29 22:26:02 +02:00
wantErr bool
2017-12-29 22:27:32 +02:00
} {
2023-12-29 22:26:02 +02:00
{ "testdata/version/v1" , semver . MustParse ( "1" ) , true } ,
{ "testdata/version/v2" , semver . MustParse ( "2" ) , true } ,
{ "testdata/version/v3" , semver . MustParse ( "3" ) , false } ,
2017-12-29 22:27:32 +02:00
}
for _ , test := range tests {
t . Run ( test . Dir , func ( t * testing . T ) {
e := task . Executor {
Dir : test . Dir ,
2021-12-04 17:37:52 +02:00
Stdout : io . Discard ,
Stderr : io . Discard ,
2017-12-29 22:27:32 +02:00
}
2023-12-29 22:26:02 +02:00
err := e . Setup ( )
if test . wantErr {
require . Error ( t , err )
return
}
require . NoError ( t , err )
2017-12-29 22:27:32 +02:00
assert . Equal ( t , test . Version , e . Taskfile . Version )
2023-04-06 13:07:57 +02:00
assert . Equal ( t , 2 , e . Taskfile . Tasks . Len ( ) )
2017-12-29 22:27:32 +02:00
} )
}
}
2018-07-10 10:44:58 +02:00
func TestTaskIgnoreErrors ( t * testing . T ) {
const dir = "testdata/ignore_errors"
2018-08-05 17:56:55 +02:00
e := task . Executor {
Dir : dir ,
2021-12-04 17:37:52 +02:00
Stdout : io . Discard ,
Stderr : io . Discard ,
2018-08-05 17:56:55 +02:00
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2018-08-05 17:56:55 +02:00
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "task-should-pass" } ) )
require . Error ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "task-should-fail" } ) )
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "cmd-should-pass" } ) )
require . Error ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "cmd-should-fail" } ) )
2018-07-10 10:44:58 +02:00
}
2018-08-01 10:47:25 +02:00
2018-07-15 20:37:20 +02:00
func TestExpand ( t * testing . T ) {
const dir = "testdata/expand"
2019-09-09 03:07:48 +02:00
home , err := os . UserHomeDir ( )
2018-07-15 20:37:20 +02:00
if err != nil {
t . Errorf ( "Couldn't get $HOME: %v" , err )
}
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "pwd" } ) )
2018-07-15 20:37:20 +02:00
assert . Equal ( t , home , strings . TrimSpace ( buff . String ( ) ) )
}
2018-08-01 00:09:55 +02:00
2018-08-05 16:28:02 +02:00
func TestDry ( t * testing . T ) {
const dir = "testdata/dry"
2018-08-01 00:09:55 +02:00
2022-08-06 23:19:07 +02:00
file := filepathext . SmartJoin ( dir , "file.txt" )
2018-08-01 00:09:55 +02:00
_ = os . Remove ( file )
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
2018-08-05 16:28:02 +02:00
Dry : true ,
2018-08-01 00:09:55 +02:00
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "build" } ) )
2018-08-01 00:09:55 +02:00
2020-11-05 22:27:42 +02:00
assert . Equal ( t , "task: [build] touch file.txt" , strings . TrimSpace ( buff . String ( ) ) )
2018-08-01 00:09:55 +02:00
if _ , err := os . Stat ( file ) ; err == nil {
t . Errorf ( "File should not exist %s" , file )
}
}
2018-10-13 21:56:51 +02:00
2019-02-09 14:41:19 +02:00
// TestDryChecksum tests if the checksum file is not being written to disk
// if the dry mode is enabled.
func TestDryChecksum ( t * testing . T ) {
const dir = "testdata/dry_checksum"
2022-08-06 23:19:07 +02:00
checksumFile := filepathext . SmartJoin ( dir , ".task/checksum/default" )
2019-02-09 14:41:19 +02:00
_ = os . Remove ( checksumFile )
e := task . Executor {
2024-06-28 18:01:11 +02:00
Dir : dir ,
TempDir : task . TempDir {
Remote : filepathext . SmartJoin ( dir , ".task" ) ,
Fingerprint : filepathext . SmartJoin ( dir , ".task" ) ,
} ,
Stdout : io . Discard ,
Stderr : io . Discard ,
Dry : true ,
2019-02-09 14:41:19 +02:00
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "default" } ) )
2019-02-09 14:41:19 +02:00
_ , err := os . Stat ( checksumFile )
2023-04-06 12:18:41 +02:00
require . Error ( t , err , "checksum file should not exist" )
2019-02-09 14:41:19 +02:00
e . Dry = false
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "default" } ) )
2019-02-09 14:41:19 +02:00
_ , err = os . Stat ( checksumFile )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err , "checksum file should exist" )
2019-02-09 14:41:19 +02:00
}
2018-10-13 21:56:51 +02:00
func TestIncludes ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/includes" ,
Target : "default" ,
TrimSpace : true ,
Files : map [ string ] string {
2020-01-29 10:25:11 +02:00
"main.txt" : "main" ,
"included_directory.txt" : "included_directory" ,
"included_directory_without_dir.txt" : "included_directory_without_dir" ,
"included_taskfile_without_dir.txt" : "included_taskfile_without_dir" ,
2024-04-21 17:28:02 +02:00
"./module2/included_directory_with_dir.txt" : "included_directory_with_dir" ,
"./module2/included_taskfile_with_dir.txt" : "included_taskfile_with_dir" ,
2020-05-17 21:03:03 +02:00
"os_include.txt" : "os" ,
2018-10-13 21:56:51 +02:00
} ,
}
tt . Run ( t )
}
2018-12-02 18:17:32 +02:00
2022-01-15 05:38:37 +02:00
func TestIncludesMultiLevel ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/includes_multi_level" ,
Target : "default" ,
TrimSpace : true ,
2022-02-21 22:31:55 +02:00
Files : map [ string ] string {
"called_one.txt" : "one" ,
"called_two.txt" : "two" ,
"called_three.txt" : "three" ,
} ,
2022-01-15 05:38:37 +02:00
}
tt . Run ( t )
}
2024-10-18 18:13:25 +02:00
func TestIncludesRemote ( t * testing . T ) {
enableExperimentForTest ( t , & experiments . RemoteTaskfiles , "1" )
dir := "testdata/includes_remote"
srv := httptest . NewServer ( http . FileServer ( http . Dir ( dir ) ) )
defer srv . Close ( )
tcs := [ ] struct {
firstRemote string
secondRemote string
} {
{
firstRemote : srv . URL + "/first/Taskfile.yml" ,
secondRemote : srv . URL + "/first/second/Taskfile.yml" ,
} ,
{
firstRemote : srv . URL + "/first/Taskfile.yml" ,
secondRemote : "./second/Taskfile.yml" ,
} ,
}
tasks := [ ] string {
"first:write-file" ,
"first:second:write-file" ,
}
for i , tc := range tcs {
t . Run ( fmt . Sprint ( i ) , func ( t * testing . T ) {
t . Setenv ( "FIRST_REMOTE_URL" , tc . firstRemote )
t . Setenv ( "SECOND_REMOTE_URL" , tc . secondRemote )
var buff SyncBuffer
executors := [ ] struct {
name string
executor * task . Executor
} {
{
name : "online, always download" ,
executor : & task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Timeout : time . Minute ,
Insecure : true ,
Logger : & logger . Logger { Stdout : & buff , Stderr : & buff , Verbose : true } ,
// Without caching
AssumeYes : true ,
Download : true ,
} ,
} ,
{
name : "offline, use cache" ,
executor : & task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Timeout : time . Minute ,
Insecure : true ,
Logger : & logger . Logger { Stdout : & buff , Stderr : & buff , Verbose : true } ,
// With caching
AssumeYes : false ,
Download : false ,
Offline : true ,
} ,
} ,
}
for j , e := range executors {
t . Run ( fmt . Sprint ( j ) , func ( t * testing . T ) {
require . NoError ( t , e . executor . Setup ( ) )
for k , task := range tasks {
t . Run ( task , func ( t * testing . T ) {
expectedContent := fmt . Sprint ( rand . Int64 ( ) )
t . Setenv ( "CONTENT" , expectedContent )
outputFile := fmt . Sprintf ( "%d.%d.txt" , i , k )
t . Setenv ( "OUTPUT_FILE" , outputFile )
path := filepath . Join ( dir , outputFile )
require . NoError ( t , os . RemoveAll ( path ) )
require . NoError ( t , e . executor . Run ( context . Background ( ) , & ast . Call { Task : task } ) )
actualContent , err := os . ReadFile ( path )
require . NoError ( t , err )
assert . Equal ( t , expectedContent , strings . TrimSpace ( string ( actualContent ) ) )
} )
}
} )
}
t . Log ( "\noutput:\n" , buff . buf . String ( ) )
} )
}
}
2022-01-15 05:38:37 +02:00
func TestIncludeCycle ( t * testing . T ) {
const dir = "testdata/includes_cycle"
2022-07-26 00:10:16 +02:00
2022-01-15 05:38:37 +02:00
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
2022-09-03 23:14:54 +02:00
err := e . Setup ( )
2023-04-06 12:18:41 +02:00
require . Error ( t , err )
2022-09-03 23:14:54 +02:00
assert . Contains ( t , err . Error ( ) , "task: include cycle detected between" )
2022-01-15 05:38:37 +02:00
}
2022-10-07 12:18:53 +02:00
func TestIncludesIncorrect ( t * testing . T ) {
const dir = "testdata/includes_incorrect"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
2022-10-15 00:50:43 +02:00
err := e . Setup ( )
2023-04-06 12:18:41 +02:00
require . Error ( t , err )
2024-05-16 03:24:02 +02:00
assert . Contains ( t , err . Error ( ) , "Failed to parse testdata/includes_incorrect/incomplete.yml:" , err . Error ( ) )
2022-10-07 12:18:53 +02:00
}
2018-12-02 18:17:32 +02:00
func TestIncludesEmptyMain ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/includes_empty" ,
Target : "included:default" ,
TrimSpace : true ,
Files : map [ string ] string {
"file.txt" : "default" ,
} ,
}
tt . Run ( t )
}
2018-12-09 19:54:58 +02:00
2024-10-06 02:40:22 +02:00
func TestIncludesHttp ( t * testing . T ) {
enableExperimentForTest ( t , & experiments . RemoteTaskfiles , "1" )
dir , err := filepath . Abs ( "testdata/includes_http" )
require . NoError ( t , err )
srv := httptest . NewServer ( http . FileServer ( http . Dir ( dir ) ) )
defer srv . Close ( )
t . Cleanup ( func ( ) {
// This test fills the .task/remote directory with cache entries because the include URL
// is different on every test due to the dynamic nature of the TCP port in srv.URL
if err := os . RemoveAll ( filepath . Join ( dir , ".task" ) ) ; err != nil {
t . Logf ( "error cleaning up: %s" , err )
}
} )
taskfiles , err := fs . Glob ( os . DirFS ( dir ) , "root-taskfile-*.yml" )
require . NoError ( t , err )
remotes := [ ] struct {
name string
root string
} {
{
name : "local" ,
root : "." ,
} ,
{
name : "http-remote" ,
root : srv . URL ,
} ,
}
for _ , taskfile := range taskfiles {
t . Run ( taskfile , func ( t * testing . T ) {
for _ , remote := range remotes {
t . Run ( remote . name , func ( t * testing . T ) {
t . Setenv ( "INCLUDE_ROOT" , remote . root )
entrypoint := filepath . Join ( dir , taskfile )
var buff SyncBuffer
e := task . Executor {
Entrypoint : entrypoint ,
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Insecure : true ,
Download : true ,
AssumeYes : true ,
Logger : & logger . Logger { Stdout : & buff , Stderr : & buff , Verbose : true } ,
Timeout : time . Minute ,
}
require . NoError ( t , e . Setup ( ) )
defer func ( ) { t . Log ( "output:" , buff . buf . String ( ) ) } ( )
tcs := [ ] struct {
name , dir string
} {
{
name : "second-with-dir-1:third-with-dir-1:default" ,
dir : filepath . Join ( dir , "dir-1" ) ,
} ,
{
name : "second-with-dir-1:third-with-dir-2:default" ,
dir : filepath . Join ( dir , "dir-2" ) ,
} ,
}
for _ , tc := range tcs {
t . Run ( tc . name , func ( t * testing . T ) {
task , err := e . CompiledTask ( & ast . Call { Task : tc . name } )
require . NoError ( t , err )
assert . Equal ( t , tc . dir , task . Dir )
} )
}
} )
}
} )
}
}
2018-12-09 19:54:58 +02:00
func TestIncludesDependencies ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/includes_deps" ,
Target : "default" ,
TrimSpace : true ,
Files : map [ string ] string {
"default.txt" : "default" ,
"called_dep.txt" : "called_dep" ,
"called_task.txt" : "called_task" ,
} ,
}
tt . Run ( t )
}
2019-02-03 01:12:57 +02:00
func TestIncludesCallingRoot ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/includes_call_root_task" ,
Target : "included:call-root" ,
TrimSpace : true ,
Files : map [ string ] string {
"root_task.txt" : "root task" ,
} ,
}
tt . Run ( t )
}
2019-02-24 10:53:49 +02:00
2021-08-11 18:28:44 +02:00
func TestIncludesOptional ( t * testing . T ) {
2021-12-04 17:37:52 +02:00
tt := fileContentTest {
Dir : "testdata/includes_optional" ,
Target : "default" ,
TrimSpace : true ,
Files : map [ string ] string {
"called_dep.txt" : "called_dep" ,
2023-03-31 21:13:29 +02:00
} ,
}
2021-12-04 17:37:52 +02:00
tt . Run ( t )
2021-08-11 18:28:44 +02:00
}
func TestIncludesOptionalImplicitFalse ( t * testing . T ) {
2022-07-26 00:10:16 +02:00
const dir = "testdata/includes_optional_implicit_false"
wd , _ := os . Getwd ( )
message := "stat %s/%s/TaskfileOptional.yml: no such file or directory"
expected := fmt . Sprintf ( message , wd , dir )
2021-08-11 18:28:44 +02:00
e := task . Executor {
2022-07-26 00:10:16 +02:00
Dir : dir ,
2021-12-04 17:37:52 +02:00
Stdout : io . Discard ,
Stderr : io . Discard ,
2021-08-11 18:28:44 +02:00
}
err := e . Setup ( )
2023-04-06 12:18:41 +02:00
require . Error ( t , err )
2022-07-26 00:10:16 +02:00
assert . Equal ( t , expected , err . Error ( ) )
2021-08-11 18:28:44 +02:00
}
func TestIncludesOptionalExplicitFalse ( t * testing . T ) {
2022-07-26 00:10:16 +02:00
const dir = "testdata/includes_optional_explicit_false"
wd , _ := os . Getwd ( )
message := "stat %s/%s/TaskfileOptional.yml: no such file or directory"
expected := fmt . Sprintf ( message , wd , dir )
2021-08-11 18:28:44 +02:00
e := task . Executor {
2022-07-26 00:10:16 +02:00
Dir : dir ,
2021-12-04 17:37:52 +02:00
Stdout : io . Discard ,
Stderr : io . Discard ,
2021-08-11 18:28:44 +02:00
}
err := e . Setup ( )
2023-04-06 12:18:41 +02:00
require . Error ( t , err )
2022-07-26 00:10:16 +02:00
assert . Equal ( t , expected , err . Error ( ) )
2021-08-11 18:28:44 +02:00
}
2021-12-04 17:37:52 +02:00
func TestIncludesFromCustomTaskfile ( t * testing . T ) {
tt := fileContentTest {
2024-02-13 03:07:00 +02:00
Entrypoint : "testdata/includes_yaml/Custom.ext" ,
2021-12-04 17:37:52 +02:00
Dir : "testdata/includes_yaml" ,
Target : "default" ,
TrimSpace : true ,
Files : map [ string ] string {
"main.txt" : "main" ,
"included_with_yaml_extension.txt" : "included_with_yaml_extension" ,
"included_with_custom_file.txt" : "included_with_custom_file" ,
} ,
}
tt . Run ( t )
}
2022-07-26 00:10:16 +02:00
func TestIncludesRelativePath ( t * testing . T ) {
const dir = "testdata/includes_rel_path"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2022-07-26 00:10:16 +02:00
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "common:pwd" } ) )
2022-07-26 00:10:16 +02:00
assert . Contains ( t , buff . String ( ) , "testdata/includes_rel_path/common" )
buff . Reset ( )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "included:common:pwd" } ) )
2022-07-26 00:10:16 +02:00
assert . Contains ( t , buff . String ( ) , "testdata/includes_rel_path/common" )
}
2022-07-22 04:16:14 +02:00
func TestIncludesInternal ( t * testing . T ) {
const dir = "testdata/internal_task"
tests := [ ] struct {
name string
task string
expectedErr bool
expectedOutput string
} {
{ "included internal task via task" , "task-1" , false , "Hello, World!\n" } ,
{ "included internal task via dep" , "task-2" , false , "Hello, World!\n" } ,
2022-12-17 15:35:30 +02:00
{ "included internal direct" , "included:task-3" , true , "task: No tasks with description available. Try --list-all to list all tasks\n" } ,
2022-07-22 04:16:14 +02:00
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2022-07-22 04:16:14 +02:00
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : test . task } )
2022-07-22 04:16:14 +02:00
if test . expectedErr {
2023-04-06 12:18:41 +02:00
require . Error ( t , err )
2022-07-22 04:16:14 +02:00
} else {
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2022-07-22 04:16:14 +02:00
}
assert . Equal ( t , test . expectedOutput , buff . String ( ) )
} )
}
}
2024-08-26 23:17:39 +02:00
func TestIncludesFlatten ( t * testing . T ) {
const dir = "testdata/includes_flatten"
tests := [ ] struct {
name string
taskfile string
task string
expectedErr bool
expectedOutput string
} {
{ name : "included flatten" , taskfile : "Taskfile.yml" , task : "gen" , expectedOutput : "gen from included\n" } ,
2024-09-06 15:44:28 +02:00
{ name : "included flatten with default" , taskfile : "Taskfile.yml" , task : "default" , expectedOutput : "default from included flatten\n" } ,
{ name : "included flatten can call entrypoint tasks" , taskfile : "Taskfile.yml" , task : "from_entrypoint" , expectedOutput : "from entrypoint\n" } ,
2024-08-26 23:17:39 +02:00
{ name : "included flatten with deps" , taskfile : "Taskfile.yml" , task : "with_deps" , expectedOutput : "gen from included\nwith_deps from included\n" } ,
{ name : "included flatten nested" , taskfile : "Taskfile.yml" , task : "from_nested" , expectedOutput : "from nested\n" } ,
{ name : "included flatten multiple same task" , taskfile : "Taskfile.multiple.yml" , task : "gen" , expectedErr : true , expectedOutput : "task: Found multiple tasks (gen) included by \"included\"\"" } ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Entrypoint : dir + "/" + test . taskfile ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
err := e . Setup ( )
if test . expectedErr {
assert . EqualError ( t , err , test . expectedOutput )
} else {
require . NoError ( t , err )
_ = e . Run ( context . Background ( ) , & ast . Call { Task : test . task } )
assert . Equal ( t , test . expectedOutput , buff . String ( ) )
}
} )
}
}
2022-11-23 19:58:08 +02:00
func TestIncludesInterpolation ( t * testing . T ) {
const dir = "testdata/includes_interpolation"
tests := [ ] struct {
name string
task string
expectedErr bool
expectedOutput string
} {
2023-09-06 02:18:30 +02:00
{ "include" , "include" , false , "include\n" } ,
2024-04-29 23:27:30 +02:00
{ "include_with_env_variable" , "include-with-env-variable" , false , "include_with_env_variable\n" } ,
2023-09-06 02:18:30 +02:00
{ "include_with_dir" , "include-with-dir" , false , "included\n" } ,
2022-11-23 19:58:08 +02:00
}
2024-04-29 23:27:30 +02:00
t . Setenv ( "MODULE" , "included" )
2022-11-23 19:58:08 +02:00
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
2023-09-06 02:18:30 +02:00
Dir : filepath . Join ( dir , test . name ) ,
2022-11-23 19:58:08 +02:00
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2022-11-23 19:58:08 +02:00
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : test . task } )
2022-11-23 19:58:08 +02:00
if test . expectedErr {
2023-04-06 12:18:41 +02:00
require . Error ( t , err )
2022-11-23 19:58:08 +02:00
} else {
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2022-11-23 19:58:08 +02:00
}
assert . Equal ( t , test . expectedOutput , buff . String ( ) )
} )
}
}
2024-05-12 21:32:09 +02:00
func TestIncludedTaskfileVarMerging ( t * testing . T ) {
const dir = "testdata/included_taskfile_var_merging"
tests := [ ] struct {
name string
task string
expectedOutput string
} {
{ "foo" , "foo:pwd" , "included_taskfile_var_merging/foo\n" } ,
{ "bar" , "bar:pwd" , "included_taskfile_var_merging/bar\n" } ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
require . NoError ( t , e . Setup ( ) )
err := e . Run ( context . Background ( ) , & ast . Call { Task : test . task } )
require . NoError ( t , err )
assert . Contains ( t , buff . String ( ) , test . expectedOutput )
} )
}
}
2022-07-22 04:15:35 +02:00
func TestInternalTask ( t * testing . T ) {
const dir = "testdata/internal_task"
tests := [ ] struct {
name string
task string
expectedErr bool
expectedOutput string
} {
{ "internal task via task" , "task-1" , false , "Hello, World!\n" } ,
{ "internal task via dep" , "task-2" , false , "Hello, World!\n" } ,
2022-11-02 16:38:26 +02:00
{ "internal direct" , "task-3" , true , "" } ,
2022-07-22 04:15:35 +02:00
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2022-07-22 04:15:35 +02:00
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : test . task } )
2022-07-22 04:15:35 +02:00
if test . expectedErr {
2023-04-06 12:18:41 +02:00
require . Error ( t , err )
2022-07-22 04:15:35 +02:00
} else {
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2022-07-22 04:15:35 +02:00
}
assert . Equal ( t , test . expectedOutput , buff . String ( ) )
} )
}
}
2022-11-02 16:27:15 +02:00
func TestIncludesShadowedDefault ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/includes_shadowed_default" ,
Target : "included" ,
TrimSpace : true ,
Files : map [ string ] string {
"file.txt" : "shadowed" ,
} ,
}
tt . Run ( t )
}
func TestIncludesUnshadowedDefault ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/includes_unshadowed_default" ,
Target : "included" ,
TrimSpace : true ,
Files : map [ string ] string {
"file.txt" : "included" ,
} ,
}
tt . Run ( t )
}
2022-02-19 23:24:43 +02:00
func TestSupportedFileNames ( t * testing . T ) {
fileNames := [ ] string {
"Taskfile.yml" ,
"Taskfile.yaml" ,
"Taskfile.dist.yml" ,
"Taskfile.dist.yaml" ,
}
for _ , fileName := range fileNames {
t . Run ( fileName , func ( t * testing . T ) {
tt := fileContentTest {
Dir : fmt . Sprintf ( "testdata/file_names/%s" , fileName ) ,
Target : "default" ,
TrimSpace : true ,
Files : map [ string ] string {
"output.txt" : "hello" ,
} ,
}
tt . Run ( t )
} )
}
}
2019-02-24 16:54:11 +02:00
func TestSummary ( t * testing . T ) {
2019-02-24 16:37:02 +02:00
const dir = "testdata/summary"
2019-02-24 10:53:49 +02:00
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
2019-02-24 16:33:09 +02:00
Summary : true ,
2019-02-24 12:01:48 +02:00
Silent : true ,
2019-02-24 10:53:49 +02:00
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "task-with-summary" } , & ast . Call { Task : "other-task-with-summary" } ) )
2019-02-24 15:20:39 +02:00
2022-08-06 23:19:07 +02:00
data , err := os . ReadFile ( filepathext . SmartJoin ( dir , "task-with-summary.txt" ) )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2019-09-02 03:26:53 +02:00
expectedOutput := string ( data )
if runtime . GOOS == "windows" {
2022-08-17 19:37:58 +02:00
expectedOutput = strings . ReplaceAll ( expectedOutput , "\r\n" , "\n" )
2019-09-02 03:26:53 +02:00
}
assert . Equal ( t , expectedOutput , buff . String ( ) )
2019-02-24 15:20:39 +02:00
}
2019-06-04 09:45:11 +02:00
func TestWhenNoDirAttributeItRunsInSameDirAsTaskfile ( t * testing . T ) {
const expected = "dir"
const dir = "testdata/" + expected
var out bytes . Buffer
e := & task . Executor {
Dir : dir ,
Stdout : & out ,
Stderr : & out ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "whereami" } ) )
2019-06-04 09:45:11 +02:00
// got should be the "dir" part of "testdata/dir"
got := strings . TrimSuffix ( filepath . Base ( out . String ( ) ) , "\n" )
assert . Equal ( t , expected , got , "Mismatch in the working directory" )
}
2019-06-04 18:36:35 +02:00
func TestWhenDirAttributeAndDirExistsItRunsInThatDir ( t * testing . T ) {
const expected = "exists"
const dir = "testdata/dir/explicit_exists"
var out bytes . Buffer
e := & task . Executor {
Dir : dir ,
Stdout : & out ,
Stderr : & out ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "whereami" } ) )
2019-06-04 18:36:35 +02:00
got := strings . TrimSuffix ( filepath . Base ( out . String ( ) ) , "\n" )
assert . Equal ( t , expected , got , "Mismatch in the working directory" )
}
2019-06-04 18:58:22 +02:00
func TestWhenDirAttributeItCreatesMissingAndRunsInThatDir ( t * testing . T ) {
const expected = "createme"
const dir = "testdata/dir/explicit_doesnt_exist/"
const toBeCreated = dir + expected
const target = "whereami"
var out bytes . Buffer
e := & task . Executor {
Dir : dir ,
Stdout : & out ,
Stderr : & out ,
}
// Ensure that the directory to be created doesn't actually exist.
2019-09-09 03:51:56 +02:00
_ = os . RemoveAll ( toBeCreated )
2019-06-04 18:58:22 +02:00
if _ , err := os . Stat ( toBeCreated ) ; err == nil {
t . Errorf ( "Directory should not exist: %v" , err )
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : target } ) )
2019-06-04 18:58:22 +02:00
got := strings . TrimSuffix ( filepath . Base ( out . String ( ) ) , "\n" )
assert . Equal ( t , expected , got , "Mismatch in the working directory" )
// Clean-up after ourselves only if no error.
2019-09-09 03:51:56 +02:00
_ = os . RemoveAll ( toBeCreated )
2021-01-07 16:17:38 +02:00
}
2021-09-26 15:30:32 +02:00
func TestDynamicVariablesRunOnTheNewCreatedDir ( t * testing . T ) {
const expected = "created"
const dir = "testdata/dir/dynamic_var_on_created_dir/"
const toBeCreated = dir + expected
const target = "default"
var out bytes . Buffer
e := & task . Executor {
Dir : dir ,
Stdout : & out ,
Stderr : & out ,
}
// Ensure that the directory to be created doesn't actually exist.
_ = os . RemoveAll ( toBeCreated )
if _ , err := os . Stat ( toBeCreated ) ; err == nil {
t . Errorf ( "Directory should not exist: %v" , err )
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : target } ) )
2019-06-04 18:58:22 +02:00
got := strings . TrimSuffix ( filepath . Base ( out . String ( ) ) , "\n" )
assert . Equal ( t , expected , got , "Mismatch in the working directory" )
// Clean-up after ourselves only if no error.
2019-09-09 03:51:56 +02:00
_ = os . RemoveAll ( toBeCreated )
2021-01-07 16:17:38 +02:00
}
func TestDynamicVariablesShouldRunOnTheTaskDir ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/dir/dynamic_var" ,
Target : "default" ,
TrimSpace : false ,
Files : map [ string ] string {
2021-01-09 17:09:23 +02:00
"subdirectory/from_root_taskfile.txt" : "subdirectory\n" ,
"subdirectory/from_included_taskfile.txt" : "subdirectory\n" ,
"subdirectory/from_included_taskfile_task.txt" : "subdirectory\n" ,
"subdirectory/from_interpolated_dir.txt" : "subdirectory\n" ,
2021-01-07 16:17:38 +02:00
} ,
}
tt . Run ( t )
2019-06-04 18:58:22 +02:00
}
2019-08-18 17:37:21 +02:00
2023-06-04 02:05:48 +02:00
func TestDisplaysErrorOnVersion1Schema ( t * testing . T ) {
2019-08-18 17:37:21 +02:00
e := task . Executor {
Dir : "testdata/version/v1" ,
2021-12-04 17:37:52 +02:00
Stdout : io . Discard ,
Stderr : io . Discard ,
2019-08-18 17:37:21 +02:00
}
2019-08-19 21:01:01 +02:00
err := e . Setup ( )
2023-04-06 12:18:41 +02:00
require . Error ( t , err )
2024-01-12 01:33:36 +02:00
assert . Regexp ( t , regexp . MustCompile ( ` task: Invalid schema version in Taskfile \".*testdata\/version\/v1\/Taskfile\.yml\":\nSchema version \(1\.0\.0\) no longer supported\. Please use v3 or above ` ) , err . Error ( ) )
2023-06-04 02:05:48 +02:00
}
2023-12-29 22:26:02 +02:00
func TestDisplaysErrorOnVersion2Schema ( t * testing . T ) {
2023-06-04 02:05:48 +02:00
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/version/v2" ,
Stdout : io . Discard ,
Stderr : & buff ,
}
err := e . Setup ( )
2023-12-29 22:26:02 +02:00
require . Error ( t , err )
2024-01-12 01:33:36 +02:00
assert . Regexp ( t , regexp . MustCompile ( ` task: Invalid schema version in Taskfile \".*testdata\/version\/v2\/Taskfile\.yml\":\nSchema version \(2\.0\.0\) no longer supported\. Please use v3 or above ` ) , err . Error ( ) )
2019-08-18 17:37:21 +02:00
}
2019-12-08 02:28:02 +02:00
func TestShortTaskNotation ( t * testing . T ) {
const dir = "testdata/short_task_notation"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "default" } ) )
2019-12-08 02:28:02 +02:00
assert . Equal ( t , "string-slice-1\nstring-slice-2\nstring\n" , buff . String ( ) )
}
2020-08-04 00:18:38 +02:00
func TestDotenvShouldIncludeAllEnvFiles ( t * testing . T ) {
tt := fileContentTest {
2020-10-04 00:39:58 +02:00
Dir : "testdata/dotenv/default" ,
2020-08-04 00:18:38 +02:00
Target : "default" ,
TrimSpace : false ,
Files : map [ string ] string {
2020-08-16 20:48:19 +02:00
"include.txt" : "INCLUDE1='from_include1' INCLUDE2='from_include2'\n" ,
2020-08-04 00:18:38 +02:00
} ,
}
tt . Run ( t )
}
func TestDotenvShouldErrorWhenIncludingDependantDotenvs ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
2024-02-13 03:07:00 +02:00
Dir : "testdata/dotenv/error_included_envs" ,
Summary : true ,
Stdout : & buff ,
Stderr : & buff ,
2020-08-04 00:18:38 +02:00
}
err := e . Setup ( )
2023-04-06 12:18:41 +02:00
require . Error ( t , err )
2020-08-04 00:18:38 +02:00
assert . Contains ( t , err . Error ( ) , "move the dotenv" )
}
2020-10-04 00:39:58 +02:00
func TestDotenvShouldAllowMissingEnv ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/dotenv/missing_env" ,
Target : "default" ,
TrimSpace : false ,
Files : map [ string ] string {
"include.txt" : "INCLUDE1='' INCLUDE2=''\n" ,
} ,
}
tt . Run ( t )
}
2020-12-27 22:15:12 +02:00
2021-06-05 20:54:10 +02:00
func TestDotenvHasLocalEnvInPath ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/dotenv/local_env_in_path" ,
Target : "default" ,
TrimSpace : false ,
Files : map [ string ] string {
"var.txt" : "VAR='var_in_dot_env_1'\n" ,
} ,
}
tt . Run ( t )
}
func TestDotenvHasLocalVarInPath ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/dotenv/local_var_in_path" ,
Target : "default" ,
TrimSpace : false ,
Files : map [ string ] string {
"var.txt" : "VAR='var_in_dot_env_3'\n" ,
} ,
}
tt . Run ( t )
}
func TestDotenvHasEnvVarInPath ( t * testing . T ) {
os . Setenv ( "ENV_VAR" , "testing" )
tt := fileContentTest {
Dir : "testdata/dotenv/env_var_in_path" ,
Target : "default" ,
TrimSpace : false ,
Files : map [ string ] string {
"var.txt" : "VAR='var_in_dot_env_2'\n" ,
} ,
}
tt . Run ( t )
}
2024-09-29 22:03:48 +02:00
func TestTaskDotenvParseErrorMessage ( t * testing . T ) {
e := task . Executor {
Dir : "testdata/dotenv/parse_error" ,
}
path , _ := filepath . Abs ( filepath . Join ( e . Dir , ".env-with-error" ) )
expected := fmt . Sprintf ( "error reading env file %s:" , path )
err := e . Setup ( )
require . ErrorContains ( t , err , expected )
}
2022-12-06 02:25:16 +02:00
func TestTaskDotenv ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/dotenv_task/default" ,
Target : "dotenv" ,
TrimSpace : true ,
Files : map [ string ] string {
"dotenv.txt" : "foo" ,
} ,
}
tt . Run ( t )
}
func TestTaskDotenvFail ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/dotenv_task/default" ,
Target : "no-dotenv" ,
TrimSpace : true ,
Files : map [ string ] string {
"no-dotenv.txt" : "global" ,
} ,
}
tt . Run ( t )
}
func TestTaskDotenvOverriddenByEnv ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/dotenv_task/default" ,
Target : "dotenv-overridden-by-env" ,
TrimSpace : true ,
Files : map [ string ] string {
"dotenv-overridden-by-env.txt" : "overridden" ,
} ,
}
tt . Run ( t )
}
func TestTaskDotenvWithVarName ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/dotenv_task/default" ,
Target : "dotenv-with-var-name" ,
TrimSpace : true ,
Files : map [ string ] string {
"dotenv-with-var-name.txt" : "foo" ,
} ,
}
tt . Run ( t )
}
2020-12-27 22:15:12 +02:00
func TestExitImmediately ( t * testing . T ) {
const dir = "testdata/exit_immediately"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2020-12-27 22:15:12 +02:00
2024-01-26 16:34:18 +02:00
require . Error ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "default" } ) )
2020-12-27 22:15:12 +02:00
assert . Contains ( t , buff . String ( ) , ` "this_should_fail": executable file not found in $PATH ` )
}
2020-08-17 21:25:17 +02:00
func TestRunOnlyRunsJobsHashOnce ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/run" ,
Target : "generate-hash" ,
Files : map [ string ] string {
"hash.txt" : "starting 1\n1\n2\n" ,
} ,
}
tt . Run ( t )
}
2021-09-14 17:01:33 +02:00
2024-06-28 17:50:02 +02:00
func TestRunOnceSharedDeps ( t * testing . T ) {
const dir = "testdata/run_once_shared_deps"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
ForceAll : true ,
}
require . NoError ( t , e . Setup ( ) )
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "build" } ) )
rx := regexp . MustCompile ( ` task: \[service-[a,b]:library:build\] echo "build library" ` )
matches := rx . FindAllStringSubmatch ( buff . String ( ) , - 1 )
assert . Len ( t , matches , 1 )
assert . Contains ( t , buff . String ( ) , ` task: [service-a:build] echo "build a" ` )
assert . Contains ( t , buff . String ( ) , ` task: [service-b:build] echo "build b" ` )
}
2021-12-15 07:03:37 +02:00
func TestDeferredCmds ( t * testing . T ) {
const dir = "testdata/deferred"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2021-12-15 07:03:37 +02:00
expectedOutputOrder := strings . TrimSpace ( `
task : [ task - 2 ] echo ' cmd ran '
cmd ran
task : [ task - 2 ] exit 1
task : [ task - 2 ] echo ' failing ' && exit 2
failing
task : [ task - 2 ] echo ' echo ran '
echo ran
2022-01-02 23:38:06 +02:00
task : [ task - 1 ] echo ' task - 1 ran successfully '
task - 1 ran successfully
2021-12-15 07:03:37 +02:00
` )
2024-01-26 16:34:18 +02:00
require . Error ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "task-2" } ) )
2021-12-15 07:03:37 +02:00
assert . Contains ( t , buff . String ( ) , expectedOutputOrder )
}
2024-08-15 03:53:14 +02:00
func TestExitCodeZero ( t * testing . T ) {
const dir = "testdata/exit_code"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
require . NoError ( t , e . Setup ( ) )
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "exit-zero" } ) )
2024-09-19 14:22:39 +02:00
assert . Equal ( t , "FOO=bar - DYNAMIC_FOO=bar - EXIT_CODE=" , strings . TrimSpace ( buff . String ( ) ) )
2024-08-15 03:53:14 +02:00
}
func TestExitCodeOne ( t * testing . T ) {
const dir = "testdata/exit_code"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
require . NoError ( t , e . Setup ( ) )
require . Error ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "exit-one" } ) )
2024-09-19 14:22:39 +02:00
assert . Equal ( t , "FOO=bar - DYNAMIC_FOO=bar - EXIT_CODE=1" , strings . TrimSpace ( buff . String ( ) ) )
2024-08-15 03:53:14 +02:00
}
2021-09-14 17:01:33 +02:00
func TestIgnoreNilElements ( t * testing . T ) {
tests := [ ] struct {
name string
dir string
} {
{ "nil cmd" , "testdata/ignore_nil_elements/cmds" } ,
{ "nil dep" , "testdata/ignore_nil_elements/deps" } ,
2021-12-04 17:37:52 +02:00
{ "nil include" , "testdata/ignore_nil_elements/includes" } ,
2021-09-14 17:01:33 +02:00
{ "nil precondition" , "testdata/ignore_nil_elements/preconditions" } ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : test . dir ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "default" } ) )
2021-09-14 17:01:33 +02:00
assert . Equal ( t , "string-slice-1\n" , buff . String ( ) )
} )
}
}
2022-01-14 02:11:47 +02:00
func TestOutputGroup ( t * testing . T ) {
const dir = "testdata/output_group"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2022-01-14 02:11:47 +02:00
expectedOutputOrder := strings . TrimSpace ( `
task : [ hello ] echo ' Hello ! '
: : group : : hello
Hello !
: : endgroup : :
task : [ bye ] echo ' Bye ! '
: : group : : bye
Bye !
: : endgroup : :
` )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "bye" } ) )
2022-01-14 02:11:47 +02:00
t . Log ( buff . String ( ) )
assert . Equal ( t , strings . TrimSpace ( buff . String ( ) ) , expectedOutputOrder )
}
2023-03-31 21:13:29 +02:00
2023-03-09 03:34:52 +02:00
func TestOutputGroupErrorOnlySwallowsOutputOnSuccess ( t * testing . T ) {
const dir = "testdata/output_group_error_only"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2023-03-09 03:34:52 +02:00
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "passing" } ) )
2023-03-09 03:34:52 +02:00
t . Log ( buff . String ( ) )
assert . Empty ( t , buff . String ( ) )
}
func TestOutputGroupErrorOnlyShowsOutputOnFailure ( t * testing . T ) {
const dir = "testdata/output_group_error_only"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2023-03-09 03:34:52 +02:00
2024-01-26 16:34:18 +02:00
require . Error ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "failing" } ) )
2023-03-09 03:34:52 +02:00
t . Log ( buff . String ( ) )
assert . Contains ( t , "failing-output" , strings . TrimSpace ( buff . String ( ) ) )
assert . NotContains ( t , "passing" , strings . TrimSpace ( buff . String ( ) ) )
}
2022-02-24 21:17:20 +02:00
func TestIncludedVars ( t * testing . T ) {
const dir = "testdata/include_with_vars"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2022-02-24 21:17:20 +02:00
expectedOutputOrder := strings . TrimSpace ( `
task : [ included1 : task1 ] echo "VAR_1 is included1-var1"
VAR_1 is included1 - var1
2022-03-19 23:41:03 +02:00
task : [ included1 : task1 ] echo "VAR_2 is included-default-var2"
VAR_2 is included - default - var2
2022-02-24 21:17:20 +02:00
task : [ included2 : task1 ] echo "VAR_1 is included2-var1"
VAR_1 is included2 - var1
2022-03-19 23:41:03 +02:00
task : [ included2 : task1 ] echo "VAR_2 is included-default-var2"
VAR_2 is included - default - var2
2022-02-24 21:17:20 +02:00
task : [ included3 : task1 ] echo "VAR_1 is included-default-var1"
VAR_1 is included - default - var1
2022-03-19 23:41:03 +02:00
task : [ included3 : task1 ] echo "VAR_2 is included-default-var2"
VAR_2 is included - default - var2
2022-02-24 21:17:20 +02:00
` )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "task1" } ) )
2022-02-24 21:17:20 +02:00
t . Log ( buff . String ( ) )
assert . Equal ( t , strings . TrimSpace ( buff . String ( ) ) , expectedOutputOrder )
}
2022-06-02 16:39:28 +02:00
2023-07-08 16:42:38 +02:00
func TestIncludedVarsMultiLevel ( t * testing . T ) {
const dir = "testdata/include_with_vars_multi_level"
var buff bytes . Buffer
e := task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
}
require . NoError ( t , e . Setup ( ) )
expectedOutputOrder := strings . TrimSpace ( `
task : [ lib : greet ] echo ' Hello world '
Hello world
task : [ foo : lib : greet ] echo ' Hello foo '
Hello foo
task : [ bar : lib : greet ] echo ' Hello bar '
Hello bar
` )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "default" } ) )
2023-07-08 16:42:38 +02:00
t . Log ( buff . String ( ) )
2024-03-10 19:28:04 +02:00
assert . Equal ( t , expectedOutputOrder , strings . TrimSpace ( buff . String ( ) ) )
2023-07-08 16:42:38 +02:00
}
2022-06-02 16:39:28 +02:00
func TestErrorCode ( t * testing . T ) {
const dir = "testdata/error_code"
2023-07-20 01:08:22 +02:00
tests := [ ] struct {
name string
task string
expected int
} {
{
name : "direct task" ,
task : "direct" ,
expected : 42 ,
} , {
name : "indirect task" ,
task : "indirect" ,
expected : 42 ,
} ,
2022-06-02 16:39:28 +02:00
}
2023-07-20 01:08:22 +02:00
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var buff bytes . Buffer
e := & task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
require . NoError ( t , e . Setup ( ) )
2022-06-02 16:39:28 +02:00
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : test . task } )
2023-07-20 01:08:22 +02:00
require . Error ( t , err )
taskRunErr , ok := err . ( * errors . TaskRunError )
assert . True ( t , ok , "cannot cast returned error to *task.TaskRunError" )
assert . Equal ( t , test . expected , taskRunErr . TaskExitCode ( ) , "unexpected exit code from task" )
} )
}
2022-06-02 16:39:28 +02:00
}
2022-08-23 18:36:19 +02:00
func TestEvaluateSymlinksInPaths ( t * testing . T ) {
const dir = "testdata/evaluate_symlinks_in_paths"
var buff bytes . Buffer
e := & task . Executor {
Dir : dir ,
Stdout : & buff ,
Stderr : & buff ,
Silent : false ,
}
2023-11-30 03:38:12 +02:00
tests := [ ] struct {
name string
task string
expected string
} {
{
name : "default (1)" ,
task : "default" ,
expected : "task: [default] echo \"some job\"\nsome job" ,
} ,
{
name : "test-sym (1)" ,
task : "test-sym" ,
expected : "task: [test-sym] echo \"shared file source changed\" > src/shared/b" ,
} ,
{
name : "default (2)" ,
task : "default" ,
expected : "task: [default] echo \"some job\"\nsome job" ,
} ,
{
name : "default (3)" ,
task : "default" ,
expected : ` task: Task "default" is up to date ` ,
} ,
{
name : "reset" ,
task : "reset" ,
expected : "task: [reset] echo \"shared file source\" > src/shared/b\ntask: [reset] echo \"file source\" > src/a" ,
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : test . task } )
2023-11-30 03:38:12 +02:00
require . NoError ( t , err )
assert . Equal ( t , test . expected , strings . TrimSpace ( buff . String ( ) ) )
buff . Reset ( )
} )
}
err := os . RemoveAll ( dir + "/.task" )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2022-08-23 18:36:19 +02:00
}
2022-09-08 19:22:44 +02:00
2022-12-06 02:58:20 +02:00
func TestTaskfileWalk ( t * testing . T ) {
tests := [ ] struct {
name string
dir string
expected string
} {
{
name : "walk from root directory" ,
dir : "testdata/taskfile_walk" ,
expected : "foo\n" ,
} , {
name : "walk from sub directory" ,
dir : "testdata/taskfile_walk/foo" ,
expected : "foo\n" ,
} , {
name : "walk from sub sub directory" ,
dir : "testdata/taskfile_walk/foo/bar" ,
expected : "foo\n" ,
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : test . dir ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "default" } ) )
2022-12-06 02:58:20 +02:00
assert . Equal ( t , test . expected , buff . String ( ) )
} )
}
}
func TestUserWorkingDirectory ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/user_working_dir" ,
Stdout : & buff ,
Stderr : & buff ,
}
wd , err := os . Getwd ( )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "default" } ) )
2022-12-06 02:58:20 +02:00
assert . Equal ( t , fmt . Sprintf ( "%s\n" , wd ) , buff . String ( ) )
}
2023-01-14 21:41:56 +02:00
2023-08-26 23:06:50 +02:00
func TestUserWorkingDirectoryWithIncluded ( t * testing . T ) {
wd , err := os . Getwd ( )
require . NoError ( t , err )
wd = filepathext . SmartJoin ( wd , "testdata/user_working_dir_with_includes/somedir" )
var buff bytes . Buffer
e := task . Executor {
UserWorkingDir : wd ,
Dir : "testdata/user_working_dir_with_includes" ,
Stdout : & buff ,
Stderr : & buff ,
}
require . NoError ( t , err )
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "included:echo" } ) )
2023-08-26 23:06:50 +02:00
assert . Equal ( t , fmt . Sprintf ( "%s\n" , wd ) , buff . String ( ) )
}
2023-01-07 02:38:35 +02:00
func TestPlatforms ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/platforms" ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "build-" + runtime . GOOS } ) )
2023-01-07 02:38:35 +02:00
assert . Equal ( t , fmt . Sprintf ( "task: [build-%s] echo 'Running task on %s'\nRunning task on %s\n" , runtime . GOOS , runtime . GOOS , runtime . GOOS ) , buff . String ( ) )
}
2023-01-14 21:41:56 +02:00
func TestPOSIXShellOptsGlobalLevel ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/shopts/global_level" ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2023-01-14 21:41:56 +02:00
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : "pipefail" } )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2023-01-14 21:41:56 +02:00
assert . Equal ( t , "pipefail\ton\n" , buff . String ( ) )
}
func TestPOSIXShellOptsTaskLevel ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/shopts/task_level" ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2023-01-14 21:41:56 +02:00
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : "pipefail" } )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2023-01-14 21:41:56 +02:00
assert . Equal ( t , "pipefail\ton\n" , buff . String ( ) )
}
func TestPOSIXShellOptsCommandLevel ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/shopts/command_level" ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2023-01-14 21:41:56 +02:00
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : "pipefail" } )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2023-01-14 21:41:56 +02:00
assert . Equal ( t , "pipefail\ton\n" , buff . String ( ) )
}
func TestBashShellOptsGlobalLevel ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/shopts/global_level" ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2023-01-14 21:41:56 +02:00
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : "globstar" } )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2023-01-14 21:41:56 +02:00
assert . Equal ( t , "globstar\ton\n" , buff . String ( ) )
}
func TestBashShellOptsTaskLevel ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/shopts/task_level" ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2023-01-14 21:41:56 +02:00
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : "globstar" } )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2023-01-14 21:41:56 +02:00
assert . Equal ( t , "globstar\ton\n" , buff . String ( ) )
}
func TestBashShellOptsCommandLevel ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/shopts/command_level" ,
Stdout : & buff ,
Stderr : & buff ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2023-01-14 21:41:56 +02:00
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : "globstar" } )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2023-01-14 21:41:56 +02:00
assert . Equal ( t , "globstar\ton\n" , buff . String ( ) )
}
2023-03-17 02:38:24 +02:00
func TestSplitArgs ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/split_args" ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
}
2023-04-06 12:18:41 +02:00
require . NoError ( t , e . Setup ( ) )
2023-03-17 02:38:24 +02:00
2023-12-29 22:32:03 +02:00
vars := & ast . Vars { }
vars . Set ( "CLI_ARGS" , ast . Var { Value : "foo bar 'foo bar baz'" } )
2023-03-17 02:38:24 +02:00
2024-01-26 16:34:18 +02:00
err := e . Run ( context . Background ( ) , & ast . Call { Task : "default" , Vars : vars } )
2023-04-06 12:18:41 +02:00
require . NoError ( t , err )
2023-03-17 02:38:24 +02:00
assert . Equal ( t , "3\n" , buff . String ( ) )
}
2023-04-27 08:23:45 +02:00
2023-06-11 03:08:28 +02:00
func TestSingleCmdDep ( t * testing . T ) {
tt := fileContentTest {
Dir : "testdata/single_cmd_dep" ,
Target : "foo" ,
Files : map [ string ] string {
"foo.txt" : "foo\n" ,
"bar.txt" : "bar\n" ,
} ,
}
tt . Run ( t )
}
2023-04-27 08:23:45 +02:00
func TestSilence ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/silent" ,
Stdout : & buff ,
Stderr : & buff ,
Silent : false ,
}
require . NoError ( t , e . Setup ( ) )
// First verify that the silent flag is in place.
2024-01-26 16:34:18 +02:00
task , err := e . GetTask ( & ast . Call { Task : "task-test-silent-calls-chatty-silenced" } )
2023-04-27 08:23:45 +02:00
require . NoError ( t , err , "Unable to look up task task-test-silent-calls-chatty-silenced" )
require . True ( t , task . Cmds [ 0 ] . Silent , "The task task-test-silent-calls-chatty-silenced should have a silent call to chatty" )
// Then test the two basic cases where the task is silent or not.
// A silenced task.
2024-01-26 16:34:18 +02:00
err = e . Run ( context . Background ( ) , & ast . Call { Task : "silent" } )
2023-04-27 08:23:45 +02:00
require . NoError ( t , err )
require . Empty ( t , buff . String ( ) , "siWhile running lent: Expected not see output, because the task is silent" )
buff . Reset ( )
// A chatty (not silent) task.
2024-01-26 16:34:18 +02:00
err = e . Run ( context . Background ( ) , & ast . Call { Task : "chatty" } )
2023-04-27 08:23:45 +02:00
require . NoError ( t , err )
require . NotEmpty ( t , buff . String ( ) , "chWhile running atty: Expected to see output, because the task is not silent" )
buff . Reset ( )
// Then test invoking the two task from other tasks.
// A silenced task that calls a chatty task.
2024-01-26 16:34:18 +02:00
err = e . Run ( context . Background ( ) , & ast . Call { Task : "task-test-silent-calls-chatty-non-silenced" } )
2023-04-27 08:23:45 +02:00
require . NoError ( t , err )
require . NotEmpty ( t , buff . String ( ) , "While running task-test-silent-calls-chatty-non-silenced: Expected to see output. The task is silenced, but the called task is not. Silence does not propagate to called tasks." )
buff . Reset ( )
// A silent task that does a silent call to a chatty task.
2024-01-26 16:34:18 +02:00
err = e . Run ( context . Background ( ) , & ast . Call { Task : "task-test-silent-calls-chatty-silenced" } )
2023-04-27 08:23:45 +02:00
require . NoError ( t , err )
require . Empty ( t , buff . String ( ) , "While running task-test-silent-calls-chatty-silenced: Expected not to see output. The task calls chatty task, but the call is silenced." )
buff . Reset ( )
// A chatty task that does a call to a chatty task.
2024-01-26 16:34:18 +02:00
err = e . Run ( context . Background ( ) , & ast . Call { Task : "task-test-chatty-calls-chatty-non-silenced" } )
2023-04-27 08:23:45 +02:00
require . NoError ( t , err )
require . NotEmpty ( t , buff . String ( ) , "While running task-test-chatty-calls-chatty-non-silenced: Expected to see output. Both caller and callee are chatty and not silenced." )
buff . Reset ( )
// A chatty task that does a silenced call to a chatty task.
2024-01-26 16:34:18 +02:00
err = e . Run ( context . Background ( ) , & ast . Call { Task : "task-test-chatty-calls-chatty-silenced" } )
2023-04-27 08:23:45 +02:00
require . NoError ( t , err )
require . NotEmpty ( t , buff . String ( ) , "While running task-test-chatty-calls-chatty-silenced: Expected to see output. Call to a chatty task is silenced, but the parent task is not." )
buff . Reset ( )
// A chatty task with no cmd's of its own that does a silenced call to a chatty task.
2024-01-26 16:34:18 +02:00
err = e . Run ( context . Background ( ) , & ast . Call { Task : "task-test-no-cmds-calls-chatty-silenced" } )
2023-04-27 08:23:45 +02:00
require . NoError ( t , err )
require . Empty ( t , buff . String ( ) , "While running task-test-no-cmds-calls-chatty-silenced: Expected not to see output. While the task itself is not silenced, it does not have any cmds and only does an invocation of a silenced task." )
buff . Reset ( )
// A chatty task that does a silenced invocation of a task.
2024-01-26 16:34:18 +02:00
err = e . Run ( context . Background ( ) , & ast . Call { Task : "task-test-chatty-calls-silenced-cmd" } )
2023-04-27 08:23:45 +02:00
require . NoError ( t , err )
require . Empty ( t , buff . String ( ) , "While running task-test-chatty-calls-silenced-cmd: Expected not to see output. While the task itself is not silenced, its call to the chatty task is silent." )
buff . Reset ( )
2023-04-27 08:28:04 +02:00
// Then test calls via dependencies.
// A silent task that depends on a chatty task.
2024-01-26 16:34:18 +02:00
err = e . Run ( context . Background ( ) , & ast . Call { Task : "task-test-is-silent-depends-on-chatty-non-silenced" } )
2023-04-27 08:28:04 +02:00
require . NoError ( t , err )
require . NotEmpty ( t , buff . String ( ) , "While running task-test-is-silent-depends-on-chatty-non-silenced: Expected to see output. The task is silent and depends on a chatty task. Dependencies does not inherit silence." )
buff . Reset ( )
// A silent task that depends on a silenced chatty task.
2024-01-26 16:34:18 +02:00
err = e . Run ( context . Background ( ) , & ast . Call { Task : "task-test-is-silent-depends-on-chatty-silenced" } )
2023-04-27 08:28:04 +02:00
require . NoError ( t , err )
require . Empty ( t , buff . String ( ) , "While running task-test-is-silent-depends-on-chatty-silenced: Expected not to see output. The task is silent and has a silenced dependency on a chatty task." )
buff . Reset ( )
// A chatty task that, depends on a silenced chatty task.
2024-01-26 16:34:18 +02:00
err = e . Run ( context . Background ( ) , & ast . Call { Task : "task-test-is-chatty-depends-on-chatty-silenced" } )
2023-04-27 08:28:04 +02:00
require . NoError ( t , err )
require . Empty ( t , buff . String ( ) , "While running task-test-is-chatty-depends-on-chatty-silenced: Expected not to see output. The task is chatty but does not have commands and has a silenced dependency on a chatty task." )
buff . Reset ( )
2023-04-27 08:23:45 +02:00
}
2023-06-18 03:32:18 +02:00
func TestForce ( t * testing . T ) {
tests := [ ] struct {
name string
env map [ string ] string
force bool
forceAll bool
} {
{
name : "force" ,
force : true ,
} ,
{
name : "force-all" ,
forceAll : true ,
} ,
{
name : "force with gentle force experiment" ,
force : true ,
env : map [ string ] string {
"TASK_X_GENTLE_FORCE" : "1" ,
} ,
} ,
{
name : "force-all with gentle force experiment" ,
forceAll : true ,
env : map [ string ] string {
"TASK_X_GENTLE_FORCE" : "1" ,
} ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/force" ,
Stdout : & buff ,
Stderr : & buff ,
Force : tt . force ,
ForceAll : tt . forceAll ,
}
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : "task-with-dep" } ) )
2023-06-18 03:32:18 +02:00
} )
}
}
2023-06-15 17:04:03 +02:00
2024-03-10 19:21:50 +02:00
func TestForCmds ( t * testing . T ) {
2023-06-15 17:04:03 +02:00
tests := [ ] struct {
name string
expectedOutput string
} {
{
name : "loop-explicit" ,
expectedOutput : "a\nb\nc\n" ,
} ,
2024-09-02 21:29:00 +02:00
{
name : "loop-matrix" ,
expectedOutput : "windows/amd64\nwindows/arm64\nlinux/amd64\nlinux/arm64\ndarwin/amd64\ndarwin/arm64\n" ,
} ,
2023-06-15 17:04:03 +02:00
{
name : "loop-sources" ,
expectedOutput : "bar\nfoo\n" ,
} ,
{
name : "loop-sources-glob" ,
expectedOutput : "bar\nfoo\n" ,
} ,
{
name : "loop-vars" ,
expectedOutput : "foo\nbar\n" ,
} ,
{
name : "loop-vars-sh" ,
expectedOutput : "bar\nfoo\n" ,
} ,
{
name : "loop-task" ,
expectedOutput : "foo\nbar\n" ,
} ,
{
name : "loop-task-as" ,
expectedOutput : "foo\nbar\n" ,
} ,
{
name : "loop-different-tasks" ,
expectedOutput : "1\n2\n3\n" ,
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
2024-03-10 19:21:50 +02:00
var stdOut bytes . Buffer
var stdErr bytes . Buffer
2023-06-15 17:04:03 +02:00
e := task . Executor {
2024-03-10 19:21:50 +02:00
Dir : "testdata/for/cmds" ,
Stdout : & stdOut ,
Stderr : & stdErr ,
Silent : true ,
Force : true ,
}
require . NoError ( t , e . Setup ( ) )
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : test . name } ) )
assert . Equal ( t , test . expectedOutput , stdOut . String ( ) )
} )
}
}
func TestForDeps ( t * testing . T ) {
tests := [ ] struct {
name string
expectedOutputContains [ ] string
} {
{
name : "loop-explicit" ,
expectedOutputContains : [ ] string { "a\n" , "b\n" , "c\n" } ,
} ,
2024-09-02 21:29:00 +02:00
{
name : "loop-matrix" ,
expectedOutputContains : [ ] string {
"windows/amd64\n" ,
"windows/arm64\n" ,
"linux/amd64\n" ,
"linux/arm64\n" ,
"darwin/amd64\n" ,
"darwin/arm64\n" ,
} ,
} ,
2024-03-10 19:21:50 +02:00
{
name : "loop-sources" ,
expectedOutputContains : [ ] string { "bar\n" , "foo\n" } ,
} ,
{
name : "loop-sources-glob" ,
expectedOutputContains : [ ] string { "bar\n" , "foo\n" } ,
} ,
{
name : "loop-vars" ,
expectedOutputContains : [ ] string { "foo\n" , "bar\n" } ,
} ,
{
name : "loop-vars-sh" ,
expectedOutputContains : [ ] string { "bar\n" , "foo\n" } ,
} ,
{
name : "loop-task" ,
expectedOutputContains : [ ] string { "foo\n" , "bar\n" } ,
} ,
{
name : "loop-task-as" ,
expectedOutputContains : [ ] string { "foo\n" , "bar\n" } ,
} ,
{
name : "loop-different-tasks" ,
expectedOutputContains : [ ] string { "1\n" , "2\n" , "3\n" } ,
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
// We need to use a sync buffer here as deps are run concurrently
var buff SyncBuffer
e := task . Executor {
Dir : "testdata/for/deps" ,
2023-06-15 17:04:03 +02:00
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
Force : true ,
2024-10-06 02:25:12 +02:00
// Force output of each dep to be grouped together to prevent interleaving
OutputStyle : ast . Output { Name : "group" } ,
2023-06-15 17:04:03 +02:00
}
require . NoError ( t , e . Setup ( ) )
2024-01-26 16:34:18 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : test . name } ) )
2024-03-10 19:21:50 +02:00
for _ , expectedOutputContains := range test . expectedOutputContains {
assert . Contains ( t , buff . buf . String ( ) , expectedOutputContains )
}
2023-06-15 17:04:03 +02:00
} )
}
}
2024-01-27 18:17:52 +02:00
func TestWildcard ( t * testing . T ) {
tests := [ ] struct {
name string
2024-02-22 22:52:05 +02:00
call string
2024-01-27 18:17:52 +02:00
expectedOutput string
wantErr bool
} {
{
2024-02-22 22:52:05 +02:00
name : "basic wildcard" ,
call : "wildcard-foo" ,
2024-01-27 18:17:52 +02:00
expectedOutput : "Hello foo\n" ,
} ,
{
2024-02-22 22:52:05 +02:00
name : "double wildcard" ,
call : "foo-wildcard-bar" ,
2024-01-27 18:17:52 +02:00
expectedOutput : "Hello foo bar\n" ,
} ,
{
2024-02-22 22:52:05 +02:00
name : "store wildcard" ,
call : "start-foo" ,
2024-01-27 18:17:52 +02:00
expectedOutput : "Starting foo\n" ,
} ,
{
2024-02-22 22:52:05 +02:00
name : "matches exactly" ,
call : "matches-exactly-*" ,
expectedOutput : "I don't consume matches: []\n" ,
2024-01-27 18:17:52 +02:00
} ,
{
2024-02-22 22:52:05 +02:00
name : "no matches" ,
call : "no-match" ,
wantErr : true ,
} ,
{
name : "multiple matches" ,
call : "wildcard-foo-bar" ,
2024-01-27 18:17:52 +02:00
wantErr : true ,
} ,
}
for _ , test := range tests {
2024-02-22 22:52:05 +02:00
t . Run ( test . call , func ( t * testing . T ) {
2024-01-27 18:17:52 +02:00
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/wildcards" ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
Force : true ,
}
require . NoError ( t , e . Setup ( ) )
if test . wantErr {
2024-02-22 22:52:05 +02:00
require . Error ( t , e . Run ( context . Background ( ) , & ast . Call { Task : test . call } ) )
2024-01-27 18:17:52 +02:00
return
}
2024-02-22 22:52:05 +02:00
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : test . call } ) )
2024-01-27 18:17:52 +02:00
assert . Equal ( t , test . expectedOutput , buff . String ( ) )
} )
}
}
2024-05-16 17:20:59 +02:00
func TestReference ( t * testing . T ) {
tests := [ ] struct {
name string
call string
expectedOutput string
} {
{
name : "reference in command" ,
call : "ref-cmd" ,
expectedOutput : "1\n" ,
} ,
{
name : "reference in dependency" ,
call : "ref-dep" ,
expectedOutput : "1\n" ,
} ,
{
name : "reference using templating resolver" ,
call : "ref-resolver" ,
expectedOutput : "1\n" ,
} ,
{
name : "reference using templating resolver and dynamic var" ,
call : "ref-resolver-sh" ,
expectedOutput : "Alice has 3 children called Bob, Charlie, and Diane\n" ,
} ,
}
for _ , test := range tests {
t . Run ( test . call , func ( t * testing . T ) {
var buff bytes . Buffer
e := task . Executor {
Dir : "testdata/var_references" ,
Stdout : & buff ,
Stderr : & buff ,
Silent : true ,
Force : true ,
}
require . NoError ( t , e . Setup ( ) )
require . NoError ( t , e . Run ( context . Background ( ) , & ast . Call { Task : test . call } ) )
assert . Equal ( t , test . expectedOutput , buff . String ( ) )
} )
}
}
2024-10-06 02:40:22 +02:00
// enableExperimentForTest enables the experiment behind pointer e for the duration of test t and sub-tests,
// with the experiment being restored to its previous state when tests complete.
//
// Typically experiments are controlled via TASK_X_ env vars, but we cannot use those in tests
// because the experiment settings are parsed during experiments.init(), before any tests run.
func enableExperimentForTest ( t * testing . T , e * experiments . Experiment , val string ) {
prev := * e
* e = experiments . Experiment {
Name : prev . Name ,
Enabled : true ,
Value : val ,
}
t . Cleanup ( func ( ) { * e = prev } )
}