Skip to content

Commit

Permalink
Merge pull request #23 from EscanBE/imp/add-more-util-methods
Browse files Browse the repository at this point in the history
imp: add more util methods
  • Loading branch information
VictorTrustyDev authored Oct 3, 2023
2 parents 37ff764 + c6f6c90 commit 77bf140
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 16 deletions.
7 changes: 4 additions & 3 deletions app/exit.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package app
import (
"fmt"
"github.com/EscanBE/go-lib/logging"
"github.com/EscanBE/go-lib/utils"
)

// AppExitFunction is an alias of function which receives params
Expand Down Expand Up @@ -36,20 +37,20 @@ func TryRecoverAndExecuteExitFunctionIfRecovered(logger logging.Logger, exitFunc
if logger != nil {
logger.Error("Panic caught", "error", err)
} else {
fmt.Printf("Panic caught, err: %v\n", err)
utils.PrintfStdErr("Panic caught, err: %v\n", err)
}
panic(err)
} else {
if logger != nil {
logger.Error("Recovered from panic, executing exit function")
} else {
fmt.Println("Recovered from panic, executing exit function")
utils.PrintfStdErr("Recovered from panic, executing exit function")
}
ExecuteExitFunction(exitFuncParams...)
if logger != nil {
logger.Error("Executed exit function, going to panic using recovered error")
} else {
fmt.Println("Executed exit function, going to panic using recovered error")
utils.PrintfStdErr("Executed exit function, going to panic using recovered error")
}
panic(err)
}
Expand Down
20 changes: 17 additions & 3 deletions utils/error_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ func ExitIfErr(err error, msg string) {
if err == nil {
return
}
fmt.Printf("Exit with error: %s\n", msg)
fmt.Println(err)
PrintlnStdErr("Exit with error:", msg, "\n", err)
osExit(1)
}

Expand All @@ -23,7 +22,7 @@ func PanicIfErr(err error, msg string) {
if err == nil {
return
}
fmt.Printf("Exit with error: %s\n", msg)
PrintlnStdErr("Exit with error:", msg)
panic(err)
}

Expand All @@ -34,3 +33,18 @@ func NilOrWrapIfError(err error, msg string) error {
}
return errors.Wrap(err, msg)
}

// PrintlnStdErr does println to StdErr
func PrintlnStdErr(a ...any) {
fmt.Fprintln(os.Stderr, a...)
}

// PrintfStdErr does printf to StdErr
func PrintfStdErr(format string, a ...any) {
fmt.Fprintf(os.Stderr, format, a...)
}

// PrintStdErr does print to StdErr
func PrintStdErr(a ...any) {
fmt.Fprint(os.Stderr, a...)
}
8 changes: 8 additions & 0 deletions utils/hash_util.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
package utils

import (
"crypto/sha256"
"encoding/hex"
"fmt"
"github.com/ethereum/go-ethereum/crypto"
)

// Keccak256Hash computes and returns Keccak-256 value of an input string
func Keccak256Hash(input string) string {
return hex.EncodeToString(crypto.Keccak256Hash([]byte(input)).Bytes())
}

// Sha256 returns SHA256 checksum string value of an input string
func Sha256(input string) string {
return fmt.Sprintf("%x", sha256.Sum256([]byte(input)))
}
29 changes: 20 additions & 9 deletions utils/hash_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,35 @@ package utils

import "testing"

