(t *testing.T)
| 426 | } |
| 427 | |
| 428 | func TestFormatStepWithCommandAndEnvYAMLSafe(t *testing.T) { |
| 429 | t.Run("json env var is single-quoted for valid YAML", func(t *testing.T) { |
| 430 | stepLines := []string{" - name: Test step"} |
| 431 | env := map[string]string{ |
| 432 | "MY_JSON": `{"key":"value","nested":{"a":1}}`, |
| 433 | } |
| 434 | result := FormatStepWithCommandAndEnv(stepLines, "echo test", env) |
| 435 | output := strings.Join(result, "\n") |
| 436 | |
| 437 | // The JSON value must be single-quoted so YAML treats it as a string |
| 438 | if !strings.Contains(output, `MY_JSON: '{"key":"value","nested":{"a":1}}'`) { |
| 439 | t.Errorf("Expected single-quoted JSON in env, got:\n%s", output) |
| 440 | } |
| 441 | }) |
| 442 | |
| 443 | t.Run("github expression env var is not quoted", func(t *testing.T) { |
| 444 | stepLines := []string{" - name: Test step"} |
| 445 | env := map[string]string{ |
| 446 | "MY_TOKEN": "${{ secrets.TOKEN }}", |
| 447 | } |
| 448 | result := FormatStepWithCommandAndEnv(stepLines, "echo test", env) |
| 449 | output := strings.Join(result, "\n") |
| 450 | |
| 451 | // GitHub Actions expressions should not be wrapped in extra quotes |
| 452 | if !strings.Contains(output, "MY_TOKEN: ${{ secrets.TOKEN }}") { |
| 453 | t.Errorf("Expected unquoted github expression in env, got:\n%s", output) |
| 454 | } |
| 455 | }) |
| 456 | |
| 457 | t.Run("multi-line env var emitted as literal block scalar", func(t *testing.T) { |
| 458 | stepLines := []string{" - name: Test step"} |
| 459 | // Continuation lines have 4-space leading whitespace (as produced by goccy/go-yaml |
| 460 | // when parsing a >- block scalar with extra-indented continuation lines). |
| 461 | multiLineValue := "${{ secrets.PAT_1 != '' && secrets.PAT_1 ||\n secrets.PAT_2 != '' && secrets.PAT_2 ||\n secrets.PAT_3 }}" |
| 462 | env := map[string]string{ |
| 463 | "COPILOT_GITHUB_TOKEN": multiLineValue, |
| 464 | } |
| 465 | result := FormatStepWithCommandAndEnv(stepLines, "echo test", env) |
| 466 | output := strings.Join(result, "\n") |
| 467 | |
| 468 | // Multi-line value must be emitted as a literal block scalar |
| 469 | if !strings.Contains(output, " COPILOT_GITHUB_TOKEN: |") { |
| 470 | t.Errorf("Expected literal block scalar indicator, got:\n%s", output) |
| 471 | } |
| 472 | if !strings.Contains(output, " ${{ secrets.PAT_1 != '' && secrets.PAT_1 ||") { |
| 473 | t.Errorf("Expected first line of multi-line value, got:\n%s", output) |
| 474 | } |
| 475 | // Continuation lines have 4-space prefix preserved, so total indentation is 12+4=16 spaces. |
| 476 | if !strings.Contains(output, " secrets.PAT_3 }}") { |
| 477 | t.Errorf("Expected last line of multi-line value with preserved continuation indentation (16 spaces), got:\n%s", output) |
| 478 | } |
| 479 | }) |
| 480 | |
| 481 | t.Run("trailing newline in env var is trimmed", func(t *testing.T) { |
| 482 | stepLines := []string{" - name: Test step"} |
| 483 | env := map[string]string{ |
| 484 | "MY_TOKEN": "${{ secrets.TOKEN }}\n", |
| 485 | } |
nothing calls this directly
no test coverage detected