├── README.md ├── cmd ├── testomatic.go └── testomatic_test.go ├── example_failure.png ├── example_success.png ├── examples ├── go │ ├── .testomatic_all.yml │ └── .testomatic_single.yml └── php │ ├── .testomatic_all.yml │ ├── .testomatic_dir.yml │ └── .testomatic_single.yml ├── go.mod ├── go.sum ├── internal └── config │ ├── testdata │ └── testomatic.yml │ ├── yaml.go │ └── yaml_test.go ├── logo.png ├── main.go └── terminal_result.png /README.md: -------------------------------------------------------------------------------- 1 | ![testomatic logo](logo.png "testomatic logo") 2 | 3 | `testomatic` is a simple CLI tool which: 4 | 1. Watch test files thanks to a configurable regular expression which match the filenames 5 | 2. Execute a command of your choice when a file watched is saved (`go test` for example) 6 | 3. Display a desktop notification indicating if your command succeeded or failed (see [screenshots](https://github.com/Phantas0s/testomatic#screenshots)) 7 | 4. You can continue coding without switching windows / terminal to see if your test passed! 8 | 9 | ## Menu 10 | 11 | [Installation](#installation) 12 | [Configuration file](#configuration-file) 13 | [Examples](#examples) 14 | [Contributing](#contributing) 15 | [Disclaimer](#disclaimer) 16 | 17 | ## Installation 18 | 19 | You can find the releases of testomatic here: [Github releases](https://github.com/Phantas0s/testomatic/releases) 20 | 21 | Here an easy way to install testomatic on Linux using your favorite shell: 22 | 23 | ```shell 24 | cd /usr/local/bin && sudo curl -LO https://github.com/Phantas0s/testomatic/releases/download/v0.2.2/testomatic && sudo chmod 755 testomatic && cd - 25 | ``` 26 | 27 | You can now normally run `testomatic` from anywhere. 28 | 29 | ## Configuration file 30 | 31 | testomatic need a valid `yaml` configuration file. The best is to create a `.testomatic` file at the root of your project. 32 | 33 | You can as well use a different name for the configuration file: in that case you can run `testomatic --config my-config-name.yml` 34 | 35 | The configuration file can change the behavior of `testomatic` drastically to adapt it to your needs. Here the details: 36 | 37 | ```yaml 38 | watch: 39 | root: src/Tests 40 | regex: "Test.php" 41 | ignore: 42 | - vendor 43 | - cache 44 | ignore_hidden: true 45 | command: 46 | bin: docker-compose 47 | scope: current 48 | ignore_path: true 49 | abs: false 50 | options: 51 | - exec 52 | - "-T" 53 | - 'php' 54 | - bin/phpunit 55 | notification: 56 | disable: false 57 | img_failure: /home/superUser/.autotest/images/failure.png 58 | img_success: /home/superUser/.autotest/images/success.png 59 | regex_success: ok 60 | regex_failure: fail 61 | display_result: true 62 | ``` 63 | 64 | ### watch 65 | 66 | | attribute | value | value type | required | default | 67 | |---------------|------------------------------------------------------------------------------------------------------------------|------------|----------|---------| 68 | | root | The root folder where your tests are. `testomatic` will watch into this folder and every subfolders recursively. | string | yes | *empty* | 69 | | regex | Every filename matching this regex will be watched. | string | yes | *empty* | 70 | | ignore | Files or folders you want to ignore (vendor for example) | array | no | *empty* | 71 | | ignore_hidden | Any files or folders beginning by a point `.` won't be watched | boolean | no | `false` | 72 | 73 | ### command 74 | 75 | | attribute | value | value type | required | default | 76 | |-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------|----------|-----------| 77 | | bin | Path of the command line interface to execute | string | yes | *empty* | 78 | | scope | The command use the path of the saved file(`current`), the directory of the saved file (`dir`) or simply the root folder defined in `watch` (`all`) as argument | string - `current`, `dir`, `all` | yes | *empty* | 79 | | abs | Use the saved file absolute path instead of the relative one | boolean | no | `false` | 80 | | ignore_path | Doesn't use the path of the file saved as command line option | boolean | yes | `false` | 81 | | options | Options to pass to the command line interface | array | no | *empty* | 82 | 83 | ### notification 84 | 85 | | attribute | value | value type | required | default | 86 | |----------------|----------------------------------------------------------------------|------------|----------|---------| 87 | | disable | Disable the desktop notifications | boolean | no | false | 88 | | img_failure | Path of image displayed when test is failing | string | no | *empty* | 89 | | img_success | Path of the image displayed when test is a success | string | no | *empty* | 90 | | regex_success | If the result of the command match this regex, the test is a success | string | yes | *empty* | 91 | | regex_failure | If the result of the command match this regex, the test is a failure | string | yes | *empty* | 92 | | display_result | Display the return of the command in the notification box | boolean | no | false | 93 | 94 | 95 | ## Examples 96 | 97 | You will find in the folder `examples` tested configuration files for running `PHPUnit` and `go test`. 98 | I included in the `php` examples how to run tests in docker using `docker-compose` with or without notifications. 99 | 100 | ## Screenshots 101 | 102 | *The notification is displayed with a text and image of your choice when saving the test* 103 | ![testomatic example success](example_success.png "testomatic example success") 104 | 105 | *Too many go here* 106 | ![testomatic example failure](example_failure.png "testomatic example failure") 107 | 108 | *The result of the test is displayed in a terminal* 109 | ![testomatic example terminal result](terminal_result.png "testomatic example terminal result") 110 | 111 | ## Contributing 112 | 113 | Pull request is the way ;) 114 | 115 | ## Disclaimer 116 | 117 | - I only tested `testomatic` on Linux (Arch linux). It works on MacOS too (thanks [@midnightrun](https://github.com/midnightrun)). 118 | - You can use testomatic to run `Golang` and `PHPUnit` tests automatically. 119 | The configuration should be flexible enough for you to use it with other test frameworks / languages. 120 | 121 | ## Licence 122 | 123 | testomatic is under the [MIT License](https://opensource.org/licenses/MIT) 124 | 125 | -------------------------------------------------------------------------------- /cmd/testomatic.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "os" 9 | "os/exec" 10 | "path/filepath" 11 | "regexp" 12 | "strings" 13 | "time" 14 | 15 | "github.com/Phantas0s/testomatic/internal/config" 16 | "github.com/gen2brain/beeep" 17 | "github.com/radovskyb/watcher" 18 | ) 19 | 20 | const ( 21 | // scopes to create the relative path 22 | current = "current" 23 | dir = "dir" 24 | all = "all" 25 | ) 26 | 27 | var ( 28 | conf config.YamlConf 29 | file = flag.String("config", ".testomatic.yml", "The config file") 30 | showWatched = flag.Bool("show", false, "Show files watched") 31 | ) 32 | 33 | func Run() error { 34 | flag.Parse() 35 | w := watcher.New() 36 | 37 | data, err := ioutil.ReadFile(*file) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | if err := conf.Parse(data); err != nil { 43 | return err 44 | } 45 | 46 | // file or directory writting (so two in total) 47 | w.SetMaxEvents(2) 48 | w.FilterOps(watcher.Write) 49 | 50 | w.IgnoreHiddenFiles(conf.Watch.IgnoreHidden) 51 | w.Ignore(conf.Watch.Ignore...) 52 | 53 | r := regexp.MustCompile(conf.Watch.Regex) 54 | w.AddFilterHook(watcher.RegexFilterHook(r, false)) 55 | 56 | if err := w.AddRecursive(conf.Watch.Root); err != nil { 57 | return err 58 | } 59 | 60 | // Print a list of all of the files and folders currently 61 | // being watched and their paths. 62 | if *showWatched { 63 | for path, f := range w.WatchedFiles() { 64 | fmt.Printf("%s: %s\n", path, f.Name()) 65 | } 66 | } 67 | 68 | go func() error { 69 | for { 70 | select { 71 | case event := <-w.Event: 72 | if !event.IsDir() { 73 | result, err := fireCmd(event) 74 | if err != nil { 75 | return err 76 | } 77 | 78 | fmt.Println(*result) 79 | 80 | if !conf.Notification.Disable { 81 | notify(conf, *result) 82 | } 83 | } 84 | case err := <-w.Error: 85 | return err 86 | case <-w.Closed: 87 | return nil 88 | } 89 | } 90 | }() 91 | 92 | if err != nil { 93 | return err 94 | } 95 | 96 | fmt.Print("Testomatic is watching the files... \n") 97 | if err := w.Start(time.Millisecond * 100); err != nil { 98 | return err 99 | } 100 | 101 | return nil 102 | } 103 | 104 | func fireCmd(event watcher.Event) (*string, error) { 105 | if conf.Command.IgnorePath { 106 | result, err := execCmd(conf.Command.Bin, conf.Command.Options) 107 | if err != nil { 108 | return nil, err 109 | } 110 | return result, nil 111 | } 112 | 113 | var path *string 114 | path = &event.Path 115 | if filepath.IsAbs(event.Path) && conf.Command.Abs != true { 116 | var err error 117 | path, err = CreateRelative(event.Path, conf.Watch.Root, conf.Command.Scope) 118 | if err != nil { 119 | return nil, err 120 | } 121 | } 122 | 123 | options := append(conf.Command.Options, *path) 124 | result, err := execCmd(conf.Command.Bin, options) 125 | if err != nil { 126 | return nil, err 127 | } 128 | 129 | return result, nil 130 | } 131 | 132 | func execCmd(cmdPath string, args []string) (*string, error) { 133 | var out bytes.Buffer 134 | var stderr bytes.Buffer 135 | 136 | // fmt.Println(cmdPath, args) 137 | cmd := exec.Command(cmdPath, args...) 138 | cmd.Stderr = &stderr 139 | cmd.Stdout = &out 140 | 141 | clear := exec.Command("clear") 142 | clear.Stdout = os.Stdout 143 | clear.Run() 144 | 145 | err := cmd.Run() 146 | if err != nil { 147 | fmt.Println(err) 148 | fmt.Println(stderr.String()) 149 | } 150 | 151 | result := out.String() 152 | return &result, nil 153 | } 154 | 155 | // CreateRelative path from absolute path 156 | // A point "." means that the path begins by the current directory 157 | // TODO refactor... 158 | func CreateRelative(path, confPath, scope string) (*string, error) { 159 | newpath := make([]string, 2) 160 | // Get the current directory where testomatic runs 161 | if strings.Index(confPath, ".") != -1 { 162 | confPath = "." 163 | currentDir, err := getProjectDir() 164 | if err != nil { 165 | return nil, err 166 | } 167 | 168 | split := strings.SplitAfter(*currentDir, "/") 169 | *currentDir = split[len(split)-1] 170 | newpath = strings.SplitAfter(path, *currentDir) 171 | } else { 172 | newpath = strings.SplitAfter(path, confPath) 173 | } 174 | 175 | if scope == dir { 176 | finalPath := confPath + filepath.Dir(newpath[1]) 177 | return &finalPath, nil 178 | } 179 | 180 | if scope == current { 181 | finalPath := confPath + newpath[1] 182 | return &finalPath, nil 183 | } 184 | 185 | if scope == all { 186 | return &confPath, nil 187 | } 188 | 189 | return nil, nil 190 | } 191 | func getProjectDir() (*string, error) { 192 | projectDir, err := filepath.Abs(".") 193 | if err != nil { 194 | return nil, err 195 | } 196 | 197 | return &projectDir, nil 198 | } 199 | 200 | func notify(conf config.YamlConf, result string) { 201 | mess := "" 202 | 203 | if conf.Notification.DisplayResult { 204 | mess = result 205 | } 206 | 207 | if match, _ := regexp.MatchString(conf.Notification.RegexFailure, result); match { 208 | beeep.Notify("Failure!", mess, conf.Notification.ImgFailure) 209 | return 210 | } 211 | 212 | if match, _ := regexp.MatchString(conf.Notification.RegexSuccess, result); match { 213 | if conf.Notification.Mute { 214 | beeep.Notify("Success!", mess, conf.Notification.ImgSuccess) 215 | } else { 216 | beeep.Alert("Success!", mess, conf.Notification.ImgSuccess) 217 | } 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /cmd/testomatic_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func ErrorTest(expected string, got string) string { 9 | return fmt.Sprintf("Expected '%s' got '%s'", expected, got) 10 | } 11 | 12 | func TestCreateRelative(t *testing.T) { 13 | path := "/home/src/tests/tests.go" 14 | filepath := "src/" 15 | 16 | expected := "src/tests/tests.go" 17 | if v, _ := CreateRelative(path, filepath, "current"); *v != expected { 18 | t.Errorf(ErrorTest(expected, *v)) 19 | } 20 | 21 | expected = "src/tests" 22 | if v, _ := CreateRelative(path, filepath, "dir"); *v != expected { 23 | t.Errorf(ErrorTest(expected, *v)) 24 | } 25 | 26 | expected = "src/" 27 | if v, _ := CreateRelative(path, filepath, "all"); *v != expected { 28 | t.Errorf(ErrorTest(expected, *v)) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /example_failure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phantas0s/testomatic/30a44d1322c5262bbd8e5e94546f52cf25a7d8a5/example_failure.png -------------------------------------------------------------------------------- /example_success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phantas0s/testomatic/30a44d1322c5262bbd8e5e94546f52cf25a7d8a5/example_success.png -------------------------------------------------------------------------------- /examples/go/.testomatic_all.yml: -------------------------------------------------------------------------------- 1 | # Execute all the project tests 2 | watch: 3 | root: . 4 | regex: "_test.go" 5 | ignore: 6 | - vendor 7 | ignore_hidden: true 8 | command: 9 | ignore_path: true 10 | bin: go 11 | scope: dir 12 | options: 13 | - test 14 | - -v 15 | - ./... 16 | notification: 17 | img_failure: /home/superUser/.testomatic/images/failure.png 18 | img_success: /home/superUser/.testomatic/images/success.png 19 | regex_success: "ok" 20 | regex_failure: "FAIL" 21 | display_result: false 22 | -------------------------------------------------------------------------------- /examples/go/.testomatic_single.yml: -------------------------------------------------------------------------------- 1 | # Test only the single test 2 | watch: 3 | root: . 4 | regex: "_test.go" 5 | ignore: 6 | - vendor 7 | ignore_hidden: true 8 | command: 9 | bin: go 10 | scope: dir 11 | options: 12 | - test 13 | notification: 14 | img_failure: /home/superUser/.testomatic/images/failure.png 15 | img_success: /home/superUser/.testomatic/images/success.png 16 | regex_success: "ok" 17 | regex_failure: "FAIL" 18 | display_result: false 19 | -------------------------------------------------------------------------------- /examples/php/.testomatic_all.yml: -------------------------------------------------------------------------------- 1 | # Execute all the tests in the root folder without notification in docker using 2 | # docker-compose 3 | watch: 4 | root: src/Tests/ 5 | regex: "Test.php" 6 | ignore_hidden: true 7 | command: 8 | bin: docker-compose 9 | scope: all 10 | options: 11 | - exec 12 | - "-T" 13 | - php 14 | - bin/phpunit 15 | notification: 16 | disable: true 17 | -------------------------------------------------------------------------------- /examples/php/.testomatic_dir.yml: -------------------------------------------------------------------------------- 1 | # Execute all the tests in the whole directory in docker using docker-compose 2 | watch: 3 | root: src/Tests/ 4 | regex: "Test.php" 5 | ignore_hidden: true 6 | command: 7 | bin: docker-compose 8 | scope: dir 9 | options: 10 | - exec 11 | - "-T" 12 | - php 13 | - bin/phpunit 14 | notification: 15 | img_failure: /home/hypnos/.testomatic/images/failure.png 16 | img_success: /home/hypnos/.testomatic/images/success.png 17 | regex_success: OK 18 | regex_failure: error 19 | display_result: false 20 | -------------------------------------------------------------------------------- /examples/php/.testomatic_single.yml: -------------------------------------------------------------------------------- 1 | # Only execute the watched test 2 | watch: 3 | root: src/Tests/ 4 | regex: "Test.php" 5 | ignore: 6 | - src/Tests/_cache 7 | - src/Tests/_fixtures 8 | ignore_hidden: true 9 | command: 10 | bin: bin/phpunit 11 | scope: current 12 | notification: 13 | img_failure: /home/superUser/.testomatic/images/failure.png 14 | img_success: /home/superUser/.testomatic/images/success.png 15 | regex_success: OK 16 | regex_failure: error 17 | display_result: false 18 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Phantas0s/testomatic 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/gen2brain/beeep v0.0.0-20190603194150-07ff5e574111 7 | github.com/godbus/dbus v4.1.0+incompatible // indirect 8 | github.com/gopherjs/gopherwasm v1.1.0 // indirect 9 | github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect 10 | github.com/radovskyb/watcher v1.0.6 11 | github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect 12 | golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 // indirect 13 | gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2 // indirect 14 | gopkg.in/yaml.v2 v2.2.2 15 | ) 16 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/gen2brain/beeep v0.0.0-20190603194150-07ff5e574111 h1:RqBJYx7nqCnDQhJtIy7jrZnJ2pwBRnYhRuVQrrlX3pU= 2 | github.com/gen2brain/beeep v0.0.0-20190603194150-07ff5e574111/go.mod h1:GprdPCZglWh5OMcIDpeKBxuUJI+fEDOTVUfxZeda4zo= 3 | github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4= 4 | github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= 5 | github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c h1:16eHWuMGvCjSfgRJKqIzapE78onvvTbdi1rMkU00lZw= 6 | github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 7 | github.com/gopherjs/gopherwasm v1.1.0 h1:fA2uLoctU5+T3OhOn2vYP0DVT6pxc7xhTlBB1paATqQ= 8 | github.com/gopherjs/gopherwasm v1.1.0/go.mod h1:SkZ8z7CWBz5VXbhJel8TxCmAcsQqzgWGR/8nMhyhZSI= 9 | github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= 10 | github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= 11 | github.com/radovskyb/watcher v1.0.6 h1:8WIQ9UxEYMZjem1OwU7dVH94DXXk9mAIE1i8eqHD+IY= 12 | github.com/radovskyb/watcher v1.0.6/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg= 13 | github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk= 14 | github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o= 15 | golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 h1:LepdCS8Gf/MVejFIt8lsiexZATdoGVyp5bcyS+rYoUI= 16 | golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 17 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 18 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 19 | gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2 h1:MZF6J7CV6s/h0HBkfqebrYfKCVEo5iN+wzE4QhV3Evo= 20 | gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2/go.mod h1:s1Sn2yZos05Qfs7NKt867Xe18emOmtsO3eAKbDaon0o= 21 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 22 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 23 | -------------------------------------------------------------------------------- /internal/config/testdata/testomatic.yml: -------------------------------------------------------------------------------- 1 | watch: 2 | root: src/Tests 3 | regex: "Test.php" 4 | ignore: 5 | - vendor 6 | ignore_hidden: true 7 | command: 8 | bin: docker-compose 9 | ignore_path: true 10 | abs: false 11 | scope: current 12 | options: 13 | - exec 14 | - "-T" 15 | - 'php' 16 | - bin/phpunit 17 | notification: 18 | disable: false 19 | img_failure: /home/superUser/.autotest/images/failure.png 20 | img_success: /home/superUser/.autotest/images/success.png 21 | regex_success: ok 22 | regex_failure: fail 23 | display_result: true 24 | mute: true 25 | -------------------------------------------------------------------------------- /internal/config/yaml.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "gopkg.in/yaml.v2" 5 | ) 6 | 7 | type ( 8 | watch struct { 9 | Root string 10 | Regex string 11 | IgnoreHidden bool `yaml:"ignore_hidden"` 12 | Ignore []string 13 | } 14 | 15 | command struct { 16 | Bin string 17 | Scope string 18 | Abs bool 19 | IgnorePath bool `yaml:"ignore_path"` 20 | Options []string 21 | } 22 | 23 | notification struct { 24 | Disable bool 25 | ImgFailure string `yaml:"img_failure"` 26 | ImgSuccess string `yaml:"img_success"` 27 | Mute bool 28 | RegexSuccess string `yaml:"regex_success"` 29 | RegexFailure string `yaml:"regex_failure"` 30 | DisplayResult bool `yaml:"display_result"` 31 | } 32 | 33 | YamlConf struct { 34 | Watch watch 35 | Command command 36 | Notification notification 37 | } 38 | ) 39 | 40 | func (c *YamlConf) Parse(data []byte) error { 41 | return yaml.Unmarshal(data, c) 42 | } 43 | -------------------------------------------------------------------------------- /internal/config/yaml_test.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | "testing" 7 | ) 8 | 9 | func assert(expected interface{}, got interface{}) { 10 | if expected != got { 11 | log.Fatalln("Expected ", expected, "got ", got) 12 | } 13 | } 14 | 15 | func TestParse(t *testing.T) { 16 | data, err := ioutil.ReadFile("./testdata/testomatic.yml") 17 | if err != nil { 18 | log.Fatal(err) 19 | } 20 | 21 | var config YamlConf 22 | if err := config.Parse(data); err != nil { 23 | log.Fatal(err) 24 | } 25 | 26 | assert("src/Tests", config.Watch.Root) 27 | assert("Test.php", config.Watch.Regex) 28 | assert("vendor", config.Watch.Ignore[0]) 29 | assert(true, config.Watch.IgnoreHidden) 30 | assert("docker-compose", config.Command.Bin) 31 | assert(false, config.Command.Abs) 32 | assert(true, config.Command.IgnorePath) 33 | assert("current", config.Command.Scope) 34 | assert("exec", config.Command.Options[0]) 35 | assert("-T", config.Command.Options[1]) 36 | assert("php", config.Command.Options[2]) 37 | assert("bin/phpunit", config.Command.Options[3]) 38 | assert("/home/superUser/.autotest/images/success.png", config.Notification.ImgSuccess) 39 | assert("/home/superUser/.autotest/images/failure.png", config.Notification.ImgFailure) 40 | assert(false, config.Notification.Disable) 41 | assert("ok", config.Notification.RegexSuccess) 42 | assert("fail", config.Notification.RegexFailure) 43 | assert(true, config.Notification.DisplayResult) 44 | assert(true, config.Notification.Mute) 45 | } 46 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phantas0s/testomatic/30a44d1322c5262bbd8e5e94546f52cf25a7d8a5/logo.png -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | testomatic "github.com/Phantas0s/testomatic/cmd" 7 | ) 8 | 9 | func main() { 10 | err := testomatic.Run() 11 | log.Fatal(err) 12 | } 13 | -------------------------------------------------------------------------------- /terminal_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phantas0s/testomatic/30a44d1322c5262bbd8e5e94546f52cf25a7d8a5/terminal_result.png --------------------------------------------------------------------------------