Skip to content

Commit 5d93f6c

Browse files
committed
test: add test coverage for untested functions
1 parent ca87f1d commit 5d93f6c

18 files changed

Lines changed: 1897 additions & 386 deletions

File tree

cmd/datastore/query_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,3 +465,55 @@ func prepareExportMockData(cm *shared.ClientsMock, numberOfItems int, maxItemsTo
465465
}
466466
return data, nil
467467
}
468+
469+
func Test_getExpressionPatterns(t *testing.T) {
470+
tests := map[string]struct {
471+
expression string
472+
wantAttrs int
473+
wantVals int
474+
}{
475+
"expression with attributes and values": {
476+
expression: "#name = :name AND #status = :status",
477+
wantAttrs: 2,
478+
wantVals: 2,
479+
},
480+
"empty expression": {
481+
expression: "",
482+
wantAttrs: 0,
483+
wantVals: 0,
484+
},
485+
}
486+
for name, tc := range tests {
487+
t.Run(name, func(t *testing.T) {
488+
attrs, vals := getExpressionPatterns(tc.expression)
489+
assert.Len(t, attrs, tc.wantAttrs)
490+
assert.Len(t, vals, tc.wantVals)
491+
})
492+
}
493+
}
494+
495+
func Test_mapAttributeFlag(t *testing.T) {
496+
tests := map[string]struct {
497+
flag string
498+
wantErr bool
499+
}{
500+
"valid JSON": {
501+
flag: `{"#name":"name"}`,
502+
},
503+
"invalid JSON": {
504+
flag: `not json`,
505+
wantErr: true,
506+
},
507+
}
508+
for name, tc := range tests {
509+
t.Run(name, func(t *testing.T) {
510+
result, err := mapAttributeFlag(tc.flag)
511+
if tc.wantErr {
512+
assert.Error(t, err)
513+
} else {
514+
assert.NoError(t, err)
515+
assert.NotNil(t, result)
516+
}
517+
})
518+
}
519+
}

internal/api/app_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,3 +519,51 @@ func TestClient_DeveloperAppInstall_RequestAppApproval(t *testing.T) {
519519
})
520520
}
521521
}
522+
523+
func TestClient_GetAppStatus_Ok(t *testing.T) {
524+
ctx := slackcontext.MockContext(t.Context())
525+
c, teardown := NewFakeClient(t, FakeClientParams{
526+
ExpectedMethod: appStatusMethod,
527+
Response: `{"ok":true,"apps":[{"app_id":"A123","status":"installed"}]}`,
528+
})
529+
defer teardown()
530+
result, err := c.GetAppStatus(ctx, "token", []string{"A123"}, "T123")
531+
require.NoError(t, err)
532+
require.NotNil(t, result)
533+
}
534+
535+
func TestClient_GetAppStatus_Error(t *testing.T) {
536+
ctx := slackcontext.MockContext(t.Context())
537+
c, teardown := NewFakeClient(t, FakeClientParams{
538+
ExpectedMethod: appStatusMethod,
539+
Response: `{"ok":false,"error":"invalid_app"}`,
540+
})
541+
defer teardown()
542+
_, err := c.GetAppStatus(ctx, "token", []string{"A123"}, "T123")
543+
require.Error(t, err)
544+
require.Contains(t, err.Error(), "invalid_app")
545+
}
546+
547+
func TestClient_ConnectionsOpen_Ok(t *testing.T) {
548+
ctx := slackcontext.MockContext(t.Context())
549+
c, teardown := NewFakeClient(t, FakeClientParams{
550+
ExpectedMethod: appConnectionsOpenMethod,
551+
Response: `{"ok":true,"url":"wss://example.com/ws"}`,
552+
})
553+
defer teardown()
554+
result, err := c.ConnectionsOpen(ctx, "token")
555+
require.NoError(t, err)
556+
require.Equal(t, "wss://example.com/ws", result.URL)
557+
}
558+
559+
func TestClient_ConnectionsOpen_Error(t *testing.T) {
560+
ctx := slackcontext.MockContext(t.Context())
561+
c, teardown := NewFakeClient(t, FakeClientParams{
562+
ExpectedMethod: appConnectionsOpenMethod,
563+
Response: `{"ok":false,"error":"token_revoked"}`,
564+
})
565+
defer teardown()
566+
_, err := c.ConnectionsOpen(ctx, "token")
567+
require.Error(t, err)
568+
require.Contains(t, err.Error(), "token_revoked")
569+
}

