From 94f8ff6478643c00e90239957e7ae93c1b8d90d6 Mon Sep 17 00:00:00 2001 From: Simon Bein Date: Sun, 12 Aug 2018 19:36:50 +0200 Subject: [PATCH] Unit tests (#2) * Add information about default configuration in Readme * Completely re-write logic behing parseConfig * Add unit test for parseConfig for directory perms 000, 100, 200, 300 * Add unit test for parseConfig for directory perms 400,500,600,700 * Move error message generation from main to CloseApp and OpenApp directly * Remove unnescessary white-spaces * Move determineAction into a separate method so it can be unit tested --- Readme.md | 2 +- applescriptHandler.go | 6 +-- main.go | 67 +++++++++++++----------- main_test.go | 118 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 34 deletions(-) create mode 100644 main_test.go diff --git a/Readme.md b/Readme.md index a5aa36d..7843726 100644 --- a/Readme.md +++ b/Readme.md @@ -6,7 +6,7 @@ Currently only working with Mac OS X, more variety to come soon. ## Set-Up -create a config file under ~/.deepwork/config.json and add the names of all communication applications. An example config can be found in [example-config.json](example-config.json) +create a config file under ~/.deepwork/config.json and add the names of all communication applications. An example config can be found in [example-config.json](example-config.json). By default Mail and Calendar will be added. ## Usage diff --git a/applescriptHandler.go b/applescriptHandler.go index 3c5f4c5..f154e85 100644 --- a/applescriptHandler.go +++ b/applescriptHandler.go @@ -6,8 +6,6 @@ import ( "strings" ) - - // OpenApp opens an application using AppleScript func OpenApp(appName string) error { script := fmt.Sprintf(` @@ -18,7 +16,7 @@ end tell err := ExecuteAppleScript(script) - return err + return fmt.Errorf("Could not open app '%s': '%v'", appName, err) } // CloseApp closes an application using AppleScript @@ -31,7 +29,7 @@ end tell err := ExecuteAppleScript(script) - return err + return fmt.Errorf("Could not close app '%s': '%v'", appName, err) } // ExecuteAppleScript takes in a fully parsed Apple-Script executes the command using osascript diff --git a/main.go b/main.go index f80a5a8..da28383 100644 --- a/main.go +++ b/main.go @@ -7,7 +7,7 @@ import ( "io/ioutil" "log" "os" - "strings" + "path" homedir "github.com/mitchellh/go-homedir" ) @@ -35,53 +35,62 @@ func main() { // Parse Command Line Flags flag.Parse() - desStage := flag.Arg(0) + desAction := flag.Arg(0) // Determine desired action var action func(name string) error - switch desStage { - case "on": - action = CloseApp - case "off": - action = OpenApp - default: - fmt.Println("Usage: deepwork [on,off]") - os.Exit(1) - } + action = determineAction(desAction) // Execute action for _, app := range config.AffectedApps { err := action(app) if err != nil { - log.Printf("Could not close app %s: %v", app, err) + log.Printf("%v", err) } } } +func determineAction(desAction string) func(name string) error { + switch desAction { + case "on": + return CloseApp + case "off": + return OpenApp + default: + return nil + } +} + func parseConfig(configLocation string) (config, error) { var conf config + confDir := path.Dir(configLocation) + + // Try to open config jsonFile, err := os.Open(configLocation) defer jsonFile.Close() - if err != nil { - // Check if there is already a config file => harmless case, just create default conf - if os.IsNotExist(err) { - defaultConfig := []byte(`{"affectedApps":["Mail","Calendar"]}`) - - // Create required directories if necessary - if err = os.Mkdir(strings.TrimRight(configLocation, "/config.json"), 0744); err != nil { - return config{}, fmt.Errorf("Could not create required directories for config: %v", err) - } - // Write File - if err = ioutil.WriteFile(configLocation, defaultConfig, 0644); err != nil { - return config{}, fmt.Errorf("Could not write default config: %v", err) - } - // Call itself again to parse newly created conf - return parseConfig(configLocation) + + // Check if there is a config file at the specified location, if not create a default config + if os.IsNotExist(err) { + defaultConfig := []byte(`{"affectedApps":["Mail","Calendar"]}`) + + // Create required directories if necessary + if err = os.MkdirAll(confDir, 0744); err != nil { + return config{}, fmt.Errorf("Could not create required directories for config: %v", err) } - // Otherwise (e.g. no permissions on conf file), return the error - return config{}, err + // Write default config + if err = ioutil.WriteFile(configLocation, defaultConfig, 0644); err != nil { + return config{}, fmt.Errorf("Could not write default config: %v", err) + } + // Call itself again to parse newly created conf + return parseConfig(configLocation) + } + + // Otherwise (e.g. no permissions on conf file or it's dir), return the error + if err != nil { + return config{}, fmt.Errorf("Could not access config file: %v", err) } + // Read in the config confByte, err := ioutil.ReadAll(jsonFile) if err != nil { diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..5c6c6e1 --- /dev/null +++ b/main_test.go @@ -0,0 +1,118 @@ +package main + +import ( + "bytes" + "io/ioutil" + "log" + "os" + "path" + "testing" + + homedir "github.com/mitchellh/go-homedir" +) + +var UserHomeDir string + +func init() { + // Determine Users home directory + var err error + UserHomeDir, err = homedir.Dir() + if err != nil { + log.Fatalf("Could not determine Users home directory: %v", err) + } +} + +func TestParseConfig(t *testing.T) { + difFolderPerm := []struct { + name string + folderPerm os.FileMode + configLocation string + expResp string + }{ + { + "no perm, directory exists", + 0000, + "/tmp/noPermissionsHere/config.json", + "Could not access config file: open /tmp/noPermissionsHere/config.json: permission denied", + }, + { + "execute only, directory doesn't exist yet", + 0100, + "/tmp/executeOnly/config.json", + "Could not write default config: open /tmp/executeOnly/config.json: permission denied", + }, + { + "write only", + 0200, + "/tmp/writeOnly/config.json", + "Could not access config file: open /tmp/writeOnly/config.json: permission denied", + }, + { + "write & execute", + 0300, + "/tmp/writeAndExecute/config.json", + "no error", + }, { + "read only", + 0400, + "/tmp/readOnly/config.json", + "Could not access config file: open /tmp/readOnly/config.json: permission denied", + }, { + "read & execute", + 0500, + "/tmp/readAndExecute/config.json", + "Could not write default config: open /tmp/readAndExecute/config.json: permission denied", + }, { + "read & write", + 0600, + "/tmp/readAndWrite/config.json", + "Could not access config file: open /tmp/readAndWrite/config.json: permission denied", + }, { + "all permissions", + 0700, + "/tmp/allPermissions/config.json", + "no error", + }, + } + + for _, tc := range difFolderPerm { + t.Run(tc.name, func(t *testing.T) { + confDir := path.Dir(tc.configLocation) + + if err := os.Mkdir(confDir, tc.folderPerm); err != nil { + t.Fatalf("Could not create dir: %s: %v", confDir, err) + } + + _, err := parseConfig(tc.configLocation) + + // Check if the response from parseConfig, is the expected one + if err != nil { + if err.Error() != tc.expResp { + t.Errorf("Expected: '%v' got: '%v'", tc.expResp, err.Error()) + } + } else { + if tc.expResp != "no error" { + t.Errorf("Got no error, but expected '%v'", tc.expResp) + } + } + + // Make sure in the successful cases the file is actually there + if tc.expResp == "no error" { + cont, err := ioutil.ReadFile(tc.configLocation) + if err != nil { + t.Errorf("Expected a file at %s, but could not read it due to: %v", tc.configLocation, err) + } + defaultConfig := []byte(`{"affectedApps":["Mail","Calendar"]}`) + if bytes.Compare(cont, defaultConfig) != 0 { + t.Errorf("%s should have the following content: '%v', but has '%v'", tc.configLocation, defaultConfig, cont) + } + } + + // Clean up + os.Chmod(confDir, 0700) + if err := os.RemoveAll(confDir); err != nil { + t.Fatalf("Could not clean up '%s': %v; Please clean up this directory manually, as it can corrupt further testing", confDir, err) + } + }) + } +}