func TestKeccak256Hash(t *testing.T) {
func Test256Hashing(t *testing.T) {
tests := []struct {
input string
want string
input string
wantKeccak256 string
wantSha256 string
}{
{
input: "abcd",
want: "48bed44d1bcd124a28c27f343a817e5f5243190d3c52bf347daf876de1dbbf77",
input: "abc",
wantKeccak256: "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45",
wantSha256: "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
},
{
input: "",
want: "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
input: "abcd",
wantKeccak256: "48bed44d1bcd124a28c27f343a817e5f5243190d3c52bf347daf876de1dbbf77",
wantSha256: "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589",
},
{
input: "",
wantKeccak256: "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
wantSha256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
if got := Keccak256Hash(tt.input); got != tt.want {
t.Errorf("Keccak256Hash() = %v, want %v", got, tt.want)
if got1 := Keccak256Hash(tt.input); got1 != tt.wantKeccak256 {
t.Errorf("Keccak256Hash() = %v, want %v", got1, tt.wantKeccak256)
}
if got2 := Sha256(tt.input); got2 != tt.wantSha256 {
t.Errorf("Sha256() = %v, want %v", got2, tt.wantSha256)
}
})
}
Expand Down
11 changes: 11 additions & 0 deletions utils/ibc_util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package utils

import (
"fmt"
"strings"
)

// BuildIbcDenom returns IBC denom based on algorithm provided by IBC docs: Sha256(path/baseDenom)
func BuildIbcDenom(path, baseDenom string) string {
return fmt.Sprintf("ibc/%s", strings.ToUpper(Sha256(fmt.Sprintf("%s/%s", path, baseDenom))))
}
33 changes: 33 additions & 0 deletions utils/ibc_util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package utils

import (
"fmt"
"testing"
)

func TestBuildIbcDenom(t *testing.T) {
//goland:noinspection SpellCheckingInspection
tests := []struct {
path string
baseDenom string
want string
}{
{
path: "transfer/channel-0",
baseDenom: "uosmo",
want: "ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518",
},
{
path: "transfer/channel-3",
baseDenom: "uatom",
want: "ibc/A4DB47A9D3CF9A068D454513891B526702455D3EF08FB9EB558C561F9DC2B701",
},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("%s/%s", tt.path, tt.baseDenom), func(t *testing.T) {
if got := BuildIbcDenom(tt.path, tt.baseDenom); got != tt.want {
t.Errorf("BuildIbcDenom() = %v, want %v", got, tt.want)
}
})
}
}
47 changes: 46 additions & 1 deletion utils/time_util.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package utils

import "time"
import (
"fmt"
"math"
"time"
)

// NowS returns the current epoch seconds
func NowS() int64 {
Expand All @@ -21,3 +25,44 @@ func DiffS(previous int64) int64 {
func DiffMs(previous int64) int64 {
return NowMs() - previous
}

// IsTimeNear returns true when t1 and t2, are the same time (maximum diff is offset), regardless timezone.
// Eg: 03:00:00 UTC+0000 is equals to 10:00:00 UTC+0700
func IsTimeNear(t1, t2 time.Time, offsetDuration time.Duration) bool {
t1 = t1.UTC()
t2 = t2.UTC()

diff := t1.Sub(t2)
return offsetDuration.Abs() >= diff.Abs()

Check failure on line 36 in utils/time_util.go

View workflow job for this annotation

GitHub Actions / build

offsetDuration.Abs undefined (type time.Duration has no field or method Abs)

Check failure on line 36 in utils/time_util.go

View workflow job for this annotation

GitHub Actions / build

diff.Abs undefined (type time.Duration has no field or method Abs)

Check failure on line 36 in utils/time_util.go

View workflow job for this annotation

GitHub Actions / build

offsetDuration.Abs undefined (type time.Duration has no field or method Abs)

Check failure on line 36 in utils/time_util.go

View workflow job for this annotation

GitHub Actions / build

diff.Abs undefined (type time.Duration has no field or method Abs)
}

// GetLocationFromUtcTimezone returns location corresponding to specified UTC-based timezone
func GetLocationFromUtcTimezone(utcTimezone int) *time.Location {
ensureUtcTimezone(utcTimezone)
return time.FixedZone(GetUtcName(utcTimezone), utcTimezone*60*60)
}

// GetUtcName returns naming convention of UTC timezone. Eg: 7 => UTC+0700
func GetUtcName(utcTimezone int) string {
ensureUtcTimezone(utcTimezone)
return fmt.Sprintf("UTC%s", getTimezoneSuffix(utcTimezone))
}

// ensureUtcTimezone will panic if timezone is out of range from -12 to 14
func ensureUtcTimezone(utcTimezone int) {
if utcTimezone < -12 || utcTimezone > 14 {
panic(fmt.Errorf("UTC timezone must be in range -12 to 14"))
}
}

func getTimezoneSuffix(timezone int) string {
if timezone > 9 {
return fmt.Sprintf("+%d00", timezone)
} else if timezone >= 0 {
return fmt.Sprintf("+0%d00", timezone)
} else if timezone >= -9 {
return fmt.Sprintf("-0%d00", int(math.Abs(float64(timezone))))
} else {
return fmt.Sprintf("%d00", timezone)
}
}
131 changes: 131 additions & 0 deletions utils/time_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package utils

import (
"fmt"
"github.com/EscanBE/go-lib/test_utils"
"testing"
"time"
)
Expand Down Expand Up @@ -45,3 +46,133 @@ func TestNowS(t *testing.T) {
t.Errorf("NowS() = %v, expected %v +-1!", nowS1, nowS2)
}
}

func TestGetLocationFromUtcTimezone(t *testing.T) {
t.Run("get location for UTC from -12 to 14", func(_ *testing.T) {
for timezone := -12; timezone <= 14; timezone++ {
loc := GetLocationFromUtcTimezone(timezone)
nowUTC := time.Date(2023, 9, 16, 0, 0, 0, 0, time.UTC)
nowWithCustomLoc := nowUTC.In(loc)
diffHours := (nowWithCustomLoc.Hour() + 24*nowWithCustomLoc.Day()) - (nowUTC.Hour() + 24*nowUTC.Day())
if diffHours != timezone {
t.Errorf("Expected diff timezone %d but got %d", timezone, diffHours)
}
}
})

for timezone := -100; timezone <= 100; timezone++ {
wantPanic := timezone < -12 || timezone > 14
t.Run(fmt.Sprintf("timezone %d %s", timezone, func() string {
if wantPanic {
return "should panic"
} else {
return "should not panic"
}
}()), func(_ *testing.T) {
defer test_utils.DeferWantPanicDepends(t, wantPanic)
_ = GetLocationFromUtcTimezone(timezone)
})
}
}

func TestGetUtcName(t *testing.T) {
tests := []struct {
utcTimezone int
want string
}{
{
utcTimezone: -12,
want: "UTC-1200",
},
{
utcTimezone: -1,
want: "UTC-0100",
},
{
utcTimezone: 0,
want: "UTC+0000",
},
{
utcTimezone: 1,
want: "UTC+0100",
},
{
utcTimezone: 14,
want: "UTC+1400",
},
}
for _, tt := range tests {
t.Run(tt.want, func(t *testing.T) {
if got := GetUtcName(tt.utcTimezone); got != tt.want {
t.Errorf("GetUtcName() = %v, want %v", got, tt.want)
}
})
}

for timezone := -100; timezone <= 100; timezone++ {
wantPanic := timezone < -12 || timezone > 14
t.Run(fmt.Sprintf("timezone %d %s", timezone, func() string {
if wantPanic {
return "should panic"
} else {
return "should not panic"
}
}()), func(_ *testing.T) {
defer test_utils.DeferWantPanicDepends(t, wantPanic)
_ = GetUtcName(timezone)
})
}
}

func TestIsTimeNear(t *testing.T) {
nowUTC := time.Now().UTC()
nowUS := nowUTC.In(GetLocationFromUtcTimezone(-7))

makeTimeUTC := func(shiftSeconds int) time.Time {
return nowUTC.Add(time.Duration(shiftSeconds) * time.Second)
}

tests := []struct {
shiftSeconds int
timeFrame time.Time
offsetDuration time.Duration
want bool
}{
{
shiftSeconds: 10,
offsetDuration: 10 * time.Second,
want: true,
},
{
shiftSeconds: 9,
offsetDuration: 10 * time.Second,
want: true,
},
{
shiftSeconds: 11,
offsetDuration: 10 * time.Second,
want: false,
},
}
for i, tt := range tests {
timeFrameUTC := makeTimeUTC(tt.shiftSeconds)

t.Run(fmt.Sprintf("[%d] UTC %v vs %v", i, nowUTC, timeFrameUTC), func(t *testing.T) {
if got := IsTimeNear(nowUTC, timeFrameUTC, tt.offsetDuration); got != tt.want {
t.Errorf("IsMatchTimeFrame() = %v, want %v", got, tt.want)
}
})

t.Run(fmt.Sprintf("[%d] AnyZone %v vs %v", i, nowUS, timeFrameUTC), func(t *testing.T) {
if got := IsTimeNear(nowUS, timeFrameUTC, tt.offsetDuration); got != tt.want {
t.Errorf("IsMatchTimeFrame() = %v, want %v", got, tt.want)
}
})

t.Run(fmt.Sprintf("[%d] Change position", i), func(t *testing.T) {
if got := IsTimeNear(timeFrameUTC, nowUS, tt.offsetDuration); got != tt.want {
t.Errorf("IsMatchTimeFrame() = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit 77bf140

Please sign in to comment.