diff --git a/slash.go b/slash.go index a41b7677..fd46abfc 100644 --- a/slash.go +++ b/slash.go @@ -1,7 +1,10 @@ package slack import ( + "encoding/json" + "fmt" "net/http" + "strconv" ) // SlashCommand contains information about a request of the slash command @@ -55,3 +58,34 @@ func (s SlashCommand) ValidateToken(verificationTokens ...string) bool { } return false } + +// UnmarshalJSON handles is_enterprise_install being either a boolean or a +// string when parsing JSON from various payloads +func (s *SlashCommand) UnmarshalJSON(data []byte) error { + type SlashCommandCopy SlashCommand + scopy := &struct { + *SlashCommandCopy + IsEnterpriseInstall interface{} `json:"is_enterprise_install"` + }{ + SlashCommandCopy: (*SlashCommandCopy)(s), + } + + if err := json.Unmarshal(data, scopy); err != nil { + return err + } + + switch rawValue := scopy.IsEnterpriseInstall.(type) { + case string: + b, err := strconv.ParseBool(rawValue) + if err != nil { + return fmt.Errorf("parsing boolean for is_enterprise_install: %w", err) + } + s.IsEnterpriseInstall = b + case bool: + s.IsEnterpriseInstall = rawValue + default: + return fmt.Errorf("wrong data type for is_enterprise_install: %T", scopy.IsEnterpriseInstall) + } + + return nil +} diff --git a/slash_test.go b/slash_test.go index e5c79e93..e068fc40 100644 --- a/slash_test.go +++ b/slash_test.go @@ -1,6 +1,7 @@ package slack import ( + "encoding/json" "fmt" "net/http" "net/url" @@ -99,3 +100,70 @@ func TestSlash_ServeHTTP(t *testing.T) { resp.Body.Close() } } + +func TestSlash_UnmarshalJSON(t *testing.T) { + tests := []struct { + body string + wantIsEnterpriseInstall bool + wantToken string + wantUnmarshalError string + }{ + { + body: `{"token":"blahblah","is_enterprise_install":"false"}`, + wantIsEnterpriseInstall: false, + wantToken: "blahblah", + wantUnmarshalError: "", + }, + { + body: `{"token":"blahblah","is_enterprise_install":false}`, + wantIsEnterpriseInstall: false, + wantToken: "blahblah", + wantUnmarshalError: "", + }, + { + body: `{"token":"blahblah","is_enterprise_install":"true"}`, + wantIsEnterpriseInstall: true, + wantToken: "blahblah", + wantUnmarshalError: "", + }, + { + body: `{"token":"blahblah","is_enterprise_install":true}`, + wantIsEnterpriseInstall: true, + wantToken: "blahblah", + wantUnmarshalError: "", + }, + { + body: `{"token":"blahblah","is_enterprise_install":42}`, + wantUnmarshalError: "wrong data type for is_enterprise_install: float64", + }, + { + body: `{"token":"blahblah","is_enterprise_install":"unconvertable to bool"}`, + wantUnmarshalError: "parsing boolean for is_enterprise_install: strconv.ParseBool: parsing \"unconvertable to bool\": invalid syntax", + }, + } + + for i, test := range tests { + var result SlashCommand + + err := json.Unmarshal([]byte(test.body), &result) + if err != nil { + if err.Error() != test.wantUnmarshalError { + t.Errorf("%d: Got error %v, want error %q", i, err, test.wantUnmarshalError) + } + continue + } + + if test.wantUnmarshalError != "" { + t.Errorf("%d: Got no error, want error %q", i, test.wantUnmarshalError) + continue + } + + if result.IsEnterpriseInstall != test.wantIsEnterpriseInstall { + t.Errorf("%d: Got IsEnterpriseInstall %v, want IsEnterpriseInstall %v", i, result.IsEnterpriseInstall, test.wantIsEnterpriseInstall) + } + + if result.Token != test.wantToken { + t.Errorf("%d: Got Token %v, want Token %v", i, result.Token, test.wantToken) + } + } +}