diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 697df5d..850f00f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,10 @@ jobs: - uses: actions/setup-go@v5 with: go-version: 1.23.1 - - run: go test -v ./... + - name: Install slangroom-exec + run: make build + - name: Run test + run: go test -v ./... release: runs-on: ubuntu-latest needs: test diff --git a/.gitignore b/.gitignore index 047b081..1c49cb5 100644 --- a/.gitignore +++ b/.gitignore @@ -26,5 +26,6 @@ !Makefile !contracts/**/* +!vendor/modules.txt # ...even if they are in subdirectories !*/ diff --git a/.golangci.yml b/.golangci.yml index fe454a7..02bde43 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -15,7 +15,7 @@ issues: linters: enable: - bodyclose - - exportloopref + - copyloopvar - goimports - gosec - nilerr diff --git a/cmd/cli.go b/cmd/cli.go index f4721a4..145134c 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -4,6 +4,7 @@ import ( "embed" "encoding/json" "fmt" + "log" "os" "path/filepath" "strings" @@ -18,11 +19,9 @@ import ( var contracts embed.FS var daemon bool -var extension string = ".slang" - -// rootCmd is the base command when called without any subcommands. -// It initializes the command tree and is responsible for starting the Gemini CLI. +var extension = ".slang" +// runCmd is the base command when called without any subcommands. func Execute(embeddedFiles embed.FS) { contracts = embeddedFiles @@ -31,7 +30,7 @@ func Execute(embeddedFiles embed.FS) { // Execute the root command if err := runCmd.Execute(); err != nil { - fmt.Println(err) + log.Println(err) os.Exit(1) } } @@ -48,7 +47,7 @@ var listCmd = &cobra.Command{ Use: "list [folder]", Short: "List all contracts in the folder or list embedded contracts if no folder is specified", Args: cobra.MaximumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { + Run: func(_ *cobra.Command, args []string) { if len(args) == 0 { // If no folder argument is provided, list embedded files fmt.Println("Listing embedded slangroom files:") @@ -56,7 +55,7 @@ var listCmd = &cobra.Command{ // If the daemon flag is set, start the HTTP server if daemon { if err := httpserver.StartHTTPServer("contracts", "", nil); err != nil { - fmt.Printf("Failed to start HTTP server: %v\n", err) + log.Printf("Failed to start HTTP server: %v\n", err) os.Exit(1) } return @@ -65,7 +64,7 @@ var listCmd = &cobra.Command{ fmt.Printf("Found file: %s (Path: %s)\n", strings.TrimSuffix(file.FileName, extension), file.Path) }) if err != nil { - fmt.Println("Error:", err) + log.Println("Error:", err) } } else { // If a folder argument is provided, list files in that folder @@ -74,7 +73,7 @@ var listCmd = &cobra.Command{ if daemon { if err := httpserver.StartHTTPServer(folder, "", nil); err != nil { - fmt.Printf("Failed to start HTTP server: %v\n", err) + log.Printf("Failed to start HTTP server: %v\n", err) os.Exit(1) } return @@ -85,7 +84,7 @@ var listCmd = &cobra.Command{ fmt.Printf("Found file: %s (Path: %s)\n", strings.TrimSuffix(file.FileName, extension), file.Path) }) if err != nil { - fmt.Println("Error:", err) + log.Println("Error:", err) } } }, @@ -128,19 +127,25 @@ func addEmbeddedFileCommands() { metadataPath := filepath.Join(file.Dir, strings.TrimSuffix(file.FileName, filepath.Ext(file.FileName))+".metadata.json") metadata, err := utils.LoadMetadata(&contracts, metadataPath) - if err == nil { + if err != nil && err.Error() != "metadata file not found" { + log.Printf("WARNING: error in metadata for contracts: %s\n", fileCmdName) + log.Println(err) + } else if err == nil { isMetadata = true // Set command description fileCmd.Short = metadata.Description - argContents, flagContents = utils.ConfigureArgumentsAndFlags(fileCmd, metadata) - fileCmd.PreRunE = func(cmd *cobra.Command, args []string) error { + argContents, flagContents, err = utils.ConfigureArgumentsAndFlags(fileCmd, metadata) + if err != nil { + log.Printf("Failed to set arguments or flags: %v\n", err) + os.Exit(1) + } + fileCmd.PreRunE = func(cmd *cobra.Command, _ []string) error { return utils.ValidateFlags(cmd, flagContents, argContents) } - } // Set the command's run function - fileCmd.Run = func(cmd *cobra.Command, args []string) { + fileCmd.Run = func(_ *cobra.Command, args []string) { runFileCommand(file, args, metadata, argContents, isMetadata, relativePath) } @@ -149,7 +154,7 @@ func addEmbeddedFileCommands() { }) if err != nil { - fmt.Println("Error adding embedded file commands:", err) + log.Println("Error adding embedded file commands:", err) } } @@ -159,7 +164,7 @@ var runCmd = &cobra.Command{ Use: "gemini [folder]", Short: "Execute a specific slangroom file in a dynamically specified folder", Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { + Run: func(_ *cobra.Command, args []string) { folder := args[0] filePath := filepath.Join(args[1:]...) input := slangroom.SlangroomInput{} @@ -174,12 +179,17 @@ var runCmd = &cobra.Command{ if relativeFilePath == filePath { found = true input.Contract = file.Content - utils.LoadAdditionalData(filepath.Join(folder, file.Dir), filename, &input) + err := utils.LoadAdditionalData(filepath.Join(folder, file.Dir), filename, &input) + + if err != nil { + log.Printf("Failed to load data from JSON file: %v\n", err) + os.Exit(1) + } // Start HTTP server if daemon flag is set if daemon { if err := httpserver.StartHTTPServer(folder, filePath, nil); err != nil { - fmt.Printf("Failed to start HTTP server: %v\n", err) + log.Printf("Failed to start HTTP server: %v\n", err) os.Exit(1) } return @@ -188,8 +198,8 @@ var runCmd = &cobra.Command{ // Execute the slangroom file res, err := slangroom.Exec(input) if err != nil { - fmt.Println("Error:", err) - fmt.Println(res.Logs) + log.Println("Error:", err) + log.Println(res.Logs) } else { fmt.Println(res.Output) } @@ -197,12 +207,12 @@ var runCmd = &cobra.Command{ }) if err != nil { - fmt.Println("Error:", err) + log.Println("Error:", err) return } if !found { - fmt.Printf("File %s not found in folder %s\n", filePath, folder) + log.Printf("File %s not found in folder %s\n", filePath, folder) } }, } @@ -210,7 +220,11 @@ var runCmd = &cobra.Command{ func runFileCommand(file fouter.SlangFile, args []string, metadata *utils.CommandMetadata, argContents map[string]string, isMetadata bool, relativePath string) { input := slangroom.SlangroomInput{Contract: file.Content} filename := strings.TrimSuffix(file.FileName, extension) - utils.LoadAdditionalData(file.Dir, filename, &input) + err := utils.LoadAdditionalData(file.Dir, filename, &input) + if err != nil { + log.Printf("Failed to load data from JSON file: %v\n", err) + os.Exit(1) + } if isMetadata { for i, arg := range args { if i < len(metadata.Arguments) { @@ -220,12 +234,12 @@ func runFileCommand(file fouter.SlangFile, args []string, metadata *utils.Comman // Convert argContents to JSON if needed jsonData, err := json.Marshal(argContents) if err != nil { - fmt.Println("Error encoding arguments to JSON:", err) + log.Println("Error encoding arguments to JSON:", err) return } if input.Data != "" { if input.Data, err = utils.MergeJSON(input.Data, string(jsonData)); err != nil { - fmt.Println("Error encoding arguments to JSON:", err) + log.Println("Error encoding arguments to JSON:", err) os.Exit(1) } } else { @@ -235,7 +249,7 @@ func runFileCommand(file fouter.SlangFile, args []string, metadata *utils.Comman // Start HTTP server if daemon flag is set if daemon { if err := httpserver.StartHTTPServer("contracts", relativePath, &input); err != nil { - fmt.Printf("Failed to start HTTP server: %v\n", err) + log.Printf("Failed to start HTTP server: %v\n", err) os.Exit(1) } return @@ -244,8 +258,8 @@ func runFileCommand(file fouter.SlangFile, args []string, metadata *utils.Comman // Execute the slangroom file res, err := slangroom.Exec(input) if err != nil { - fmt.Println("Error:", err) - fmt.Println(res.Logs) + log.Println("Error:", err) + log.Println(res.Logs) } else { fmt.Println(res.Output) } diff --git a/cmd/cli_test.go b/cmd/cli_test.go index 3f34cc2..f609067 100644 --- a/cmd/cli_test.go +++ b/cmd/cli_test.go @@ -10,7 +10,6 @@ import ( ) func TestListCommand(t *testing.T) { - // Test listing embedded files t.Run("List Embedded Files", func(t *testing.T) { // Prepare the command without any arguments @@ -31,11 +30,11 @@ func TestListCommand(t *testing.T) { if !contains(output, "Listing embedded slangroom files:") { t.Errorf("Expected output to contain 'Listing embedded slangroom files:', got %v", output) } - if !contains(output, "Found file: hello.slang") { - t.Errorf("Expected output to contain 'Found file: hello.slang', got %v", output) + if !contains(output, "Found file: hello") { + t.Errorf("Expected output to contain 'Found file: hello', got %v", output) } - if !contains(output, "Found file: test.slang") { - t.Errorf("Expected output to contain 'Found file: test.slang', got %v", output) + if !contains(output, "Found file: test") { + t.Errorf("Expected output to contain 'Found file: test', got %v", output) } }) @@ -45,12 +44,12 @@ func TestListCommand(t *testing.T) { tempDir := t.TempDir() // Create sample slangroom files for the folder - err := os.WriteFile(filepath.Join(tempDir, "file1.slang"), []byte("contract content 1"), 0644) + err := os.WriteFile(filepath.Join(tempDir, "file1.slang"), []byte("contract content 1"), 0600) if err != nil { t.Fatalf("Failed to create file1.slang: %v", err) } - err = os.WriteFile(filepath.Join(tempDir, "file2.slang"), []byte("contract content 2"), 0644) + err = os.WriteFile(filepath.Join(tempDir, "file2.slang"), []byte("contract content 2"), 0600) if err != nil { t.Fatalf("Failed to create file2.slang: %v", err) } @@ -69,14 +68,14 @@ func TestListCommand(t *testing.T) { // Verify the output for files in the folder output := out.String() - if !contains(output, "Listing slangroom files in folder:") { - t.Errorf("Expected output to contain 'Listing slangroom files in folder:', got %v", output) + if !contains(output, "Listing contracts in folder:") { + t.Errorf("Expected output to contain 'Listing contracts in folder:', got %v", output) } - if !contains(output, "Found file: file1.slang") { - t.Errorf("Expected output to contain 'Found file: file1.slang', got %v", output) + if !contains(output, "Found file: file1") { + t.Errorf("Expected output to contain 'Found file: file1', got %v", output) } - if !contains(output, "Found file: file2.slang") { - t.Errorf("Expected output to contain 'Found file: file2.slang', got %v", output) + if !contains(output, "Found file: file2") { + t.Errorf("Expected output to contain 'Found file: file2', got %v", output) } }) } @@ -88,7 +87,7 @@ func TestRunCommand(t *testing.T) { // Write a sample slangroom file in the filesystem directory content := `Given nothing Then print the string 'Hello'` - err := os.WriteFile(filepath.Join(tempDir, "test.slang"), []byte(content), 0644) + err := os.WriteFile(filepath.Join(tempDir, "test.slang"), []byte(content), 0600) if err != nil { t.Fatalf("Failed to create test.slang: %v", err) } diff --git a/cmd/httpserver/http.go b/cmd/httpserver/http.go index a9be649..37d689c 100644 --- a/cmd/httpserver/http.go +++ b/cmd/httpserver/http.go @@ -7,6 +7,7 @@ import ( "net/http" "path/filepath" "strings" + "time" "github.com/ForkbombEu/fouter" slangroom "github.com/dyne/slangroom-exec/bindings/go" @@ -19,39 +20,60 @@ var port string // listSlangFilesHandler returns an HTTP handler that lists available slangroom files in the provided directories. // It generates an HTML page displaying the slangroom files for each directory. func listSlangFilesHandler(slangFiles map[string][]string) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/html") - fmt.Fprintln(w, "

