migrate from mockery to moq

This commit is contained in:
Dmitry Verkhoturov
2022-10-02 21:21:28 -05:00
committed by Umputun
parent 53cc370727
commit 050f1b7941
29 changed files with 903 additions and 5340 deletions
-1
View File
@@ -33,7 +33,6 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rs/xid v1.4.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/stretchr/objx v0.4.0 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
golang.org/x/image v0.0.0-20220617043117-41969df76e82 // indirect
golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect
-1
View File
@@ -58,7 +58,6 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+26 -25
View File
@@ -12,7 +12,6 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/umputun/remark42/backend/app/store/image"
@@ -95,7 +94,8 @@ func TestImage_Replace(t *testing.T) {
}
func TestImage_Routes(t *testing.T) {
imageStore := image.MockStore{}
// no image supposed to be cached
imageStore := image.StoreMock{LoadFunc: func(id string) ([]byte, error) { return nil, nil }}
img := Image{
HTTP2HTTPS: true,
RemarkURL: "https://demo.remark42.com",
@@ -110,9 +110,6 @@ func TestImage_Routes(t *testing.T) {
encodedImgURL := base64.URLEncoding.EncodeToString([]byte(httpSrv.URL + "/image/img1.png"))
// no image supposed to be cached
imageStore.On("Load", mock.Anything).Times(2).Return(nil, nil)
resp, err := http.Get(ts.URL + "/?src=" + encodedImgURL)
require.NoError(t, err)
assert.NoError(t, resp.Body.Close())
@@ -131,10 +128,11 @@ func TestImage_Routes(t *testing.T) {
require.NoError(t, err)
assert.NoError(t, resp.Body.Close())
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
assert.Equal(t, 2, len(imageStore.LoadCalls()))
}
func TestImage_DisabledCachingAndHTTP2HTTPS(t *testing.T) {
imageStore := image.MockStore{}
imageStore := image.StoreMock{LoadFunc: func(id string) ([]byte, error) { return nil, nil }}
img := Image{
RemarkURL: "https://demo.remark42.com",
RoutePath: "/api/v1/proxy",
@@ -148,8 +146,6 @@ func TestImage_DisabledCachingAndHTTP2HTTPS(t *testing.T) {
encodedImgURL := base64.URLEncoding.EncodeToString([]byte(httpSrv.URL + "/image/img1.png"))
imageStore.On("Load", mock.Anything).Once().Return(nil, nil)
resp, err := http.Get(ts.URL + "/?src=" + encodedImgURL)
require.NoError(t, err)
assert.NoError(t, resp.Body.Close())
@@ -157,11 +153,18 @@ func TestImage_DisabledCachingAndHTTP2HTTPS(t *testing.T) {
assert.Equal(t, "1462", resp.Header["Content-Length"][0])
assert.Equal(t, "image/png", resp.Header["Content-Type"][0])
imageStore.AssertCalled(t, "Load", mock.Anything)
assert.Equal(t, 1, len(imageStore.LoadCalls()))
}
func TestImage_RoutesCachingImage(t *testing.T) {
imageStore := image.MockStore{}
imageStore := image.StoreMock{
LoadFunc: func(id string) ([]byte, error) {
return nil, nil
},
SaveFunc: func(id string, img []byte) error {
return nil
},
}
img := Image{
CacheExternal: true,
RemarkURL: "https://demo.remark42.com",
@@ -177,9 +180,6 @@ func TestImage_RoutesCachingImage(t *testing.T) {
imgURL := httpSrv.URL + "/image/img1.png"
encodedImgURL := base64.URLEncoding.EncodeToString([]byte(imgURL))
imageStore.On("Load", mock.Anything).Once().Return(nil, nil)
imageStore.On("Save", mock.Anything, mock.Anything).Once().Return(nil)
resp, err := http.Get(ts.URL + "/?src=" + encodedImgURL)
require.NoError(t, err)
assert.NoError(t, resp.Body.Close())
@@ -187,12 +187,18 @@ func TestImage_RoutesCachingImage(t *testing.T) {
assert.Equal(t, "1462", resp.Header["Content-Length"][0])
assert.Equal(t, "image/png", resp.Header["Content-Type"][0])
imageStore.AssertCalled(t, "Load", mock.Anything)
imageStore.AssertCalled(t, "Save", "cached_images/4b84b15bff6ee5796152495a230e45e3d7e947d9-"+image.Sha1Str(imgURL), gopherPNGBytes())
assert.Equal(t, 1, len(imageStore.LoadCalls()))
assert.Equal(t, 1, len(imageStore.SaveCalls()))
assert.Equal(t, "cached_images/4b84b15bff6ee5796152495a230e45e3d7e947d9-"+image.Sha1Str(imgURL), imageStore.SaveCalls()[0].ID)
assert.Equal(t, gopherPNGBytes(), imageStore.SaveCalls()[0].Img)
}
func TestImage_RoutesUsingCachedImage(t *testing.T) {
imageStore := image.MockStore{}
// In order to validate that cached data used cache "will return" some other data from what http server would
testImage := []byte(fmt.Sprintf("%256s", "X"))
imageStore := image.StoreMock{LoadFunc: func(id string) ([]byte, error) {
return testImage, nil
}}
img := Image{
CacheExternal: true,
RemarkURL: "https://demo.remark42.com",
@@ -207,10 +213,6 @@ func TestImage_RoutesUsingCachedImage(t *testing.T) {
encodedImgURL := base64.URLEncoding.EncodeToString([]byte(httpSrv.URL + "/image/img1.png"))
// In order to validate that cached data used cache "will return" some other data from what http server would
testImage := []byte(fmt.Sprintf("%256s", "X"))
imageStore.On("Load", mock.Anything).Once().Return(testImage, nil)
resp, err := http.Get(ts.URL + "/?src=" + encodedImgURL)
require.NoError(t, err)
assert.NoError(t, resp.Body.Close())
@@ -219,11 +221,12 @@ func TestImage_RoutesUsingCachedImage(t *testing.T) {
assert.Equal(t, "text/plain; charset=utf-8", resp.Header["Content-Type"][0],
"if you save text you receive text/plain in response, that's only fair option you got")
imageStore.AssertCalled(t, "Load", mock.Anything)
assert.Equal(t, 1, len(imageStore.LoadCalls()))
}
func TestImage_RoutesTimedOut(t *testing.T) {
imageStore := image.MockStore{}
// no image supposed to be cached
imageStore := image.StoreMock{LoadFunc: func(id string) ([]byte, error) { return nil, nil }}
img := Image{
HTTP2HTTPS: true,
RemarkURL: "https://demo.remark42.com",
@@ -239,9 +242,6 @@ func TestImage_RoutesTimedOut(t *testing.T) {
encodedImgURL := base64.URLEncoding.EncodeToString([]byte(httpSrv.URL + "/image/img-slow.png"))
// no image supposed to be cached
imageStore.On("Load", mock.Anything).Once().Return(nil, nil)
resp, err := http.Get(ts.URL + "/?src=" + encodedImgURL)
require.NoError(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
@@ -250,6 +250,7 @@ func TestImage_RoutesTimedOut(t *testing.T) {
require.NoError(t, err)
t.Log(string(b))
assert.True(t, strings.Contains(string(b), "deadline exceeded"))
assert.Equal(t, 1, len(imageStore.LoadCalls()))
}
func TestImage_ConvertProxyMode(t *testing.T) {
+2 -2
View File
@@ -11,8 +11,8 @@ import (
"github.com/umputun/remark42/backend/app/store"
)
// NOTE: mockery should be installed globally and works with `go generate ./...`
//go:generate mockery --inpackage --name Interface --filename engine_mock.go
// NOTE: matryer/moq should be installed globally and works with `go generate ./...`
//go:generate moq --out engine_mock.go . Interface
// Interface defines methods provided by low-level storage engine
type Interface interface {
+461 -199
View File
@@ -1,246 +1,508 @@
// Code generated by mockery v2.14.0. DO NOT EDIT.
// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package engine
import (
mock "github.com/stretchr/testify/mock"
store "github.com/umputun/remark42/backend/app/store"
"sync"
)
// MockInterface is an autogenerated mock type for the Interface type
type MockInterface struct {
mock.Mock
}
// Ensure, that InterfaceMock does implement Interface.
// If this is not the case, regenerate this file with moq.
var _ Interface = &InterfaceMock{}
// Close provides a mock function with given fields:
func (_m *MockInterface) Close() error {
ret := _m.Called()
// InterfaceMock is a mock implementation of Interface.
//
// func TestSomethingThatUsesInterface(t *testing.T) {
//
// // make and configure a mocked Interface
// mockedInterface := &InterfaceMock{
// CloseFunc: func() error {
// panic("mock out the Close method")
// },
// CountFunc: func(req FindRequest) (int, error) {
// panic("mock out the Count method")
// },
// CreateFunc: func(comment store.Comment) (string, error) {
// panic("mock out the Create method")
// },
// DeleteFunc: func(req DeleteRequest) error {
// panic("mock out the Delete method")
// },
// FindFunc: func(req FindRequest) ([]store.Comment, error) {
// panic("mock out the Find method")
// },
// FlagFunc: func(req FlagRequest) (bool, error) {
// panic("mock out the Flag method")
// },
// GetFunc: func(req GetRequest) (store.Comment, error) {
// panic("mock out the Get method")
// },
// InfoFunc: func(req InfoRequest) ([]store.PostInfo, error) {
// panic("mock out the Info method")
// },
// ListFlagsFunc: func(req FlagRequest) ([]interface{}, error) {
// panic("mock out the ListFlags method")
// },
// UpdateFunc: func(comment store.Comment) error {
// panic("mock out the Update method")
// },
// UserDetailFunc: func(req UserDetailRequest) ([]UserDetailEntry, error) {
// panic("mock out the UserDetail method")
// },
// }
//
// // use mockedInterface in code that requires Interface
// // and then make assertions.
//
// }
type InterfaceMock struct {
// CloseFunc mocks the Close method.
CloseFunc func() error
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
// CountFunc mocks the Count method.
CountFunc func(req FindRequest) (int, error)
return r0
}
// CreateFunc mocks the Create method.
CreateFunc func(comment store.Comment) (string, error)
// Count provides a mock function with given fields: req
func (_m *MockInterface) Count(req FindRequest) (int, error) {
ret := _m.Called(req)
// DeleteFunc mocks the Delete method.
DeleteFunc func(req DeleteRequest) error
var r0 int
if rf, ok := ret.Get(0).(func(FindRequest) int); ok {
r0 = rf(req)
} else {
r0 = ret.Get(0).(int)
}
// FindFunc mocks the Find method.
FindFunc func(req FindRequest) ([]store.Comment, error)
var r1 error
if rf, ok := ret.Get(1).(func(FindRequest) error); ok {
r1 = rf(req)
} else {
r1 = ret.Error(1)
}
// FlagFunc mocks the Flag method.
FlagFunc func(req FlagRequest) (bool, error)
return r0, r1
}
// GetFunc mocks the Get method.
GetFunc func(req GetRequest) (store.Comment, error)
// Create provides a mock function with given fields: comment
func (_m *MockInterface) Create(comment store.Comment) (string, error) {
ret := _m.Called(comment)
// InfoFunc mocks the Info method.
InfoFunc func(req InfoRequest) ([]store.PostInfo, error)
var r0 string
if rf, ok := ret.Get(0).(func(store.Comment) string); ok {
r0 = rf(comment)
} else {
r0 = ret.Get(0).(string)
}
// ListFlagsFunc mocks the ListFlags method.
ListFlagsFunc func(req FlagRequest) ([]interface{}, error)
var r1 error
if rf, ok := ret.Get(1).(func(store.Comment) error); ok {
r1 = rf(comment)
} else {
r1 = ret.Error(1)
}
// UpdateFunc mocks the Update method.
UpdateFunc func(comment store.Comment) error
return r0, r1
}
// UserDetailFunc mocks the UserDetail method.
UserDetailFunc func(req UserDetailRequest) ([]UserDetailEntry, error)
// Delete provides a mock function with given fields: req
func (_m *MockInterface) Delete(req DeleteRequest) error {
ret := _m.Called(req)
var r0 error
if rf, ok := ret.Get(0).(func(DeleteRequest) error); ok {
r0 = rf(req)
} else {
r0 = ret.Error(0)
}
return r0
}
// Find provides a mock function with given fields: req
func (_m *MockInterface) Find(req FindRequest) ([]store.Comment, error) {
ret := _m.Called(req)
var r0 []store.Comment
if rf, ok := ret.Get(0).(func(FindRequest) []store.Comment); ok {
r0 = rf(req)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]store.Comment)
// calls tracks calls to the methods.
calls struct {
// Close holds details about calls to the Close method.
Close []struct {
}
// Count holds details about calls to the Count method.
Count []struct {
// Req is the req argument value.
Req FindRequest
}
// Create holds details about calls to the Create method.
Create []struct {
// Comment is the comment argument value.
Comment store.Comment
}
// Delete holds details about calls to the Delete method.
Delete []struct {
// Req is the req argument value.
Req DeleteRequest
}
// Find holds details about calls to the Find method.
Find []struct {
// Req is the req argument value.
Req FindRequest
}
// Flag holds details about calls to the Flag method.
Flag []struct {
// Req is the req argument value.
Req FlagRequest
}
// Get holds details about calls to the Get method.
Get []struct {
// Req is the req argument value.
Req GetRequest
}
// Info holds details about calls to the Info method.
Info []struct {
// Req is the req argument value.
Req InfoRequest
}
// ListFlags holds details about calls to the ListFlags method.
ListFlags []struct {
// Req is the req argument value.
Req FlagRequest
}
// Update holds details about calls to the Update method.
Update []struct {
// Comment is the comment argument value.
Comment store.Comment
}
// UserDetail holds details about calls to the UserDetail method.
UserDetail []struct {
// Req is the req argument value.
Req UserDetailRequest
}
}
var r1 error
if rf, ok := ret.Get(1).(func(FindRequest) error); ok {
r1 = rf(req)
} else {
r1 = ret.Error(1)
}
return r0, r1
lockClose sync.RWMutex
lockCount sync.RWMutex
lockCreate sync.RWMutex
lockDelete sync.RWMutex
lockFind sync.RWMutex
lockFlag sync.RWMutex
lockGet sync.RWMutex
lockInfo sync.RWMutex
lockListFlags sync.RWMutex
lockUpdate sync.RWMutex
lockUserDetail sync.RWMutex
}
// Flag provides a mock function with given fields: req
func (_m *MockInterface) Flag(req FlagRequest) (bool, error) {
ret := _m.Called(req)
var r0 bool
if rf, ok := ret.Get(0).(func(FlagRequest) bool); ok {
r0 = rf(req)
} else {
r0 = ret.Get(0).(bool)
// Close calls CloseFunc.
func (mock *InterfaceMock) Close() error {
if mock.CloseFunc == nil {
panic("InterfaceMock.CloseFunc: method is nil but Interface.Close was just called")
}
var r1 error
if rf, ok := ret.Get(1).(func(FlagRequest) error); ok {
r1 = rf(req)
} else {
r1 = ret.Error(1)
}
return r0, r1
callInfo := struct {
}{}
mock.lockClose.Lock()
mock.calls.Close = append(mock.calls.Close, callInfo)
mock.lockClose.Unlock()
return mock.CloseFunc()
}
// Get provides a mock function with given fields: req
func (_m *MockInterface) Get(req GetRequest) (store.Comment, error) {
ret := _m.Called(req)
var r0 store.Comment
if rf, ok := ret.Get(0).(func(GetRequest) store.Comment); ok {
r0 = rf(req)
} else {
r0 = ret.Get(0).(store.Comment)
// CloseCalls gets all the calls that were made to Close.
// Check the length with:
//
// len(mockedInterface.CloseCalls())
func (mock *InterfaceMock) CloseCalls() []struct {
} {
var calls []struct {
}
var r1 error
if rf, ok := ret.Get(1).(func(GetRequest) error); ok {
r1 = rf(req)
} else {
r1 = ret.Error(1)
}
return r0, r1
mock.lockClose.RLock()
calls = mock.calls.Close
mock.lockClose.RUnlock()
return calls
}
// Info provides a mock function with given fields: req
func (_m *MockInterface) Info(req InfoRequest) ([]store.PostInfo, error) {
ret := _m.Called(req)
var r0 []store.PostInfo
if rf, ok := ret.Get(0).(func(InfoRequest) []store.PostInfo); ok {
r0 = rf(req)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]store.PostInfo)
}
// Count calls CountFunc.
func (mock *InterfaceMock) Count(req FindRequest) (int, error) {
if mock.CountFunc == nil {
panic("InterfaceMock.CountFunc: method is nil but Interface.Count was just called")
}
var r1 error
if rf, ok := ret.Get(1).(func(InfoRequest) error); ok {
r1 = rf(req)
} else {
r1 = ret.Error(1)
callInfo := struct {
Req FindRequest
}{
Req: req,
}
return r0, r1
mock.lockCount.Lock()
mock.calls.Count = append(mock.calls.Count, callInfo)
mock.lockCount.Unlock()
return mock.CountFunc(req)
}
// ListFlags provides a mock function with given fields: req
func (_m *MockInterface) ListFlags(req FlagRequest) ([]interface{}, error) {
ret := _m.Called(req)
var r0 []interface{}
if rf, ok := ret.Get(0).(func(FlagRequest) []interface{}); ok {
r0 = rf(req)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]interface{})
}
// CountCalls gets all the calls that were made to Count.
// Check the length with:
//
// len(mockedInterface.CountCalls())
func (mock *InterfaceMock) CountCalls() []struct {
Req FindRequest
} {
var calls []struct {
Req FindRequest
}
var r1 error
if rf, ok := ret.Get(1).(func(FlagRequest) error); ok {
r1 = rf(req)
} else {
r1 = ret.Error(1)
}
return r0, r1
mock.lockCount.RLock()
calls = mock.calls.Count
mock.lockCount.RUnlock()
return calls
}
// Update provides a mock function with given fields: comment
func (_m *MockInterface) Update(comment store.Comment) error {
ret := _m.Called(comment)
var r0 error
if rf, ok := ret.Get(0).(func(store.Comment) error); ok {
r0 = rf(comment)
} else {
r0 = ret.Error(0)
// Create calls CreateFunc.
func (mock *InterfaceMock) Create(comment store.Comment) (string, error) {
if mock.CreateFunc == nil {
panic("InterfaceMock.CreateFunc: method is nil but Interface.Create was just called")
}
return r0
}
// UserDetail provides a mock function with given fields: req
func (_m *MockInterface) UserDetail(req UserDetailRequest) ([]UserDetailEntry, error) {
ret := _m.Called(req)
var r0 []UserDetailEntry
if rf, ok := ret.Get(0).(func(UserDetailRequest) []UserDetailEntry); ok {
r0 = rf(req)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]UserDetailEntry)
}
callInfo := struct {
Comment store.Comment
}{
Comment: comment,
}
mock.lockCreate.Lock()
mock.calls.Create = append(mock.calls.Create, callInfo)
mock.lockCreate.Unlock()
return mock.CreateFunc(comment)
}
var r1 error
if rf, ok := ret.Get(1).(func(UserDetailRequest) error); ok {
r1 = rf(req)
} else {
r1 = ret.Error(1)
// CreateCalls gets all the calls that were made to Create.
// Check the length with:
//
// len(mockedInterface.CreateCalls())
func (mock *InterfaceMock) CreateCalls() []struct {
Comment store.Comment
} {
var calls []struct {
Comment store.Comment
}
return r0, r1
mock.lockCreate.RLock()
calls = mock.calls.Create
mock.lockCreate.RUnlock()
return calls
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
// Delete calls DeleteFunc.
func (mock *InterfaceMock) Delete(req DeleteRequest) error {
if mock.DeleteFunc == nil {
panic("InterfaceMock.DeleteFunc: method is nil but Interface.Delete was just called")
}
callInfo := struct {
Req DeleteRequest
}{
Req: req,
}
mock.lockDelete.Lock()
mock.calls.Delete = append(mock.calls.Delete, callInfo)
mock.lockDelete.Unlock()
return mock.DeleteFunc(req)
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)
// DeleteCalls gets all the calls that were made to Delete.
// Check the length with:
//
// len(mockedInterface.DeleteCalls())
func (mock *InterfaceMock) DeleteCalls() []struct {
Req DeleteRequest
} {
var calls []struct {
Req DeleteRequest
}
mock.lockDelete.RLock()
calls = mock.calls.Delete
mock.lockDelete.RUnlock()
return calls
}
t.Cleanup(func() { mock.AssertExpectations(t) })
// Find calls FindFunc.
func (mock *InterfaceMock) Find(req FindRequest) ([]store.Comment, error) {
if mock.FindFunc == nil {
panic("InterfaceMock.FindFunc: method is nil but Interface.Find was just called")
}
callInfo := struct {
Req FindRequest
}{
Req: req,
}
mock.lockFind.Lock()
mock.calls.Find = append(mock.calls.Find, callInfo)
mock.lockFind.Unlock()
return mock.FindFunc(req)
}
return mock
// FindCalls gets all the calls that were made to Find.
// Check the length with:
//
// len(mockedInterface.FindCalls())
func (mock *InterfaceMock) FindCalls() []struct {
Req FindRequest
} {
var calls []struct {
Req FindRequest
}
mock.lockFind.RLock()
calls = mock.calls.Find
mock.lockFind.RUnlock()
return calls
}
// Flag calls FlagFunc.
func (mock *InterfaceMock) Flag(req FlagRequest) (bool, error) {
if mock.FlagFunc == nil {
panic("InterfaceMock.FlagFunc: method is nil but Interface.Flag was just called")
}
callInfo := struct {
Req FlagRequest
}{
Req: req,
}
mock.lockFlag.Lock()
mock.calls.Flag = append(mock.calls.Flag, callInfo)
mock.lockFlag.Unlock()
return mock.FlagFunc(req)
}
// FlagCalls gets all the calls that were made to Flag.
// Check the length with:
//
// len(mockedInterface.FlagCalls())
func (mock *InterfaceMock) FlagCalls() []struct {
Req FlagRequest
} {
var calls []struct {
Req FlagRequest
}
mock.lockFlag.RLock()
calls = mock.calls.Flag
mock.lockFlag.RUnlock()
return calls
}
// Get calls GetFunc.
func (mock *InterfaceMock) Get(req GetRequest) (store.Comment, error) {
if mock.GetFunc == nil {
panic("InterfaceMock.GetFunc: method is nil but Interface.Get was just called")
}
callInfo := struct {
Req GetRequest
}{
Req: req,
}
mock.lockGet.Lock()
mock.calls.Get = append(mock.calls.Get, callInfo)
mock.lockGet.Unlock()
return mock.GetFunc(req)
}
// GetCalls gets all the calls that were made to Get.
// Check the length with:
//
// len(mockedInterface.GetCalls())
func (mock *InterfaceMock) GetCalls() []struct {
Req GetRequest
} {
var calls []struct {
Req GetRequest
}
mock.lockGet.RLock()
calls = mock.calls.Get
mock.lockGet.RUnlock()
return calls
}
// Info calls InfoFunc.
func (mock *InterfaceMock) Info(req InfoRequest) ([]store.PostInfo, error) {
if mock.InfoFunc == nil {
panic("InterfaceMock.InfoFunc: method is nil but Interface.Info was just called")
}
callInfo := struct {
Req InfoRequest
}{
Req: req,
}
mock.lockInfo.Lock()
mock.calls.Info = append(mock.calls.Info, callInfo)
mock.lockInfo.Unlock()
return mock.InfoFunc(req)
}
// InfoCalls gets all the calls that were made to Info.
// Check the length with:
//
// len(mockedInterface.InfoCalls())
func (mock *InterfaceMock) InfoCalls() []struct {
Req InfoRequest
} {
var calls []struct {
Req InfoRequest
}
mock.lockInfo.RLock()
calls = mock.calls.Info
mock.lockInfo.RUnlock()
return calls
}
// ListFlags calls ListFlagsFunc.
func (mock *InterfaceMock) ListFlags(req FlagRequest) ([]interface{}, error) {
if mock.ListFlagsFunc == nil {
panic("InterfaceMock.ListFlagsFunc: method is nil but Interface.ListFlags was just called")
}
callInfo := struct {
Req FlagRequest
}{
Req: req,
}
mock.lockListFlags.Lock()
mock.calls.ListFlags = append(mock.calls.ListFlags, callInfo)
mock.lockListFlags.Unlock()
return mock.ListFlagsFunc(req)
}
// ListFlagsCalls gets all the calls that were made to ListFlags.
// Check the length with:
//
// len(mockedInterface.ListFlagsCalls())
func (mock *InterfaceMock) ListFlagsCalls() []struct {
Req FlagRequest
} {
var calls []struct {
Req FlagRequest
}
mock.lockListFlags.RLock()
calls = mock.calls.ListFlags
mock.lockListFlags.RUnlock()
return calls
}
// Update calls UpdateFunc.
func (mock *InterfaceMock) Update(comment store.Comment) error {
if mock.UpdateFunc == nil {
panic("InterfaceMock.UpdateFunc: method is nil but Interface.Update was just called")
}
callInfo := struct {
Comment store.Comment
}{
Comment: comment,
}
mock.lockUpdate.Lock()
mock.calls.Update = append(mock.calls.Update, callInfo)
mock.lockUpdate.Unlock()
return mock.UpdateFunc(comment)
}
// UpdateCalls gets all the calls that were made to Update.
// Check the length with:
//
// len(mockedInterface.UpdateCalls())
func (mock *InterfaceMock) UpdateCalls() []struct {
Comment store.Comment
} {
var calls []struct {
Comment store.Comment
}
mock.lockUpdate.RLock()
calls = mock.calls.Update
mock.lockUpdate.RUnlock()
return calls
}
// UserDetail calls UserDetailFunc.
func (mock *InterfaceMock) UserDetail(req UserDetailRequest) ([]UserDetailEntry, error) {
if mock.UserDetailFunc == nil {
panic("InterfaceMock.UserDetailFunc: method is nil but Interface.UserDetail was just called")
}
callInfo := struct {
Req UserDetailRequest
}{
Req: req,
}
mock.lockUserDetail.Lock()
mock.calls.UserDetail = append(mock.calls.UserDetail, callInfo)
mock.lockUserDetail.Unlock()
return mock.UserDetailFunc(req)
}
// UserDetailCalls gets all the calls that were made to UserDetail.
// Check the length with:
//
// len(mockedInterface.UserDetailCalls())
func (mock *InterfaceMock) UserDetailCalls() []struct {
Req UserDetailRequest
} {
var calls []struct {
Req UserDetailRequest
}
mock.lockUserDetail.RLock()
calls = mock.calls.UserDetail
mock.lockUserDetail.RUnlock()
return calls
}
+2 -2
View File
@@ -3,8 +3,8 @@
// Service object encloses Store and add common methods, this is the one consumer should use.
package image
// NOTE: mockery should be installed globally and works with `go generate ./...`
//go:generate mockery --inpackage --name Store --filename image_mock.go
// NOTE: matryer/moq should be installed globally and works with `go generate ./...`
//go:generate moq --out image_mock.go . Store
import (
"bytes"
+271 -100
View File
@@ -1,130 +1,301 @@
// Code generated by mockery v2.14.0. DO NOT EDIT.
// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package image
import (
context "context"
"sync"
time "time"
mock "github.com/stretchr/testify/mock"
)
// MockStore is an autogenerated mock type for the Store type
type MockStore struct {
mock.Mock
}
// Ensure, that StoreMock does implement Store.
// If this is not the case, regenerate this file with moq.
var _ Store = &StoreMock{}
// Cleanup provides a mock function with given fields: ctx, ttl
func (_m *MockStore) Cleanup(ctx context.Context, ttl time.Duration) error {
ret := _m.Called(ctx, ttl)
// StoreMock is a mock implementation of Store.
//
// func TestSomethingThatUsesStore(t *testing.T) {
//
// // make and configure a mocked Store
// mockedStore := &StoreMock{
// CleanupFunc: func(ctx context.Context, ttl time.Duration) error {
// panic("mock out the Cleanup method")
// },
// CommitFunc: func(id string) error {
// panic("mock out the Commit method")
// },
// InfoFunc: func() (StoreInfo, error) {
// panic("mock out the Info method")
// },
// LoadFunc: func(id string) ([]byte, error) {
// panic("mock out the Load method")
// },
// ResetCleanupTimerFunc: func(id string) error {
// panic("mock out the ResetCleanupTimer method")
// },
// SaveFunc: func(id string, img []byte) error {
// panic("mock out the Save method")
// },
// }
//
// // use mockedStore in code that requires Store
// // and then make assertions.
//
// }
type StoreMock struct {
// CleanupFunc mocks the Cleanup method.
CleanupFunc func(ctx context.Context, ttl time.Duration) error
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, time.Duration) error); ok {
r0 = rf(ctx, ttl)
} else {
r0 = ret.Error(0)
}
// CommitFunc mocks the Commit method.
CommitFunc func(id string) error
return r0
}
// InfoFunc mocks the Info method.
InfoFunc func() (StoreInfo, error)
// Commit provides a mock function with given fields: id
func (_m *MockStore) Commit(id string) error {
ret := _m.Called(id)
// LoadFunc mocks the Load method.
LoadFunc func(id string) ([]byte, error)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(id)
} else {
r0 = ret.Error(0)
}
// ResetCleanupTimerFunc mocks the ResetCleanupTimer method.
ResetCleanupTimerFunc func(id string) error
return r0
}
// SaveFunc mocks the Save method.
SaveFunc func(id string, img []byte) error
// Info provides a mock function with given fields:
func (_m *MockStore) Info() (StoreInfo, error) {
ret := _m.Called()
var r0 StoreInfo
if rf, ok := ret.Get(0).(func() StoreInfo); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(StoreInfo)
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Load provides a mock function with given fields: id
func (_m *MockStore) Load(id string) ([]byte, error) {
ret := _m.Called(id)
var r0 []byte
if rf, ok := ret.Get(0).(func(string) []byte); ok {
r0 = rf(id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
// calls tracks calls to the methods.
calls struct {
// Cleanup holds details about calls to the Cleanup method.
Cleanup []struct {
// Ctx is the ctx argument value.
Ctx context.Context
// TTL is the ttl argument value.
TTL time.Duration
}
// Commit holds details about calls to the Commit method.
Commit []struct {
// ID is the id argument value.
ID string
}
// Info holds details about calls to the Info method.
Info []struct {
}
// Load holds details about calls to the Load method.
Load []struct {
// ID is the id argument value.
ID string
}
// ResetCleanupTimer holds details about calls to the ResetCleanupTimer method.
ResetCleanupTimer []struct {
// ID is the id argument value.
ID string
}
// Save holds details about calls to the Save method.
Save []struct {
// ID is the id argument value.
ID string
// Img is the img argument value.
Img []byte
}
}
lockCleanup sync.RWMutex
lockCommit sync.RWMutex
lockInfo sync.RWMutex
lockLoad sync.RWMutex
lockResetCleanupTimer sync.RWMutex
lockSave sync.RWMutex
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(id)
} else {
r1 = ret.Error(1)
// Cleanup calls CleanupFunc.
func (mock *StoreMock) Cleanup(ctx context.Context, ttl time.Duration) error {
if mock.CleanupFunc == nil {
panic("StoreMock.CleanupFunc: method is nil but Store.Cleanup was just called")
}
return r0, r1
}
// ResetCleanupTimer provides a mock function with given fields: id
func (_m *MockStore) ResetCleanupTimer(id string) error {
ret := _m.Called(id)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(id)
} else {
r0 = ret.Error(0)
callInfo := struct {
Ctx context.Context
TTL time.Duration
}{
Ctx: ctx,
TTL: ttl,
}
return r0
mock.lockCleanup.Lock()
mock.calls.Cleanup = append(mock.calls.Cleanup, callInfo)
mock.lockCleanup.Unlock()
return mock.CleanupFunc(ctx, ttl)
}
// Save provides a mock function with given fields: id, img
func (_m *MockStore) Save(id string, img []byte) error {
ret := _m.Called(id, img)
var r0 error
if rf, ok := ret.Get(0).(func(string, []byte) error); ok {
r0 = rf(id, img)
} else {
r0 = ret.Error(0)
// CleanupCalls gets all the calls that were made to Cleanup.
// Check the length with:
//
// len(mockedStore.CleanupCalls())
func (mock *StoreMock) CleanupCalls() []struct {
Ctx context.Context
TTL time.Duration
} {
var calls []struct {
Ctx context.Context
TTL time.Duration
}
return r0
mock.lockCleanup.RLock()
calls = mock.calls.Cleanup
mock.lockCleanup.RUnlock()
return calls
}
type mockConstructorTestingTNewMockStore interface {
mock.TestingT
Cleanup(func())
// Commit calls CommitFunc.
func (mock *StoreMock) Commit(id string) error {
if mock.CommitFunc == nil {
panic("StoreMock.CommitFunc: method is nil but Store.Commit was just called")
}
callInfo := struct {
ID string
}{
ID: id,
}
mock.lockCommit.Lock()
mock.calls.Commit = append(mock.calls.Commit, callInfo)
mock.lockCommit.Unlock()
return mock.CommitFunc(id)
}
// NewMockStore creates a new instance of MockStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockStore(t mockConstructorTestingTNewMockStore) *MockStore {
mock := &MockStore{}
mock.Mock.Test(t)
// CommitCalls gets all the calls that were made to Commit.
// Check the length with:
//
// len(mockedStore.CommitCalls())
func (mock *StoreMock) CommitCalls() []struct {
ID string
} {
var calls []struct {
ID string
}
mock.lockCommit.RLock()
calls = mock.calls.Commit
mock.lockCommit.RUnlock()
return calls
}
t.Cleanup(func() { mock.AssertExpectations(t) })
// Info calls InfoFunc.
func (mock *StoreMock) Info() (StoreInfo, error) {
if mock.InfoFunc == nil {
panic("StoreMock.InfoFunc: method is nil but Store.Info was just called")
}
callInfo := struct {
}{}
mock.lockInfo.Lock()
mock.calls.Info = append(mock.calls.Info, callInfo)
mock.lockInfo.Unlock()
return mock.InfoFunc()
}
return mock
// InfoCalls gets all the calls that were made to Info.
// Check the length with:
//
// len(mockedStore.InfoCalls())
func (mock *StoreMock) InfoCalls() []struct {
} {
var calls []struct {
}
mock.lockInfo.RLock()
calls = mock.calls.Info
mock.lockInfo.RUnlock()
return calls
}
// Load calls LoadFunc.
func (mock *StoreMock) Load(id string) ([]byte, error) {
if mock.LoadFunc == nil {
panic("StoreMock.LoadFunc: method is nil but Store.Load was just called")
}
callInfo := struct {
ID string
}{
ID: id,
}
mock.lockLoad.Lock()
mock.calls.Load = append(mock.calls.Load, callInfo)
mock.lockLoad.Unlock()
return mock.LoadFunc(id)
}
// LoadCalls gets all the calls that were made to Load.
// Check the length with:
//
// len(mockedStore.LoadCalls())
func (mock *StoreMock) LoadCalls() []struct {
ID string
} {
var calls []struct {
ID string
}
mock.lockLoad.RLock()
calls = mock.calls.Load
mock.lockLoad.RUnlock()
return calls
}
// ResetCleanupTimer calls ResetCleanupTimerFunc.
func (mock *StoreMock) ResetCleanupTimer(id string) error {
if mock.ResetCleanupTimerFunc == nil {
panic("StoreMock.ResetCleanupTimerFunc: method is nil but Store.ResetCleanupTimer was just called")
}
callInfo := struct {
ID string
}{
ID: id,
}
mock.lockResetCleanupTimer.Lock()
mock.calls.ResetCleanupTimer = append(mock.calls.ResetCleanupTimer, callInfo)
mock.lockResetCleanupTimer.Unlock()
return mock.ResetCleanupTimerFunc(id)
}
// ResetCleanupTimerCalls gets all the calls that were made to ResetCleanupTimer.
// Check the length with:
//
// len(mockedStore.ResetCleanupTimerCalls())
func (mock *StoreMock) ResetCleanupTimerCalls() []struct {
ID string
} {
var calls []struct {
ID string
}
mock.lockResetCleanupTimer.RLock()
calls = mock.calls.ResetCleanupTimer
mock.lockResetCleanupTimer.RUnlock()
return calls
}
// Save calls SaveFunc.
func (mock *StoreMock) Save(id string, img []byte) error {
if mock.SaveFunc == nil {
panic("StoreMock.SaveFunc: method is nil but Store.Save was just called")
}
callInfo := struct {
ID string
Img []byte
}{
ID: id,
Img: img,
}
mock.lockSave.Lock()
mock.calls.Save = append(mock.calls.Save, callInfo)
mock.lockSave.Unlock()
return mock.SaveFunc(id, img)
}
// SaveCalls gets all the calls that were made to Save.
// Check the length with:
//
// len(mockedStore.SaveCalls())
func (mock *StoreMock) SaveCalls() []struct {
ID string
Img []byte
} {
var calls []struct {
ID string
Img []byte
}
mock.lockSave.RLock()
calls = mock.calls.Save
mock.lockSave.RUnlock()
return calls
}
+55 -28
View File
@@ -14,22 +14,30 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
func TestService_SaveAndLoad(t *testing.T) {
store := MockStore{}
store := StoreMock{
SaveFunc: func(id string, img []byte) error {
return nil
},
LoadFunc: func(id string) ([]byte, error) {
return nil, nil
},
}
svc := NewService(&store, ServiceParams{MaxSize: 1500, MaxWidth: 32, MaxHeight: 32})
store.On("Save", "test_id", mock.Anything).Return(nil)
err := svc.SaveWithID("test_id", gopherPNG())
assert.NoError(t, err)
assert.Equal(t, 1, len(store.SaveCalls()))
assert.Equal(t, "test_id", store.SaveCalls()[0].ID)
store.On("Load", "test_id", mock.Anything).Return(nil, nil)
img, err := svc.Load("test_id")
assert.NoError(t, err)
assert.Nil(t, img)
assert.Equal(t, 1, len(store.LoadCalls()))
assert.Equal(t, "test_id", store.LoadCalls()[0].ID)
}
func TestService_Resize(t *testing.T) {
@@ -116,72 +124,91 @@ func TestService_ExtractPictures(t *testing.T) {
}
func TestService_Cleanup(t *testing.T) {
store := MockStore{}
store.On("Cleanup", mock.Anything, mock.Anything).Times(10).Return(nil)
store := StoreMock{
CleanupFunc: func(ctx context.Context, ttl time.Duration) error {
return nil
},
}
svc := NewService(&store, ServiceParams{EditDuration: 20 * time.Millisecond})
// cancel context after 2.1 cleanup TTLs
ctx, cancel := context.WithTimeout(context.Background(), svc.EditDuration/100*15*21)
defer cancel()
svc.Cleanup(ctx)
store.AssertNumberOfCalls(t, "Cleanup", 2)
assert.Equal(t, 2, len(store.CleanupCalls()))
}
func TestService_Submit(t *testing.T) {
store := MockStore{}
store.On("Commit", mock.Anything, mock.Anything).Times(7).Return(nil)
store.On("ResetCleanupTimer", mock.Anything, mock.Anything).Times(7).Return(nil)
store := StoreMock{
CommitFunc: func(id string) error {
return nil
},
ResetCleanupTimerFunc: func(id string) error {
return nil
},
}
svc := NewService(&store, ServiceParams{ImageAPI: "/blah/", EditDuration: time.Millisecond * 100})
svc.Submit(func() []string { return []string{"id1", "id2", "id3"} })
store.AssertNumberOfCalls(t, "ResetCleanupTimer", 3)
assert.Equal(t, 3, len(store.ResetCleanupTimerCalls()))
err := svc.SubmitAndCommit(func() []string { return []string{"id4", "id5"} })
assert.NoError(t, err)
svc.Submit(func() []string { return []string{"id6", "id7"} })
store.AssertNumberOfCalls(t, "ResetCleanupTimer", 5)
assert.Equal(t, 5, len(store.ResetCleanupTimerCalls()))
svc.Submit(nil)
store.AssertNumberOfCalls(t, "Commit", 2)
assert.Equal(t, 2, len(store.CommitCalls()))
time.Sleep(time.Millisecond * 175)
store.AssertNumberOfCalls(t, "Commit", 7)
assert.Equal(t, 7, len(store.CommitCalls()))
svc.Close(context.TODO())
}
func TestService_Close(t *testing.T) {
store := MockStore{}
store.On("Commit", mock.Anything, mock.Anything).Times(5).Return(nil)
store.On("ResetCleanupTimer", mock.Anything, mock.Anything).Times(5).Return(nil)
store := StoreMock{
CommitFunc: func(id string) error {
return nil
},
ResetCleanupTimerFunc: func(id string) error {
return nil
},
}
svc := Service{store: &store, ServiceParams: ServiceParams{ImageAPI: "/blah/", EditDuration: time.Hour * 24}}
svc.Submit(func() []string { return []string{"id1", "id2", "id3"} })
svc.Submit(func() []string { return []string{"id4", "id5"} })
svc.Submit(nil)
store.AssertNumberOfCalls(t, "ResetCleanupTimer", 5)
assert.Equal(t, 5, len(store.ResetCleanupTimerCalls()))
svc.Close(context.TODO())
store.AssertNumberOfCalls(t, "Commit", 5)
assert.Equal(t, 5, len(store.CommitCalls()))
}
func TestService_SubmitDelay(t *testing.T) {
store := MockStore{}
store.On("Commit", mock.Anything, mock.Anything).Times(5).Return(nil)
store.On("ResetCleanupTimer", mock.Anything, mock.Anything).Times(5).Return(nil)
store := StoreMock{
CommitFunc: func(id string) error {
return nil
},
ResetCleanupTimerFunc: func(id string) error {
return nil
},
}
svc := NewService(&store, ServiceParams{EditDuration: 20 * time.Millisecond})
svc.Submit(func() []string { return []string{"id1", "id2", "id3"} })
time.Sleep(150 * time.Millisecond) // let first batch to pass TTL
svc.Submit(func() []string { return []string{"id4", "id5"} })
svc.Submit(nil)
store.AssertNumberOfCalls(t, "ResetCleanupTimer", 5)
store.AssertNumberOfCalls(t, "Commit", 3)
assert.Equal(t, 5, len(store.ResetCleanupTimerCalls()))
assert.Equal(t, 3, len(store.CommitCalls()))
svc.Close(context.TODO())
store.AssertNumberOfCalls(t, "Commit", 5)
assert.Equal(t, 5, len(store.CommitCalls()))
}
func TestService_Info(t *testing.T) {
store := MockStore{}
store.On("Info", mock.Anything, mock.Anything).Once().Return(StoreInfo{}, nil)
store := StoreMock{InfoFunc: func() (StoreInfo, error) {
return StoreInfo{}, nil
}}
svc := Service{store: &store, ServiceParams: ServiceParams{}}
info, err := svc.Info()
assert.NoError(t, err)
assert.True(t, info.FirstStagingImageTS.IsZero())
store.AssertNumberOfCalls(t, "Info", 1)
assert.Equal(t, 1, len(store.InfoCalls()))
}
func TestService_resize(t *testing.T) {
+86 -40
View File
@@ -1358,11 +1358,10 @@ func TestService_DeleteAll(t *testing.T) {
func TestService_submitImages(t *testing.T) {
lgr.Setup(lgr.Debug, lgr.CallerFile, lgr.CallerFunc)
mockStore := image.MockStore{}
mockStore.On("Commit", "dev/pic1.png").Once().Return(nil)
mockStore.On("Commit", "dev/pic2.png").Once().Return(nil)
mockStore.On("ResetCleanupTimer", "dev/pic1.png").Once().Return(nil)
mockStore.On("ResetCleanupTimer", "dev/pic2.png").Once().Return(nil)
mockStore := image.StoreMock{
CommitFunc: func(id string) error { return nil },
ResetCleanupTimerFunc: func(id string) error { return nil },
}
imgSvc := image.NewService(&mockStore,
image.ServiceParams{
EditDuration: 50 * time.Millisecond,
@@ -1388,13 +1387,25 @@ func TestService_submitImages(t *testing.T) {
assert.NoError(t, err)
b.submitImages(c)
mockStore.AssertNumberOfCalls(t, "ResetCleanupTimer", 2)
assert.Equal(t, 2, len(mockStore.ResetCleanupTimerCalls()))
assert.Equal(t, "dev/pic1.png", mockStore.ResetCleanupTimerCalls()[0].ID)
assert.Equal(t, "dev/pic2.png", mockStore.ResetCleanupTimerCalls()[1].ID)
time.Sleep(b.EditDuration + 100*time.Millisecond)
mockStore.AssertNumberOfCalls(t, "Commit", 2)
assert.Equal(t, 2, len(mockStore.CommitCalls()))
assert.Equal(t, "dev/pic1.png", mockStore.CommitCalls()[0].ID)
assert.Equal(t, "dev/pic2.png", mockStore.CommitCalls()[1].ID)
}
func TestService_ResubmitStagingImages(t *testing.T) {
mockStore := image.MockStore{}
mockStore := image.StoreMock{
InfoFunc: func() (image.StoreInfo, error) {
return image.StoreInfo{FirstStagingImageTS: time.Time{}.Add(time.Second)}, nil
},
CommitFunc: func(id string) error {
return nil
},
ResetCleanupTimerFunc: func(id string) error { return nil },
}
imgSvc := image.NewService(&mockStore,
image.ServiceParams{
EditDuration: 10 * time.Millisecond,
@@ -1407,10 +1418,6 @@ func TestService_ResubmitStagingImages(t *testing.T) {
defer teardown()
b := DataStore{Engine: eng, EditDuration: 10 * time.Millisecond, ImageService: imgSvc}
mockStore.On("ResetCleanupTimer", "dev_user/bqf122eq9r8ad657n3ng").Once().Return(nil)
mockStore.On("ResetCleanupTimer", "dev_user/bqf321eq9r8ad657n3ng").Once().Return(nil)
mockStore.On("ResetCleanupTimer", "cached_images/12318fbd4c55e9d177b8b5ae197bc89c5afd8e07-a41fcb00643f28d700504256ec81cbf2e1aac53e").Once().Return(nil)
// create comment with three images without preparing it properly
comment := store.Comment{
ID: "id-0",
@@ -1426,21 +1433,19 @@ func TestService_ResubmitStagingImages(t *testing.T) {
require.NoError(t, err)
// resubmit single comment with three images, of which two are in staging storage
mockStore.On("Info").Once().Return(image.StoreInfo{FirstStagingImageTS: time.Time{}.Add(time.Second)}, nil)
err = b.ResubmitStagingImages([]string{"radio-t"})
assert.NoError(t, err)
// wait for Submit goroutine to commit image
mockStore.On("Commit", "dev_user/bqf122eq9r8ad657n3ng").Once().Return(nil)
mockStore.On("Commit", "dev_user/bqf321eq9r8ad657n3ng").Once().Return(nil)
mockStore.On("Commit", "cached_images/12318fbd4c55e9d177b8b5ae197bc89c5afd8e07-a41fcb00643f28d700504256ec81cbf2e1aac53e").Once().Return(nil)
time.Sleep(b.EditDuration + time.Millisecond*100)
mockStore.AssertNumberOfCalls(t, "Info", 1)
mockStore.AssertNumberOfCalls(t, "Commit", 3)
assert.Equal(t, 1, len(mockStore.InfoCalls()))
assert.Equal(t, 3, len(mockStore.CommitCalls()))
// empty answer
mockStoreEmpty := image.MockStore{}
mockStoreEmpty := image.StoreMock{InfoFunc: func() (image.StoreInfo, error) {
return image.StoreInfo{FirstStagingImageTS: time.Time{}}, nil
}}
imgSvcEmpty := image.NewService(&mockStoreEmpty,
image.ServiceParams{
EditDuration: 10 * time.Millisecond,
@@ -1449,15 +1454,16 @@ func TestService_ResubmitStagingImages(t *testing.T) {
defer imgSvcEmpty.Close(context.TODO())
bEmpty := DataStore{Engine: eng, EditDuration: 10 * time.Millisecond, ImageService: imgSvcEmpty}
// resubmit receive empty timestamp and should do nothing
mockStoreEmpty.On("Info").Once().Return(image.StoreInfo{FirstStagingImageTS: time.Time{}}, nil)
// resubmit receive empty timestamp and should do nothing )
err = bEmpty.ResubmitStagingImages([]string{"radio-t", "non_existent"})
assert.NoError(t, err)
mockStoreEmpty.AssertNumberOfCalls(t, "Info", 1)
assert.Equal(t, 1, len(mockStore.InfoCalls()))
// error from image storage
mockStoreError := image.MockStore{}
mockStoreError := image.StoreMock{InfoFunc: func() (image.StoreInfo, error) {
return image.StoreInfo{}, fmt.Errorf("mock_err")
}}
imgSvcError := image.NewService(&mockStoreError,
image.ServiceParams{
EditDuration: 10 * time.Millisecond,
@@ -1467,15 +1473,20 @@ func TestService_ResubmitStagingImages(t *testing.T) {
bError := DataStore{Engine: eng, EditDuration: 10 * time.Millisecond, ImageService: imgSvcError}
// resubmit will receive error from image storage and should return it
mockStoreError.On("Info").Once().Return(image.StoreInfo{}, fmt.Errorf("mock_err"))
err = bError.ResubmitStagingImages([]string{"radio-t"})
assert.EqualError(t, err, "mock_err")
mockStoreError.AssertNumberOfCalls(t, "Info", 1)
assert.Equal(t, 1, len(mockStore.InfoCalls()))
assert.Equal(t, 3, len(mockStore.ResetCleanupTimerCalls()))
assert.Equal(t, "dev_user/bqf122eq9r8ad657n3ng", mockStore.ResetCleanupTimerCalls()[0].ID)
assert.Equal(t, "dev_user/bqf321eq9r8ad657n3ng", mockStore.ResetCleanupTimerCalls()[1].ID)
assert.Equal(t, "cached_images/12318fbd4c55e9d177b8b5ae197bc89c5afd8e07-a41fcb00643f28d700504256ec81cbf2e1aac53e", mockStore.ResetCleanupTimerCalls()[2].ID)
}
func TestService_ResubmitStagingImages_EngineError(t *testing.T) {
mockStore := image.MockStore{}
mockStore := image.StoreMock{InfoFunc: func() (image.StoreInfo, error) {
return image.StoreInfo{FirstStagingImageTS: time.Time{}.Add(time.Second)}, nil
}}
imgSvc := image.NewService(&mockStore,
image.ServiceParams{
EditDuration: 10 * time.Millisecond,
@@ -1483,26 +1494,37 @@ func TestService_ResubmitStagingImages_EngineError(t *testing.T) {
})
defer imgSvc.Close(context.TODO())
engineMock := engine.MockInterface{}
first := true
engineMock := engine.InterfaceMock{
FindFunc: func(req engine.FindRequest) ([]store.Comment, error) {
if first {
first = false
return nil, nil
}
return nil, fmt.Errorf("mockError")
},
}
site1Req := engine.FindRequest{Locator: store.Locator{SiteID: "site1", URL: ""}, Sort: "time", Since: time.Time{}.Add(time.Second)}
site2Req := engine.FindRequest{Locator: store.Locator{SiteID: "site2", URL: ""}, Sort: "time", Since: time.Time{}.Add(time.Second)}
engineMock.On("Find", site1Req).Return(nil, nil)
engineMock.On("Find", site2Req).Return(nil, fmt.Errorf("mockError"))
b := DataStore{Engine: &engineMock, EditDuration: 10 * time.Millisecond, ImageService: imgSvc}
// One call without error and one with error
mockStore.On("Info").Once().Return(image.StoreInfo{FirstStagingImageTS: time.Time{}.Add(time.Second)}, nil)
err := b.ResubmitStagingImages([]string{"site1", "site2"})
assert.Error(t, err)
assert.Contains(t, err.Error(), "problem finding comments for site site2: mockError")
mockStore.AssertNumberOfCalls(t, "Info", 1)
assert.Equal(t, 1, len(mockStore.InfoCalls()))
assert.Equal(t, 2, len(engineMock.FindCalls()))
assert.Equal(t, site1Req, engineMock.FindCalls()[0].Req)
assert.Equal(t, site2Req, engineMock.FindCalls()[1].Req)
}
func TestService_alterComment(t *testing.T) {
engineMock := engine.MockInterface{}
engineMock.On("Flag", engine.FlagRequest{Flag: engine.Blocked, UserID: "devid"}).Return(false, nil)
engineMock.On("Flag", engine.FlagRequest{Flag: engine.Verified, UserID: "devid"}).Return(false, nil)
engineMock := engine.InterfaceMock{
FlagFunc: func(req engine.FlagRequest) (bool, error) {
return false, nil
},
}
svc := DataStore{Engine: &engineMock}
r := svc.alterComment(store.Comment{ID: "123", User: store.User{IP: "127.0.0.1", ID: "devid"},
@@ -1513,24 +1535,48 @@ func TestService_alterComment(t *testing.T) {
r = svc.alterComment(store.Comment{ID: "123", User: store.User{IP: "127.0.0.1", ID: "devid"}},
store.User{Name: "dev", ID: "devid", Admin: true})
assert.Equal(t, store.Comment{ID: "123", User: store.User{IP: "127.0.0.1", ID: "devid"}}, r, "ip not cleaned")
assert.Equal(t, 4, len(engineMock.FlagCalls()))
assert.Equal(t, engine.FlagRequest{Flag: engine.Blocked, UserID: "devid"}, engineMock.FlagCalls()[0].Req)
assert.Equal(t, engine.FlagRequest{Flag: engine.Verified, UserID: "devid"}, engineMock.FlagCalls()[1].Req)
assert.Equal(t, engine.FlagRequest{Flag: engine.Blocked, UserID: "devid"}, engineMock.FlagCalls()[2].Req)
assert.Equal(t, engine.FlagRequest{Flag: engine.Verified, UserID: "devid"}, engineMock.FlagCalls()[3].Req)
engineMock = engine.MockInterface{}
engineMock.On("Flag", engine.FlagRequest{Flag: engine.Blocked, UserID: "devid"}).Return(false, nil)
engineMock.On("Flag", engine.FlagRequest{Flag: engine.Verified, UserID: "devid"}).Return(true, nil)
first := true
engineMock = engine.InterfaceMock{
FlagFunc: func(req engine.FlagRequest) (bool, error) {
if first {
first = false
return false, nil
}
return true, nil
},
}
svc = DataStore{Engine: &engineMock}
r = svc.alterComment(store.Comment{ID: "123", User: store.User{IP: "127.0.0.1", ID: "devid", Verified: true}},
store.User{Name: "dev", ID: "devid", Admin: false})
assert.Equal(t, store.Comment{ID: "123", User: store.User{IP: "", ID: "devid", Verified: true}}, r, "verified set")
assert.Equal(t, 2, len(engineMock.FlagCalls()))
assert.Equal(t, engine.FlagRequest{Flag: engine.Blocked, UserID: "devid"}, engineMock.FlagCalls()[0].Req)
assert.Equal(t, engine.FlagRequest{Flag: engine.Verified, UserID: "devid"}, engineMock.FlagCalls()[1].Req)
engineMock = engine.MockInterface{}
engineMock.On("Flag", engine.FlagRequest{Flag: engine.Blocked, UserID: "devid"}).Return(true, nil)
engineMock.On("Flag", engine.FlagRequest{Flag: engine.Verified, UserID: "devid"}).Return(false, nil)
first = true
engineMock = engine.InterfaceMock{
FlagFunc: func(req engine.FlagRequest) (bool, error) {
if first {
first = false
return true, nil
}
return false, nil
},
}
svc = DataStore{Engine: &engineMock}
r = svc.alterComment(store.Comment{ID: "123", User: store.User{IP: "127.0.0.1", ID: "devid", Verified: true},
Locator: store.Locator{URL: "javascript:alert('XSS1')"}},
store.User{Name: "dev", ID: "devid", Admin: false})
assert.Equal(t, store.Comment{ID: "123", User: store.User{IP: "", Verified: true, Blocked: true, ID: "devid"},
Deleted: false}, r, "blocked")
assert.Equal(t, 1, len(engineMock.FlagCalls()))
assert.Equal(t, engine.FlagRequest{Flag: engine.Blocked, UserID: "devid"}, engineMock.FlagCalls()[0].Req)
}
func Benchmark_ServiceCreate(b *testing.B) {
-1
View File
@@ -63,7 +63,6 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/slack-go/slack v0.10.3 // indirect
github.com/stretchr/objx v0.4.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.1 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect
-1
View File
@@ -342,7 +342,6 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-21
View File
@@ -1,21 +0,0 @@
engines:
gofmt:
enabled: true
golint:
enabled: true
govet:
enabled: true
exclude_patterns:
- ".github/"
- "vendor/"
- "codegen/"
- "*.yml"
- ".*.yml"
- "*.md"
- "Gopkg.*"
- "doc.go"
- "type_specific_codegen_test.go"
- "type_specific_codegen.go"
- ".gitignore"
- "LICENSE"
-11
View File
@@ -1,11 +0,0 @@
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
-22
View File
@@ -1,22 +0,0 @@
The MIT License
Copyright (c) 2014 Stretchr, Inc.
Copyright (c) 2017-2018 objx contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-80
View File
@@ -1,80 +0,0 @@
# Objx
[![Build Status](https://travis-ci.org/stretchr/objx.svg?branch=master)](https://travis-ci.org/stretchr/objx)
[![Go Report Card](https://goreportcard.com/badge/github.com/stretchr/objx)](https://goreportcard.com/report/github.com/stretchr/objx)
[![Maintainability](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/maintainability)](https://codeclimate.com/github/stretchr/objx/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/test_coverage)](https://codeclimate.com/github/stretchr/objx/test_coverage)
[![Sourcegraph](https://sourcegraph.com/github.com/stretchr/objx/-/badge.svg)](https://sourcegraph.com/github.com/stretchr/objx)
[![GoDoc](https://godoc.org/github.com/stretchr/objx?status.svg)](https://godoc.org/github.com/stretchr/objx)
Objx - Go package for dealing with maps, slices, JSON and other data.
Get started:
- Install Objx with [one line of code](#installation), or [update it with another](#staying-up-to-date)
- Check out the API Documentation http://godoc.org/github.com/stretchr/objx
## Overview
Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes a powerful `Get` method (among others) that allows you to easily and quickly get access to data within the map, without having to worry too much about type assertions, missing data, default values etc.
### Pattern
Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going:
m, err := objx.FromJSON(json)
NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, the rest will be optimistic and try to figure things out without panicking.
Use `Get` to access the value you're interested in. You can use dot and array
notation too:
m.Get("places[0].latlng")
Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type.
if m.Get("code").IsStr() { // Your code... }
Or you can just assume the type, and use one of the strong type methods to extract the real value:
m.Get("code").Int()
If there's no value there (or if it's the wrong type) then a default value will be returned, or you can be explicit about the default value.
Get("code").Int(-1)
If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, manipulating and selecting that data. You can find out more by exploring the index below.
### Reading data
A simple example of how to use Objx:
// Use MustFromJSON to make an objx.Map from some JSON
m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
// Get the details
name := m.Get("name").Str()
age := m.Get("age").Int()
// Get their nickname (or use their name if they don't have one)
nickname := m.Get("nickname").Str(name)
### Ranging
Since `objx.Map` is a `map[string]interface{}` you can treat it as such. For example, to `range` the data, do what you would expect:
m := objx.MustFromJSON(json)
for key, value := range m {
// Your code...
}
## Installation
To install Objx, use go get:
go get github.com/stretchr/objx
### Staying up to date
To update Objx to the latest version, run:
go get -u github.com/stretchr/objx
### Supported go versions
We support the lastest three major Go versions, which are 1.10, 1.11 and 1.12 at the moment.
## Contributing
Please feel free to submit issues, fork the repository and send pull requests!
-30
View File
@@ -1,30 +0,0 @@
version: '2'
env:
GOFLAGS: -mod=vendor
tasks:
default:
deps: [test]
lint:
desc: Checks code style
cmds:
- gofmt -d -s *.go
- go vet ./...
silent: true
lint-fix:
desc: Fixes code style
cmds:
- gofmt -w -s *.go
test:
desc: Runs go tests
cmds:
- go test -race ./...
test-coverage:
desc: Runs go tests and calucates test coverage
cmds:
- go test -race -coverprofile=c.out ./...
-197
View File
@@ -1,197 +0,0 @@
package objx
import (
"reflect"
"regexp"
"strconv"
"strings"
)
const (
// PathSeparator is the character used to separate the elements
// of the keypath.
//
// For example, `location.address.city`
PathSeparator string = "."
// arrayAccesRegexString is the regex used to extract the array number
// from the access path
arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`
// mapAccessRegexString is the regex used to extract the map key
// from the access path
mapAccessRegexString = `^([^\[]*)\[([^\]]+)\](.*)$`
)
// arrayAccesRegex is the compiled arrayAccesRegexString
var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)
// mapAccessRegex is the compiled mapAccessRegexString
var mapAccessRegex = regexp.MustCompile(mapAccessRegexString)
// Get gets the value using the specified selector and
// returns it inside a new Obj object.
//
// If it cannot find the value, Get will return a nil
// value inside an instance of Obj.
//
// Get can only operate directly on map[string]interface{} and []interface.
//
// Example
//
// To access the title of the third chapter of the second book, do:
//
// o.Get("books[1].chapters[2].title")
func (m Map) Get(selector string) *Value {
rawObj := access(m, selector, nil, false)
return &Value{data: rawObj}
}
// Set sets the value using the specified selector and
// returns the object on which Set was called.
//
// Set can only operate directly on map[string]interface{} and []interface
//
// Example
//
// To set the title of the third chapter of the second book, do:
//
// o.Set("books[1].chapters[2].title","Time to Go")
func (m Map) Set(selector string, value interface{}) Map {
access(m, selector, value, true)
return m
}
// getIndex returns the index, which is hold in s by two braches.
// It also returns s withour the index part, e.g. name[1] will return (1, name).
// If no index is found, -1 is returned
func getIndex(s string) (int, string) {
arrayMatches := arrayAccesRegex.FindStringSubmatch(s)
if len(arrayMatches) > 0 {
// Get the key into the map
selector := arrayMatches[1]
// Get the index into the array at the key
// We know this cannt fail because arrayMatches[2] is an int for sure
index, _ := strconv.Atoi(arrayMatches[2])
return index, selector
}
return -1, s
}
// getKey returns the key which is held in s by two brackets.
// It also returns the next selector.
func getKey(s string) (string, string) {
selSegs := strings.SplitN(s, PathSeparator, 2)
thisSel := selSegs[0]
nextSel := ""
if len(selSegs) > 1 {
nextSel = selSegs[1]
}
mapMatches := mapAccessRegex.FindStringSubmatch(s)
if len(mapMatches) > 0 {
if _, err := strconv.Atoi(mapMatches[2]); err != nil {
thisSel = mapMatches[1]
nextSel = "[" + mapMatches[2] + "]" + mapMatches[3]
if thisSel == "" {
thisSel = mapMatches[2]
nextSel = mapMatches[3]
}
if nextSel == "" {
selSegs = []string{"", ""}
} else if nextSel[0] == '.' {
nextSel = nextSel[1:]
}
}
}
return thisSel, nextSel
}
// access accesses the object using the selector and performs the
// appropriate action.
func access(current interface{}, selector string, value interface{}, isSet bool) interface{} {
thisSel, nextSel := getKey(selector)
indexes := []int{}
for strings.Contains(thisSel, "[") {
prevSel := thisSel
index := -1
index, thisSel = getIndex(thisSel)
indexes = append(indexes, index)
if prevSel == thisSel {
break
}
}
if curMap, ok := current.(Map); ok {
current = map[string]interface{}(curMap)
}
// get the object in question
switch current.(type) {
case map[string]interface{}:
curMSI := current.(map[string]interface{})
if nextSel == "" && isSet {
curMSI[thisSel] = value
return nil
}
_, ok := curMSI[thisSel].(map[string]interface{})
if !ok {
_, ok = curMSI[thisSel].(Map)
}
if (curMSI[thisSel] == nil || !ok) && len(indexes) == 0 && isSet {
curMSI[thisSel] = map[string]interface{}{}
}
current = curMSI[thisSel]
default:
current = nil
}
// do we need to access the item of an array?
if len(indexes) > 0 {
num := len(indexes)
for num > 0 {
num--
index := indexes[num]
indexes = indexes[:num]
if array, ok := interSlice(current); ok {
if index < len(array) {
current = array[index]
} else {
current = nil
break
}
}
}
}
if nextSel != "" {
current = access(current, nextSel, value, isSet)
}
return current
}
func interSlice(slice interface{}) ([]interface{}, bool) {
if array, ok := slice.([]interface{}); ok {
return array, ok
}
s := reflect.ValueOf(slice)
if s.Kind() != reflect.Slice {
return nil, false
}
ret := make([]interface{}, s.Len())
for i := 0; i < s.Len(); i++ {
ret[i] = s.Index(i).Interface()
}
return ret, true
}
-280
View File
@@ -1,280 +0,0 @@
package objx
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/url"
"strconv"
)
// SignatureSeparator is the character that is used to
// separate the Base64 string from the security signature.
const SignatureSeparator = "_"
// URLValuesSliceKeySuffix is the character that is used to
// specify a suffic for slices parsed by URLValues.
// If the suffix is set to "[i]", then the index of the slice
// is used in place of i
// Ex: Suffix "[]" would have the form a[]=b&a[]=c
// OR Suffix "[i]" would have the form a[0]=b&a[1]=c
// OR Suffix "" would have the form a=b&a=c
var urlValuesSliceKeySuffix = "[]"
const (
URLValuesSliceKeySuffixEmpty = ""
URLValuesSliceKeySuffixArray = "[]"
URLValuesSliceKeySuffixIndex = "[i]"
)
// SetURLValuesSliceKeySuffix sets the character that is used to
// specify a suffic for slices parsed by URLValues.
// If the suffix is set to "[i]", then the index of the slice
// is used in place of i
// Ex: Suffix "[]" would have the form a[]=b&a[]=c
// OR Suffix "[i]" would have the form a[0]=b&a[1]=c
// OR Suffix "" would have the form a=b&a=c
func SetURLValuesSliceKeySuffix(s string) error {
if s == URLValuesSliceKeySuffixEmpty || s == URLValuesSliceKeySuffixArray || s == URLValuesSliceKeySuffixIndex {
urlValuesSliceKeySuffix = s
return nil
}
return errors.New("objx: Invalid URLValuesSliceKeySuffix provided.")
}
// JSON converts the contained object to a JSON string
// representation
func (m Map) JSON() (string, error) {
for k, v := range m {
m[k] = cleanUp(v)
}
result, err := json.Marshal(m)
if err != nil {
err = errors.New("objx: JSON encode failed with: " + err.Error())
}
return string(result), err
}
func cleanUpInterfaceArray(in []interface{}) []interface{} {
result := make([]interface{}, len(in))
for i, v := range in {
result[i] = cleanUp(v)
}
return result
}
func cleanUpInterfaceMap(in map[interface{}]interface{}) Map {
result := Map{}
for k, v := range in {
result[fmt.Sprintf("%v", k)] = cleanUp(v)
}
return result
}
func cleanUpStringMap(in map[string]interface{}) Map {
result := Map{}
for k, v := range in {
result[k] = cleanUp(v)
}
return result
}
func cleanUpMSIArray(in []map[string]interface{}) []Map {
result := make([]Map, len(in))
for i, v := range in {
result[i] = cleanUpStringMap(v)
}
return result
}
func cleanUpMapArray(in []Map) []Map {
result := make([]Map, len(in))
for i, v := range in {
result[i] = cleanUpStringMap(v)
}
return result
}
func cleanUp(v interface{}) interface{} {
switch v := v.(type) {
case []interface{}:
return cleanUpInterfaceArray(v)
case []map[string]interface{}:
return cleanUpMSIArray(v)
case map[interface{}]interface{}:
return cleanUpInterfaceMap(v)
case Map:
return cleanUpStringMap(v)
case []Map:
return cleanUpMapArray(v)
default:
return v
}
}
// MustJSON converts the contained object to a JSON string
// representation and panics if there is an error
func (m Map) MustJSON() string {
result, err := m.JSON()
if err != nil {
panic(err.Error())
}
return result
}
// Base64 converts the contained object to a Base64 string
// representation of the JSON string representation
func (m Map) Base64() (string, error) {
var buf bytes.Buffer
jsonData, err := m.JSON()
if err != nil {
return "", err
}
encoder := base64.NewEncoder(base64.StdEncoding, &buf)
_, _ = encoder.Write([]byte(jsonData))
_ = encoder.Close()
return buf.String(), nil
}
// MustBase64 converts the contained object to a Base64 string
// representation of the JSON string representation and panics
// if there is an error
func (m Map) MustBase64() string {
result, err := m.Base64()
if err != nil {
panic(err.Error())
}
return result
}
// SignedBase64 converts the contained object to a Base64 string
// representation of the JSON string representation and signs it
// using the provided key.
func (m Map) SignedBase64(key string) (string, error) {
base64, err := m.Base64()
if err != nil {
return "", err
}
sig := HashWithKey(base64, key)
return base64 + SignatureSeparator + sig, nil
}
// MustSignedBase64 converts the contained object to a Base64 string
// representation of the JSON string representation and signs it
// using the provided key and panics if there is an error
func (m Map) MustSignedBase64(key string) string {
result, err := m.SignedBase64(key)
if err != nil {
panic(err.Error())
}
return result
}
/*
URL Query
------------------------------------------------
*/
// URLValues creates a url.Values object from an Obj. This
// function requires that the wrapped object be a map[string]interface{}
func (m Map) URLValues() url.Values {
vals := make(url.Values)
m.parseURLValues(m, vals, "")
return vals
}
func (m Map) parseURLValues(queryMap Map, vals url.Values, key string) {
useSliceIndex := false
if urlValuesSliceKeySuffix == "[i]" {
useSliceIndex = true
}
for k, v := range queryMap {
val := &Value{data: v}
switch {
case val.IsObjxMap():
if key == "" {
m.parseURLValues(val.ObjxMap(), vals, k)
} else {
m.parseURLValues(val.ObjxMap(), vals, key+"["+k+"]")
}
case val.IsObjxMapSlice():
sliceKey := k
if key != "" {
sliceKey = key + "[" + k + "]"
}
if useSliceIndex {
for i, sv := range val.MustObjxMapSlice() {
sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]"
m.parseURLValues(sv, vals, sk)
}
} else {
sliceKey = sliceKey + urlValuesSliceKeySuffix
for _, sv := range val.MustObjxMapSlice() {
m.parseURLValues(sv, vals, sliceKey)
}
}
case val.IsMSISlice():
sliceKey := k
if key != "" {
sliceKey = key + "[" + k + "]"
}
if useSliceIndex {
for i, sv := range val.MustMSISlice() {
sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]"
m.parseURLValues(New(sv), vals, sk)
}
} else {
sliceKey = sliceKey + urlValuesSliceKeySuffix
for _, sv := range val.MustMSISlice() {
m.parseURLValues(New(sv), vals, sliceKey)
}
}
case val.IsStrSlice(), val.IsBoolSlice(),
val.IsFloat32Slice(), val.IsFloat64Slice(),
val.IsIntSlice(), val.IsInt8Slice(), val.IsInt16Slice(), val.IsInt32Slice(), val.IsInt64Slice(),
val.IsUintSlice(), val.IsUint8Slice(), val.IsUint16Slice(), val.IsUint32Slice(), val.IsUint64Slice():
sliceKey := k
if key != "" {
sliceKey = key + "[" + k + "]"
}
if useSliceIndex {
for i, sv := range val.StringSlice() {
sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]"
vals.Set(sk, sv)
}
} else {
sliceKey = sliceKey + urlValuesSliceKeySuffix
vals[sliceKey] = val.StringSlice()
}
default:
if key == "" {
vals.Set(k, val.String())
} else {
vals.Set(key+"["+k+"]", val.String())
}
}
}
}
// URLQuery gets an encoded URL query representing the given
// Obj. This function requires that the wrapped object be a
// map[string]interface{}
func (m Map) URLQuery() (string, error) {
return m.URLValues().Encode(), nil
}
-66
View File
@@ -1,66 +0,0 @@
/*
Objx - Go package for dealing with maps, slices, JSON and other data.
Overview
Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes
a powerful `Get` method (among others) that allows you to easily and quickly get
access to data within the map, without having to worry too much about type assertions,
missing data, default values etc.
Pattern
Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy.
Call one of the `objx.` functions to create your `objx.Map` to get going:
m, err := objx.FromJSON(json)
NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong,
the rest will be optimistic and try to figure things out without panicking.
Use `Get` to access the value you're interested in. You can use dot and array
notation too:
m.Get("places[0].latlng")
Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type.
if m.Get("code").IsStr() { // Your code... }
Or you can just assume the type, and use one of the strong type methods to extract the real value:
m.Get("code").Int()
If there's no value there (or if it's the wrong type) then a default value will be returned,
or you can be explicit about the default value.
Get("code").Int(-1)
If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating,
manipulating and selecting that data. You can find out more by exploring the index below.
Reading data
A simple example of how to use Objx:
// Use MustFromJSON to make an objx.Map from some JSON
m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
// Get the details
name := m.Get("name").Str()
age := m.Get("age").Int()
// Get their nickname (or use their name if they don't have one)
nickname := m.Get("nickname").Str(name)
Ranging
Since `objx.Map` is a `map[string]interface{}` you can treat it as such.
For example, to `range` the data, do what you would expect:
m := objx.MustFromJSON(json)
for key, value := range m {
// Your code...
}
*/
package objx
-215
View File
@@ -1,215 +0,0 @@
package objx
import (
"encoding/base64"
"encoding/json"
"errors"
"io/ioutil"
"net/url"
"strings"
)
// MSIConvertable is an interface that defines methods for converting your
// custom types to a map[string]interface{} representation.
type MSIConvertable interface {
// MSI gets a map[string]interface{} (msi) representing the
// object.
MSI() map[string]interface{}
}
// Map provides extended functionality for working with
// untyped data, in particular map[string]interface (msi).
type Map map[string]interface{}
// Value returns the internal value instance
func (m Map) Value() *Value {
return &Value{data: m}
}
// Nil represents a nil Map.
var Nil = New(nil)
// New creates a new Map containing the map[string]interface{} in the data argument.
// If the data argument is not a map[string]interface, New attempts to call the
// MSI() method on the MSIConvertable interface to create one.
func New(data interface{}) Map {
if _, ok := data.(map[string]interface{}); !ok {
if converter, ok := data.(MSIConvertable); ok {
data = converter.MSI()
} else {
return nil
}
}
return Map(data.(map[string]interface{}))
}
// MSI creates a map[string]interface{} and puts it inside a new Map.
//
// The arguments follow a key, value pattern.
//
//
// Returns nil if any key argument is non-string or if there are an odd number of arguments.
//
// Example
//
// To easily create Maps:
//
// m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true))
//
// // creates an Map equivalent to
// m := objx.Map{"name": "Mat", "age": 29, "subobj": objx.Map{"active": true}}
func MSI(keyAndValuePairs ...interface{}) Map {
newMap := Map{}
keyAndValuePairsLen := len(keyAndValuePairs)
if keyAndValuePairsLen%2 != 0 {
return nil
}
for i := 0; i < keyAndValuePairsLen; i = i + 2 {
key := keyAndValuePairs[i]
value := keyAndValuePairs[i+1]
// make sure the key is a string
keyString, keyStringOK := key.(string)
if !keyStringOK {
return nil
}
newMap[keyString] = value
}
return newMap
}
// ****** Conversion Constructors
// MustFromJSON creates a new Map containing the data specified in the
// jsonString.
//
// Panics if the JSON is invalid.
func MustFromJSON(jsonString string) Map {
o, err := FromJSON(jsonString)
if err != nil {
panic("objx: MustFromJSON failed with error: " + err.Error())
}
return o
}
// MustFromJSONSlice creates a new slice of Map containing the data specified in the
// jsonString. Works with jsons with a top level array
//
// Panics if the JSON is invalid.
func MustFromJSONSlice(jsonString string) []Map {
slice, err := FromJSONSlice(jsonString)
if err != nil {
panic("objx: MustFromJSONSlice failed with error: " + err.Error())
}
return slice
}
// FromJSON creates a new Map containing the data specified in the
// jsonString.
//
// Returns an error if the JSON is invalid.
func FromJSON(jsonString string) (Map, error) {
var m Map
err := json.Unmarshal([]byte(jsonString), &m)
if err != nil {
return Nil, err
}
return m, nil
}
// FromJSONSlice creates a new slice of Map containing the data specified in the
// jsonString. Works with jsons with a top level array
//
// Returns an error if the JSON is invalid.
func FromJSONSlice(jsonString string) ([]Map, error) {
var slice []Map
err := json.Unmarshal([]byte(jsonString), &slice)
if err != nil {
return nil, err
}
return slice, nil
}
// FromBase64 creates a new Obj containing the data specified
// in the Base64 string.
//
// The string is an encoded JSON string returned by Base64
func FromBase64(base64String string) (Map, error) {
decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))
decoded, err := ioutil.ReadAll(decoder)
if err != nil {
return nil, err
}
return FromJSON(string(decoded))
}
// MustFromBase64 creates a new Obj containing the data specified
// in the Base64 string and panics if there is an error.
//
// The string is an encoded JSON string returned by Base64
func MustFromBase64(base64String string) Map {
result, err := FromBase64(base64String)
if err != nil {
panic("objx: MustFromBase64 failed with error: " + err.Error())
}
return result
}
// FromSignedBase64 creates a new Obj containing the data specified
// in the Base64 string.
//
// The string is an encoded JSON string returned by SignedBase64
func FromSignedBase64(base64String, key string) (Map, error) {
parts := strings.Split(base64String, SignatureSeparator)
if len(parts) != 2 {
return nil, errors.New("objx: Signed base64 string is malformed")
}
sig := HashWithKey(parts[0], key)
if parts[1] != sig {
return nil, errors.New("objx: Signature for base64 data does not match")
}
return FromBase64(parts[0])
}
// MustFromSignedBase64 creates a new Obj containing the data specified
// in the Base64 string and panics if there is an error.
//
// The string is an encoded JSON string returned by Base64
func MustFromSignedBase64(base64String, key string) Map {
result, err := FromSignedBase64(base64String, key)
if err != nil {
panic("objx: MustFromSignedBase64 failed with error: " + err.Error())
}
return result
}
// FromURLQuery generates a new Obj by parsing the specified
// query.
//
// For queries with multiple values, the first value is selected.
func FromURLQuery(query string) (Map, error) {
vals, err := url.ParseQuery(query)
if err != nil {
return nil, err
}
m := Map{}
for k, vals := range vals {
m[k] = vals[0]
}
return m, nil
}
// MustFromURLQuery generates a new Obj by parsing the specified
// query.
//
// For queries with multiple values, the first value is selected.
//
// Panics if it encounters an error
func MustFromURLQuery(query string) Map {
o, err := FromURLQuery(query)
if err != nil {
panic("objx: MustFromURLQuery failed with error: " + err.Error())
}
return o
}
-77
View File
@@ -1,77 +0,0 @@
package objx
// Exclude returns a new Map with the keys in the specified []string
// excluded.
func (m Map) Exclude(exclude []string) Map {
excluded := make(Map)
for k, v := range m {
if !contains(exclude, k) {
excluded[k] = v
}
}
return excluded
}
// Copy creates a shallow copy of the Obj.
func (m Map) Copy() Map {
copied := Map{}
for k, v := range m {
copied[k] = v
}
return copied
}
// Merge blends the specified map with a copy of this map and returns the result.
//
// Keys that appear in both will be selected from the specified map.
// This method requires that the wrapped object be a map[string]interface{}
func (m Map) Merge(merge Map) Map {
return m.Copy().MergeHere(merge)
}
// MergeHere blends the specified map with this map and returns the current map.
//
// Keys that appear in both will be selected from the specified map. The original map
// will be modified. This method requires that
// the wrapped object be a map[string]interface{}
func (m Map) MergeHere(merge Map) Map {
for k, v := range merge {
m[k] = v
}
return m
}
// Transform builds a new Obj giving the transformer a chance
// to change the keys and values as it goes. This method requires that
// the wrapped object be a map[string]interface{}
func (m Map) Transform(transformer func(key string, value interface{}) (string, interface{})) Map {
newMap := Map{}
for k, v := range m {
modifiedKey, modifiedVal := transformer(k, v)
newMap[modifiedKey] = modifiedVal
}
return newMap
}
// TransformKeys builds a new map using the specified key mapping.
//
// Unspecified keys will be unaltered.
// This method requires that the wrapped object be a map[string]interface{}
func (m Map) TransformKeys(mapping map[string]string) Map {
return m.Transform(func(key string, value interface{}) (string, interface{}) {
if newKey, ok := mapping[key]; ok {
return newKey, value
}
return key, value
})
}
// Checks if a string slice contains a string
func contains(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
-12
View File
@@ -1,12 +0,0 @@
package objx
import (
"crypto/sha1"
"encoding/hex"
)
// HashWithKey hashes the specified string using the security key
func HashWithKey(data, key string) string {
d := sha1.Sum([]byte(data + ":" + key))
return hex.EncodeToString(d[:])
}
-17
View File
@@ -1,17 +0,0 @@
package objx
// Has gets whether there is something at the specified selector
// or not.
//
// If m is nil, Has will always return false.
func (m Map) Has(selector string) bool {
if m == nil {
return false
}
return !m.Get(selector).IsNil()
}
// IsNil gets whether the data is nil or not.
func (v *Value) IsNil() bool {
return v == nil || v.data == nil
}
-346
View File
@@ -1,346 +0,0 @@
package objx
/*
MSI (map[string]interface{} and []map[string]interface{})
*/
// MSI gets the value as a map[string]interface{}, returns the optionalDefault
// value or a system default object if the value is the wrong type.
func (v *Value) MSI(optionalDefault ...map[string]interface{}) map[string]interface{} {
if s, ok := v.data.(map[string]interface{}); ok {
return s
}
if s, ok := v.data.(Map); ok {
return map[string]interface{}(s)
}
if len(optionalDefault) == 1 {
return optionalDefault[0]
}
return nil
}
// MustMSI gets the value as a map[string]interface{}.
//
// Panics if the object is not a map[string]interface{}.
func (v *Value) MustMSI() map[string]interface{} {
if s, ok := v.data.(Map); ok {
return map[string]interface{}(s)
}
return v.data.(map[string]interface{})
}
// MSISlice gets the value as a []map[string]interface{}, returns the optionalDefault
// value or nil if the value is not a []map[string]interface{}.
func (v *Value) MSISlice(optionalDefault ...[]map[string]interface{}) []map[string]interface{} {
if s, ok := v.data.([]map[string]interface{}); ok {
return s
}
s := v.ObjxMapSlice()
if s == nil {
if len(optionalDefault) == 1 {
return optionalDefault[0]
}
return nil
}
result := make([]map[string]interface{}, len(s))
for i := range s {
result[i] = s[i].Value().MSI()
}
return result
}
// MustMSISlice gets the value as a []map[string]interface{}.
//
// Panics if the object is not a []map[string]interface{}.
func (v *Value) MustMSISlice() []map[string]interface{} {
if s := v.MSISlice(); s != nil {
return s
}
return v.data.([]map[string]interface{})
}
// IsMSI gets whether the object contained is a map[string]interface{} or not.
func (v *Value) IsMSI() bool {
_, ok := v.data.(map[string]interface{})
if !ok {
_, ok = v.data.(Map)
}
return ok
}
// IsMSISlice gets whether the object contained is a []map[string]interface{} or not.
func (v *Value) IsMSISlice() bool {
_, ok := v.data.([]map[string]interface{})
if !ok {
_, ok = v.data.([]Map)
if !ok {
s, ok := v.data.([]interface{})
if ok {
for i := range s {
switch s[i].(type) {
case Map:
case map[string]interface{}:
default:
return false
}
}
return true
}
}
}
return ok
}
// EachMSI calls the specified callback for each object
// in the []map[string]interface{}.
//
// Panics if the object is the wrong type.
func (v *Value) EachMSI(callback func(int, map[string]interface{}) bool) *Value {
for index, val := range v.MustMSISlice() {
carryon := callback(index, val)
if !carryon {
break
}
}
return v
}
// WhereMSI uses the specified decider function to select items
// from the []map[string]interface{}. The object contained in the result will contain
// only the selected items.
func (v *Value) WhereMSI(decider func(int, map[string]interface{}) bool) *Value {
var selected []map[string]interface{}
v.EachMSI(func(index int, val map[string]interface{}) bool {
shouldSelect := decider(index, val)
if !shouldSelect {
selected = append(selected, val)
}
return true
})
return &Value{data: selected}
}
// GroupMSI uses the specified grouper function to group the items
// keyed by the return of the grouper. The object contained in the
// result will contain a map[string][]map[string]interface{}.
func (v *Value) GroupMSI(grouper func(int, map[string]interface{}) string) *Value {
groups := make(map[string][]map[string]interface{})
v.EachMSI(func(index int, val map[string]interface{}) bool {
group := grouper(index, val)
if _, ok := groups[group]; !ok {
groups[group] = make([]map[string]interface{}, 0)
}
groups[group] = append(groups[group], val)
return true
})
return &Value{data: groups}
}
// ReplaceMSI uses the specified function to replace each map[string]interface{}s
// by iterating each item. The data in the returned result will be a
// []map[string]interface{} containing the replaced items.
func (v *Value) ReplaceMSI(replacer func(int, map[string]interface{}) map[string]interface{}) *Value {
arr := v.MustMSISlice()
replaced := make([]map[string]interface{}, len(arr))
v.EachMSI(func(index int, val map[string]interface{}) bool {
replaced[index] = replacer(index, val)
return true
})
return &Value{data: replaced}
}
// CollectMSI uses the specified collector function to collect a value
// for each of the map[string]interface{}s in the slice. The data returned will be a
// []interface{}.
func (v *Value) CollectMSI(collector func(int, map[string]interface{}) interface{}) *Value {
arr := v.MustMSISlice()
collected := make([]interface{}, len(arr))
v.EachMSI(func(index int, val map[string]interface{}) bool {
collected[index] = collector(index, val)
return true
})
return &Value{data: collected}
}
/*
ObjxMap ((Map) and [](Map))
*/
// ObjxMap gets the value as a (Map), returns the optionalDefault
// value or a system default object if the value is the wrong type.
func (v *Value) ObjxMap(optionalDefault ...(Map)) Map {
if s, ok := v.data.((Map)); ok {
return s
}
if s, ok := v.data.(map[string]interface{}); ok {
return s
}
if len(optionalDefault) == 1 {
return optionalDefault[0]
}
return New(nil)
}
// MustObjxMap gets the value as a (Map).
//
// Panics if the object is not a (Map).
func (v *Value) MustObjxMap() Map {
if s, ok := v.data.(map[string]interface{}); ok {
return s
}
return v.data.((Map))
}
// ObjxMapSlice gets the value as a [](Map), returns the optionalDefault
// value or nil if the value is not a [](Map).
func (v *Value) ObjxMapSlice(optionalDefault ...[](Map)) [](Map) {
if s, ok := v.data.([]Map); ok {
return s
}
if s, ok := v.data.([]map[string]interface{}); ok {
result := make([]Map, len(s))
for i := range s {
result[i] = s[i]
}
return result
}
s, ok := v.data.([]interface{})
if !ok {
if len(optionalDefault) == 1 {
return optionalDefault[0]
}
return nil
}
result := make([]Map, len(s))
for i := range s {
switch s[i].(type) {
case Map:
result[i] = s[i].(Map)
case map[string]interface{}:
result[i] = New(s[i])
default:
return nil
}
}
return result
}
// MustObjxMapSlice gets the value as a [](Map).
//
// Panics if the object is not a [](Map).
func (v *Value) MustObjxMapSlice() [](Map) {
if s := v.ObjxMapSlice(); s != nil {
return s
}
return v.data.([](Map))
}
// IsObjxMap gets whether the object contained is a (Map) or not.
func (v *Value) IsObjxMap() bool {
_, ok := v.data.((Map))
if !ok {
_, ok = v.data.(map[string]interface{})
}
return ok
}
// IsObjxMapSlice gets whether the object contained is a [](Map) or not.
func (v *Value) IsObjxMapSlice() bool {
_, ok := v.data.([](Map))
if !ok {
_, ok = v.data.([]map[string]interface{})
if !ok {
s, ok := v.data.([]interface{})
if ok {
for i := range s {
switch s[i].(type) {
case Map:
case map[string]interface{}:
default:
return false
}
}
return true
}
}
}
return ok
}
// EachObjxMap calls the specified callback for each object
// in the [](Map).
//
// Panics if the object is the wrong type.
func (v *Value) EachObjxMap(callback func(int, Map) bool) *Value {
for index, val := range v.MustObjxMapSlice() {
carryon := callback(index, val)
if !carryon {
break
}
}
return v
}
// WhereObjxMap uses the specified decider function to select items
// from the [](Map). The object contained in the result will contain
// only the selected items.
func (v *Value) WhereObjxMap(decider func(int, Map) bool) *Value {
var selected [](Map)
v.EachObjxMap(func(index int, val Map) bool {
shouldSelect := decider(index, val)
if !shouldSelect {
selected = append(selected, val)
}
return true
})
return &Value{data: selected}
}
// GroupObjxMap uses the specified grouper function to group the items
// keyed by the return of the grouper. The object contained in the
// result will contain a map[string][](Map).
func (v *Value) GroupObjxMap(grouper func(int, Map) string) *Value {
groups := make(map[string][](Map))
v.EachObjxMap(func(index int, val Map) bool {
group := grouper(index, val)
if _, ok := groups[group]; !ok {
groups[group] = make([](Map), 0)
}
groups[group] = append(groups[group], val)
return true
})
return &Value{data: groups}
}
// ReplaceObjxMap uses the specified function to replace each (Map)s
// by iterating each item. The data in the returned result will be a
// [](Map) containing the replaced items.
func (v *Value) ReplaceObjxMap(replacer func(int, Map) Map) *Value {
arr := v.MustObjxMapSlice()
replaced := make([](Map), len(arr))
v.EachObjxMap(func(index int, val Map) bool {
replaced[index] = replacer(index, val)
return true
})
return &Value{data: replaced}
}
// CollectObjxMap uses the specified collector function to collect a value
// for each of the (Map)s in the slice. The data returned will be a
// []interface{}.
func (v *Value) CollectObjxMap(collector func(int, Map) interface{}) *Value {
arr := v.MustObjxMapSlice()
collected := make([]interface{}, len(arr))
v.EachObjxMap(func(index int, val Map) bool {
collected[index] = collector(index, val)
return true
})
return &Value{data: collected}
}
File diff suppressed because it is too large Load Diff
-159
View File
@@ -1,159 +0,0 @@
package objx
import (
"fmt"
"strconv"
)
// Value provides methods for extracting interface{} data in various
// types.
type Value struct {
// data contains the raw data being managed by this Value
data interface{}
}
// Data returns the raw data contained by this Value
func (v *Value) Data() interface{} {
return v.data
}
// String returns the value always as a string
func (v *Value) String() string {
switch {
case v.IsNil():
return ""
case v.IsStr():
return v.Str()
case v.IsBool():
return strconv.FormatBool(v.Bool())
case v.IsFloat32():
return strconv.FormatFloat(float64(v.Float32()), 'f', -1, 32)
case v.IsFloat64():
return strconv.FormatFloat(v.Float64(), 'f', -1, 64)
case v.IsInt():
return strconv.FormatInt(int64(v.Int()), 10)
case v.IsInt8():
return strconv.FormatInt(int64(v.Int8()), 10)
case v.IsInt16():
return strconv.FormatInt(int64(v.Int16()), 10)
case v.IsInt32():
return strconv.FormatInt(int64(v.Int32()), 10)
case v.IsInt64():
return strconv.FormatInt(v.Int64(), 10)
case v.IsUint():
return strconv.FormatUint(uint64(v.Uint()), 10)
case v.IsUint8():
return strconv.FormatUint(uint64(v.Uint8()), 10)
case v.IsUint16():
return strconv.FormatUint(uint64(v.Uint16()), 10)
case v.IsUint32():
return strconv.FormatUint(uint64(v.Uint32()), 10)
case v.IsUint64():
return strconv.FormatUint(v.Uint64(), 10)
}
return fmt.Sprintf("%#v", v.Data())
}
// StringSlice returns the value always as a []string
func (v *Value) StringSlice(optionalDefault ...[]string) []string {
switch {
case v.IsStrSlice():
return v.MustStrSlice()
case v.IsBoolSlice():
slice := v.MustBoolSlice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatBool(iv)
}
return vals
case v.IsFloat32Slice():
slice := v.MustFloat32Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatFloat(float64(iv), 'f', -1, 32)
}
return vals
case v.IsFloat64Slice():
slice := v.MustFloat64Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatFloat(iv, 'f', -1, 64)
}
return vals
case v.IsIntSlice():
slice := v.MustIntSlice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatInt(int64(iv), 10)
}
return vals
case v.IsInt8Slice():
slice := v.MustInt8Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatInt(int64(iv), 10)
}
return vals
case v.IsInt16Slice():
slice := v.MustInt16Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatInt(int64(iv), 10)
}
return vals
case v.IsInt32Slice():
slice := v.MustInt32Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatInt(int64(iv), 10)
}
return vals
case v.IsInt64Slice():
slice := v.MustInt64Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatInt(iv, 10)
}
return vals
case v.IsUintSlice():
slice := v.MustUintSlice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatUint(uint64(iv), 10)
}
return vals
case v.IsUint8Slice():
slice := v.MustUint8Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatUint(uint64(iv), 10)
}
return vals
case v.IsUint16Slice():
slice := v.MustUint16Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatUint(uint64(iv), 10)
}
return vals
case v.IsUint32Slice():
slice := v.MustUint32Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatUint(uint64(iv), 10)
}
return vals
case v.IsUint64Slice():
slice := v.MustUint64Slice()
vals := make([]string, len(slice))
for i, iv := range slice {
vals[i] = strconv.FormatUint(iv, 10)
}
return vals
}
if len(optionalDefault) == 1 {
return optionalDefault[0]
}
return []string{}
}
-44
View File
@@ -1,44 +0,0 @@
// Package mock provides a system by which it is possible to mock your objects
// and verify calls are happening as expected.
//
// Example Usage
//
// The mock package provides an object, Mock, that tracks activity on another object. It is usually
// embedded into a test object as shown below:
//
// type MyTestObject struct {
// // add a Mock object instance
// mock.Mock
//
// // other fields go here as normal
// }
//
// When implementing the methods of an interface, you wire your functions up
// to call the Mock.Called(args...) method, and return the appropriate values.
//
// For example, to mock a method that saves the name and age of a person and returns
// the year of their birth or an error, you might write this:
//
// func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) {
// args := o.Called(firstname, lastname, age)
// return args.Int(0), args.Error(1)
// }
//
// The Int, Error and Bool methods are examples of strongly typed getters that take the argument
// index position. Given this argument list:
//
// (12, true, "Something")
//
// You could read them out strongly typed like this:
//
// args.Int(0)
// args.Bool(1)
// args.String(2)
//
// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion:
//
// return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine)
//
// This may cause a panic if the object you are getting is nil (the type assertion will fail), in those
// cases you should check for nil first.
package mock
File diff suppressed because it is too large Load Diff
-4
View File
@@ -197,13 +197,9 @@ github.com/slack-go/slack/internal/errorsx
github.com/slack-go/slack/internal/misc
github.com/slack-go/slack/internal/timex
github.com/slack-go/slack/slackutilsx
# github.com/stretchr/objx v0.4.0
## explicit; go 1.12
github.com/stretchr/objx
# github.com/stretchr/testify v1.8.0
## explicit; go 1.13
github.com/stretchr/testify/assert
github.com/stretchr/testify/mock
github.com/stretchr/testify/require
# github.com/xdg-go/pbkdf2 v1.0.0
## explicit; go 1.9