github.com/ninadingole/gotest-ls@v0.0.3/main.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "flag" 8 "fmt" 9 "io" 10 "os" 11 12 "github.com/ninadingole/gotest-ls/pkg" 13 ) 14 15 var ( 16 // pretty is a flag to print the json output in a pretty format. 17 pretty = flag.Bool("p", false, "pretty print") 18 19 // file is a flag to specify a single file to parse. 20 file = flag.String("f", "", "file") 21 22 // help is a flag to print the help text. 23 help = flag.Bool("h", false, "help") 24 ) 25 26 var ( 27 // errPathIssue is the error message when the user provides both a file and a directory. 28 errPathIssue = errors.New("ERROR: cannot specify both a file and a directory") 29 30 // errNotAFile is the error message when the user provides a directory as a file. 31 errNotAFile = errors.New("ERROR: required file, provided directory") 32 33 // errUnknown is the error message when the error is not an expected type. 34 errUnknown = errors.New("ERROR: unknown error") 35 ) 36 37 func main() { 38 flag.Usage = printHelpText(flag.CommandLine.Output()) 39 flag.Parse() 40 41 err := Process(&args{ 42 file: *file, 43 dirs: flag.Args(), 44 help: *help, 45 pretty: *pretty, 46 }, os.Stdout) 47 if err != nil { 48 fmt.Println(err) 49 os.Exit(1) 50 } 51 } 52 53 // args is a struct that contains the arguments provided by the user. 54 type args struct { 55 file string 56 dirs []string 57 help bool 58 pretty bool 59 } 60 61 // Process is the main function that processes the arguments and prints the output. 62 func Process(proc *args, writer io.Writer) error { 63 if requiresHelp(proc) { 64 printHelpText(writer)() 65 66 return nil 67 } 68 69 if err := validateArgs(proc); err != nil { 70 return err 71 } 72 73 if proc.file != "" { 74 proc.dirs = append(proc.dirs, proc.file) 75 } 76 77 tests, err := pkg.List(proc.dirs) 78 if err != nil { 79 return fmt.Errorf("%s: %w", errUnknown, err) 80 } 81 82 if len(tests) == 0 { 83 _, _ = writer.Write([]byte("No tests found\n")) 84 85 return nil 86 } 87 88 marshal, err := json.Marshal(tests) 89 if err != nil { 90 return fmt.Errorf("%s: %w", errUnknown, err) 91 } 92 93 if proc.pretty { 94 if err := prettyPrint(marshal, writer); err != nil { 95 return err 96 } 97 } else { 98 _, _ = writer.Write(marshal) 99 } 100 101 return nil 102 } 103 104 // validateArgs validates the arguments provided by the user. 105 func validateArgs(args *args) error { 106 if args.file != "" && len(args.dirs) > 0 { 107 return errPathIssue 108 } 109 110 if args.file != "" { 111 stat, err := os.Stat(args.file) 112 if err != nil { 113 return fmt.Errorf("%s: %w", errUnknown, err) 114 } 115 116 if stat.IsDir() { 117 return errNotAFile 118 } 119 } 120 121 return nil 122 } 123 124 // requiresHelp checks if the user has requested help and not provided any required arguments. 125 func requiresHelp(proc *args) bool { 126 return (len(proc.dirs) == 0 && proc.file == "") || proc.help 127 } 128 129 // prettyPrint prints the given json in a pretty format. 130 func prettyPrint(data []byte, writer io.Writer) error { 131 var prettyJSON bytes.Buffer 132 133 err := json.Indent(&prettyJSON, data, "", "\t") 134 if err != nil { 135 return fmt.Errorf("%s: %w", errUnknown, err) 136 } 137 138 _, err = writer.Write(prettyJSON.Bytes()) 139 140 return err 141 } 142 143 // printHelpText prints the help text for the program. 144 func printHelpText(writer io.Writer) func() { 145 return func() { 146 writer := writer 147 148 _, _ = fmt.Fprintf(writer, `gotest-ls provides a list of all tests in a package or a file in JSON format. 149 150 Usage: 151 gotest-ls [flags] [directories] 152 153 Examples: 154 gotest-ls . 155 gotest-ls -p ./cmd 156 gotest-ls -p ./cmd ./pkg 157 gotest-ls -f ./pkg/random_test.go 158 gotest-ls -p -f ./pkg/random_test.go 159 160 Flags: 161 -f, --file string Path to a file, cannot be used with directories 162 -h, --help help for gotest-ls 163 -p, --pretty Pretty print the output in JSON format 164 `) 165 } 166 }