Skip to content

Commit

Permalink
feat: support limit flag (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
cecobask authored Nov 13, 2023
1 parent 5fb68f2 commit 65be4e5
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 1 deletion.
1 change: 1 addition & 0 deletions cmd/followdata/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func NewRootCommand() *cobra.Command {
}

func addCommonFlags(cmd *cobra.Command) {
cmd.Flags().Int(instagram.FlagLimit, instagram.Unlimited, `maximum results to display, leave empty for unlimited`)
cmd.Flags().String(instagram.FlagOrder, instagram.OrderDesc, `order direction ("asc", "desc")`)
cmd.Flags().String(instagram.FlagOutput, instagram.OutputTable, `output format ("json", "table", "yaml")`)
cmd.Flags().String(instagram.FlagSortBy, instagram.FieldTimestamp, `sort by field ("timestamp", "username")`)
Expand Down
3 changes: 3 additions & 0 deletions cmd/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package root

import (
"fmt"
"os"

"github.com/cecobask/instagram-insights/cmd/followdata"
"github.com/cecobask/instagram-insights/cmd/information"
Expand All @@ -24,6 +25,8 @@ func NewRootCommand() *cobra.Command {
SilenceUsage: true,
DisableAutoGenTag: true,
}
cmd.SetOut(os.Stdout)
cmd.SetErr(os.Stderr)
cmd.AddCommand(
information.NewRootCommand(),
followdata.NewRootCommand(),
Expand Down
2 changes: 2 additions & 0 deletions pkg/instagram/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package instagram
const (
FieldTimestamp = "timestamp"
FieldUsername = "username"
Unlimited = 0
OrderAsc = "asc"
OrderDesc = "desc"
OutputJson = "json"
Expand All @@ -12,6 +13,7 @@ const (
)

const (
FlagLimit = "limit"
FlagOrder = "order"
FlagOutput = "output"
FlagSortBy = "sort-by"
Expand Down
9 changes: 9 additions & 0 deletions pkg/instagram/followdata/followdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func (h *handler) Followers(opts *instagram.Options) (*string, error) {
}
}
h.followData.Followers.Sort(opts.SortBy, opts.Order)
h.followData.Followers.Limit(opts.Limit)
return h.followData.Followers.output(opts.Output)
}

Expand All @@ -59,6 +60,7 @@ func (h *handler) Following(opts *instagram.Options) (*string, error) {
return nil, err
}
h.followData.Following.Sort(opts.SortBy, opts.Order)
h.followData.Following.Limit(opts.Limit)
return h.followData.Following.output(opts.Output)
}

Expand All @@ -72,6 +74,7 @@ func (h *handler) Unfollowers(opts *instagram.Options) (*string, error) {
}
h.followData.hydrateUnfollowers()
h.followData.Unfollowers.Sort(opts.SortBy, opts.Order)
h.followData.Unfollowers.Limit(opts.Limit)
return h.followData.Unfollowers.output(opts.Output)
}

Expand Down Expand Up @@ -283,3 +286,9 @@ func (ul *userList) Sort(field string, order string) {
slices.Reverse(ul.users)
}
}

func (ul *userList) Limit(limit int) {
if limit > 0 && limit < len(ul.users) {
ul.users = ul.users[:limit]
}
}
61 changes: 61 additions & 0 deletions pkg/instagram/followdata/followdata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,3 +462,64 @@ func Test_userList_Sort(t *testing.T) {
})
}
}

func Test_userList_Limit(t *testing.T) {
type fields struct {
users []user
}
type args struct {
limit int
}
testUsers := []user{
{
ProfileUrl: "https://www.instagram.com/username1",
Username: "username1",
Timestamp: &timestamp{},
},
{
ProfileUrl: "https://www.instagram.com/username2",
Username: "username2",
Timestamp: &timestamp{},
},
}
tests := []struct {
name string
fields fields
args args
assertions func(t *testing.T, ul *userList)
}{
{
name: "succeeds to limit users",
fields: fields{
users: testUsers,
},
args: args{
limit: 1,
},
assertions: func(t *testing.T, ul *userList) {
assert.Equal(t, 1, len(ul.users))
},
},
{
name: "avoids to limit users when limit is unlimited",
fields: fields{
users: testUsers,
},
args: args{
limit: instagram.Unlimited,
},
assertions: func(t *testing.T, ul *userList) {
assert.Equal(t, 2, len(ul.users))
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ul := &userList{
users: tt.fields.users,
}
ul.Limit(tt.args.limit)
tt.assertions(t, ul)
})
}
}
17 changes: 17 additions & 0 deletions pkg/instagram/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ import (
)