internal/api/datastore_test.go

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,3 +490,192 @@ func TestClient_AppsDatastoreGet(t *testing.T) {
490490
})
491491
}
492492
}
493+
494+
func TestClient_AppsDatastoreBulkPut(t *testing.T) {
495+
tests := map[string]struct {
496+
request types.AppDatastoreBulkPut
497+
httpResponseJSON string
498+
statusCode int
499+
wantErr bool
500+
errMessage string
501+
}{
502+
"success": {
503+
request: types.AppDatastoreBulkPut{
504+
Datastore: "my_ds",
505+
App: "A1",
506+
Items: []map[string]interface{}{{"id": "1", "name": "test"}},
507+
},
508+
httpResponseJSON: `{"ok":true,"datastore":"my_ds"}`,
509+
},
510+
"api_error": {
511+
request: types.AppDatastoreBulkPut{
512+
Datastore: "my_ds",
513+
App: "A1",
514+
Items: []map[string]interface{}{{"id": "1"}},
515+
},
516+
httpResponseJSON: `{"ok":false,"error":"datastore_error"}`,
517+
wantErr: true,
518+
errMessage: "datastore_error",
519+
},
520+
}
521+
for name, tc := range tests {
522+
t.Run(name, func(t *testing.T) {
523+
ctx := slackcontext.MockContext(t.Context())
524+
c, teardown := NewFakeClient(t, FakeClientParams{
525+
ExpectedMethod: appDatastoreBulkPutMethod,
526+
Response: tc.httpResponseJSON,
527+
StatusCode: tc.statusCode,
528+
})
529+
defer teardown()
530+
_, err := c.AppsDatastoreBulkPut(ctx, "token", tc.request)
531+
if tc.wantErr {
532+
require.Error(t, err)
533+
require.Contains(t, err.Error(), tc.errMessage)
534+
} else {
535+
require.NoError(t, err)
536+
}
537+
})
538+
}
539+
}
540+
541+
func TestClient_AppsDatastoreCount(t *testing.T) {
542+
tests := map[string]struct {
543+
request types.AppDatastoreCount
544+
httpResponseJSON string
545+
statusCode int
546+
wantCount int
547+
wantErr bool
548+
errMessage string
549+
}{
550+
"success": {
551+
request: types.AppDatastoreCount{
552+
Datastore: "my_ds",
553+
App: "A1",
554+
},
555+
httpResponseJSON: `{"ok":true,"datastore":"my_ds","count":42}`,
556+
wantCount: 42,
557+
},
558+
"api_error": {
559+
request: types.AppDatastoreCount{
560+
Datastore: "my_ds",
561+
App: "A1",
562+
},
563+
httpResponseJSON: `{"ok":false,"error":"datastore_error"}`,
564+
wantErr: true,
565+
errMessage: "datastore_error",
566+
},
567+
}
568+
for name, tc := range tests {
569+
t.Run(name, func(t *testing.T) {
570+
ctx := slackcontext.MockContext(t.Context())
571+
c, teardown := NewFakeClient(t, FakeClientParams{
572+
ExpectedMethod: appDatastoreCountMethod,
573+
Response: tc.httpResponseJSON,
574+
StatusCode: tc.statusCode,
575+
})
576+
defer teardown()
577+
got, err := c.AppsDatastoreCount(ctx, "token", tc.request)
578+
if tc.wantErr {
579+
require.Error(t, err)
580+
require.Contains(t, err.Error(), tc.errMessage)
581+
} else {
582+
require.NoError(t, err)
583+
require.Equal(t, tc.wantCount, got.Count)
584+
}
585+
})
586+
}
587+
}
588+
589+
func TestClient_AppsDatastoreBulkDelete(t *testing.T) {
590+
tests := map[string]struct {
591+
request types.AppDatastoreBulkDelete
592+
httpResponseJSON string
593+
statusCode int
594+
wantErr bool
595+
errMessage string
596+
}{
597+
"success": {
598+
request: types.AppDatastoreBulkDelete{
599+
Datastore: "my_ds",
600+
App: "A1",
601+
IDs: []string{"id1", "id2"},
602+
},
603+
httpResponseJSON: `{"ok":true}`,
604+
},
605+
"api_error": {
606+
request: types.AppDatastoreBulkDelete{
607+
Datastore: "my_ds",
608+
App: "A1",
609+
IDs: []string{"id1"},
610+
},
611+
httpResponseJSON: `{"ok":false,"error":"not_found"}`,
612+
wantErr: true,
613+
errMessage: "not_found",
614+
},
615+
}
616+
for name, tc := range tests {
617+
t.Run(name, func(t *testing.T) {
618+
ctx := slackcontext.MockContext(t.Context())
619+
c, teardown := NewFakeClient(t, FakeClientParams{
620+
ExpectedMethod: appDatastoreBulkDeleteMethod,
621+
Response: tc.httpResponseJSON,
622+
StatusCode: tc.statusCode,
623+
})
624+
defer teardown()
625+
_, err := c.AppsDatastoreBulkDelete(ctx, "token", tc.request)
626+
if tc.wantErr {
627+
require.Error(t, err)
628+
require.Contains(t, err.Error(), tc.errMessage)
629+
} else {
630+
require.NoError(t, err)
631+
}
632+
})
633+
}
634+
}
635+
636+
func TestClient_AppsDatastoreBulkGet(t *testing.T) {
637+
tests := map[string]struct {
638+
request types.AppDatastoreBulkGet
639+
httpResponseJSON string
640+
statusCode int
641+
wantErr bool
642+
errMessage string
643+
}{
644+
"success": {
645+
request: types.AppDatastoreBulkGet{
646+
Datastore: "my_ds",
647+
App: "A1",
648+
IDs: []string{"id1", "id2"},
649+
},
650+
httpResponseJSON: `{"ok":true,"datastore":"my_ds","items":[{"id":"id1","name":"test"}]}`,
651+
},
652+
"api_error": {
653+
request: types.AppDatastoreBulkGet{
654+
Datastore: "my_ds",
655+
App: "A1",
656+
IDs: []string{"id1"},
657+
},
658+
httpResponseJSON: `{"ok":false,"error":"not_found"}`,
659+
wantErr: true,
660+
errMessage: "not_found",
661+
},
662+
}
663+
for name, tc := range tests {
664+
t.Run(name, func(t *testing.T) {
665+
ctx := slackcontext.MockContext(t.Context())
666+
c, teardown := NewFakeClient(t, FakeClientParams{
667+
ExpectedMethod: appDatastoreBulkGetMethod,
668+
Response: tc.httpResponseJSON,
669+
StatusCode: tc.statusCode,
670+
})
671+
defer teardown()
672+
_, err := c.AppsDatastoreBulkGet(ctx, "token", tc.request)
673+
if tc.wantErr {
674+
require.Error(t, err)
675+
require.Contains(t, err.Error(), tc.errMessage)
676+
} else {
677+
require.NoError(t, err)
678+
}
679+
})
680+
}
681+
}

