Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.claude/
CLAUDE.md
.pi/

# Test and coverage
coverage.out
Expand Down
40 changes: 36 additions & 4 deletions exprenv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,15 @@ func TestArgExprEnv_JSONSerialization(t *testing.T) {
t.Parallel()

env := zapscript.ArgExprEnv{
Platform: "mister",
Version: "2.0.0",
ScanMode: "hold",
Platform: "mister",
Version: "2.0.0",
ScanMode: "hold",
MediaPlaying: true,
MediaReady: true,
Hook: zapscript.ExprEnvHook{
Name: "startup",
FirstBootStart: true,
},
Device: zapscript.ExprEnvDevice{
Hostname: "mister",
OS: "linux",
Expand All @@ -43,7 +49,6 @@ func TestArgExprEnv_JSONSerialization(t *testing.T) {
Value: "**launch:snes/mario",
Data: "extra-data",
},
MediaPlaying: true,
ActiveMedia: zapscript.ExprEnvActiveMedia{
LauncherID: "retroarch",
SystemID: "snes",
Expand All @@ -63,6 +68,9 @@ func TestArgExprEnv_JSONSerialization(t *testing.T) {
assert.Contains(t, jsonStr, `"version"`, "should contain version field")
assert.Contains(t, jsonStr, `"scan_mode"`, "should contain scan_mode field")
assert.Contains(t, jsonStr, `"media_playing"`, "should contain media_playing field")
assert.Contains(t, jsonStr, `"media_ready"`, "should contain media_ready field")
assert.Contains(t, jsonStr, `"hook"`, "should contain hook field")
assert.Contains(t, jsonStr, `"first_boot_start"`, "should contain first_boot_start field")
assert.Contains(t, jsonStr, `"active_media"`, "should contain active_media field")
assert.Contains(t, jsonStr, `"last_scanned"`, "should contain last_scanned field")
assert.Contains(t, jsonStr, `"launcher_id"`, "should contain launcher_id field")
Expand All @@ -85,6 +93,11 @@ func TestArgExprEnv_JSONRoundTrip(t *testing.T) {
Version: "1.0.0",
ScanMode: "tap",
MediaPlaying: true,
MediaReady: true,
Hook: zapscript.ExprEnvHook{
Name: "startup",
FirstBootStart: true,
},
Device: zapscript.ExprEnvDevice{
Hostname: "testhost",
OS: "linux",
Expand Down Expand Up @@ -115,6 +128,9 @@ func TestArgExprEnv_JSONRoundTrip(t *testing.T) {
assert.Equal(t, original.Version, decoded.Version)
assert.Equal(t, original.ScanMode, decoded.ScanMode)
assert.Equal(t, original.MediaPlaying, decoded.MediaPlaying)
assert.Equal(t, original.MediaReady, decoded.MediaReady)
assert.Equal(t, original.Hook.Name, decoded.Hook.Name)
assert.Equal(t, original.Hook.FirstBootStart, decoded.Hook.FirstBootStart)
assert.Equal(t, original.Device.Hostname, decoded.Device.Hostname)
assert.Equal(t, original.LastScanned.ID, decoded.LastScanned.ID)
assert.Equal(t, original.ActiveMedia.Path, decoded.ActiveMedia.Path)
Expand Down Expand Up @@ -158,6 +174,22 @@ func TestExprEnvLaunching_JSONSerialization(t *testing.T) {
assert.Contains(t, jsonStr, `"launcher_id"`)
}

func TestExprEnvHook_JSONSerialization(t *testing.T) {
t.Parallel()

hook := zapscript.ExprEnvHook{
Name: "startup",
FirstBootStart: true,
}

jsonBytes, err := json.Marshal(hook)
require.NoError(t, err)

jsonStr := string(jsonBytes)
assert.Contains(t, jsonStr, `"name"`)
assert.Contains(t, jsonStr, `"first_boot_start"`)
}

// TestArgExprEnv_EmptyFieldsSerialization verifies that empty struct fields are serialized
// (no omitempty behavior) for consistent JSON structure in external scripts.
func TestArgExprEnv_EmptyFieldsSerialization(t *testing.T) {
Expand Down
10 changes: 10 additions & 0 deletions expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ type ExprEnvLaunching struct {
LauncherID string `expr:"launcher_id" json:"launcher_id"`
}

// ExprEnvHook represents hook context for expression evaluation.
//
//nolint:tagliatelle // JSON uses snake_case to match expression env naming
type ExprEnvHook struct {
Name string `expr:"name" json:"name"`
FirstBootStart bool `expr:"first_boot_start" json:"first_boot_start"`
}

//nolint:tagliatelle // JSON uses snake_case to match expression env naming
type ArgExprEnv struct {
ActiveMedia ExprEnvActiveMedia `expr:"active_media" json:"active_media"`
Expand All @@ -71,7 +79,9 @@ type ArgExprEnv struct {
Platform string `expr:"platform" json:"platform"`
Version string `expr:"version" json:"version"`
ScanMode string `expr:"scan_mode" json:"scan_mode"`
Hook ExprEnvHook `expr:"hook" json:"hook,omitempty"`
MediaPlaying bool `expr:"media_playing" json:"media_playing"`
MediaReady bool `expr:"media_ready" json:"media_ready"`
}

//nolint:tagliatelle // JSON uses snake_case to match expression env naming
Expand Down
20 changes: 20 additions & 0 deletions parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,21 @@ func TestPostProcess(t *testing.T) {
input: "something " + zapscript.TokExpStart + "true" + zapscript.TokExprEnd,
want: `something true`,
},
{
name: "test expression hook name",
input: zapscript.TokExpStart + "hook.name" + zapscript.TokExprEnd,
want: `startup`,
},
{
name: "test expression hook first boot start",
input: zapscript.TokExpStart + "hook.first_boot_start" + zapscript.TokExprEnd,
want: `true`,
},
{
name: "test expression media ready",
input: zapscript.TokExpStart + "media_ready" + zapscript.TokExprEnd,
want: `true`,
},
{
name: "bad return type",
input: zapscript.TokExpStart + "device" + zapscript.TokExprEnd,
Expand All @@ -422,7 +437,12 @@ func TestPostProcess(t *testing.T) {
Platform: "mister",
Version: "1.2.3",
MediaPlaying: true,
MediaReady: true,
ScanMode: "tap",
Hook: zapscript.ExprEnvHook{
Name: "startup",
FirstBootStart: true,
},
Device: zapscript.ExprEnvDevice{
Hostname: "test-device",
OS: "linux",
Expand Down
Loading