github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/pkg/project/expander_test.go (about) 1 package project_test 2 3 import ( 4 "fmt" 5 "os" 6 "runtime" 7 "strings" 8 "testing" 9 10 "github.com/stretchr/testify/require" 11 12 "github.com/stretchr/testify/assert" 13 "gopkg.in/yaml.v2" 14 15 "github.com/ActiveState/cli/internal/fileutils" 16 "github.com/ActiveState/cli/internal/language" 17 18 "github.com/ActiveState/cli/pkg/project" 19 "github.com/ActiveState/cli/pkg/projectfile" 20 ) 21 22 func loadProject(t *testing.T) *project.Project { 23 projectfile.Reset() 24 25 pjFile := &projectfile.Project{} 26 contents := strings.TrimSpace(` 27 project: "https://platform.activestate.com/Expander/general?branch=main" 28 lock: branchname@0.0.0-SHA123abcd 29 constants: 30 - name: constant 31 value: value 32 - name: recursive 33 value: recursive $constants.constant 34 secrets: 35 project: 36 - name: proj-secret 37 user: 38 - name: user-proj-secret 39 scripts: 40 - name: test 41 value: make test 42 - name: recursive 43 value: echo $scripts.recursive 44 - name: pythonScript 45 language: python3 46 value: scriptValue 47 - name: scriptPath 48 value: $scripts.pythonScript.path() 49 - name: scriptRecursive 50 value: $scripts.scriptRecursive.path() 51 - name: bashScriptPath 52 language: bash 53 value: ${scripts.pythonScript.path()} 54 `) 55 56 err := yaml.Unmarshal([]byte(contents), pjFile) 57 assert.Nil(t, err, "Unmarshalled YAML") 58 59 require.NoError(t, pjFile.Init()) 60 61 require.NoError(t, pjFile.Persist()) 62 63 proj, err := project.Get() 64 require.NoError(t, err) 65 66 return proj 67 } 68 69 func TestExpandProject(t *testing.T) { 70 prj := loadProject(t) 71 prj.Source().SetPath(fmt.Sprintf("spoofed path%sactivestate.yaml", string(os.PathSeparator))) 72 73 expanded, err := project.ExpandFromProject("$project.url()", prj) 74 require.NoError(t, err) 75 assert.Equal(t, prj.URL(), expanded) 76 77 expanded, err = project.ExpandFromProject("$project.branch()", prj) 78 require.NoError(t, err) 79 assert.Equal(t, "main", expanded) 80 81 expanded, err = project.ExpandFromProject("$project.owner()", prj) 82 require.NoError(t, err) 83 assert.Equal(t, "Expander", expanded) 84 85 expanded, err = project.ExpandFromProject("$project.name()", prj) 86 require.NoError(t, err) 87 assert.Equal(t, "general", expanded) 88 89 expanded, err = project.ExpandFromProject("$project.namespace()", prj) 90 require.NoError(t, err) 91 assert.Equal(t, "Expander/general", expanded) 92 93 expanded, err = project.ExpandFromProject("$project.path()", prj) 94 require.NoError(t, err) 95 assert.Equal(t, "spoofed path", expanded) 96 97 if runtime.GOOS == "windows" { 98 prj.Source().SetPath(`c:\another\spoofed path\activestate.yaml`) 99 expanded, err = project.ExpandFromProjectBashifyPaths("$project.path()", prj) 100 require.NoError(t, err) 101 assert.Equal(t, `/c/another/spoofed\ path`, expanded) 102 } 103 } 104 105 func TestExpandTopLevel(t *testing.T) { 106 prj := loadProject(t) 107 108 expanded, err := project.ExpandFromProject("$project", prj) 109 assert.NoError(t, err, "Ran without failure") 110 111 assert.Equal(t, "https://platform.activestate.com/Expander/general?branch=main", expanded) 112 113 expanded, err = project.ExpandFromProject("$lock", prj) 114 assert.NoError(t, err, "Ran without failure") 115 assert.Equal(t, "branchname@0.0.0-SHA123abcd", expanded) 116 117 expanded, err = project.ExpandFromProject("$notcovered", prj) 118 assert.NoError(t, err, "Ran without failure") 119 assert.Equal(t, "$notcovered", expanded) 120 } 121 122 func TestExpandProjectScript(t *testing.T) { 123 prj := loadProject(t) 124 125 expanded, err := project.ExpandFromProject("$ $scripts.test", prj) 126 assert.NoError(t, err, "Ran without failure") 127 assert.Equal(t, "$ make test", expanded, "Expanded simple script") 128 } 129 130 func TestExpandProjectConstant(t *testing.T) { 131 prj := loadProject(t) 132 133 expanded, err := project.ExpandFromProject("$ $constants.constant", prj) 134 assert.NoError(t, err, "Ran without failure") 135 assert.Equal(t, "$ value", expanded, "Expanded simple constant") 136 137 expanded, err = project.ExpandFromProject("$ $constants.recursive", prj) 138 assert.NoError(t, err, "Ran without failure") 139 assert.Equal(t, "$ recursive value", expanded, "Expanded recursive constant") 140 } 141 142 func TestExpandProjectSecret(t *testing.T) { 143 pj := loadProject(t) 144 145 err := project.RegisterExpander("secrets", func(_ string, category string, meta string, isFunction bool, ctx *project.Expansion) (string, error) { 146 if category == project.ProjectCategory { 147 return "proj-value", nil 148 } 149 return "user-proj-value", nil 150 }) 151 require.NoError(t, err) 152 153 expanded, err := project.ExpandFromProject("$ $secrets.user.user-proj-secret", pj) 154 assert.NoError(t, err, "Ran without failure") 155 assert.Equal(t, "$ user-proj-value", expanded, "Expanded simple constant") 156 157 expanded, err = project.ExpandFromProject("$ $secrets.project.proj-secret", pj) 158 assert.NoError(t, err, "Ran without failure") 159 assert.Equal(t, "$ proj-value", expanded, "Expanded simple constant") 160 } 161 162 func TestExpandProjectAlternateSyntax(t *testing.T) { 163 prj := loadProject(t) 164 165 expanded, err := project.ExpandFromProject("${project.name()}", prj) 166 assert.NoError(t, err, "Ran without failure") 167 assert.Equal(t, "general", expanded, "Expanded project variable") 168 } 169 170 func TestExpandProjectUnknownCategory(t *testing.T) { 171 prj := loadProject(t) 172 173 expanded, err := project.ExpandFromProject("$unknown.unknown", prj) 174 assert.NoError(t, err, "Ran without failure") 175 assert.Equal(t, "$unknown.unknown", expanded, "Didn't expand variable it doesnt own") 176 } 177 178 func TestExpandProjectInfiniteRecursion(t *testing.T) { 179 prj := loadProject(t) 180 181 _, err := project.ExpandFromProject("$scripts.recursive", prj) 182 require.Error(t, err, "Ran with failure") 183 assert.Contains(t, err.Error(), "Infinite recursion trying to expand variable", "Handled unknown category") 184 } 185 186 func TestExpandDashed(t *testing.T) { 187 projectFile := &projectfile.Project{} 188 contents := strings.TrimSpace(` 189 project: "https://platform.activestate.com/Expander/Dashed" 190 scripts: 191 - name: foo-bar 192 value: bar 193 `) 194 195 err := yaml.Unmarshal([]byte(contents), projectFile) 196 assert.Nil(t, err, "Unmarshalled YAML") 197 require.NoError(t, projectFile.Persist()) 198 prj, err := project.Get() 199 require.NoError(t, err) 200 201 expanded, err := project.ExpandFromProject("- $scripts.foo-bar -", prj) 202 assert.NoError(t, err, "Ran without failure") 203 assert.Equal(t, "- bar -", expanded) 204 projectfile.Reset() 205 } 206 207 func TestExpandScriptPath(t *testing.T) { 208 prj := loadProject(t) 209 210 expanded, err := project.ExpandFromProject("$scripts.scriptPath", prj) 211 assert.NoError(t, err, "Ran without failure") 212 assert.True(t, strings.HasSuffix(expanded, language.Python3.Ext()), fmt.Sprintf("%s should have suffix %s", expanded, language.Python3.Ext())) 213 214 contents, err := fileutils.ReadFile(expanded) 215 require.NoError(t, err) 216 assert.Contains(t, string(contents), language.Python3.Header(), "Has Python3 header") 217 assert.Contains(t, string(contents), "scriptValue", "Contains intended script value") 218 } 219 220 func TestExpandScriptPathRecursive(t *testing.T) { 221 prj := loadProject(t) 222 223 expanded, err := project.ExpandFromProject("$scripts.scriptRecursive", prj) 224 assert.NoError(t, err, "Ran without failure") 225 226 contents, err := fileutils.ReadFile(expanded) 227 require.NoError(t, err) 228 assert.NotContains(t, contents, "$scripts.scriptRecursive.path()") 229 } 230 231 func TestExpandBashScriptPath(t *testing.T) { 232 prj := loadProject(t) 233 script := prj.ScriptByName("bashScriptPath") 234 require.NotNil(t, script, "bashScriptPath script does not exist") 235 value, err := script.Value() 236 require.NoError(t, err) 237 assert.Contains(t, value, "/pythonScript") // assert bash backslashes, even on Windows 238 }