internal/config/flags_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,44 @@ import (
2424
"github.com/stretchr/testify/assert"
2525
)
2626

27+
func TestSetFlags(t *testing.T) {
28+
fs := slackdeps.NewFsMock()
29+
os := slackdeps.NewOsMock()
30+
config := NewConfig(fs, os)
31+
cmd := &cobra.Command{}
32+
cmd.Flags().String("test-flag", "default", "a test flag")
33+
34+
config.SetFlags(cmd)
35+
assert.NotNil(t, config.Flags)
36+
f := config.Flags.Lookup("test-flag")
37+
assert.NotNil(t, f)
38+
assert.Equal(t, "default", f.DefValue)
39+
}
40+
41+
func TestInitializeGlobalFlags(t *testing.T) {
42+
fs := slackdeps.NewFsMock()
43+
os := slackdeps.NewOsMock()
44+
config := NewConfig(fs, os)
45+
cmd := &cobra.Command{}
46+
47+
config.InitializeGlobalFlags(cmd)
48+
49+
// Verify that key persistent flags were registered
50+
flagNames := []string{
51+
"apihost", "app", "config-dir", "experiment",
52+
"force", "no-color", "skip-update", "slackdev",
53+
"runtime", "team", "token", "verbose",
54+
}
55+
for _, name := range flagNames {
56+
f := cmd.PersistentFlags().Lookup(name)
57+
assert.NotNil(t, f, "flag %s should be registered", name)
58+
}
59+
60+
// Verify hidden flags
61+
assert.True(t, cmd.PersistentFlags().Lookup("apihost").Hidden)
62+
assert.True(t, cmd.PersistentFlags().Lookup("slackdev").Hidden)
63+
}
64+
2765
func TestDeprecatedFlagSubstitutions(t *testing.T) {
2866
tests := map[string]struct {
2967
expectedWarnings []string

internal/deputil/url_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,30 @@ func Test_URLChecker(t *testing.T) {
5353
httpClientMock.On("Head", mock.Anything).Return(nil, fmt.Errorf("HTTPClient error"))
5454
},
5555
},
56+
"Returns an empty string for HTTP 500 Internal Server Error": {
57+
url: "https://example.com/server-error",
58+
expectedURL: "",
59+
setupHTTPClientMock: func(httpClientMock *slackhttp.HTTPClientMock) {
60+
res := slackhttp.MockHTTPResponse(http.StatusInternalServerError, "Internal Server Error")
61+
httpClientMock.On("Head", mock.Anything).Return(res, nil)
62+
},
63+
},
64+
"Returns an empty string for HTTP 301 redirect": {
65+
url: "https://example.com/redirect",
66+
expectedURL: "",
67+
setupHTTPClientMock: func(httpClientMock *slackhttp.HTTPClientMock) {
68+
res := slackhttp.MockHTTPResponse(http.StatusMovedPermanently, "Moved")
69+
httpClientMock.On("Head", mock.Anything).Return(res, nil)
70+
},
71+
},
72+
"Returns an empty string for HTTP 403 Forbidden": {
73+
url: "https://example.com/forbidden",
74+
expectedURL: "",
75+
setupHTTPClientMock: func(httpClientMock *slackhttp.HTTPClientMock) {
76+
res := slackhttp.MockHTTPResponse(http.StatusForbidden, "Forbidden")
77+
httpClientMock.On("Head", mock.Anything).Return(res, nil)
78+
},
79+
},
5680
}
5781
for name, tc := range tests {
5882
t.Run(name, func(t *testing.T) {

0 commit comments

Comments
 (0)