github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/parse_time_test.go (about)

     1  // Copyright (c) 2015-2022 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"testing"
    22  )
    23  
    24  var parseDurationTests = []struct {
    25  	in   string
    26  	ok   bool
    27  	want Duration
    28  }{
    29  	// simple
    30  	{"0", true, 0},
    31  	{"5s", true, 5 * Second},
    32  	{"30s", true, 30 * Second},
    33  	{"1478s", true, 1478 * Second},
    34  	// sign
    35  	{"-5s", true, -5 * Second},
    36  	{"+5s", true, 5 * Second},
    37  	{"-0", true, 0},
    38  	{"+0", true, 0},
    39  	// decimal
    40  	{"5.0s", true, 5 * Second},
    41  	{"5.6s", true, 5*Second + 600*Millisecond},
    42  	{"5.s", true, 5 * Second},
    43  	{".5s", true, 500 * Millisecond},
    44  	{"1.0s", true, 1 * Second},
    45  	{"1.00s", true, 1 * Second},
    46  	{"1.004s", true, 1*Second + 4*Millisecond},
    47  	{"1.0040s", true, 1*Second + 4*Millisecond},
    48  	{"100.00100s", true, 100*Second + 1*Millisecond},
    49  	// different units
    50  	{"10ns", true, 10 * Nanosecond},
    51  	{"11us", true, 11 * Microsecond},
    52  	{"12µs", true, 12 * Microsecond}, // U+00B5
    53  	{"12μs", true, 12 * Microsecond}, // U+03BC
    54  	{"13ms", true, 13 * Millisecond},
    55  	{"14s", true, 14 * Second},
    56  	{"15m", true, 15 * Minute},
    57  	{"16h", true, 16 * Hour},
    58  	{"12d", true, 12 * Day},
    59  	{"3w", true, 3 * Week},
    60  	// composite durations
    61  	{"3h30m", true, 3*Hour + 30*Minute},
    62  	{"10.5s4m", true, 4*Minute + 10*Second + 500*Millisecond},
    63  	{"-2m3.4s", true, -(2*Minute + 3*Second + 400*Millisecond)},
    64  	{"1h2m3s4ms5us6ns", true, 1*Hour + 2*Minute + 3*Second + 4*Millisecond + 5*Microsecond + 6*Nanosecond},
    65  	{"39h9m14.425s", true, 39*Hour + 9*Minute + 14*Second + 425*Millisecond},
    66  	{"2w3d12h", true, 2*Week + 3*Day + 12*Hour},
    67  	// large value
    68  	{"52763797000ns", true, 52763797000 * Nanosecond},
    69  	// more than 9 digits after decimal point, see https://golang.org/issue/6617
    70  	{"0.3333333333333333333h", true, 20 * Minute},
    71  	// 9007199254740993 = 1<<53+1 cannot be stored precisely in a float64
    72  	{"9007199254740993ns", true, (1<<53 + 1) * Nanosecond},
    73  	// largest duration that can be represented by int64 in nanoseconds
    74  	{"9223372036854775807ns", true, (1<<63 - 1) * Nanosecond},
    75  	{"9223372036854775.807us", true, (1<<63 - 1) * Nanosecond},
    76  	{"9223372036s854ms775us807ns", true, (1<<63 - 1) * Nanosecond},
    77  	// large negative value
    78  	{"-9223372036854775807ns", true, -1<<63 + 1*Nanosecond},
    79  
    80  	// errors
    81  	{"", false, 0},
    82  	{"3", false, 0},
    83  	{"-", false, 0},
    84  	{"s", false, 0},
    85  	{".", false, 0},
    86  	{"-.", false, 0},
    87  	{".s", false, 0},
    88  	{"+.s", false, 0},
    89  	{"3000000h", false, 0},                  // overflow
    90  	{"9223372036854775808ns", false, 0},     // overflow
    91  	{"9223372036854775.808us", false, 0},    // overflow
    92  	{"9223372036854ms775us808ns", false, 0}, // overflow
    93  	// largest negative value of type int64 in nanoseconds should fail
    94  	// see https://go-review.googlesource.com/#/c/2461/
    95  	{"-9223372036854775808ns", false, 0},
    96  }
    97  
    98  func TestParseDuration(t *testing.T) {
    99  	for _, tc := range parseDurationTests {
   100  		t.Run(tc.in, func(t *testing.T) {
   101  			d, err := ParseDuration(tc.in)
   102  			if tc.ok && (err != nil || d != tc.want) {
   103  				t.Errorf("ParseDuration(%q) = %v, %v, want %v, nil", tc.in, d, err, tc.want)
   104  			} else if !tc.ok && err == nil {
   105  				t.Errorf("ParseDuration(%q) = _, nil, want _, non-nil", tc.in)
   106  			}
   107  		})
   108  	}
   109  }
   110  
   111  // Test for ParseDurationTime. Validates the returned value
   112  // for given time value in days, hours and minute format.
   113  func TestParseDurationTime(t *testing.T) {
   114  	testCases := []struct {
   115  		timeValue string
   116  		expected  Duration
   117  		err       string
   118  	}{
   119  		// Test 1: empty string as input
   120  		{"", 0, "invalid empty duration"},
   121  		// Test 2: Input string contains 4 day, 10 hour and 3 minutes
   122  		{"4d10h3m", 381780000000000, ""},
   123  		// Test 3: Input string contains 10 day and  3 hours
   124  		{"10d3h", 874800000000000, ""},
   125  		// Test 4: Input string contains minutes and days
   126  		{"3m7d", 604980000000000, ""},
   127  		// Test 5: Input string contains unknown unit
   128  		{"4a3d", 0, "unknown unit a in duration 4a3d"},
   129  		// Test 6: Input string contains fractional day
   130  		{"1.5d", 129600000000000, ""},
   131  		// Test 6: Input string contains fractional day and hour
   132  		{"2.5d1.5h", 221400000000000, ""},
   133  		// Test 7: Input string contains fractional day , hour and minute
   134  		{"2.5d1.5h3.5m", 221610000000000, ""},
   135  	}
   136  
   137  	for _, testCase := range testCases {
   138  		testCase := testCase
   139  		t.Run("", func(t *testing.T) {
   140  			myVal, err := ParseDuration(testCase.timeValue)
   141  			if err != nil && err.Error() != testCase.err {
   142  				t.Error()
   143  			}
   144  			if myVal != testCase.expected {
   145  				t.Errorf("Expected %v, got %v", testCase.expected, myVal)
   146  			}
   147  		})
   148  	}
   149  }