Skip to content

Commit 375aaf5

Browse files
mirkoCrobumirkoCrobu
andauthored
refactoring tests
Co-authored-by: mirkoCrobu <mirkocrobu@NB-0531.localdomain>
1 parent e71d54e commit 375aaf5

File tree

13 files changed

+173
-252
lines changed

13 files changed

+173
-252
lines changed
Lines changed: 72 additions & 252 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package generator
22

33
import (
4-
"flag"
4+
"bytes"
5+
"fmt"
6+
"io/fs"
57
"os"
68
"path/filepath"
9+
"sort"
710
"testing"
811

912
"github.com/arduino/go-paths-helper"
@@ -12,279 +15,96 @@ import (
1215
"github.com/arduino/arduino-app-cli/internal/orchestrator/app"
1316
)
1417

15-
var update = flag.Bool("update", false, "update golden files")
16-
17-
func TestGenerateSketch(t *testing.T) {
18-
19-
tempDir := t.TempDir()
20-
err := generateSketch(paths.New(tempDir))
21-
require.NoError(t, err, "generateSketch should run without errors")
18+
func TestGenerateApp(t *testing.T) {
19+
baseApp := app.AppDescriptor{
20+
Name: "test app all",
21+
Description: "test description.",
22+
Icon: "🚀",
23+
Ports: []int{8080, 9000, 90},
24+
}
2225

2326
testCases := []struct {
24-
filename string
27+
name string
28+
options Opts
29+
goldenPath string
2530
}{
26-
{filename: "sketch.ino"},
27-
{filename: "sketch.yaml"},
31+
{
32+
name: "generate complete app",
33+
options: None,
34+
goldenPath: "testdata/app-all.golden",
35+
},
36+
{
37+
name: "skip sketch",
38+
options: SkipSketch,
39+
goldenPath: "testdata/app-no-sketch.golden",
40+
},
41+
{
42+
name: "skip python",
43+
options: SkipPython,
44+
goldenPath: "testdata/app-no-python.golden",
45+
},
2846
}
2947

3048
for _, tc := range testCases {
31-
t.Run(tc.filename, func(t *testing.T) {
49+
t.Run(tc.name, func(t *testing.T) {
50+
tempDir := t.TempDir()
3251

33-
actualFilePath := filepath.Join(tempDir, "sketch", tc.filename)
34-
require.FileExists(t, actualFilePath)
35-
actualContent, err := os.ReadFile(actualFilePath)
52+
err := GenerateApp(paths.New(tempDir), baseApp, tc.options)
3653
require.NoError(t, err)
3754

38-
goldenFilePath := filepath.Join("testdata", tc.filename+".golden")
39-
40-
if *update {
41-
err := os.WriteFile(goldenFilePath, actualContent, 0600)
42-
require.NoError(t, err, "failed to update golden file: %s", goldenFilePath)
55+
if os.Getenv("UPDATE_GOLDEN") == "true" {
56+
t.Logf("UPDATE_GOLDEN=true: updating golden files in %s", tc.goldenPath)
57+
require.NoError(t, os.RemoveAll(tc.goldenPath))
58+
require.NoError(t, os.CopyFS(tempDir, os.DirFS(tc.goldenPath)))
59+
} else {
60+
compareFolders(t, paths.New(tempDir), paths.New(tc.goldenPath))
4361
}
44-
45-
expectedContent, err := os.ReadFile(goldenFilePath)
46-
require.NoError(t, err, "failed to read golden file: %s", goldenFilePath)
47-
48-
require.Equal(t, string(expectedContent), string(actualContent), "the generated content does not match the .golden file")
4962
})
5063
}
5164
}
5265

53-
func TestGeneratePython(t *testing.T) {
54-
tempDir := t.TempDir()
55-
56-
err := generatePython(paths.New(tempDir))
57-
require.NoError(t, err, "GeneratePython() should not return an error")
58-
59-
verifyPythonGenerated(t, tempDir)
60-
}
61-
62-
func TestGenerateReadme(t *testing.T) {
63-
tempDir := t.TempDir()
64-
testApp := app.AppDescriptor{
65-
Name: "test name",
66-
Description: "test description.",
67-
Icon: "🚀",
68-
Ports: []int{8080, 9000},
69-
}
70-
71-
err := generateReadme(paths.New(tempDir), testApp)
72-
require.NoError(t, err, "GenerateReadme() should not return an error")
73-
74-
verifyReadmeGenerated(t, testApp, tempDir)
75-
76-
}
77-
78-
func TestGenerateAppYaml(t *testing.T) {
79-
tempDir := t.TempDir()
80-
81-
testApp := app.AppDescriptor{
82-
Name: "test name",
83-
Description: "test description.",
84-
Icon: "🚀",
85-
Ports: []int{8080, 9000, 90},
86-
}
87-
88-
err := generateAppYaml(paths.New(tempDir), testApp)
89-
require.NoError(t, err, "GenerateAppYaml() should not return an error")
90-
91-
yamlPath := filepath.Join(tempDir, "app.yaml")
92-
require.FileExists(t, yamlPath, "The app.yaml file should exist")
93-
94-
actualContent, err := os.ReadFile(yamlPath)
95-
require.NoError(t, err, "Failed to read the generated app.yaml file")
96-
97-
contentString := string(actualContent)
98-
require.Contains(t, contentString, "name: test name", "The YAML should contain the correct name")
99-
require.Contains(t, contentString, `description: "test description."`, "The YAML should contain the correct description")
100-
require.Contains(t, contentString, "icon: 🚀", "The YAML should contain the correct icon")
101-
require.Contains(t, contentString, "ports: [8080, 9000, 90]", "The YAML should contain the correct ports list"+contentString)
102-
require.Contains(t, contentString, "bricks: []", "The YAML should contain an empty bricks list")
103-
104-
}
105-
106-
func TestGenerateAndParseAppYaml_RoundTrip(t *testing.T) {
107-
tempDir := t.TempDir()
108-
109-
testApp := app.AppDescriptor{
110-
Name: "test name",
111-
Description: "test description.",
112-
Icon: "🚀",
113-
Ports: []int{8080, 9000, 90},
114-
Bricks: []app.Brick{},
115-
}
116-
117-
err := generateAppYaml(paths.New(tempDir), testApp)
118-
require.NoError(t, err, "Step 1: Generation should not fail")
119-
120-
parsedApp, err := app.ParseDescriptorFile(paths.New(tempDir, "app.yaml"))
121-
require.NoError(t, err, "Parsing the generated file should not fail")
122-
require.Equal(t, testApp, parsedApp, "The parsed app should be identical to the original one")
123-
}
124-
125-
func TestGeneratCompleteApp(t *testing.T) {
126-
tempDir := t.TempDir()
127-
128-
testApp := app.AppDescriptor{
129-
Name: "test name",
130-
Description: "test description.",
131-
Icon: "🚀",
132-
Ports: []int{8080, 9000, 90},
133-
Bricks: []app.Brick{},
134-
}
135-
136-
var options Opts = 0
137-
138-
err := GenerateApp(paths.New(tempDir), testApp, options)
139-
require.NoError(t, err, "GenerateApp() should not return an error")
140-
141-
parsedApp, err := app.ParseDescriptorFile(paths.New(tempDir, "app.yaml"))
142-
require.NoError(t, err, "Parsing the generated file should not fail")
143-
require.Equal(t, testApp, parsedApp, "The parsed app should be identical to the original one")
144-
145-
verifyReadmeGenerated(t, testApp, tempDir)
146-
verifySketchGenerated(t, tempDir)
147-
verifyPythonGenerated(t, tempDir)
148-
149-
}
150-
151-
func TestGeneratAppSkipPython(t *testing.T) {
152-
tempDir := t.TempDir()
66+
func compareFolders(t *testing.T, actualPath, goldenPath *paths.Path) {
67+
t.Helper()
15368

154-
testApp := app.AppDescriptor{
155-
Name: "test name",
156-
Description: "test description.",
157-
Icon: "🚀",
158-
Ports: []int{8080, 9000, 90},
159-
Bricks: []app.Brick{},
69+
getFiles := func(root string) ([]string, error) {
70+
var files []string
71+
err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
72+
if err != nil {
73+
return err
74+
}
75+
if d.IsDir() {
76+
return nil
77+
}
78+
rel, err := filepath.Rel(root, path)
79+
if err != nil {
80+
return fmt.Errorf("failed to retrieve relative path for %q: %w", path, err)
81+
}
82+
files = append(files, rel)
83+
return nil
84+
})
85+
return files, err
16086
}
161-
var options Opts = 0
162-
options |= SkipPython
16387

164-
err := GenerateApp(paths.New(tempDir), testApp, options)
165-
require.NoError(t, err, "GenerateApp() should not return an error")
88+
goldenDir := goldenPath.String()
89+
actualDir := actualPath.String()
16690

167-
parsedApp, err := app.ParseDescriptorFile(paths.New(tempDir, "app.yaml"))
168-
require.NoError(t, err, "Parsing the generated file should not fail")
169-
require.Equal(t, testApp, parsedApp, "The parsed app should be identical to the original one")
91+
goldenFiles, err := getFiles(goldenDir)
92+
require.NoError(t, err, "failed reading golden dir")
17093

171-
verifyReadmeGenerated(t, testApp, tempDir)
172-
verifySketchGenerated(t, tempDir)
94+
actualFiles, err := getFiles(actualDir)
95+
require.NoError(t, err, "failed reading actual dir")
17396

174-
pythonPath := filepath.Join(tempDir, "python")
175-
require.NoDirExists(t, pythonPath, "The 'python' directory should NOT exist when skipped")
176-
}
97+
sort.Strings(goldenFiles)
98+
sort.Strings(actualFiles)
17799

178-
func TestGeneratAppSkipSketch(t *testing.T) {
179-
tempDir := t.TempDir()
100+
require.Equal(t, goldenFiles, actualFiles, "golden dir and actual dir should have the same structure")
180101

181-
testApp := app.AppDescriptor{
182-
Name: "test name",
183-
Description: "test description.",
184-
Icon: "🚀",
185-
Ports: []int{8080, 9000, 90},
186-
Bricks: []app.Brick{},
187-
}
188-
var options Opts = 0
189-
options |= SkipSketch
190-
191-
err := GenerateApp(paths.New(tempDir), testApp, options)
192-
require.NoError(t, err, "GenerateApp() should not return an error")
193-
194-
parsedApp, err := app.ParseDescriptorFile(paths.New(tempDir, "app.yaml"))
195-
require.NoError(t, err, "Parsing the generated file should not fail")
196-
require.Equal(t, testApp, parsedApp, "The parsed app should be identical to the original one")
102+
for _, relPath := range goldenFiles {
103+
goldenContent, err := os.ReadFile(filepath.Join(goldenDir, relPath))
104+
require.NoError(t, err, "failed reading golden file: %q", relPath)
105+
actualContent, err := os.ReadFile(filepath.Join(actualDir, relPath))
106+
require.NoError(t, err, "failed reading actual file: %s", relPath)
107+
require.True(t, bytes.Equal(goldenContent, actualContent), "content should be the same: %q", relPath)
197108

198-
verifyReadmeGenerated(t, testApp, tempDir)
199-
verifyPythonGenerated(t, tempDir)
200-
201-
sketchPath := filepath.Join(tempDir, "sketch")
202-
require.NoDirExists(t, sketchPath, "The 'sketch' directory should NOT exist when skipped")
203-
}
204-
205-
func TestGeneratAppSkipBoth(t *testing.T) {
206-
tempDir := t.TempDir()
207-
208-
testApp := app.AppDescriptor{
209-
Name: "test name",
210-
Description: "test description.",
211-
Icon: "🚀",
212-
Ports: []int{8080, 9000, 90},
213-
Bricks: []app.Brick{},
214109
}
215-
var options Opts = 0
216-
options |= SkipSketch
217-
options |= SkipPython
218-
219-
err := GenerateApp(paths.New(tempDir), testApp, options)
220-
require.NoError(t, err, "GenerateApp() should not return an error")
221-
222-
parsedApp, err := app.ParseDescriptorFile(paths.New(tempDir, "app.yaml"))
223-
require.NoError(t, err, "Parsing the generated file should not fail")
224-
require.Equal(t, testApp, parsedApp, "The parsed app should be identical to the original one")
225-
226-
verifyReadmeGenerated(t, testApp, tempDir)
227-
228-
pythonPath := filepath.Join(tempDir, "python")
229-
require.NoDirExists(t, pythonPath, "The 'python' directory should NOT exist when skipped")
230-
231-
sketchPath := filepath.Join(tempDir, "sketch")
232-
require.NoDirExists(t, sketchPath, "The 'sketch' directory should NOT exist when skipped")
233-
}
234-
235-
func verifySketchGenerated(t *testing.T, basePath string) {
236-
t.Helper()
237-
238-
sketchPath := filepath.Join(basePath, "sketch")
239-
inoPath := filepath.Join(sketchPath, "sketch.ino")
240-
yamlPath := filepath.Join(sketchPath, "sketch.yaml")
241-
242-
require.DirExists(t, sketchPath, "The 'sketch' directory should exist")
243-
require.FileExists(t, inoPath, "The 'sketch.ino' file should exist")
244-
require.FileExists(t, yamlPath, "The 'sketch.yaml' file should exist")
245-
246-
expectedInoContent, err := fsApp.ReadFile("app_template/sketch/sketch.ino")
247-
require.NoError(t, err)
248-
actualInoContent, err := os.ReadFile(inoPath)
249-
require.NoError(t, err)
250-
require.Equal(t, string(expectedInoContent), string(actualInoContent))
251-
252-
expectedYamlContent, err := fsApp.ReadFile("app_template/sketch/sketch.yaml")
253-
require.NoError(t, err)
254-
actualYamlContent, err := os.ReadFile(yamlPath)
255-
require.NoError(t, err)
256-
require.Equal(t, string(expectedYamlContent), string(actualYamlContent))
257-
}
258-
259-
func verifyPythonGenerated(t *testing.T, basePath string) {
260-
t.Helper()
261-
262-
pythonPath := filepath.Join(basePath, "python")
263-
mainPath := filepath.Join(pythonPath, "main.py")
264-
265-
require.DirExists(t, pythonPath, "The 'python' directory should exist")
266-
require.FileExists(t, mainPath, "The 'main.py' file should exist")
267-
268-
expectedMainContent, err := fsApp.ReadFile("app_template/python/main.py")
269-
require.NoError(t, err)
270-
actualMainContent, err := os.ReadFile(mainPath)
271-
require.NoError(t, err)
272-
require.Equal(t, string(expectedMainContent), string(actualMainContent))
273-
}
274-
275-
func verifyReadmeGenerated(t *testing.T, testApp app.AppDescriptor, basePath string) {
276-
t.Helper()
277-
278-
readmePath := filepath.Join(basePath, "README.md")
279-
require.FileExists(t, readmePath, "The README.md file should exist")
280-
281-
actualContent, err := os.ReadFile(readmePath)
282-
require.NoError(t, err, "Failed to read the generated README.md file")
283-
284-
contentString := string(actualContent)
285-
require.Contains(t, contentString, testApp.Name, "The README should contain the app name")
286-
require.Contains(t, contentString, testApp.Description, "The README should contain the app description")
287-
require.Contains(t, contentString, testApp.Icon, "The README should contain the app icon")
288-
require.Contains(t, contentString, "8080, 9000", "The README should contain the formatted port list")
289-
require.Contains(t, contentString, "Available application ports:", "The README should contain the static text for ports")
290110
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# 🚀 test app all
2+
3+
### Description
4+
5+
test description.
6+
7+
Available application ports: 8080, 9000, 90
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# app.yaml: The main configuration file for your Arduino App.
2+
# This file describes the application's metadata and properties.
3+
4+
# The user-visible name of the application.
5+
name: test app all
6+
7+
# A brief description of what the application does.
8+
description: "test description."
9+
10+
# The icon for the application, can be an emoji or a short string.
11+
icon: 🚀
12+
13+
# A list of network ports that the application exposes.
14+
# Example: [80, 443]
15+
ports: [8080, 9000, 90]
16+
17+
# A list of bricks used by this application.
18+
bricks: []
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
def main():
2+
print("Hello World!")
3+
4+
5+
if __name__ == "__main__":
6+
main()

0 commit comments

Comments
 (0)