checkpoint: new parser for TimeDurationValue, new tests for TimeDurationValue
This commit is contained in:
parent
61a00d7a5b
commit
1ab313e558
3 changed files with 125 additions and 11 deletions
|
@ -269,16 +269,21 @@ enbas show --type blocked
|
||||||
|
|
||||||
### Mute an account
|
### Mute an account
|
||||||
|
|
||||||
```
|
- Mute an account indefinitely.
|
||||||
enbas mute --type account --account-name @name@example.social --mute-notifications --mute-duration="1h"
|
```
|
||||||
```
|
enbas mute --type account --account-name @name@example.social --mute-notifications"
|
||||||
|
```
|
||||||
|
- Mute an account for 1 and a half hours.
|
||||||
|
```
|
||||||
|
enbas mute --type account --account-name @name@example.social --mute-notifications --mute-duration="1 hour and 30 minutes"
|
||||||
|
```
|
||||||
|
|
||||||
| flag | type | required | description | default |
|
| flag | type | required | description | default |
|
||||||
|------|------|----------|-------------|---------|
|
|------|------|----------|-------------|---------|
|
||||||
| `type` | string | true | The resource you want to mute.<br>Here this should be `account`. | |
|
| `type` | string | true | The resource you want to mute.<br>Here this should be `account`. | |
|
||||||
| `account-name` | string | true | The name of the account to mute. | |
|
| `account-name` | string | true | The name of the account to mute. | |
|
||||||
| `mute-notifications` | boolean | false | Set to `true` to mute notifications as well as statuses. | false |
|
| `mute-notifications` | boolean | false | Set to `true` to mute notifications as well as statuses. | false |
|
||||||
| `mute-duration` | string | false | Specify how long the account should be muted for.<br>Set to `0s` to mute indefinitely | 0s (indefinitely). |
|
| `mute-duration` | string | false | Specify how long the account should be muted for.<br>Set to `0 seconds` to mute indefinitely | 0 seconds (indefinitely). |
|
||||||
|
|
||||||
### Unmute an account
|
### Unmute an account
|
||||||
|
|
||||||
|
@ -476,7 +481,7 @@ Creates a new status.
|
||||||
--content "The age-old question: which text editor do you prefer?" \
|
--content "The age-old question: which text editor do you prefer?" \
|
||||||
--add-poll \
|
--add-poll \
|
||||||
--poll-allows-multiple-choices=false \
|
--poll-allows-multiple-choices=false \
|
||||||
--poll-expires-in 168h \
|
--poll-expires-in "7 days" \
|
||||||
--poll-option "emacs" \
|
--poll-option "emacs" \
|
||||||
--poll-option "vim/neovim" \
|
--poll-option "vim/neovim" \
|
||||||
--poll-option "nano" \
|
--poll-option "nano" \
|
||||||
|
|
|
@ -2,16 +2,21 @@ package flag
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const timeDurationRegexPattern string = `[0-9]{1,4}\s+(days?|hours?|minutes?|seconds?)`
|
||||||
|
|
||||||
type TimeDurationValue struct {
|
type TimeDurationValue struct {
|
||||||
Duration time.Duration
|
Duration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTimeDurationValue() TimeDurationValue {
|
func NewTimeDurationValue() TimeDurationValue {
|
||||||
return TimeDurationValue{
|
return TimeDurationValue{
|
||||||
Duration: 0 * time.Second,
|
Duration: time.Duration(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,13 +24,56 @@ func (v TimeDurationValue) String() string {
|
||||||
return v.Duration.String()
|
return v.Duration.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *TimeDurationValue) Set(text string) error {
|
func (v *TimeDurationValue) Set(value string) error {
|
||||||
duration, err := time.ParseDuration(text)
|
pattern := regexp.MustCompile(timeDurationRegexPattern)
|
||||||
if err != nil {
|
matches := pattern.FindAllString(value, -1)
|
||||||
return fmt.Errorf("unable to parse the value as time duration: %w", err)
|
|
||||||
|
days, hours, minutes, seconds := 0, 0, 0, 0
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for ind := range len(matches) {
|
||||||
|
switch {
|
||||||
|
case strings.Contains(matches[ind], "day"):
|
||||||
|
days, err = parseInt(matches[ind])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to parse the integer from %s: %w", matches[ind], err)
|
||||||
|
}
|
||||||
|
case strings.Contains(matches[ind], "hour"):
|
||||||
|
hours, err = parseInt(matches[ind])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to parse the integer from %s: %w", matches[ind], err)
|
||||||
|
}
|
||||||
|
case strings.Contains(matches[ind], "minute"):
|
||||||
|
minutes, err = parseInt(matches[ind])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to parse the integer from %s: %w", matches[ind], err)
|
||||||
|
}
|
||||||
|
case strings.Contains(matches[ind], "second"):
|
||||||
|
seconds, err = parseInt(matches[ind])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to parse the integer from %s: %w", matches[ind], err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v.Duration = duration
|
durationValue := (days * 86400) + (hours * 3600) + (minutes * 60) + seconds
|
||||||
|
|
||||||
|
v.Duration = time.Duration(durationValue) * time.Second
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseInt(text string) (int, error) {
|
||||||
|
split := strings.SplitN(text, " ", 2)
|
||||||
|
if len(split) != 2 {
|
||||||
|
return 0, fmt.Errorf("unexpected number of split for %s: want 2, got %d", text, len(split))
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := strconv.Atoi(split[0])
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("unable to convert %s to an integer: %w", text, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
|
|
61
internal/flag/timedurationvalue_test.go
Normal file
61
internal/flag/timedurationvalue_test.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package flag_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
internalFlag "codeflow.dananglin.me.uk/apollo/enbas/internal/flag"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTimeDurationValue(t *testing.T) {
|
||||||
|
parsingTests := []struct {
|
||||||
|
input string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: "1 day",
|
||||||
|
want: "24h0m0s",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "3 days, 5 hours, 39 minutes and 6 seconds",
|
||||||
|
want: "77h39m6s",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "1 minute and 30 seconds",
|
||||||
|
want: "1m30s",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "(7 seconds) (21 hours) (41 days)",
|
||||||
|
want: "1005h0m7s",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
value := internalFlag.NewTimeDurationValue()
|
||||||
|
|
||||||
|
for _, test := range slices.All(parsingTests) {
|
||||||
|
if err := value.Set(test.input); err != nil {
|
||||||
|
t.Fatalf(
|
||||||
|
"Unable to parse %s into a TimeDurationValue: %v",
|
||||||
|
test.input,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
got := value.String()
|
||||||
|
|
||||||
|
if got != test.want {
|
||||||
|
t.Errorf(
|
||||||
|
"Unexpected duration parsed from %s: want %s, got %s",
|
||||||
|
test.input,
|
||||||
|
test.want,
|
||||||
|
got,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
t.Logf(
|
||||||
|
"Expected duration parsed from %s: got %s",
|
||||||
|
test.input,
|
||||||
|
got,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue