diff --git a/src/github.com/matrix-org/go-neb/clients/clients.go b/src/github.com/matrix-org/go-neb/clients/clients.go index 0b4287a..4352766 100644 --- a/src/github.com/matrix-org/go-neb/clients/clients.go +++ b/src/github.com/matrix-org/go-neb/clients/clients.go @@ -16,7 +16,7 @@ import ( ) type nextBatchStore struct { - db *database.ServiceDB + db database.Storer } func (s nextBatchStore) Save(userID, nextBatch string) { @@ -42,7 +42,7 @@ func (s nextBatchStore) Load(userID string) string { // A Clients is a collection of clients used for bot services. type Clients struct { - db *database.ServiceDB + db database.Storer httpClient *http.Client dbMutex sync.Mutex mapMutex sync.Mutex @@ -50,7 +50,7 @@ type Clients struct { } // New makes a new collection of matrix clients -func New(db *database.ServiceDB, cli *http.Client) *Clients { +func New(db database.Storer, cli *http.Client) *Clients { clients := &Clients{ db: db, httpClient: cli, @@ -192,6 +192,12 @@ func (c *Clients) onMessageEvent(client *matrix.Client, event *matrix.Event) { return } + // replace all smart quotes with their normal counterparts so shellwords can parse it + body = strings.Replace(body, `‘`, `'`, -1) + body = strings.Replace(body, `’`, `'`, -1) + body = strings.Replace(body, `“`, `"`, -1) + body = strings.Replace(body, `”`, `"`, -1) + var responses []interface{} for _, service := range services { diff --git a/src/github.com/matrix-org/go-neb/clients/clients_test.go b/src/github.com/matrix-org/go-neb/clients/clients_test.go new file mode 100644 index 0000000..bc6f70e --- /dev/null +++ b/src/github.com/matrix-org/go-neb/clients/clients_test.go @@ -0,0 +1,95 @@ +package clients + +import ( + "fmt" + "github.com/matrix-org/go-neb/database" + "github.com/matrix-org/go-neb/matrix" + "github.com/matrix-org/go-neb/types" + "net/http" + "net/url" + "reflect" + "testing" +) + +var commandParseTests = []struct { + body string + expectArgs []string +}{ + {"!test word", []string{"word"}}, + {"!test two words", []string{"two", "words"}}, + {`!test "words with double quotes"`, []string{"words with double quotes"}}, + {"!test 'words with single quotes'", []string{"words with single quotes"}}, + {`!test 'single quotes' "double quotes"`, []string{"single quotes", "double quotes"}}, + {`!test ‘smart single quotes’ “smart double quotes”`, []string{"smart single quotes", "smart double quotes"}}, +} + +type MockService struct { + types.DefaultService + commands []types.Command +} + +func (s *MockService) Commands(cli *matrix.Client) []types.Command { + return s.commands +} + +type MockStore struct { + database.NopStorage + service types.Service +} + +func (d *MockStore) LoadServicesForUser(userID string) ([]types.Service, error) { + return []types.Service{d.service}, nil +} + +type MockTransport struct { + roundTrip func(*http.Request) (*http.Response, error) +} + +func (t MockTransport) RoundTrip(req *http.Request) (*http.Response, error) { + return t.roundTrip(req) +} + +func TestCommandParsing(t *testing.T) { + var executedCmdArgs []string + cmds := []types.Command{ + types.Command{ + Path: []string{"test"}, + Command: func(roomID, userID string, args []string) (interface{}, error) { + executedCmdArgs = args + return nil, nil + }, + }, + } + s := MockService{commands: cmds} + store := MockStore{service: &s} + database.SetServiceDB(&store) + + trans := struct{ MockTransport }{} + trans.roundTrip = func(*http.Request) (*http.Response, error) { + return nil, fmt.Errorf("unhandled test path") + } + cli := &http.Client{ + Transport: trans, + } + clients := New(&store, cli) + hsURL, _ := url.Parse("https://someplace.somewhere") + mxCli := matrix.NewClient(cli, hsURL, "token", "@service:user") + + for _, input := range commandParseTests { + executedCmdArgs = []string{} + event := matrix.Event{ + Type: "m.room.message", + Sender: "@someone:somewhere", + RoomID: "!foo:bar", + Content: map[string]interface{}{ + "body": input.body, + "msgtype": "m.text", + }, + } + clients.onMessageEvent(mxCli, &event) + if !reflect.DeepEqual(executedCmdArgs, input.expectArgs) { + t.Errorf("TestCommandParsing want %s, got %s", input.expectArgs, executedCmdArgs) + } + } + +}