Available contract files:

") - + _, err := fmt.Fprintln(w, "

Available contract files:

") + if err != nil { + fmt.Printf("Failed to write http page: %v\n", err) + } for dir, files := range slangFiles { - fmt.Fprintf(w, "

Directory: %s

") + if err != nil { + fmt.Printf("Failed to write http page: %v\n", err) + } } - fmt.Fprintln(w, "") + _, err = fmt.Fprintln(w, "") + if err != nil { + fmt.Printf("Failed to write http page: %v\n", err) + } } } // slangFilePageHandler returns an HTTP handler that displays the contents of a single slangroom file. // It generates an HTML page showing the content of the file along with a button to execute it. func slangFilePageHandler(file fouter.SlangFile) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, _ *http.Request) { name := strings.TrimSuffix(file.FileName, filepath.Ext(file.FileName)) w.Header().Set("Content-Type", "text/html") - fmt.Fprintf(w, "

%s

%s
", name, file.Content) + _, err := fmt.Fprintf(w, "

%s

%s
", name, file.Content) + if err != nil { + fmt.Printf("Failed to write http page: %v\n", err) + } relativePath := filepath.Join(file.Dir, name) - fmt.Fprintf(w, `
+ _, err = fmt.Fprintf(w, `
`, relativePath, filepath.Base(file.Path)) - - fmt.Fprintln(w, "") + if err != nil { + fmt.Printf("Failed to write http page: %v\n", err) + } + _, err = fmt.Fprintln(w, "") + if err != nil { + fmt.Printf("Failed to write http page: %v\n", err) + } } } @@ -65,7 +87,6 @@ func executeSlangFileHandler(file fouter.SlangFile, baseFolder string, execution } var input slangroom.SlangroomInput if executionData == nil { - input.Contract = file.Content // Load additional data from JSON files with matching names @@ -122,7 +143,7 @@ func StartHTTPServer(folder string, filePath string, input *slangroom.SlangroomI port = "3000" listener, err := net.Listen("tcp", ":"+port) if err != nil { - listener, err = net.Listen("tcp", ":0") + listener, err = net.Listen("tcp", "localhost:0") if err != nil { return fmt.Errorf("error finding an open port: %v", err) } @@ -135,8 +156,13 @@ func StartHTTPServer(folder string, filePath string, input *slangroom.SlangroomI } else { fmt.Printf("Access the contract files at: http://localhost:%s/slang/\n", port) } - - if err := http.Serve(listener, r); err != nil { + server := &http.Server{ + Handler: r, + ReadTimeout: 10 * time.Second, + WriteTimeout: 10 * time.Second, + IdleTimeout: 30 * time.Second, + } + if err := server.Serve(listener); err != nil { return fmt.Errorf("error starting HTTP server: %v", err) } diff --git a/cmd/utils/utils.go b/cmd/utils/utils.go index 5818d8e..808a50a 100644 --- a/cmd/utils/utils.go +++ b/cmd/utils/utils.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "io" + "log" "os" "path/filepath" "strings" @@ -13,6 +14,7 @@ import ( "github.com/spf13/cobra" ) +// CommandMetadata contains the data from the metadata.json type CommandMetadata struct { Description string `json:"description"` Arguments []struct { @@ -30,6 +32,7 @@ type CommandMetadata struct { } `json:"options"` } +// FlagData contains the necessary data for a given flag type FlagData struct { Choices []string Env []string @@ -50,7 +53,6 @@ func LoadAdditionalData(path string, filename string, input *slangroom.Slangroom } for _, field := range fields { - jsonFile := filepath.Join(path, fmt.Sprintf("%s.%s.json", filename, field.fieldName)) if _, err := os.Stat(jsonFile); os.IsNotExist(err) { continue // Skip if file does not exist @@ -92,9 +94,15 @@ func LoadMetadata(folder *embed.FS, path string) (*CommandMetadata, error) { } if err != nil { + if os.IsNotExist(err) { + // Specific error message for file not found + return nil, fmt.Errorf("metadata file not found") + } + // Generic error for other types of failures return nil, fmt.Errorf("failed to open metadata file: %w", err) } - defer file.Close() + + defer checks(file.Close) var metadata CommandMetadata if err := json.NewDecoder(file).Decode(&metadata); err != nil { @@ -127,7 +135,7 @@ func GetArgumentNames(arguments []struct { return names } -func IsValidChoice(value string, choices []string) bool { +func isValidChoice(value string, choices []string) bool { if value == "" { return true } @@ -139,6 +147,7 @@ func IsValidChoice(value string, choices []string) bool { return false } +// MergeJSON combines two JSON strings into one, with keys from the second JSON overwriting those in the first. func MergeJSON(json1, json2 string) (string, error) { var map1, map2 map[string]interface{} @@ -163,7 +172,7 @@ func MergeJSON(json1, json2 string) (string, error) { } // ConfigureArgumentsAndFlags configures the command's arguments and flags based on provided metadata, -func ConfigureArgumentsAndFlags(fileCmd *cobra.Command, metadata *CommandMetadata) (map[string]string, map[string]FlagData) { +func ConfigureArgumentsAndFlags(fileCmd *cobra.Command, metadata *CommandMetadata) (map[string]string, map[string]FlagData, error) { argContents := make(map[string]string) flagContents := make(map[string]FlagData) @@ -172,7 +181,7 @@ func ConfigureArgumentsAndFlags(fileCmd *cobra.Command, metadata *CommandMetadat for _, arg := range metadata.Arguments { argContents[NormalizeArgumentName(arg.Name)] = "" if strings.HasPrefix(arg.Name, "<") && strings.HasSuffix(arg.Name, ">") { - requiredArgs += 1 + requiredArgs++ } else { fileCmd.Args = cobra.MaximumNArgs(len(metadata.Arguments)) } @@ -216,7 +225,10 @@ func ConfigureArgumentsAndFlags(fileCmd *cobra.Command, metadata *CommandMetadat fileCmd.Flags().StringP(flag, shorthand, "", description) } if opt.Hidden { - fileCmd.Flags().MarkHidden(flag) + err := fileCmd.Flags().MarkHidden(flag) + if err != nil { + return nil, nil, fmt.Errorf("error hiding a flag: %v", err) + } } flagContents[flag] = FlagData{ @@ -230,10 +242,10 @@ func ConfigureArgumentsAndFlags(fileCmd *cobra.Command, metadata *CommandMetadat } } - return argContents, flagContents + return argContents, flagContents, nil } -// validateFlags checks if the flag values passed to the command match any predefined choices and +// ValidateFlags checks if the flag values passed to the command match any predefined choices and // sets corresponding environment variables if specified in the flag's metadata. If a flag's value // does not match an available choice, an error is returned. func ValidateFlags(cmd *cobra.Command, flagContents map[string]FlagData, argContents map[string]string) error { @@ -249,16 +261,13 @@ func ValidateFlags(cmd *cobra.Command, flagContents map[string]FlagData, argCont return fmt.Errorf("error reading value for flag %s from stdin: %w", flag, err) } } else if value != "" { - fileContent, err = os.ReadFile(value) if err != nil { return fmt.Errorf("failed to read file at path %s: %w", value, err) } - } value = strings.TrimSpace(string(fileContent)) } - if value == "" && len(content.Env) > 0 { // Try reading the value from the environment variables for _, envVar := range content.Env { @@ -272,9 +281,18 @@ func ValidateFlags(cmd *cobra.Command, flagContents map[string]FlagData, argCont if value != "" { argContents[flag] = value } - if (content.Choices != nil) && !IsValidChoice(value, content.Choices) { + if (content.Choices != nil) && !isValidChoice(value, content.Choices) { return fmt.Errorf("invalid input '%s' for flag: %s. Valid choices are: %v", value, flag, content.Choices) } } return nil } + +// a functionfor defer error handling +func checks(fs ...func() error) { + for i := len(fs) - 1; i >= 0; i-- { + if err := fs[i](); err != nil { + log.Println("Error::", err) + } + } +} diff --git a/cmd/utils/utils_test.go b/cmd/utils/utils_test.go index 5a95561..b6440ad 100644 --- a/cmd/utils/utils_test.go +++ b/cmd/utils/utils_test.go @@ -72,7 +72,7 @@ func TestLoadAdditionalData(t *testing.T) { var createdFiles []string for filename, content := range tt.files { filePath := filepath.Join(tempDir, filename) - err := os.WriteFile(filePath, []byte(content), 0644) + err := os.WriteFile(filePath, []byte(content), 0600) if err != nil { t.Fatalf("Failed to create file: %v", err) } @@ -152,7 +152,6 @@ func TestValidateJSON(t *testing.T) { } func TestLoadMetadata(t *testing.T) { - sampleMetadata := CommandMetadata{ Description: "Test description", Arguments: []struct { @@ -186,7 +185,7 @@ func TestLoadMetadata(t *testing.T) { t.Fatalf("Failed to marshal sample metadata: %v", err) } - if err := os.WriteFile(metadataPath, fileContent, 0644); err != nil { + if err := os.WriteFile(metadataPath, fileContent, 0600); err != nil { t.Fatalf("Failed to write metadata file: %v", err) } @@ -279,7 +278,10 @@ func TestConfigureArgumentsAndFlags(t *testing.T) { }, } - args, flags := ConfigureArgumentsAndFlags(cmd, metadata) + args, flags, err := ConfigureArgumentsAndFlags(cmd, metadata) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } if len(args) != 2 || len(flags) != 1 { t.Errorf("Expected 2 arguments and 1 flag, got %d arguments and %d flags", len(args), len(flags)) @@ -320,12 +322,19 @@ func TestValidateFlags(t *testing.T) { argContents := map[string]string{} // Test for valid choice and check environment variable setting - cmd.Flags().Set("flag1", "opt1") - cmd.Flags().Set("flag2", "opt2") - - os.Setenv("TEST_FLAG_ENV_VAR", "test") - - err := ValidateFlags(cmd, flagContents, argContents) + err := cmd.Flags().Set("flag1", "opt1") + if err != nil { + t.Errorf("Unexpected error setting test flag: %v", err) + } + err = cmd.Flags().Set("flag2", "opt2") + if err != nil { + t.Errorf("Unexpected error setting test flag: %v", err) + } + err = os.Setenv("TEST_FLAG_ENV_VAR", "test") + if err != nil { + t.Errorf("Unexpected error setting test env variable: %v", err) + } + err = ValidateFlags(cmd, flagContents, argContents) if err != nil { t.Errorf("Expected no error, got: %v", err) } @@ -341,8 +350,7 @@ func TestValidateFlags(t *testing.T) { if err != nil { t.Fatalf("error creating pipe: %v", err) } - defer r.Close() - defer w.Close() + defer checks(r.Close) originalStdin := os.Stdin defer func() { os.Stdin = originalStdin }() @@ -352,10 +360,12 @@ func TestValidateFlags(t *testing.T) { if err != nil { t.Errorf("Error writing to stdin pipe: %v", err) } - w.Close() - - cmd.Flags().Set("fileFlag", "-") + checks(w.Close) + err = cmd.Flags().Set("fileFlag", "-") + if err != nil { + t.Errorf("Unexpected error setting test flag: %v", err) + } err = ValidateFlags(cmd, flagContents, argContents) if err != nil { t.Errorf("Expected no error for stdin read, got: %v", err) @@ -370,18 +380,27 @@ func TestValidateFlags(t *testing.T) { if err != nil { t.Fatalf("error creating temp file: %v", err) } - defer os.Remove(tmpFile.Name()) - + defer func() { + err := os.Remove(tmpFile.Name()) + if err != nil { + t.Fatalf("error removing temp file: %v", err) + } + }() // Write some content to the file _, err = tmpFile.Write([]byte("content from file")) if err != nil { t.Fatalf("error writing to temp file: %v", err) } - tmpFile.Close() + err = tmpFile.Close() + if err != nil { + t.Fatalf("error creating temp file: %v", err) + } // Set the fileFlag to the path of the temporary file - cmd.Flags().Set("fileFlag", tmpFile.Name()) - + err = cmd.Flags().Set("fileFlag", tmpFile.Name()) + if err != nil { + t.Errorf("Unexpected error setting test flag: %v", err) + } err = ValidateFlags(cmd, flagContents, argContents) if err != nil { t.Errorf("Expected no error for file read, got: %v", err) @@ -390,10 +409,12 @@ func TestValidateFlags(t *testing.T) { t.Errorf("Expected 'content from file' for fileFlag, got: %v", argContents["fileFlag"]) } // Test for invalid choice - cmd.Flags().Set("flag2", "invalid_choice") + err = cmd.Flags().Set("flag2", "invalid_choice") + if err != nil { + t.Errorf("Unexpected error setting test flag: %v", err) + } err = ValidateFlags(cmd, flagContents, argContents) if err == nil { t.Errorf("Expected error for invalid flag choice, got: nil") } - } diff --git a/examples_test.go b/examples_test.go index 6cbe066..a84fd7e 100644 --- a/examples_test.go +++ b/examples_test.go @@ -3,13 +3,13 @@ package main import ( "bytes" "fmt" + "log" "os" "os/exec" ) // Example of using the list command in a folder with slang files. func Example_listCmd() { - // Prepare the command cmd := exec.Command("go", "run", "main.go", "list", "contracts") @@ -20,7 +20,7 @@ func Example_listCmd() { // Check for errors if err != nil { - fmt.Println("Command execution failed:", err) + log.Println("Command execution failed:", err) return } @@ -29,18 +29,17 @@ func Example_listCmd() { fmt.Print(output) // Output: - // Listing slangroom files in folder: contracts - // Found file: env.slang (Path: contracts/test/env.slang) - // Found file: execute_zencode.slang (Path: contracts/test/execute_zencode.slang) - // Found file: hello.slang (Path: contracts/test/hello.slang) - // Found file: param.slang (Path: contracts/test/param.slang) - // Found file: stdin.slang (Path: contracts/test/stdin.slang) - // Found file: test.slang (Path: contracts/test/test.slang) + // Listing contracts in folder: contracts + // Found file: env (Path: contracts/test/env.slang) + // Found file: execute_zencode (Path: contracts/test/execute_zencode.slang) + // Found file: hello (Path: contracts/test/hello.slang) + // Found file: param (Path: contracts/test/param.slang) + // Found file: stdin (Path: contracts/test/stdin.slang) + // Found file: test (Path: contracts/test/test.slang) } // Example of using the run command to execute a specific slangroom file. func Example_runCmd() { - // Prepare the command to run the slang file cmd := exec.Command("go", "run", "main.go", "test", "hello") @@ -51,7 +50,7 @@ func Example_runCmd() { // Check for errors if err != nil { - fmt.Println("Command execution failed:", err) + log.Println("Command execution failed:", err) return } @@ -62,7 +61,6 @@ func Example_runCmd() { // {"output":["Hello_from_embedded!"]} } func Example_runCmdWithExtraData() { - // Prepare the command to run the slang file cmd := exec.Command("go", "run", "main.go", "test", "execute_zencode") @@ -73,7 +71,7 @@ func Example_runCmdWithExtraData() { // Check for errors if err != nil { - fmt.Println("Command execution failed:", err) + log.Println("Command execution failed:", err) return } @@ -85,7 +83,6 @@ func Example_runCmdWithExtraData() { } func Example_runCmdWithParam() { - // Prepare the command to run the slang file cmd := exec.Command("go", "run", "main.go", "test", "param", "username", "-n", "testname", "-D", "small") @@ -96,7 +93,7 @@ func Example_runCmdWithParam() { // Check for errors if err != nil { - fmt.Println("Command execution failed:", err) + log.Println("Command execution failed:", err) return } @@ -108,18 +105,21 @@ func Example_runCmdWithParam() { } func Example_runCmdWithEnvVariable() { - // Prepare the command to run the slang file cmd := exec.Command("go", "run", "main.go", "test", "env") - os.Setenv("FILE_CONTENT", "The enviroment variable is set correctly") + err := os.Setenv("FILE_CONTENT", "The enviroment variable is set correctly") + if err != nil { + log.Println("Command execution failed:", err) + return + } // Capture the output var out bytes.Buffer cmd.Stdout = &out - err := cmd.Run() + err = cmd.Run() // Check for errors if err != nil { - fmt.Println("Command execution failed:", err) + log.Println("Command execution failed:", err) return } @@ -131,33 +131,32 @@ func Example_runCmdWithEnvVariable() { } func Example_runCmdWithStdinInput() { - // Prepare the command to run the slang file cmd1 := exec.Command("cat", "contracts/test/hello.txt") cmd2 := exec.Command("go", "run", "main.go", "test", "stdin") pipe, err := cmd1.StdoutPipe() if err != nil { - fmt.Println("Command execution failed:", err) + log.Println("Command execution failed:", err) } var out bytes.Buffer cmd2.Stdin = pipe cmd2.Stdout = &out // Step 4: Start cmd1 and cmd2 if err := cmd1.Start(); err != nil { - fmt.Println("Command execution failed:", err) + log.Println("Command execution failed:", err) } if err := cmd2.Start(); err != nil { - fmt.Println("Command execution failed:", err) + log.Println("Command execution failed:", err) } // Step 5: Wait for both commands to finish if err := cmd1.Wait(); err != nil { - fmt.Println("Command execution failed:", err) + log.Println("Command execution failed:", err) } if err := cmd2.Wait(); err != nil { - fmt.Println("Command execution failed:", err) + log.Println("Command execution failed:", err) } // Output the results @@ -168,7 +167,6 @@ func Example_runCmdWithStdinInput() { } func Example_runCmdWithFilePath() { - // Prepare the command to run the slang file cmd := exec.Command("go", "run", "main.go", "test", "stdin", "-f", "contracts/test/hello.txt") // Capture the output @@ -178,7 +176,7 @@ func Example_runCmdWithFilePath() { // Check for errors if err != nil { - fmt.Println("Command execution failed:", err) + log.Println("Command execution failed:", err) return } diff --git a/go.sum b/go.sum index 33ffcfa..c9fe4a6 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/ForkbombEu/fouter v0.0.0-20241022095749-0ee9674e39ba h1:ykq4une26auveGEHQUNZSMCgYp5O0WRI2hMoz9yoqto= -github.com/ForkbombEu/fouter v0.0.0-20241022095749-0ee9674e39ba/go.mod h1:2tDPOtHNr7Q/WFJh1Oy6xdMbFfj7oz3tgPNFMtHl7us= github.com/ForkbombEu/fouter v0.0.0-20241025081836-854f54912b1c h1:z4F130r2kpdNCzWOHBmL6wcZZ5gAQ1E3Qjf2f9Trjn4= github.com/ForkbombEu/fouter v0.0.0-20241025081836-854f54912b1c/go.mod h1:2tDPOtHNr7Q/WFJh1Oy6xdMbFfj7oz3tgPNFMtHl7us= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= diff --git a/vendor/modules.txt b/vendor/modules.txt new file mode 100644 index 0000000..916b9be --- /dev/null +++ b/vendor/modules.txt @@ -0,0 +1,18 @@ +# github.com/ForkbombEu/fouter v0.0.0-20241025081836-854f54912b1c +## explicit; go 1.22 +github.com/ForkbombEu/fouter +# github.com/dyne/slangroom-exec/bindings/go v0.0.0-20241017085658-fb538b02efa3 +## explicit; go 1.22 +github.com/dyne/slangroom-exec/bindings/go +# github.com/gorilla/mux v1.8.1 +## explicit; go 1.20 +github.com/gorilla/mux +# github.com/inconshreveable/mousetrap v1.1.0 +## explicit; go 1.18 +github.com/inconshreveable/mousetrap +# github.com/spf13/cobra v1.8.1 +## explicit; go 1.15 +github.com/spf13/cobra +# github.com/spf13/pflag v1.0.5 +## explicit; go 1.12 +github.com/spf13/pflag