type Options struct {
Limit int
Order string
Output string
SortBy string
}

func NewOptions(flags *pflag.FlagSet) (*Options, error) {
limit, err := flags.GetInt(FlagLimit)
if err != nil {
return nil, err
}
order, err := flags.GetString(FlagOrder)
if err != nil {
return nil, err
Expand All @@ -26,6 +31,7 @@ func NewOptions(flags *pflag.FlagSet) (*Options, error) {
return nil, err
}
return &Options{
Limit: limit,
Order: order,
Output: output,
SortBy: sortBy,
Expand All @@ -39,6 +45,9 @@ func NewEmptyOptions() *Options {
}

func (o *Options) Validate() error {
if err := validateLimit(o.Limit); err != nil {
return err
}
if err := validateOrder(o.Order); err != nil {
return err
}
Expand All @@ -51,6 +60,14 @@ func (o *Options) Validate() error {
return nil
}

func validateLimit(value int) error {
if value < 0 {
return fmt.Errorf("invalid limit: %d", value)
}
return nil

}

func validateOrder(value string) error {
switch value {
case OrderAsc, OrderDesc:
Expand Down
28 changes: 27 additions & 1 deletion pkg/instagram/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func Test_validateOutput(t *testing.T) {

func TestOptions_Validate(t *testing.T) {
type fields struct {
Limit int
Order string
Output string
SortBy string
Expand All @@ -54,12 +55,20 @@ func TestOptions_Validate(t *testing.T) {
{
name: "succeeds to validate all options",
fields: fields{
Limit: Unlimited,
Order: OrderAsc,
Output: OutputTable,
SortBy: FieldTimestamp,
},
wantErr: false,
},
{
name: "fails to validate limit",
fields: fields{
Limit: -1,
},
wantErr: true,
},
{
name: "fails to validate order",
fields: fields{
Expand Down Expand Up @@ -88,6 +97,7 @@ func TestOptions_Validate(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := Options{
Limit: tt.fields.Limit,
Order: tt.fields.Order,
Output: tt.fields.Output,
SortBy: tt.fields.SortBy,
Expand All @@ -114,32 +124,47 @@ func TestNewOptions(t *testing.T) {
args: args{
flags: func() *pflag.FlagSet {
flags := pflag.NewFlagSet("", pflag.ExitOnError)
flags.Int(FlagLimit, 1000, "")
flags.String(FlagOrder, OrderAsc, "")
flags.String(FlagOutput, OutputTable, "")
flags.String(FlagSortBy, FieldTimestamp, "")
return flags
}(),
},
want: &Options{
Limit: 1000,
Order: OrderAsc,
Output: OutputTable,
SortBy: FieldTimestamp,
},
wantErr: false,
},
{
name: "fails to find flag order",
name: "fails to find flag limit",
args: args{
flags: pflag.NewFlagSet("", pflag.ExitOnError),
},
want: nil,
wantErr: true,
},
{
name: "fails to find flag order",
args: args{
flags: func() *pflag.FlagSet {
flags := pflag.NewFlagSet("", pflag.ExitOnError)
flags.Int(FlagLimit, Unlimited, "")
return flags
}(),
},
want: nil,
wantErr: true,
},
{
name: "fails to find flag output",
args: args{
flags: func() *pflag.FlagSet {
flags := pflag.NewFlagSet("", pflag.ExitOnError)
flags.Int(FlagLimit, Unlimited, "")
flags.String(FlagOrder, OrderAsc, "")
return flags
}(),
Expand All @@ -152,6 +177,7 @@ func TestNewOptions(t *testing.T) {
args: args{
flags: func() *pflag.FlagSet {
flags := pflag.NewFlagSet("", pflag.ExitOnError)
flags.Int(FlagLimit, Unlimited, "")
flags.String(FlagOrder, OrderAsc, "")
flags.String(FlagOutput, OutputTable, "")
return flags
Expand Down

0 comments on commit 65be4e5

Please sign in to comment.