mirror of https://github.com/XTLS/Xray-core
Browse Source
Occasional error is observed when we execute long test Print time and memory for better troubleshooting in the future Co-authored-by: Jebbs <qjebbs@gmail.com>pull/854/head
yuhan6665
3 years ago
3 changed files with 179 additions and 1 deletions
@ -0,0 +1,100 @@ |
|||||||
|
package units |
||||||
|
|
||||||
|
import ( |
||||||
|
"errors" |
||||||
|
"strconv" |
||||||
|
"strings" |
||||||
|
"unicode" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
errInvalidSize = errors.New("invalid size") |
||||||
|
errInvalidUnit = errors.New("invalid or unsupported unit") |
||||||
|
) |
||||||
|
|
||||||
|
// ByteSize is the size of bytes
|
||||||
|
type ByteSize uint64 |
||||||
|
|
||||||
|
const ( |
||||||
|
_ = iota |
||||||
|
// KB = 1KB
|
||||||
|
KB ByteSize = 1 << (10 * iota) |
||||||
|
// MB = 1MB
|
||||||
|
MB |
||||||
|
// GB = 1GB
|
||||||
|
GB |
||||||
|
// TB = 1TB
|
||||||
|
TB |
||||||
|
// PB = 1PB
|
||||||
|
PB |
||||||
|
// EB = 1EB
|
||||||
|
EB |
||||||
|
) |
||||||
|
|
||||||
|
func (b ByteSize) String() string { |
||||||
|
unit := "" |
||||||
|
value := float64(0) |
||||||
|
switch { |
||||||
|
case b == 0: |
||||||
|
return "0" |
||||||
|
case b < KB: |
||||||
|
unit = "B" |
||||||
|
value = float64(b) |
||||||
|
case b < MB: |
||||||
|
unit = "KB" |
||||||
|
value = float64(b) / float64(KB) |
||||||
|
case b < GB: |
||||||
|
unit = "MB" |
||||||
|
value = float64(b) / float64(MB) |
||||||
|
case b < TB: |
||||||
|
unit = "GB" |
||||||
|
value = float64(b) / float64(GB) |
||||||
|
case b < PB: |
||||||
|
unit = "TB" |
||||||
|
value = float64(b) / float64(TB) |
||||||
|
case b < EB: |
||||||
|
unit = "PB" |
||||||
|
value = float64(b) / float64(PB) |
||||||
|
default: |
||||||
|
unit = "EB" |
||||||
|
value = float64(b) / float64(EB) |
||||||
|
} |
||||||
|
result := strconv.FormatFloat(value, 'f', 2, 64) |
||||||
|
result = strings.TrimSuffix(result, ".0") |
||||||
|
return result + unit |
||||||
|
} |
||||||
|
|
||||||
|
// Parse parses ByteSize from string
|
||||||
|
func (b *ByteSize) Parse(s string) error { |
||||||
|
s = strings.TrimSpace(s) |
||||||
|
s = strings.ToUpper(s) |
||||||
|
i := strings.IndexFunc(s, unicode.IsLetter) |
||||||
|
if i == -1 { |
||||||
|
return errInvalidUnit |
||||||
|
} |
||||||
|
|
||||||
|
bytesString, multiple := s[:i], s[i:] |
||||||
|
bytes, err := strconv.ParseFloat(bytesString, 64) |
||||||
|
if err != nil || bytes <= 0 { |
||||||
|
return errInvalidSize |
||||||
|
} |
||||||
|
switch multiple { |
||||||
|
case "B": |
||||||
|
*b = ByteSize(bytes) |
||||||
|
case "K", "KB", "KIB": |
||||||
|
*b = ByteSize(bytes * float64(KB)) |
||||||
|
case "M", "MB", "MIB": |
||||||
|
*b = ByteSize(bytes * float64(MB)) |
||||||
|
case "G", "GB", "GIB": |
||||||
|
*b = ByteSize(bytes * float64(GB)) |
||||||
|
case "T", "TB", "TIB": |
||||||
|
*b = ByteSize(bytes * float64(TB)) |
||||||
|
case "P", "PB", "PIB": |
||||||
|
*b = ByteSize(bytes * float64(PB)) |
||||||
|
case "E", "EB", "EIB": |
||||||
|
*b = ByteSize(bytes * float64(EB)) |
||||||
|
default: |
||||||
|
return errInvalidUnit |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
@ -0,0 +1,66 @@ |
|||||||
|
package units_test |
||||||
|
|
||||||
|
import ( |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/units" |
||||||
|
) |
||||||
|
|
||||||
|
func TestByteSizes(t *testing.T) { |
||||||
|
size := units.ByteSize(0) |
||||||
|
assertSizeString(t, size, "0") |
||||||
|
size++ |
||||||
|
assertSizeValue(t, |
||||||
|
assertSizeString(t, size, "1.00B"), |
||||||
|
size, |
||||||
|
) |
||||||
|
size <<= 10 |
||||||
|
assertSizeValue(t, |
||||||
|
assertSizeString(t, size, "1.00KB"), |
||||||
|
size, |
||||||
|
) |
||||||
|
size <<= 10 |
||||||
|
assertSizeValue(t, |
||||||
|
assertSizeString(t, size, "1.00MB"), |
||||||
|
size, |
||||||
|
) |
||||||
|
size <<= 10 |
||||||
|
assertSizeValue(t, |
||||||
|
assertSizeString(t, size, "1.00GB"), |
||||||
|
size, |
||||||
|
) |
||||||
|
size <<= 10 |
||||||
|
assertSizeValue(t, |
||||||
|
assertSizeString(t, size, "1.00TB"), |
||||||
|
size, |
||||||
|
) |
||||||
|
size <<= 10 |
||||||
|
assertSizeValue(t, |
||||||
|
assertSizeString(t, size, "1.00PB"), |
||||||
|
size, |
||||||
|
) |
||||||
|
size <<= 10 |
||||||
|
assertSizeValue(t, |
||||||
|
assertSizeString(t, size, "1.00EB"), |
||||||
|
size, |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
func assertSizeValue(t *testing.T, size string, expected units.ByteSize) { |
||||||
|
actual := units.ByteSize(0) |
||||||
|
err := actual.Parse(size) |
||||||
|
if err != nil { |
||||||
|
t.Error(err) |
||||||
|
} |
||||||
|
if actual != expected { |
||||||
|
t.Errorf("expect %s, but got %s", expected, actual) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func assertSizeString(t *testing.T, size units.ByteSize, expected string) string { |
||||||
|
actual := size.String() |
||||||
|
if actual != expected { |
||||||
|
t.Errorf("expect %s, but got %s", expected, actual) |
||||||
|
} |
||||||
|
return expected |
||||||
|
} |
Loading…
Reference in new issue