Test improvements.
This commit is contained in:
parent
b743781dc8
commit
beef68a365
11 changed files with 198 additions and 74 deletions
|
@ -17,14 +17,12 @@ import (
|
|||
func ExampleSelectColor() {
|
||||
zenity.SelectColor(
|
||||
zenity.Color(color.NRGBA{R: 0x66, G: 0x33, B: 0x99, A: 0x80}))
|
||||
// Output:
|
||||
}
|
||||
|
||||
func ExampleSelectColor_palette() {
|
||||
zenity.SelectColor(
|
||||
zenity.ShowPalette(),
|
||||
zenity.Color(color.NRGBA{R: 0x66, G: 0x33, B: 0x99, A: 0xff}))
|
||||
// Output:
|
||||
}
|
||||
|
||||
func TestSelectColor_timeout(t *testing.T) {
|
||||
|
@ -59,22 +57,25 @@ func TestSelectColor_script(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
call string
|
||||
opts []zenity.Option
|
||||
want color.Color
|
||||
err error
|
||||
}{
|
||||
{name: "Cancel", call: "cancel", want: nil, err: zenity.ErrCanceled},
|
||||
{name: "Black", call: "choose black", want: color.Black, err: nil},
|
||||
{name: "White", call: "choose white", want: color.White, err: nil},
|
||||
{name: "Cancel", call: "cancel", err: zenity.ErrCanceled},
|
||||
{name: "Black", call: "choose black", want: color.Black},
|
||||
{name: "White", call: "choose white", want: color.White},
|
||||
{name: "Rebecca", call: "press OK", want: color.NRGBA{R: 0x66, G: 0x33, B: 0x99, A: 0xff},
|
||||
opts: []zenity.Option{zenity.ShowPalette(), zenity.Color(color.NRGBA{R: 0x66, G: 0x33, B: 0x99, A: 0xff})}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
zenity.Info(fmt.Sprintf("In the color selection dialog, %s.", tt.call))
|
||||
color, err := zenity.SelectColor()
|
||||
got, err := zenity.SelectColor(tt.opts...)
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if !zenutil.ColorEquals(color, tt.want) || err != tt.err {
|
||||
t.Errorf("SelectColor() = %v, %v; want %v, %v", color, err, tt.want, tt.err)
|
||||
if !zenutil.ColorEquals(got, tt.want) || err != tt.err {
|
||||
t.Errorf("SelectColor() = %v, %v; want %v, %v", got, err, tt.want, tt.err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
func ExampleEntry() {
|
||||
zenity.Entry("Enter new text:",
|
||||
zenity.Title("Add a new entry"))
|
||||
// Output:
|
||||
}
|
||||
|
||||
func TestEntry_timeout(t *testing.T) {
|
||||
|
@ -54,20 +53,20 @@ func TestEntry_script(t *testing.T) {
|
|||
want string
|
||||
err error
|
||||
}{
|
||||
{name: "Cancel", call: "cancel", want: "", err: zenity.ErrCanceled},
|
||||
{name: "123", call: "enter 123", want: "123", err: nil},
|
||||
{name: "abc", call: "enter abc", want: "abc", err: nil},
|
||||
{name: "Password", call: "press OK", want: "xpto", err: nil,
|
||||
opts: []zenity.Option{zenity.HideText(), zenity.EntryText("xpto")}},
|
||||
{name: "Cancel", call: "cancel", err: zenity.ErrCanceled},
|
||||
{name: "123", call: "enter 123", want: "123"},
|
||||
{name: "abc", call: "enter abc", want: "abc"},
|
||||
{name: "Password", call: "press OK", want: "Χρτο",
|
||||
opts: []zenity.Option{zenity.HideText(), zenity.EntryText("Χρτο")}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
text, err := zenity.Entry(fmt.Sprintf("Please, %s.", tt.call), tt.opts...)
|
||||
got, err := zenity.Entry(fmt.Sprintf("Please, %s.", tt.call), tt.opts...)
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if text != tt.want || err != tt.err {
|
||||
t.Errorf("Entry() = %q, %v; want %q, %v", text, err, tt.want, tt.err)
|
||||
if got != tt.want || err != tt.err {
|
||||
t.Errorf("Entry() = %q, %v; want %q, %v", got, err, tt.want, tt.err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
162
file_test.go
162
file_test.go
|
@ -3,6 +3,7 @@ package zenity_test
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -22,7 +23,6 @@ func ExampleSelectFile() {
|
|||
{"Web files", []string{"*.html", "*.js", "*.css"}},
|
||||
{"Image files", []string{"*.png", "*.gif", "*.ico", "*.jpg", "*.webp"}},
|
||||
})
|
||||
// Output:
|
||||
}
|
||||
|
||||
func ExampleSelectFileMutiple() {
|
||||
|
@ -33,7 +33,6 @@ func ExampleSelectFileMutiple() {
|
|||
{"Web files", []string{"*.html", "*.js", "*.css"}},
|
||||
{"Image files", []string{"*.png", "*.gif", "*.ico", "*.jpg", "*.webp"}},
|
||||
})
|
||||
// Output:
|
||||
}
|
||||
|
||||
func ExampleSelectFileSave() {
|
||||
|
@ -52,61 +51,154 @@ func ExampleSelectFile_directory() {
|
|||
zenity.SelectFile(
|
||||
zenity.Filename(defaultPath),
|
||||
zenity.Directory())
|
||||
// Output:
|
||||
}
|
||||
|
||||
func ExampleSelectFileMutiple_directory() {
|
||||
zenity.SelectFileMutiple(
|
||||
zenity.Filename(defaultPath),
|
||||
zenity.Directory())
|
||||
// Output:
|
||||
}
|
||||
|
||||
var fileFuncs = []func(...zenity.Option) (string, error){
|
||||
zenity.SelectFile,
|
||||
zenity.SelectFileSave,
|
||||
func(o ...zenity.Option) (string, error) {
|
||||
var fileFuncs = []struct {
|
||||
name string
|
||||
fn func(...zenity.Option) (string, error)
|
||||
}{
|
||||
{"Open", zenity.SelectFile},
|
||||
{"Save", zenity.SelectFileSave},
|
||||
{"Directory", func(o ...zenity.Option) (string, error) {
|
||||
return zenity.SelectFile(append(o, zenity.Directory())...)
|
||||
},
|
||||
func(o ...zenity.Option) (string, error) {
|
||||
}},
|
||||
{"Mutiple", func(o ...zenity.Option) (string, error) {
|
||||
_, err := zenity.SelectFileMutiple(append(o, zenity.Directory())...)
|
||||
return "", err
|
||||
},
|
||||
func(o ...zenity.Option) (string, error) {
|
||||
}},
|
||||
{"MutipleDirectory", func(o ...zenity.Option) (string, error) {
|
||||
_, err := zenity.SelectFileMutiple(o...)
|
||||
return "", err
|
||||
},
|
||||
}},
|
||||
}
|
||||
|
||||
func TestFile_timeout(t *testing.T) {
|
||||
for _, f := range fileFuncs {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second/10)
|
||||
func TestSelectFile_timeout(t *testing.T) {
|
||||
for _, tt := range fileFuncs {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
defer goleak.VerifyNone(t)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second/10)
|
||||
defer cancel()
|
||||
|
||||
_, err := f(zenity.Context(ctx))
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if !os.IsTimeout(err) {
|
||||
t.Error("did not timeout:", err)
|
||||
}
|
||||
|
||||
cancel()
|
||||
goleak.VerifyNone(t)
|
||||
_, err := tt.fn(zenity.Context(ctx))
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if !os.IsTimeout(err) {
|
||||
t.Error("did not timeout:", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFile_cancel(t *testing.T) {
|
||||
defer goleak.VerifyNone(t)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
func TestSelectFile_cancel(t *testing.T) {
|
||||
for _, tt := range fileFuncs {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
defer goleak.VerifyNone(t)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
for _, f := range fileFuncs {
|
||||
_, err := f(zenity.Context(ctx))
|
||||
_, err := tt.fn(zenity.Context(ctx))
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if !errors.Is(err, context.Canceled) {
|
||||
t.Error("was not canceled:", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectFile_script(t *testing.T) {
|
||||
t.Run("Cancel", func(t *testing.T) {
|
||||
zenity.Info(fmt.Sprintf("In the file selection dialog, cancel."))
|
||||
str, err := zenity.SelectFile()
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if !errors.Is(err, context.Canceled) {
|
||||
t.Error("was not canceled:", err)
|
||||
if str != "" || err != zenity.ErrCanceled {
|
||||
t.Errorf("SelectFile() = %q, %v; want %q, %v", str, err, "", zenity.ErrCanceled)
|
||||
}
|
||||
}
|
||||
})
|
||||
t.Run("File", func(t *testing.T) {
|
||||
zenity.Info(fmt.Sprintf("In the file selection dialog, pick any file."))
|
||||
str, err := zenity.SelectFile()
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if str == "" || err != nil {
|
||||
t.Errorf("SelectFile() = %q, %v; want [path], nil", str, err)
|
||||
}
|
||||
if _, serr := os.Stat(str); serr != nil {
|
||||
t.Errorf("SelectFile() = %q, %v; %v", str, err, serr)
|
||||
}
|
||||
})
|
||||
t.Run("Directory", func(t *testing.T) {
|
||||
zenity.Info(fmt.Sprintf("In the file selection dialog, pick any directory."))
|
||||
str, err := zenity.SelectFile(zenity.Directory())
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if str == "" || err != nil {
|
||||
t.Errorf("SelectFile() = %q, %v; want [path], nil", str, err)
|
||||
}
|
||||
if s, serr := os.Stat(str); serr != nil {
|
||||
t.Errorf("SelectFile() = %q, %v; %v", str, err, serr)
|
||||
} else if !s.IsDir() {
|
||||
t.Errorf("SelectFile() = %q, %v; not a directory", str, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSelectFileMutiple_script(t *testing.T) {
|
||||
t.Run("Cancel", func(t *testing.T) {
|
||||
zenity.Info(fmt.Sprintf("In the file selection dialog, cancel."))
|
||||
lst, err := zenity.SelectFileMutiple()
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if lst != nil || err != zenity.ErrCanceled {
|
||||
t.Errorf("SelectFileMutiple() = %v, %v; want nil, %v", lst, err, zenity.ErrCanceled)
|
||||
}
|
||||
})
|
||||
t.Run("Files", func(t *testing.T) {
|
||||
zenity.Info(fmt.Sprintf("In the file selection dialog, pick two files."))
|
||||
lst, err := zenity.SelectFileMutiple()
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if lst == nil || err != nil {
|
||||
t.Errorf("SelectFileMutiple() = %v, %v; want [path, path], nil", lst, err)
|
||||
}
|
||||
for _, str := range lst {
|
||||
if _, serr := os.Stat(str); serr != nil {
|
||||
t.Errorf("SelectFileMutiple() = %q, %v; %v", lst, err, serr)
|
||||
}
|
||||
}
|
||||
})
|
||||
t.Run("Directories", func(t *testing.T) {
|
||||
zenity.Info(fmt.Sprintf("In the file selection dialog, pick two directories."))
|
||||
lst, err := zenity.SelectFileMutiple(zenity.Directory())
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if err == zenity.ErrUnsupported {
|
||||
t.Skip("was not unsupported:", err)
|
||||
}
|
||||
if lst == nil || err != nil {
|
||||
t.Errorf("SelectFileMutiple() = %v, %v; want [path, path], nil", lst, err)
|
||||
}
|
||||
for _, str := range lst {
|
||||
if s, serr := os.Stat(str); serr != nil {
|
||||
t.Errorf("SelectFileMutiple() = %q, %v; %v", str, err, serr)
|
||||
} else if !s.IsDir() {
|
||||
t.Errorf("SelectFileMutiple() = %q, %v; not a directory", str, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -199,6 +199,9 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
|||
_CLSID_FileOpenDialog, 0, 0x17, // CLSCTX_ALL
|
||||
_IID_IFileOpenDialog, uintptr(unsafe.Pointer(&dialog)))
|
||||
if int32(hr) < 0 {
|
||||
if multi {
|
||||
return "", nil, ErrUnsupported
|
||||
}
|
||||
return browseForFolder(opts)
|
||||
}
|
||||
defer dialog.Call(dialog.Release)
|
||||
|
|
26
list_test.go
26
list_test.go
|
@ -20,14 +20,12 @@ func ExampleList() {
|
|||
zenity.Title("Select items from the list"),
|
||||
zenity.DisallowEmpty(),
|
||||
)
|
||||
// Output:
|
||||
}
|
||||
|
||||
func ExampleListItems() {
|
||||
zenity.ListItems(
|
||||
"Select items from the list below:",
|
||||
"apples", "oranges", "bananas", "strawberries")
|
||||
// Output:
|
||||
}
|
||||
|
||||
func ExampleListMultiple() {
|
||||
|
@ -37,14 +35,12 @@ func ExampleListMultiple() {
|
|||
zenity.Title("Select items from the list"),
|
||||
zenity.DefaultItems("apples", "bananas"),
|
||||
)
|
||||
// Output:
|
||||
}
|
||||
|
||||
func ExampleListMultipleItems() {
|
||||
zenity.ListMultipleItems(
|
||||
"Select items from the list below:",
|
||||
"apples", "oranges", "bananas", "strawberries")
|
||||
// Output:
|
||||
}
|
||||
|
||||
func TestList_timeout(t *testing.T) {
|
||||
|
@ -80,21 +76,20 @@ func TestList_script(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
call string
|
||||
opts []zenity.Option
|
||||
want string
|
||||
err error
|
||||
}{
|
||||
{name: "Cancel", call: "cancel", want: "", err: zenity.ErrCanceled},
|
||||
{name: "Apples", call: "select apples", want: "apples", err: nil},
|
||||
{name: "Cancel", call: "cancel", err: zenity.ErrCanceled},
|
||||
{name: "Apples", call: "select apples", want: "apples"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
text, err := zenity.List(fmt.Sprintf("Please, %s.", tt.call), items, tt.opts...)
|
||||
got, err := zenity.ListItems(fmt.Sprintf("Please, %s.", tt.call), items...)
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if text != tt.want || err != tt.err {
|
||||
t.Errorf("List() = %q, %v; want %q, %v", text, err, tt.want, tt.err)
|
||||
if got != tt.want || err != tt.err {
|
||||
t.Errorf("List() = %q, %v; want %q, %v", got, err, tt.want, tt.err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -105,19 +100,18 @@ func TestListMultiple_script(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
call string
|
||||
opts []zenity.Option
|
||||
want []string
|
||||
err error
|
||||
}{
|
||||
{name: "Cancel", call: "cancel", want: nil, err: zenity.ErrCanceled},
|
||||
{name: "Nothing", call: "select nothing", want: []string{}, err: nil},
|
||||
{name: "Apples", call: "select apples", want: []string{"apples"}, err: nil},
|
||||
{name: "Cancel", call: "cancel", err: zenity.ErrCanceled},
|
||||
{name: "Nothing", call: "select nothing", want: []string{}},
|
||||
{name: "Apples", call: "select apples", want: []string{"apples"}},
|
||||
{name: "Apples & Oranges", call: "select apples and oranges",
|
||||
want: []string{"apples", "oranges"}, err: nil},
|
||||
want: []string{"apples", "oranges"}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := zenity.ListMultiple(fmt.Sprintf("Please, %s.", tt.call), items, tt.opts...)
|
||||
got, err := zenity.ListMultipleItems(fmt.Sprintf("Please, %s.", tt.call), items...)
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ func TestMessage_script(t *testing.T) {
|
|||
call string
|
||||
err error
|
||||
}{
|
||||
{name: "QuestionYes", call: "press Yes", err: nil},
|
||||
{name: "QuestionYes", call: "press Yes"},
|
||||
{name: "QuestionNo", call: "press No", err: zenity.ErrExtraButton},
|
||||
{name: "QuestionCancel", call: "cancel", err: zenity.ErrCanceled},
|
||||
}
|
||||
|
|
2
pwd.go
2
pwd.go
|
@ -3,7 +3,7 @@ package zenity
|
|||
// Password displays the password dialog.
|
||||
//
|
||||
// Valid options: Title, OKLabel, CancelLabel, ExtraButton, Icon, Username.
|
||||
func Password(options ...Option) (usr string, pw string, err error) {
|
||||
func Password(options ...Option) (usr string, pwd string, err error) {
|
||||
return password(applyOptions(options))
|
||||
}
|
||||
|
||||
|
|
34
pwd_test.go
34
pwd_test.go
|
@ -3,6 +3,7 @@ package zenity_test
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
@ -14,14 +15,12 @@ import (
|
|||
|
||||
func ExamplePassword() {
|
||||
zenity.Password(zenity.Title("Type your password"))
|
||||
// Output:
|
||||
}
|
||||
|
||||
func ExamplePassword_username() {
|
||||
zenity.Password(
|
||||
zenity.Title("Type your username and password"),
|
||||
zenity.Username())
|
||||
// Output:
|
||||
}
|
||||
|
||||
func TestPassword_timeout(t *testing.T) {
|
||||
|
@ -71,3 +70,34 @@ func TestPassword_username(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPassword_script(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
call string
|
||||
opts []zenity.Option
|
||||
usr string
|
||||
pwd string
|
||||
err error
|
||||
}{
|
||||
{name: "Cancel", call: "cancel", err: zenity.ErrCanceled},
|
||||
{name: "Password", call: "enter pwd", pwd: "pwd"},
|
||||
{name: "User", call: "enter usr and pwd (if supported)", usr: "usr", pwd: "pwd",
|
||||
opts: []zenity.Option{zenity.Username()}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
zenity.Info(fmt.Sprintf("In the password dialog, %s.", tt.call))
|
||||
usr, pwd, err := zenity.Password(tt.opts...)
|
||||
if skip, err := skip(err); skip {
|
||||
t.Skip("skipping:", err)
|
||||
}
|
||||
if err == zenity.ErrUnsupported {
|
||||
t.Skip("was not unsupported:", err)
|
||||
}
|
||||
if usr != tt.usr || pwd != tt.pwd || err != tt.err {
|
||||
t.Errorf("Password() = %q, %q, %v; want %q, %q, %v", usr, pwd, err, tt.usr, tt.pwd, tt.err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ func password(opts options) (string, string, error) {
|
|||
out, err := zenutil.Run(opts.ctx, args)
|
||||
str, err := strResult(opts, out, err)
|
||||
if err == nil && opts.username {
|
||||
if split := strings.SplitN(string(out), "|", 2); len(split) == 2 {
|
||||
if split := strings.SplitN(str, "|", 2); len(split) == 2 {
|
||||
return split[0], split[1], nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,6 +124,7 @@ func setup() context.CancelFunc {
|
|||
var icc _INITCOMMONCONTROLSEX
|
||||
icc.Size = uint32(unsafe.Sizeof(icc))
|
||||
icc.ICC = 0x00004020 // ICC_STANDARD_CLASSES|ICC_PROGRESS_CLASS
|
||||
initCommonControlsEx.Call(uintptr(unsafe.Pointer(&icc)))
|
||||
|
||||
return func() {
|
||||
if restore != 0 {
|
||||
|
|
|
@ -42,12 +42,16 @@ func Test_applyOptions(t *testing.T) {
|
|||
{name: "ConfirmCreate", args: ConfirmCreate(), want: options{confirmCreate: true}},
|
||||
{name: "ShowHidden", args: ShowHidden(), want: options{showHidden: true}},
|
||||
{name: "Filename", args: Filename("file.go"), want: options{filename: "file.go"}},
|
||||
{name: "FileFilters", args: FileFilter{"Go files", []string{"*.go"}}, want: options{
|
||||
{name: "FileFilter", args: FileFilter{"Go files", []string{"*.go"}}, want: options{
|
||||
fileFilters: FileFilters{{"Go files", []string{"*.go"}}},
|
||||
}},
|
||||
{name: "FileFilters", args: FileFilters{{"Go files", []string{"*.go"}}}, want: options{
|
||||
fileFilters: FileFilters{{"Go files", []string{"*.go"}}},
|
||||
}},
|
||||
|
||||
// Progress indication options
|
||||
{name: "MaxValue", args: MaxValue(100), want: options{maxValue: 100}},
|
||||
{name: "Pulsate", args: Pulsate(), want: options{maxValue: -1}},
|
||||
{name: "NoCancel", args: NoCancel(), want: options{noCancel: true}},
|
||||
{name: "TimeRemaining", args: TimeRemaining(), want: options{timeRemaining: true}},
|
||||
|
||||
|
|
Loading…
Reference in a new issue