From 4a2f7576335eb4de9a7473e0da49052d24502238 Mon Sep 17 00:00:00 2001 From: Rustam Gilyazov <16064414+rusq@users.noreply.github.com> Date: Sat, 16 Nov 2024 08:25:59 +1000 Subject: [PATCH] create CreateAndSelect --- auth/auth_ui/auth_ui.go | 32 ----- auth/auth_ui/auth_ui_test.go | 34 ----- auth/auth_ui/cli.go | 3 +- auth/auth_ui/huh.go | 5 +- auth/auth_ui/validation.go | 4 +- auth/browser.go | 3 +- auth/rod.go | 3 +- .../internal/workspace/workspaceui/api.go | 39 ------ .../workspace/workspaceui/api_test.go | 117 ------------------ .../workspace/workspaceui/ezlogin3000.go | 4 +- .../workspace/workspaceui/filesecrets.go | 4 +- .../workspace/workspaceui/tokencookie.go | 8 +- .../workspace/workspaceui/workspaceui.go | 6 + internal/cache/manager.go | 23 ++++ internal/cache/manager_test.go | 111 +++++++++++++++++ internal/structures/structures.go | 28 +++++ internal/structures/structures_test.go | 31 +++++ 17 files changed, 219 insertions(+), 236 deletions(-) delete mode 100644 auth/auth_ui/auth_ui_test.go delete mode 100644 cmd/slackdump/internal/workspace/workspaceui/api.go delete mode 100644 cmd/slackdump/internal/workspace/workspaceui/api_test.go diff --git a/auth/auth_ui/auth_ui.go b/auth/auth_ui/auth_ui.go index 28f377cf..20dee0ee 100644 --- a/auth/auth_ui/auth_ui.go +++ b/auth/auth_ui/auth_ui.go @@ -1,12 +1,5 @@ package auth_ui -import ( - "errors" - "fmt" - "net/url" - "strings" -) - // LoginType is the login type, that is used to choose the authentication flow, // for example login headlessly or interactively. type LoginType int8 @@ -21,28 +14,3 @@ const ( // LCancel should be returned if the user cancels the login intent. LCancel ) - -var ErrInvalidDomain = errors.New("invalid domain") - -// Sanitize takes a workspace name or URL and returns the workspace name. -func Sanitize(workspace string) (string, error) { - if !strings.Contains(workspace, ".slack.com") && !strings.Contains(workspace, ".") { - return workspace, nil - } - if strings.HasPrefix(workspace, "https://") { - uri, err := url.Parse(workspace) - if err != nil { - return "", err - } - workspace = uri.Host - } - // parse - name, domain, found := strings.Cut(workspace, ".") - if !found { - return "", errors.New("workspace name is empty") - } - if strings.TrimRight(domain, "/") != "slack.com" { - return "", fmt.Errorf("%s: %w", domain, ErrInvalidDomain) - } - return name, nil -} diff --git a/auth/auth_ui/auth_ui_test.go b/auth/auth_ui/auth_ui_test.go deleted file mode 100644 index a1473def..00000000 --- a/auth/auth_ui/auth_ui_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package auth_ui - -import "testing" - -func TestSanitize(t *testing.T) { - type args struct { - workspace string - } - tests := []struct { - name string - args args - want string - wantErr bool - }{ - {"not a URL", args{"blahblah"}, "blahblah", false}, - {"url slash", args{"https://blahblah.slack.com/"}, "blahblah", false}, - {"url no slash", args{"https://blahblah.slack.com"}, "blahblah", false}, - {"url no schema slash", args{"blahblah.slack.com/"}, "blahblah", false}, - {"url no schema no slash", args{"blahblah.slack.com"}, "blahblah", false}, - {"not a slack domain", args{"blahblah.example.com"}, "", true}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := Sanitize(tt.args.workspace) - if (err != nil) != tt.wantErr { - t.Errorf("sanitize() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("sanitize() got = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/auth/auth_ui/cli.go b/auth/auth_ui/cli.go index 93260af2..38ff5b6e 100644 --- a/auth/auth_ui/cli.go +++ b/auth/auth_ui/cli.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/fatih/color" + "github.com/rusq/slackdump/v3/internal/structures" "golang.org/x/term" ) @@ -30,7 +31,7 @@ func (cl *CLI) RequestWorkspace(w io.Writer) (string, error) { if err != nil { return "", err } - return Sanitize(workspace) + return structures.ExtractWorkspace(workspace) } func (*CLI) RequestCreds(w io.Writer, workspace string) (email string, passwd string, err error) { diff --git a/auth/auth_ui/huh.go b/auth/auth_ui/huh.go index 80d48e51..752be6a7 100644 --- a/auth/auth_ui/huh.go +++ b/auth/auth_ui/huh.go @@ -11,6 +11,7 @@ import ( "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/huh" "github.com/rusq/slackauth" + "github.com/rusq/slackdump/v3/internal/structures" ) // Huh is the Auth UI that uses the huh library to provide a terminal UI. @@ -120,7 +121,7 @@ func (*Huh) RequestLoginType(ctx context.Context, w io.Writer, workspace string) fields = append(fields, huh.NewSelect[LoginType](). TitleFunc(func() string { - wsp, err := Sanitize(ret.Workspace) + wsp, err := structures.ExtractWorkspace(ret.Workspace) if err != nil { return "Select login type" } @@ -150,7 +151,7 @@ func (*Huh) RequestLoginType(ctx context.Context, w io.Writer, workspace string) return ret, err } var err error - ret.Workspace, err = Sanitize(ret.Workspace) + ret.Workspace, err = structures.ExtractWorkspace(ret.Workspace) if err != nil { return ret, err } diff --git a/auth/auth_ui/validation.go b/auth/auth_ui/validation.go index 1b2b9e44..a33f9414 100644 --- a/auth/auth_ui/validation.go +++ b/auth/auth_ui/validation.go @@ -3,6 +3,8 @@ package auth_ui import ( "errors" "regexp" + + "github.com/rusq/slackdump/v3/internal/structures" ) var ( @@ -105,6 +107,6 @@ func valWorkspace(s string) error { if err := valRequired(s); err != nil { return err } - _, err := Sanitize(s) + _, err := structures.ExtractWorkspace(s) return err } diff --git a/auth/browser.go b/auth/browser.go index 4f772be7..e5391d01 100644 --- a/auth/browser.go +++ b/auth/browser.go @@ -8,6 +8,7 @@ import ( "github.com/rusq/slackdump/v3/auth/auth_ui" "github.com/rusq/slackdump/v3/auth/browser" + "github.com/rusq/slackdump/v3/internal/structures" ) var _ Provider = BrowserAuth{} @@ -58,7 +59,7 @@ func NewBrowserAuth(ctx context.Context, opts ...Option) (BrowserAuth, error) { } defer br.opts.flow.Stop() } - if wsp, err := auth_ui.Sanitize(br.opts.workspace); err != nil { + if wsp, err := structures.ExtractWorkspace(br.opts.workspace); err != nil { return br, err } else { br.opts.workspace = wsp diff --git a/auth/rod.go b/auth/rod.go index f415ab46..a49d240c 100644 --- a/auth/rod.go +++ b/auth/rod.go @@ -11,6 +11,7 @@ import ( "github.com/rusq/slackauth" "github.com/rusq/slackdump/v3/auth/auth_ui" + "github.com/rusq/slackdump/v3/internal/structures" "github.com/rusq/slackdump/v3/logger" ) @@ -89,7 +90,7 @@ func NewRODAuth(ctx context.Context, opts ...Option) (RodAuth, error) { for _, opt := range opts { opt(&r.opts) } - if wsp, err := auth_ui.Sanitize(r.opts.workspace); err != nil { + if wsp, err := structures.ExtractWorkspace(r.opts.workspace); err != nil { return r, err } else { r.opts.workspace = wsp diff --git a/cmd/slackdump/internal/workspace/workspaceui/api.go b/cmd/slackdump/internal/workspace/workspaceui/api.go deleted file mode 100644 index 89bcab23..00000000 --- a/cmd/slackdump/internal/workspace/workspaceui/api.go +++ /dev/null @@ -1,39 +0,0 @@ -package workspaceui - -import ( - "context" - "errors" - - "github.com/rusq/slackdump/v3/auth" - "github.com/rusq/slackdump/v3/auth/auth_ui" -) - -//go:generate mockgen -package workspaceui -destination=test_mock_manager.go -source api.go manager -type manager interface { - SaveProvider(workspace string, p auth.Provider) error - Select(workspace string) error -} - -// createAndSelect creates a new workspace with the given provider and selects it. -// It returns the workspace name on success. -func createAndSelect(ctx context.Context, m manager, prov auth.Provider) (string, error) { - authInfo, err := prov.Test(ctx) - if err != nil { - return "", err - } - - wsp, err := auth_ui.Sanitize(authInfo.URL) - if err != nil { - return "", err - } - if wsp == "" { - return "", errors.New("workspace name is empty") - } - if err := m.SaveProvider(wsp, prov); err != nil { - return "", err - } - if err := m.Select(wsp); err != nil { - return "", err - } - return wsp, nil -} diff --git a/cmd/slackdump/internal/workspace/workspaceui/api_test.go b/cmd/slackdump/internal/workspace/workspaceui/api_test.go deleted file mode 100644 index 7b58a2de..00000000 --- a/cmd/slackdump/internal/workspace/workspaceui/api_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package workspaceui - -import ( - "context" - "testing" - - "github.com/rusq/slack" - "github.com/rusq/slackdump/v3/internal/fixtures" - "github.com/rusq/slackdump/v3/internal/mocks/mock_auth" - "github.com/stretchr/testify/assert" - gomock "go.uber.org/mock/gomock" -) - -func Test_createAndSelect(t *testing.T) { - type args struct { - ctx context.Context - // m manager - // prov auth.Provider - } - tests := []struct { - name string - args args - expectFn func(mp *mock_auth.MockProvider, mm *Mockmanager) - want string - wantErr bool - }{ - { - name: "provider test fails", - args: args{ - ctx: context.Background(), - }, - expectFn: func(mp *mock_auth.MockProvider, mm *Mockmanager) { - mp.EXPECT().Test(gomock.Any()).Return(nil, assert.AnError) - }, - want: "", - wantErr: true, - }, - { - name: "save provider fails", - args: args{ - ctx: context.Background(), - }, - expectFn: func(mp *mock_auth.MockProvider, mm *Mockmanager) { - mp.EXPECT().Test(gomock.Any()).Return(fixtures.LoadPtr[slack.AuthTestResponse](string(fixtures.TestAuthTestInfo)), nil) - mm.EXPECT().SaveProvider(gomock.Any(), gomock.Any()).Return(assert.AnError) - }, - want: "", - wantErr: true, - }, - { - name: "select fails", - args: args{ - ctx: context.Background(), - }, - expectFn: func(mp *mock_auth.MockProvider, mm *Mockmanager) { - mp.EXPECT().Test(gomock.Any()).Return(fixtures.LoadPtr[slack.AuthTestResponse](string(fixtures.TestAuthTestInfo)), nil) - mm.EXPECT().SaveProvider(gomock.Any(), gomock.Any()).Return(nil) - mm.EXPECT().Select(gomock.Any()).Return(assert.AnError) - }, - want: "", - wantErr: true, - }, - { - name: "success", - args: args{ - ctx: context.Background(), - }, - expectFn: func(mp *mock_auth.MockProvider, mm *Mockmanager) { - mp.EXPECT().Test(gomock.Any()).Return(fixtures.LoadPtr[slack.AuthTestResponse](string(fixtures.TestAuthTestInfo)), nil) - mm.EXPECT().SaveProvider(gomock.Any(), gomock.Any()).Return(nil) - mm.EXPECT().Select(gomock.Any()).Return(nil) - }, - want: "test", - wantErr: false, - }, - { - name: "url empty fails", - args: args{ - ctx: context.Background(), - }, - expectFn: func(mp *mock_auth.MockProvider, mm *Mockmanager) { - mp.EXPECT().Test(gomock.Any()).Return(&slack.AuthTestResponse{URL: ""}, nil) - }, - want: "", - wantErr: true, - }, - { - name: "url sanitize fails", - args: args{ - ctx: context.Background(), - }, - expectFn: func(mp *mock_auth.MockProvider, mm *Mockmanager) { - mp.EXPECT().Test(gomock.Any()).Return(&slack.AuthTestResponse{URL: "ftp://lol.example.com"}, nil) - }, - want: "", - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ctrl := gomock.NewController(t) - mp := mock_auth.NewMockProvider(ctrl) - mm := NewMockmanager(ctrl) - if tt.expectFn != nil { - tt.expectFn(mp, mm) - } - got, err := createAndSelect(tt.args.ctx, mm, mp) - if (err != nil) != tt.wantErr { - t.Errorf("createAndSelect() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("createAndSelect() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/cmd/slackdump/internal/workspace/workspaceui/ezlogin3000.go b/cmd/slackdump/internal/workspace/workspaceui/ezlogin3000.go index e5ec6687..bc1289ed 100644 --- a/cmd/slackdump/internal/workspace/workspaceui/ezlogin3000.go +++ b/cmd/slackdump/internal/workspace/workspaceui/ezlogin3000.go @@ -65,7 +65,7 @@ func playwrightLogin(ctx context.Context, mgr manager) error { return err } - name, err := createAndSelect(ctx, mgr, prov) + name, err := mgr.CreateAndSelect(ctx, prov) if err != nil { return err } @@ -77,7 +77,7 @@ func rodLogin(ctx context.Context, mgr manager) error { if err != nil { return err } - name, err := createAndSelect(ctx, mgr, prov) + name, err := mgr.CreateAndSelect(ctx, prov) if err != nil { return err } diff --git a/cmd/slackdump/internal/workspace/workspaceui/filesecrets.go b/cmd/slackdump/internal/workspace/workspaceui/filesecrets.go index 57420dc1..d0a195e9 100644 --- a/cmd/slackdump/internal/workspace/workspaceui/filesecrets.go +++ b/cmd/slackdump/internal/workspace/workspaceui/filesecrets.go @@ -41,12 +41,12 @@ func fileWithSecrets(ctx context.Context, mgr manager) error { if err != nil { return err } - wsp, err := createAndSelect(ctx, mgr, prov) + name, err := mgr.CreateAndSelect(ctx, prov) if err != nil { return err } - return success(ctx, wsp) + return success(ctx, name) } func validateSecrets(filename string) error { diff --git a/cmd/slackdump/internal/workspace/workspaceui/tokencookie.go b/cmd/slackdump/internal/workspace/workspaceui/tokencookie.go index f3df4579..6ad90eaa 100644 --- a/cmd/slackdump/internal/workspace/workspaceui/tokencookie.go +++ b/cmd/slackdump/internal/workspace/workspaceui/tokencookie.go @@ -11,7 +11,7 @@ import ( const sampleToken = "xoxc-610187951300-604451271234-3473161557912-4c426dd426a45208707725b710302b32dda0ab002b80ccd8c4c8ac9971a11558" -func prgTokenCookie(ctx context.Context, m manager) error { +func prgTokenCookie(ctx context.Context, mgr manager) error { var ( token string cookie string @@ -46,7 +46,7 @@ func prgTokenCookie(ctx context.Context, m manager) error { if err != nil { return err } - name, err := createAndSelect(ctx, m, prov) + name, err := mgr.CreateAndSelect(ctx, prov) if err != nil { confirmed = false retry := askRetry(ctx, name, err) @@ -83,7 +83,7 @@ func makeValidator[P auth.Provider](ctx context.Context, token *string, val *str } } -func prgTokenCookieFile(ctx context.Context, m manager) error { +func prgTokenCookieFile(ctx context.Context, mgr manager) error { var ( token string cookiefile string @@ -116,7 +116,7 @@ func prgTokenCookieFile(ctx context.Context, m manager) error { if err != nil { return err } - name, err := createAndSelect(ctx, m, prov) + name, err := mgr.CreateAndSelect(ctx, prov) if err != nil { confirmed = false retry := askRetry(ctx, name, err) diff --git a/cmd/slackdump/internal/workspace/workspaceui/workspaceui.go b/cmd/slackdump/internal/workspace/workspaceui/workspaceui.go index 6c85766f..9d97a5e6 100644 --- a/cmd/slackdump/internal/workspace/workspaceui/workspaceui.go +++ b/cmd/slackdump/internal/workspace/workspaceui/workspaceui.go @@ -7,12 +7,18 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/huh" + "github.com/rusq/slackdump/v3/auth" "github.com/rusq/slackdump/v3/cmd/slackdump/internal/cfg" "github.com/rusq/slackdump/v3/cmd/slackdump/internal/golang/base" "github.com/rusq/slackdump/v3/cmd/slackdump/internal/ui/bubbles/menu" "github.com/rusq/slackdump/v3/internal/cache" ) +//go:generate mockgen -package workspaceui -destination=test_mock_manager.go -source api.go manager +type manager interface { + CreateAndSelect(ctx context.Context, p auth.Provider) (string, error) +} + func WorkspaceNew(ctx context.Context, _ *base.Command, _ []string) error { const ( actLogin = "ezlogin" diff --git a/internal/cache/manager.go b/internal/cache/manager.go index e46f4d64..2d52b520 100644 --- a/internal/cache/manager.go +++ b/internal/cache/manager.go @@ -18,6 +18,7 @@ import ( "github.com/rusq/slackdump/v3/auth" "github.com/rusq/slackdump/v3/internal/osext" + "github.com/rusq/slackdump/v3/internal/structures" ) // Manager is the workspace manager. It is an abstraction over the directory @@ -407,3 +408,25 @@ func (m *Manager) LoadChannels(teamID string, maxAge time.Duration) ([]slack.Cha func (m *Manager) CacheChannels(teamID string, cc []slack.Channel) error { return saveChannels(m.dir, m.channelFile, teamID, cc) } + +func (m *Manager) CreateAndSelect(ctx context.Context, prov auth.Provider) (string, error) { + authInfo, err := prov.Test(ctx) + if err != nil { + return "", err + } + + wsp, err := structures.ExtractWorkspace(authInfo.URL) + if err != nil { + return "", err + } + if wsp == "" { + return "", errors.New("workspace name is empty") + } + if err := m.SaveProvider(wsp, prov); err != nil { + return "", err + } + if err := m.Select(wsp); err != nil { + return "", err + } + return wsp, nil +} diff --git a/internal/cache/manager_test.go b/internal/cache/manager_test.go index 43e4c9a9..627340e5 100644 --- a/internal/cache/manager_test.go +++ b/internal/cache/manager_test.go @@ -1,14 +1,20 @@ package cache import ( + "context" "errors" "io" + "net/http" "sort" "strings" "testing" + "github.com/rusq/slack" + "github.com/rusq/slackdump/v3/auth" "github.com/rusq/slackdump/v3/internal/fixtures" + "github.com/rusq/slackdump/v3/internal/mocks/mock_auth" "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" ) func Test_currentWsp(t *testing.T) { @@ -140,3 +146,108 @@ func TestManager_ExistsErr(t *testing.T) { assert.Equal(t, e.Workspace, "baz") }) } + +func TestManager_CreateAndSelect(t *testing.T) { + type fields struct { + // dir string + authOptions []auth.Option + userFile string + channelFile string + } + type args struct { + ctx context.Context + // prov auth.Provider + } + tests := []struct { + name string + fields fields + expectFn func(mp *mock_auth.MockProvider) + args args + want string + wantErr bool + }{ + { + name: "provider test fails", + args: args{ + ctx: context.Background(), + }, + expectFn: func(mp *mock_auth.MockProvider) { + mp.EXPECT().Test(gomock.Any()).Return(nil, assert.AnError) + }, + want: "", + wantErr: true, + }, + { + name: "url empty fails", + args: args{ + ctx: context.Background(), + }, + expectFn: func(mp *mock_auth.MockProvider) { + mp.EXPECT().Test(gomock.Any()).Return(&slack.AuthTestResponse{URL: ""}, nil) + }, + want: "", + wantErr: true, + }, + { + name: "url sanitize fails", + args: args{ + ctx: context.Background(), + }, + expectFn: func(mp *mock_auth.MockProvider) { + mp.EXPECT().Test(gomock.Any()).Return(&slack.AuthTestResponse{URL: "ftp://lol.example.com"}, nil) + }, + want: "", + wantErr: true, + }, + { + name: "success", + args: args{ + ctx: context.Background(), + }, + expectFn: func(mp *mock_auth.MockProvider) { + mp.EXPECT().Test(gomock.Any()).Return(fixtures.LoadPtr[slack.AuthTestResponse](string(fixtures.TestAuthTestInfo)), nil) + mp.EXPECT().Validate().Return(nil) + mp.EXPECT().SlackToken().Return(fixtures.TestClientToken) + mp.EXPECT().Cookies().Return([]*http.Cookie{}) + }, + want: "test", + wantErr: false, + }, + { + name: "save provider fails", + args: args{ + ctx: context.Background(), + }, + expectFn: func(mp *mock_auth.MockProvider) { + mp.EXPECT().Test(gomock.Any()).Return(fixtures.LoadPtr[slack.AuthTestResponse](string(fixtures.TestAuthTestInfo)), nil) + mp.EXPECT().Validate().Return(assert.AnError) // emulate the provider validation error + }, + want: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + dir := t.TempDir() + m := &Manager{ + dir: dir, + authOptions: tt.fields.authOptions, + userFile: tt.fields.userFile, + channelFile: tt.fields.channelFile, + } + ctrl := gomock.NewController(t) + mp := mock_auth.NewMockProvider(ctrl) + if tt.expectFn != nil { + tt.expectFn(mp) + } + got, err := m.CreateAndSelect(tt.args.ctx, mp) + if (err != nil) != tt.wantErr { + t.Errorf("Manager.CreateAndSelect() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("Manager.CreateAndSelect() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/structures/structures.go b/internal/structures/structures.go index fe99ab28..017eaf6c 100644 --- a/internal/structures/structures.go +++ b/internal/structures/structures.go @@ -3,7 +3,10 @@ package structures import ( "errors" + "fmt" + "net/url" "regexp" + "strings" ) const ( @@ -26,3 +29,28 @@ func ValidateToken(token string) error { } return nil } + +var ErrInvalidDomain = errors.New("invalid domain") + +// ExtractWorkspace takes a workspace name or URL and returns the workspace name. +func ExtractWorkspace(workspace string) (string, error) { + if !strings.Contains(workspace, ".slack.com") && !strings.Contains(workspace, ".") { + return workspace, nil + } + if strings.HasPrefix(workspace, "https://") { + uri, err := url.Parse(workspace) + if err != nil { + return "", err + } + workspace = uri.Host + } + // parse + name, domain, found := strings.Cut(workspace, ".") + if !found { + return "", errors.New("workspace name is empty") + } + if strings.TrimRight(domain, "/") != "slack.com" { + return "", fmt.Errorf("%s: %w", domain, ErrInvalidDomain) + } + return name, nil +} diff --git a/internal/structures/structures_test.go b/internal/structures/structures_test.go index 7166a83e..0b176244 100644 --- a/internal/structures/structures_test.go +++ b/internal/structures/structures_test.go @@ -75,3 +75,34 @@ func TestValidateToken(t *testing.T) { }) } } + +func TestSanitize(t *testing.T) { + type args struct { + workspace string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + {"not a URL", args{"blahblah"}, "blahblah", false}, + {"url slash", args{"https://blahblah.slack.com/"}, "blahblah", false}, + {"url no slash", args{"https://blahblah.slack.com"}, "blahblah", false}, + {"url no schema slash", args{"blahblah.slack.com/"}, "blahblah", false}, + {"url no schema no slash", args{"blahblah.slack.com"}, "blahblah", false}, + {"not a slack domain", args{"blahblah.example.com"}, "", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ExtractWorkspace(tt.args.workspace) + if (err != nil) != tt.wantErr { + t.Errorf("sanitize() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("sanitize() got = %v, want %v", got, tt.want) + } + }) + } +}