From 2b99b265385547b41a2aa0ab98874b65f9ce40c4 Mon Sep 17 00:00:00 2001 From: Reza Date: Thu, 17 Feb 2022 12:38:46 +0100 Subject: [PATCH] http call --- TODO.md | 1 + cmd/evo/ng/generator.go | 8 +- cmd/evo/ng/skeleton.go | 86 ++++-- config.go | 31 +- go.mod | 82 +----- http/context.fn.go | 574 ++++++++++++++++++++++++++++++++++++ http/context.go | 336 +++++++++++++++++++++ http/go.mod | 3 + lib/generic/generic_test.go | 123 ++++---- lib/intl/date_test.go | 35 +-- 10 files changed, 1085 insertions(+), 194 deletions(-) create mode 100644 http/context.fn.go create mode 100644 http/context.go create mode 100644 http/go.mod diff --git a/TODO.md b/TODO.md index ba4975a..f23ee64 100644 --- a/TODO.md +++ b/TODO.md @@ -1,2 +1,3 @@ - Event: onBeforeWrite +- Cache Middleware - Redis: Universal client diff --git a/cmd/evo/ng/generator.go b/cmd/evo/ng/generator.go index ab6f2cf..722c16b 100644 --- a/cmd/evo/ng/generator.go +++ b/cmd/evo/ng/generator.go @@ -37,10 +37,10 @@ var ContextInterface = Function{ } func Start() { - err := os.Remove("./go.mod") - if err != nil { - evo.Panic(err) + if !file.IsFileExist("./app.json") { + panic("missing app.json") } + os.Remove("./go.mod") skeleton = GetSkeleton("./app.json") main.Events.Set("OverRide", generator.NewFunc(nil, generator.NewFuncSignature("OverRide"))) @@ -148,6 +148,8 @@ func run(cmd string, args ...string) { fmt.Println(cmd, strings.Join(args, " ")) c := exec.Command(cmd, args...) c.Dir = file.WorkingDir() + c.Stdout = os.Stdout + c.Stderr = os.Stderr err := c.Run() if err != nil { evo.Panic(err) diff --git a/cmd/evo/ng/skeleton.go b/cmd/evo/ng/skeleton.go index 4a67b8c..f498b9e 100644 --- a/cmd/evo/ng/skeleton.go +++ b/cmd/evo/ng/skeleton.go @@ -67,9 +67,6 @@ func (s *Skeleton) GenContext() { context, ) - var commonStatements = append(statements, generator.NewReturnStatement("callback.(func(*Context) error)(c)")) - var wsStatements = append(statements, generator.NewReturnStatement("callback.(func(*Context,*websocket.Conn) error)(c,ws)")) - root = root.AddStatements(generator.NewNewline(), generator.NewCommentf("New create new type of struct"), generator.NewFunc( @@ -77,35 +74,64 @@ func (s *Skeleton) GenContext() { generator.NewFuncSignature("New").AddReturnTypes("evo.ContextInterface"), generator.NewReturnStatement("&Context{}"), )) - for _, method := range []string{"Get", "Post", "All", "Put", "Patch", "Options", "Connect", "Head", "Delete", "Use", "WebSocket"} { - if method == "WebSocket" { - root = root.AddStatements( - generator.NewNewline(), - generator.NewCommentf("%s Wrap context http %s requests. callback accepts func(*http.Context,*websocket.Conn)", method, method), - generator.NewFunc( - generator.NewFuncReceiver("c", "*Context"), - generator.NewFuncSignature(method).AddParameters( - generator.NewFuncParameter("request ", "*evo.Context"), - generator.NewFuncParameter("callback", "interface{}"), - generator.NewFuncParameter("ws", "*websocket.Conn"), - ).AddReturnTypes("err error"), - wsStatements..., - ), - generator.NewNewline(), - generator.NewCommentf("%s Matches http %s requests. callback accepts func(*http.Context)", method, method), - generator.NewFunc( - nil, - generator.NewFuncSignature(method).AddParameters( - generator.NewFuncParameter("url ", "string"), - generator.NewFuncParameter("callback", "func(*Context,*websocket.Conn) error"), - generator.NewFuncParameter("params...", "interface{}"), + root = root.AddStatements( + generator.NewNewline(), + generator.NewCommentf("%s Wrap context ws/wss %s requests. callback accepts func(*http.Context,*websocket.Conn)", "WebSocket", "WebSocket"), + generator.NewFunc( + generator.NewFuncReceiver("c", "*Context"), + generator.NewFuncSignature("WebSocket").AddParameters( + generator.NewFuncParameter("request ", "*evo.Context"), + generator.NewFuncParameter("callback", "interface{}"), + generator.NewFuncParameter("ws", "*websocket.Conn"), + ).AddReturnTypes("err error"), + append(statements, generator.NewReturnStatement("callback.(func(*Context,*websocket.Conn) error)(c,ws)"))..., + ), + + generator.NewNewline(), + generator.NewCommentf("%s Matches http %s requests. callback accepts func(*http.Context)", "WebSocket", "WebSocket"), + generator.NewFunc( + nil, + generator.NewFuncSignature("WebSocket").AddParameters( + generator.NewFuncParameter("url ", "string"), + generator.NewFuncParameter("callback", "func(*Context,*websocket.Conn) error"), + generator.NewFuncParameter("params...", "interface{}"), + ), + generator.NewRawStatement("evo."+"WebSocket"+("(url,callback,params...)")), + ), + ) + var commonStatements = append(statements, generator.NewReturnStatement("callback.(func(*Context) error)(c)")) + for _, method := range []string{"Get", "Post", "All", "Put", "Patch", "Options", "Connect", "Head", "Delete", "Use"} { + /* if method == "WebSocket" { + var wsStatements = append(statements, generator.NewReturnStatement("callback.(func(*Context,*websocket.Conn) error)(c,ws)")) + root = root.AddStatements( + generator.NewNewline(), + generator.NewCommentf("%s Wrap context ws/wss %s requests. callback accepts func(*http.Context,*websocket.Conn)", method, method), + generator.NewFunc( + generator.NewFuncReceiver("c", "*Context"), + generator.NewFuncSignature(method).AddParameters( + generator.NewFuncParameter("request ", "*evo.Context"), + generator.NewFuncParameter("callback", "interface{}"), + generator.NewFuncParameter("ws", "*websocket.Conn"), + ).AddReturnTypes("err error"), + wsStatements..., ), - generator.NewRawStatement("evo."+method+("(url,callback,params...)")), - ), - ) - continue - } + + generator.NewNewline(), + generator.NewCommentf("%s Matches http %s requests. callback accepts func(*http.Context)", method, method), + generator.NewFunc( + nil, + generator.NewFuncSignature(method).AddParameters( + generator.NewFuncParameter("url ", "string"), + generator.NewFuncParameter("callback", "func(*Context,*websocket.Conn) error"), + generator.NewFuncParameter("params...", "interface{}"), + ), + generator.NewRawStatement("evo."+method+("(url,callback,params...)")), + ), + ) + continue + }*/ + root = root.AddStatements( generator.NewNewline(), generator.NewCommentf("%s Wrap context http %s requests. callback accepts func(*http.Context)", method, method), diff --git a/config.go b/config.go index a6c896a..94cdf4c 100644 --- a/config.go +++ b/config.go @@ -3,7 +3,6 @@ package evo import ( "context" "fmt" - "github.com/coreos/etcd/clientv3" "github.com/creasty/defaults" "github.com/getevo/evo-ng/lib/args" consul_api "github.com/hashicorp/consul/api" @@ -11,12 +10,10 @@ import ( "github.com/heetch/confita" "github.com/heetch/confita/backend/consul" "github.com/heetch/confita/backend/env" - "github.com/heetch/confita/backend/etcd" "github.com/heetch/confita/backend/file" "github.com/heetch/confita/backend/flags" "github.com/heetch/confita/backend/vault" "reflect" - "strings" "time" ) @@ -145,22 +142,22 @@ func ParseConfig(params ...interface{}) error { ) } else if args.Get("-etcd") != "" { fmt.Println("Load config from etcd") - client, err := clientv3.New(clientv3.Config{ - Username: args.Get("-etcd-username"), - Password: args.Get("-etcd-password"), - Endpoints: strings.Split(args.Get("-etcd"), ","), - }) - if err == nil { - return err - } + /* client, err := clientv3.New(clientv3.Config{ + Username: args.Get("-etcd-username"), + Password: args.Get("-etcd-password"), + Endpoints: strings.Split(args.Get("-etcd"), ","), + }) + if err == nil { + return err + } - loader = confita.NewLoader( - etcd.NewBackend(client, etcd.WithPrefix("-etcd-prefix")), - ) + loader = confita.NewLoader( + etcd.NewBackend(client, etcd.WithPrefix("-etcd-prefix")), + ) - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - loader.Load(ctx, params[out]) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + loader.Load(ctx, params[out])*/ } else if args.Get("-vault") != "" { var cfg = vault_api.DefaultConfig() diff --git a/go.mod b/go.mod index c2dd7c4..4c36f83 100644 --- a/go.mod +++ b/go.mod @@ -1,91 +1,41 @@ module github.com/getevo/evo-ng -go 1.17 +go 1.16 require ( github.com/CloudyKit/jet/v6 v6.1.0 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de github.com/awoodbeck/strftime v0.0.0-20180221155908-016cde65fcde github.com/creasty/defaults v1.5.2 - github.com/fasthttp/websocket v1.4.4 + github.com/fasthttp/websocket v1.4.6 github.com/fatih/color v1.13.0 - github.com/getevo/evo v1.0.6 + github.com/getevo/evo v1.0.9 github.com/getevo/monday v1.0.2 github.com/go-git/go-git/v5 v5.4.2 github.com/go-redis/redis/v8 v8.11.4 github.com/go-redis/redis_rate/v9 v9.1.2 - github.com/gofiber/fiber/v2 v2.24.0 + github.com/gofiber/fiber/v2 v2.27.0 github.com/hart87/GoFlake v0.0.0-20210517135841-c95a47da3eb9 + github.com/hart87/goflake v0.0.0-20210517135841-c95a47da3eb9 // indirect + github.com/hashicorp/consul/api v1.12.0 + github.com/hashicorp/vault/api v1.3.1 + github.com/heetch/confita v0.10.0 github.com/kelindar/binary v1.0.17 github.com/mattn/go-zglob v0.0.3 - github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/moznion/gowrtr v1.5.1 github.com/otiai10/copy v1.7.0 github.com/pkg/errors v0.9.1 - github.com/tidwall/gjson v1.12.1 + github.com/stretchr/testify v1.7.0 + github.com/tidwall/gjson v1.14.0 github.com/tidwall/sjson v1.2.4 - github.com/valyala/fasthttp v1.31.0 - golang.org/x/mod v0.3.0 + github.com/valyala/fasthttp v1.33.0 + golang.org/x/mod v0.5.1 golang.org/x/text v0.3.7 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b - gorm.io/driver/mysql v1.0.4 + gorm.io/driver/mysql v1.2.3 gorm.io/driver/postgres v1.2.3 - gorm.io/driver/sqlite v1.1.4 - gorm.io/driver/sqlserver v1.0.6 - gorm.io/gorm v1.22.3 + gorm.io/driver/sqlite v1.2.6 + gorm.io/driver/sqlserver v1.2.1 + gorm.io/gorm v1.22.5 gorm.io/plugin/dbresolver v1.1.0 ) - -require ( - github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect - github.com/CloudyKit/jet v2.1.2+incompatible // indirect - github.com/Microsoft/go-winio v0.4.16 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect - github.com/acomagu/bufpipe v1.0.3 // indirect - github.com/andybalholm/brotli v1.0.2 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc // indirect - github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/emirpasic/gods v1.12.0 // indirect - github.com/go-git/gcfg v1.5.0 // indirect - github.com/go-git/go-billy/v5 v5.3.1 // indirect - github.com/go-sql-driver/mysql v1.5.0 // indirect - github.com/gofiber/websocket/v2 v2.0.15 // indirect - github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect - github.com/hart87/goflake v0.0.0-20210517135841-c95a47da3eb9 // indirect - github.com/heetch/confita v0.10.0 - github.com/imdario/mergo v0.3.12 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.10.1 // indirect - github.com/jackc/pgio v1.0.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.2.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.9.0 // indirect - github.com/jackc/pgx/v4 v4.14.0 // indirect - github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/jinzhu/copier v0.3.4 // indirect - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.2 // indirect - github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect - github.com/klauspost/compress v1.13.4 // indirect - github.com/mattn/go-colorable v0.1.9 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/mattn/go-sqlite3 v1.14.5 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/savsgio/gotils v0.0.0-20211223103454-d0aaa54c5899 // indirect - github.com/sergi/go-diff v1.1.0 // indirect - github.com/stretchr/testify v1.7.0 - github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - github.com/wzshiming/ctc v1.2.3 // indirect - github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae // indirect - github.com/xanzy/ssh-agent v0.3.0 // indirect - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect - golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect - golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect - gopkg.in/warnings.v0 v0.1.2 // indirect -) diff --git a/http/context.fn.go b/http/context.fn.go new file mode 100644 index 0000000..0fc4a46 --- /dev/null +++ b/http/context.fn.go @@ -0,0 +1,574 @@ +package http + +//DO NOT EDIT THIS FILE + +import ( + "bytes" + "encoding/json" + "fmt" + "github.com/CloudyKit/jet/v6" + "github.com/getevo/evo-ng/lib/generic" + "github.com/getevo/evo-ng/lib/shared" + "github.com/getevo/evo/lib/log" + "github.com/gofiber/fiber/v2" + "github.com/valyala/fasthttp" + "io" + "mime/multipart" + "net/url" + "reflect" + "strings" + "time" +) + +// Cookie container wrapper struct +type Cookie fiber.Cookie + +// Response represent formal form of response defined by evo +type Response struct { + Success bool `json:"success"` + Message string `json:"message,omitempty"` + Error []error `json:"error,omitempty"` + Data interface{} `json:"data,omitempty"` +} + +// URL describe url +type URL struct { + Query url.Values + Host string + Scheme string + Path string + Raw string +} + +// Cookie is used for getting a cookie value by key. +// value accepts string,int,int64,int8,int32,int16,uint,uint64,uint8,uint16,uint32,float32,float64,complex64,complex128 as value of cookie +// value accepts struct and turn it into json string as value of cookie +// value accepts time.Time,time.Duration as expiration time of cookie +// value accepts fiber.Cookie,request.Cookie as custom cookie settings +// Make copies or use the Immutable setting to use the value outside the Handler. +func (ctx *Context) Cookie(key string, value ...interface{}) generic.Value { + if len(value) > 0 { + var cookie = fiber.Cookie{} + for _, item := range value { + switch val := item.(type) { + case Cookie: + cookie = fiber.Cookie(val) + case *Cookie: + cookie = fiber.Cookie(*val) + case fiber.Cookie: + cookie = val + case *fiber.Cookie: + cookie = *val + case time.Duration: + cookie.Expires = time.Now().Add(val) + case time.Time: + cookie.Expires = val + case string: + cookie.Value = val + case int, int64, int8, int32, int16, uint, uint64, uint8, uint16, uint32, float32, float64, complex64, complex128: + cookie.Value = fmt.Sprint(val) + default: + var b, err = json.Marshal(val) + if err != nil { + log.Error(err) + } else { + cookie.Value = string(b) + } + + } + } + cookie.Name = key + ctx.fiber.Cookie(&cookie) + } + return generic.Parse(ctx.fiber.Cookies(key)) +} + +// Header set/get the HTTP request header specified by field and value. +// Field names are case-insensitive +// value will be join by semicolon in case of more than one +// Returned value is only valid within the handler. Do not store any references. +// Make copies or use the Immutable setting instead. +func (c *Context) Header(key string, value ...string) string { + if len(value) > 0 { + c.FastHTTP().Response.Header.Set(key, strings.Join(value, ";")) + } + return c.fiber.Get(key) +} + +// Status sets the HTTP status for the response. +// This method is chainable. +// @receiver c +// @param status +// @return *Context +func (c *Context) Status(status int) *Context { + c.FastHTTP().Response.SetStatusCode(status) + return c +} + +// Query returns the query string parameter in the url. +// Defaults to empty string "" if the query doesn't exist. +// If a default value is given, it will return that value if the query doesn't exist. +// Returned value is only valid within the handler. Do not store any references. +// Make copies or use the Immutable setting to use the value outside the Handler. +// @receiver ctx +// @param key +// @param defaultValue +// @return string +func (ctx *Context) Query(key string, defaultValue ...string) string { + return ctx.fiber.Query(key, defaultValue...) +} + +// Protocol contains the request protocol string: http or https for TLS requests. +// @receiver ctx +// @return string +func (ctx *Context) Protocol() string { + return ctx.fiber.Protocol() +} + +// Hostname contains the hostname derived from the Host HTTP header. +// Returned value is only valid within the handler. Do not store any references. +// Make copies or use the Immutable setting instead. +// @receiver c +// @return string +func (c *Context) Hostname() string { + return c.fiber.Hostname() +} + +// IPs returns an string slice of IP addresses specified in the X-Forwarded-For request header. +// @receiver c +// @return ips +func (c *Context) IPs() (ips []string) { + return c.fiber.IPs() +} + +// Is returns the matching content type, +// if the incoming request's Content-Type HTTP header field matches the MIME type specified by the type parameter +// @receiver c +// @param extension +// @return bool +func (c *Context) Is(extension string) bool { + return c.fiber.Is(extension) +} + +// Locals makes it possible to pass interface{} values under string keys scoped to the request +// and therefore available to all following routes that match the request. +// @receiver c +// @param key +// @param value +// @return generic.Value +func (c *Context) Locals(key string, value ...interface{}) generic.Value { + return generic.Parse(c.fiber.Locals(key, value...)) +} + +// Location sets the response Location HTTP header to the specified path parameter. +// @receiver c +// @param path +func (c *Context) Location(path string) { + c.fiber.Location(path) +} + +// Redirect to the URL derived from the specified path, with specified status. +// If status is not specified, status defaults to 302 Found. +// @receiver c +// @param location +// @param status +func (c *Context) Redirect(location string, status ...int) { + c.fiber.Redirect(location, status...) +} + +// Method contains a string corresponding to the HTTP method of the request: GET, POST, PUT and so on. +// @receiver c +// @param override +// @return string +func (c *Context) Method(override ...string) string { + return c.fiber.Method() +} + +// Subdomains returns a string slice of subdomains in the domain name of the request. +// The subdomain offset, which defaults to 2, is used for determining the beginning of the subdomain segments. +// @receiver c +// @param offset +// @return []string +func (c *Context) Subdomains(offset ...int) []string { + o := 2 + if len(offset) > 0 { + o = offset[0] + } + subdomains := strings.Split(c.Hostname(), ".") + l := len(subdomains) - o + // Check index to avoid slice bounds out of range panic + if l < 0 { + l = len(subdomains) + } + subdomains = subdomains[:l] + return subdomains +} + +// String returns unique string representation of the ctx. +// +// The returned value may be useful for logging. +func (c *Context) String() string { + return c.fiber.String() +} + +// Vary adds the given header field to the Vary response header. +// This will append the header, if not already listed, otherwise leaves it listed in the current location. +func (c *Context) Vary(fields ...string) { + c.fiber.Vary(fields...) +} + +// Accepts checks if the specified extensions or content types are acceptable. +func (c *Context) Accepts(offers ...string) string { + return c.fiber.Accepts(offers...) +} + +// AcceptsCharsets checks if the specified charset is acceptable. +func (c *Context) AcceptsCharsets(offers ...string) string { + return c.fiber.AcceptsCharsets(offers...) +} + +// AcceptsEncodings checks if the specified encoding is acceptable. +func (c *Context) AcceptsEncodings(offers ...string) string { + return c.fiber.AcceptsEncodings(offers...) +} + +// AcceptsLanguages checks if the specified language is acceptable. +func (c *Context) AcceptsLanguages(offers ...string) string { + return c.fiber.AcceptsLanguages(offers...) +} + +// ClearCookie expires a specific cookie by key on the client side. +// If no key is provided it expires all cookies that came with the request. +func (c *Context) ClearCookie(key ...string) { + c.fiber.ClearCookie(key...) +} + +// Download transfers the file from path as an attachment. +// Typically, browsers will prompt the user for download. +// By default, the Content-Disposition header filename= parameter is the filepath (this typically appears in the browser dialog). +// Override this default with the filename parameter. +func (c *Context) Download(file string, filename ...string) error { + return c.fiber.Download(file, filename...) +} + +// Fresh check if this request is fresh and is not beign cached +// @receiver c +// @return bool +func (c *Context) Fresh() bool { + return c.fiber.Fresh() +} + +// Request return the *fasthttp.Request object +// This allows you to use all fasthttp request methods +// https://godoc.org/github.com/valyala/fasthttp#Request +// @receiver c +// @return *fasthttp.Request +func (c *Context) Request() *fasthttp.Request { + return c.fiber.Request() +} + +// Response return the *fasthttp.Response object +// @receiver c +// @return *fasthttp.Response +// This allows you to use all fasthttp response methods +// https://godoc.org/github.com/valyala/fasthttp#Response +func (c *Context) Response() *fasthttp.Response { + return c.fiber.Response() +} + +// Format performs content-negotiation on the Accept HTTP header. +// @receiver c +// @param body +// @return error +// It uses Accepts to select a proper format. +// If the header is not specified or there is no proper format, text/plain is used. +func (c *Context) Format(body interface{}) error { + return c.fiber.Format(body) +} + +// FormFile returns the first file by key from a MultipartForm. +// @receiver c +// @param key +// @return *multipart.FileHeader +// @return error +func (c *Context) FormFile(key string) (*multipart.FileHeader, error) { + return c.fiber.FormFile(key) +} + +// MultipartForm parse form entries from binary. +// This returns a map[string][]string, so given a key the value will be a string slice. +// @receiver c +// @return *multipart.Form +// @return error +func (c *Context) MultipartForm() (*multipart.Form, error) { + return c.FastHTTP().MultipartForm() +} + +// FastHTTP returns *fasthttp.RequestCtx that carries a deadline +// a cancellation signal, and other values across API boundaries. +// @receiver c +// @return *fasthttp.RequestCtx +func (c *Context) FastHTTP() *fasthttp.RequestCtx { + return c.fiber.Context() +} + +// XHR returns a Boolean property, that is true, if the request's X-Requested-With header field is XMLHttpRequest, +// indicating that the request was issued by a client library (such as jQuery). +// @receiver c +// @return bool +func (c *Context) XHR() bool { + return c.fiber.XHR() +} + +// Route returns the matched Route struct. +// @receiver c +// @return *fiber.Route +func (c *Context) Route() *fiber.Route { + return c.fiber.Route() +} + +// SaveFile saves any multipart file to disk. +// @receiver c +// @param fileheader +// @param path +// @return error +func (c *Context) SaveFile(fileheader *multipart.FileHeader, path string) error { + return fasthttp.SaveMultipartFile(fileheader, path) +} + +// Secure returns a boolean property, that is true, if a TLS connection is established. +// @receiver c +// @return bool +func (c *Context) Secure() bool { + return c.FastHTTP().IsTLS() +} + +// WriteBytes sets the HTTP response body without copying it. +// From this point onward the body argument must not be changed. +// @receiver c +// @param body +func (c *Context) WriteBytes(body []byte) { + // Write response body + c.FastHTTP().Response.SetBodyRaw(body) +} + +// WriteString sets the HTTP response body without copying it. +// From this point onward the body argument must not be changed. +// @receiver c +// @param body +func (c *Context) WriteString(body string) { + // Write response body + c.fiber.Send([]byte(body)) +} + +// SendFile transfers the file from the given path. +// The file is not compressed by default, enable this by passing a 'true' argument +// Sets the Content-Type response HTTP header field based on the filenames extension. +// @receiver c +// @param file +// @param compress +// @return error +func (c *Context) SendFile(file string, compress ...bool) error { + return c.fiber.SendFile(file, compress...) +} + +// SendStatus sets the HTTP status code and if the response body is empty, +// it sets the correct status message in the body. +// @receiver c +// @param status +// @return error +func (c *Context) SendStatus(status int) error { + return c.fiber.SendStatus(status) +} + +// SendStream sets response body stream and optional body size. +// @receiver c +// @param stream +// @param size +// @return error +func (c *Context) SendStream(stream io.Reader, size ...int) error { + return c.fiber.SendStream(stream, size...) +} + +// WriteJSON sets the HTTP response body without copying it. +// From this point onward the body argument must not be changed. +// @receiver c +// @param body +func (c *Context) WriteJSON(body interface{}) { + // Write response body + var b, err = json.Marshal(body) + if err != nil { + c.fiber.Status(400) + c.fiber.WriteString(err.Error()) + } else { + c.fiber.Write(b) + } +} + +// WriteResponse writes json Response object to http response +// @receiver c +// @param args +func (c *Context) WriteResponse(args ...interface{}) { + var resp = Response{} + var s = false + for _, arg := range args { + switch val := arg.(type) { + case string: + resp.Message = val + case error: + resp.Error = append(resp.Error, val) + case bool: + s = true + resp.Success = val + default: + resp.Data = val + } + } + if !s && (resp.Data != nil || resp.Message != "") { + resp.Success = true + } + c.WriteJSON(resp) +} + +// Write generic write function +// @receiver c +// @param data +func (c *Context) Write(data interface{}) { + switch w := data.(type) { + case []byte: + c.fiber.Write(w) + case string: + c.fiber.Write([]byte(w)) + case int, int64, int8, int32, int16, uint, uint64, uint8, uint16, uint32, float32, float64, complex64, complex128: + c.fiber.WriteString(fmt.Sprint(w)) + case error: + c.fiber.Status(400) + c.fiber.WriteString(w.Error()) + default: + var b, err = json.Marshal(w) + if err != nil { + c.fiber.Status(400) + c.fiber.WriteString(err.Error()) + } else { + c.fiber.Write(b) + } + } +} + +// Next executes the message method in the stack that matches the current route. +// @receiver c +// @return error +func (c *Context) Next() error { + return c.fiber.Next() +} + +// Fiber returns underlying fiber context +// @receiver c +// @return *fiber.Ctx +func (c *Context) Fiber() *fiber.Ctx { + return c.fiber +} + +// Router keep prefix of the path group +type Router struct { + Prefix string +} + +// Group create group of routers +// @param url +// @return Router +func Group(url string) Router { + return Router{ + Prefix: url, + } +} + +// Group create group of routers +// @receiver r +// @param url +// @return Router +func (r Router) Group(url string) Router { + return Router{ + Prefix: r.Prefix + url, + } +} + +// View render a view into output +// @receiver c +// @param env +// @param view +// @param data +// @return error +func (c *Context) View(env, view string, data ...interface{}) error { + var vars = jet.VarMap{} + if e, ok := shared.Views[env]; ok { + var v, err = e.GetTemplate(view) + if err != nil { + return err + } + for i, item := range data { + switch c := item.(type) { + case string: + if len(data) > i+1 { + vars[c] = reflect.ValueOf(data[i+1]) + } + case map[string]interface{}: + for key, val := range c { + vars[key] = reflect.ValueOf(val) + } + } + } + + vars["request"] = reflect.ValueOf(c) + + var buff = bytes.Buffer{} + err = v.Execute(&buff, vars, nil) + if err != nil { + return err + } + + c.Header("Content-Type", "text/html") + c.Status(200) + c.WriteBytes(buff.Bytes()) + return nil + } + return fmt.Errorf("invalid environment %s", env) +} + +// URL parse parts of the url +// @receiver c +// @return *URL +func (c *Context) URL() *URL { + u := URL{} + var fiber = c.Fiber() + base := strings.Split(fiber.BaseURL(), "://") + u.Scheme = base[0] + u.Host = c.Hostname() + u.Raw = fiber.OriginalURL() + parts := strings.Split(u.Raw, "?") + if len(parts) == 1 { + u.Query = url.Values{} + u.Path = u.Raw + } else { + u.Path = parts[0] + u.Query, _ = url.ParseQuery(strings.Join(parts[1:], "?")) + } + return &u +} + +// Set set url query string variable +// @receiver u +// @param key +// @param value +// @return *URL +func (u *URL) Set(key string, value interface{}) *URL { + u.Query.Set(key, fmt.Sprint(value)) + return u +} + +// String build string url of URL struct +// @receiver u +// @return string +func (u *URL) String() string { + return u.Path + "?" + u.Query.Encode() +} diff --git a/http/context.go b/http/context.go new file mode 100644 index 0000000..1129608 --- /dev/null +++ b/http/context.go @@ -0,0 +1,336 @@ +package http + +//GENERATED BY EVO-NG +import ( + "github.com/getevo/evo-ng" + "github.com/getevo/evo-ng/websocket" + "github.com/gofiber/fiber/v2" +) + +//Context struct represents the Context which hold the HTTP request and response. It has methods and variables for the request query string, parameters, body, HTTP headers, and so on which can also extends. +type Context struct { + Base *evo.Context + fiber *fiber.Ctx +} + +//New create new type of struct +func (c *Context) New() evo.ContextInterface { + return &Context{} +} + +//WebSocket Wrap context ws/wss WebSocket requests. callback accepts func(*http.Context,*websocket.Conn) +func (c *Context) WebSocket( + request *evo.Context, + callback interface{}, + ws *websocket.Conn, +) (err error) { + c.Base = request + c.fiber = request.Fiber() + return callback.(func(*Context) error)(c) +} + +//WebSocket Matches http WebSocket requests. callback accepts func(*http.Context) +func WebSocket( + url string, + callback func(*Context, *websocket.Conn) error, + params ...interface{}, +) { + evo.WebSocket(url, callback, params...) +} + +//Get Wrap context http Get requests. callback accepts func(*http.Context) +func (c *Context) Get( + request *evo.Context, + callback interface{}, +) (err error) { + c.Base = request + c.fiber = request.Fiber() + return callback.(func(*Context) error)(c) +} + +//Get Matches http Get requests. callback accepts func(*http.Context) +func Get( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Get(url, callback, params...) +} + +//Get Matches http Get requests. callback accepts func(*http.Context) +func (r *Router) Get( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Get(r.Prefix+url, callback, params...) +} + +//Post Wrap context http Post requests. callback accepts func(*http.Context) +func (c *Context) Post( + request *evo.Context, + callback interface{}, +) (err error) { + c.Base = request + c.fiber = request.Fiber() + return callback.(func(*Context) error)(c) +} + +//Post Matches http Post requests. callback accepts func(*http.Context) +func Post( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Post(url, callback, params...) +} + +//Post Matches http Post requests. callback accepts func(*http.Context) +func (r *Router) Post( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Post(r.Prefix+url, callback, params...) +} + +//All Wrap context http All requests. callback accepts func(*http.Context) +func (c *Context) All( + request *evo.Context, + callback interface{}, +) (err error) { + c.Base = request + c.fiber = request.Fiber() + + return callback.(func(*Context) error)(c) +} + +//All Matches http All requests. callback accepts func(*http.Context) +func All( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.All(url, callback, params...) +} + +//All Matches http All requests. callback accepts func(*http.Context) +func (r *Router) All( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.All(r.Prefix+url, callback, params...) +} + +//Put Wrap context http Put requests. callback accepts func(*http.Context) +func (c *Context) Put( + request *evo.Context, + callback interface{}, +) (err error) { + c.Base = request + c.fiber = request.Fiber() + + return callback.(func(*Context) error)(c) +} + +//Put Matches http Put requests. callback accepts func(*http.Context) +func Put( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Put(url, callback, params...) +} + +//Put Matches http Put requests. callback accepts func(*http.Context) +func (r *Router) Put( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Put(r.Prefix+url, callback, params...) +} + +//Patch Wrap context http Patch requests. callback accepts func(*http.Context) +func (c *Context) Patch( + request *evo.Context, + callback interface{}, +) (err error) { + c.Base = request + c.fiber = request.Fiber() + + return callback.(func(*Context) error)(c) +} + +//Patch Matches http Patch requests. callback accepts func(*http.Context) +func Patch( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Patch(url, callback, params...) +} + +//Patch Matches http Patch requests. callback accepts func(*http.Context) +func (r *Router) Patch( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Patch(r.Prefix+url, callback, params...) +} + +//Options Wrap context http Options requests. callback accepts func(*http.Context) +func (c *Context) Options( + request *evo.Context, + callback interface{}, +) (err error) { + c.Base = request + c.fiber = request.Fiber() + + return callback.(func(*Context) error)(c) +} + +//Options Matches http Options requests. callback accepts func(*http.Context) +func Options( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Options(url, callback, params...) +} + +//Options Matches http Options requests. callback accepts func(*http.Context) +func (r *Router) Options( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Options(r.Prefix+url, callback, params...) +} + +//Connect Wrap context http Connect requests. callback accepts func(*http.Context) +func (c *Context) Connect( + request *evo.Context, + callback interface{}, +) (err error) { + c.Base = request + c.fiber = request.Fiber() + + return callback.(func(*Context) error)(c) +} + +//Connect Matches http Connect requests. callback accepts func(*http.Context) +func Connect( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Connect(url, callback, params...) +} + +//Connect Matches http Connect requests. callback accepts func(*http.Context) +func (r *Router) Connect( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Connect(r.Prefix+url, callback, params...) +} + +//Head Wrap context http Head requests. callback accepts func(*http.Context) +func (c *Context) Head( + request *evo.Context, + callback interface{}, +) (err error) { + c.Base = request + c.fiber = request.Fiber() + + return callback.(func(*Context) error)(c) +} + +//Head Matches http Head requests. callback accepts func(*http.Context) +func Head( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Head(url, callback, params...) +} + +//Head Matches http Head requests. callback accepts func(*http.Context) +func (r *Router) Head( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Head(r.Prefix+url, callback, params...) +} + +//Delete Wrap context http Delete requests. callback accepts func(*http.Context) +func (c *Context) Delete( + request *evo.Context, + callback interface{}, +) (err error) { + c.Base = request + c.fiber = request.Fiber() + + return callback.(func(*Context) error)(c) +} + +//Delete Matches http Delete requests. callback accepts func(*http.Context) +func Delete( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Delete(url, callback, params...) +} + +//Delete Matches http Delete requests. callback accepts func(*http.Context) +func (r *Router) Delete( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Delete(r.Prefix+url, callback, params...) +} + +//Use Wrap context http Use requests. callback accepts func(*http.Context) +func (c *Context) Use( + request *evo.Context, + callback interface{}, +) (err error) { + c.Base = request + c.fiber = request.Fiber() + + return callback.(func(*Context) error)(c) +} + +//Use Matches http Use requests. callback accepts func(*http.Context) +func Use( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Use(url, callback, params...) +} + +//Use Matches http Use requests. callback accepts func(*http.Context) +func (r *Router) Use( + url string, + callback func(*Context) error, + params ...interface{}, +) { + evo.Use(r.Prefix+url, callback, params...) +} + +//Asset create url to asset dir.%!(EXTRA string=Asset) +func Asset( + url string, + localPath string, + params ...evo.AssetConfig, +) { + evo.Asset(url, localPath, params...) +} diff --git a/http/go.mod b/http/go.mod new file mode 100644 index 0000000..52238e8 --- /dev/null +++ b/http/go.mod @@ -0,0 +1,3 @@ +module github.com/getevo/evo-ng/http + +go 1.16 diff --git a/lib/generic/generic_test.go b/lib/generic/generic_test.go index 1ee0608..7f1292b 100644 --- a/lib/generic/generic_test.go +++ b/lib/generic/generic_test.go @@ -1,7 +1,8 @@ -package generic +package generic_test import ( "fmt" + "github.com/getevo/evo-ng/lib/generic" "github.com/stretchr/testify/assert" "reflect" "testing" @@ -11,75 +12,75 @@ import ( func TestGeneric(t *testing.T) { var string = "Hello World" - assert.Equal(t, uint64(4294967296), Parse("4mb").SizeInBytes()) - assert.Equal(t, uint64(4398046511104), Parse("4GB").SizeInBytes()) - assert.Equal(t, uint64(10737418240), Parse("10").SizeInBytes()) - assert.Equal(t, uint64(10), Parse("10B").SizeInBytes()) - - assert.Equal(t, Parse("4294967296").ByteCount(), "4.0 GB") - assert.Equal(t, Parse("4398046511104").ByteCount(), "4.0 TB") - assert.Equal(t, Parse("10737418240").ByteCount(), "10.0 GB") - - assert.Equal(t, string, Parse(string).String()) - assert.Equal(t, 0, Parse(string).Int()) - assert.Equal(t, float64(0), Parse(string).Float()) - assert.Equal(t, false, Parse(string).IsNil()) - assert.Equal(t, false, Parse(string).Bool()) - - assert.Equal(t, uint64(12222222222), Parse(12222222222).Uint64()) - assert.Equal(t, int64(-12222222222), Parse("-12222222222").Int64()) - - assert.Equal(t, "", Parse(nil).String()) - assert.Equal(t, 0, Parse(nil).Int()) - assert.Equal(t, float64(0), Parse(nil).Float()) - assert.Equal(t, true, Parse(nil).IsNil()) - assert.Equal(t, false, Parse(nil).Bool()) - - assert.Equal(t, "6.3", Parse(6.3).String()) - assert.Equal(t, uint64(6), Parse(6.3).Uint64()) - assert.Equal(t, int64(6), Parse(6.3).Int64()) - assert.Equal(t, 6, Parse(6.3).Int()) - assert.Equal(t, float64(6.3), Parse(6.3).Float()) - assert.Equal(t, false, Parse(6.3).IsNil()) - assert.Equal(t, false, Parse(6.3).Bool()) - - assert.Equal(t, "78", Parse(78).String()) - assert.Equal(t, uint64(78), Parse(78).Uint64()) - assert.Equal(t, int64(78), Parse(78).Int64()) - assert.Equal(t, 78, Parse(78).Int()) - assert.Equal(t, float64(78), Parse(78).Float()) - assert.Equal(t, false, Parse(78).IsNil()) - assert.Equal(t, false, Parse(78).Bool()) - - assert.Equal(t, true, Parse("Yes").Bool()) - assert.Equal(t, true, Parse("True").Bool()) - assert.Equal(t, true, Parse("yes").Bool()) - assert.Equal(t, true, Parse(1).Bool()) + assert.Equal(t, uint64(4294967296), generic.Parse("4mb").SizeInBytes()) + assert.Equal(t, uint64(4398046511104), generic.Parse("4GB").SizeInBytes()) + assert.Equal(t, uint64(10737418240), generic.Parse("10").SizeInBytes()) + assert.Equal(t, uint64(10), generic.Parse("10B").SizeInBytes()) + + assert.Equal(t, generic.Parse(4294967296).ByteCount(), "4.0 GB") + assert.Equal(t, generic.Parse("4398046511104").ByteCount(), "4.0 TB") + assert.Equal(t, generic.Parse("10737418240").ByteCount(), "10.0 GB") + + assert.Equal(t, string, generic.Parse(string).String()) + assert.Equal(t, 0, generic.Parse(string).Int()) + assert.Equal(t, float64(0), generic.Parse(string).Float()) + assert.Equal(t, false, generic.Parse(string).IsNil()) + assert.Equal(t, false, generic.Parse(string).Bool()) + + assert.Equal(t, uint64(12222222222), generic.Parse(12222222222).Uint64()) + assert.Equal(t, int64(-12222222222), generic.Parse("-12222222222").Int64()) + + assert.Equal(t, "", generic.Parse(nil).String()) + assert.Equal(t, 0, generic.Parse(nil).Int()) + assert.Equal(t, float64(0), generic.Parse(nil).Float()) + assert.Equal(t, true, generic.Parse(nil).IsNil()) + assert.Equal(t, false, generic.Parse(nil).Bool()) + + assert.Equal(t, "6.3", generic.Parse(6.3).String()) + assert.Equal(t, uint64(6), generic.Parse(6.3).Uint64()) + assert.Equal(t, int64(6), generic.Parse(6.3).Int64()) + assert.Equal(t, 6, generic.Parse(6.3).Int()) + assert.Equal(t, float64(6.3), generic.Parse(6.3).Float()) + assert.Equal(t, false, generic.Parse(6.3).IsNil()) + assert.Equal(t, false, generic.Parse(6.3).Bool()) + + assert.Equal(t, "78", generic.Parse(78).String()) + assert.Equal(t, uint64(78), generic.Parse(78).Uint64()) + assert.Equal(t, int64(78), generic.Parse(78).Int64()) + assert.Equal(t, 78, generic.Parse(78).Int()) + assert.Equal(t, float64(78), generic.Parse(78).Float()) + assert.Equal(t, false, generic.Parse(78).IsNil()) + assert.Equal(t, false, generic.Parse(78).Bool()) + + assert.Equal(t, true, generic.Parse("Yes").Bool()) + assert.Equal(t, true, generic.Parse("True").Bool()) + assert.Equal(t, true, generic.Parse("yes").Bool()) + assert.Equal(t, true, generic.Parse(1).Bool()) var date time.Time var err error var duration time.Duration - date, err = Parse("10/13/2021").Time() + date, err = generic.Parse("10/13/2021").Time() assert.NoError(t, err) assert.Equal(t, "2021-10-13 00:00:00 +0000 UTC", date.String()) - date, err = Parse("03.31.2014").Time() + date, err = generic.Parse("03.31.2014").Time() assert.NoError(t, err) assert.Equal(t, "2014-03-31 00:00:00 +0000 UTC", date.String()) - date, err = Parse(time.Now().Unix()).Time() + date, err = generic.Parse(time.Now().Unix()).Time() assert.NoError(t, err) assert.Equal(t, time.Now().Format("2006-01-02 15:04:05"), date.Format("2006-01-02 15:04:05")) - date, err = Parse(time.Now().UnixNano()).Time() + date, err = generic.Parse(time.Now().UnixNano()).Time() assert.NoError(t, err) assert.Equal(t, time.Now().Format("2006-01-02 15:04:05"), date.Format("2006-01-02 15:04:05")) - duration, err = Parse("6h12m16s").Duration() + duration, err = generic.Parse("6h12m16s").Duration() assert.NoError(t, err) assert.Equal(t, "6h12m16s", duration.String()) - duration, err = Parse(6 * time.Hour).Duration() + duration, err = generic.Parse(6 * time.Hour).Duration() assert.NoError(t, err) assert.Equal(t, "6h0m0s", duration.String()) @@ -93,21 +94,21 @@ func TestString(t *testing.T) { X: sample, } var array = []string{"a", "b", "c"} - fmt.Println(sample, "=>", ToString(sample)) - fmt.Println(&sample, "=>", ToString(&sample)) + fmt.Println(sample, "=>", generic.ToString(sample)) + fmt.Println(&sample, "=>", generic.ToString(&sample)) - fmt.Println(array, "=>", ToString(array)) - fmt.Println(object, "=>", ToString(&object)) + fmt.Println(array, "=>", generic.ToString(array)) + fmt.Println(object, "=>", generic.ToString(&object)) - fmt.Println(123, "=>", ToString(123)) + fmt.Println(123, "=>", generic.ToString(123)) } func TestTypeOf(t *testing.T) { var s = "string" - fmt.Println(TypeOf(s).Indirect().Is(reflect.String)) - fmt.Println(TypeOf(&s).Is(reflect.String)) - fmt.Println(TypeOf(&s).Indirect().Is(reflect.String)) - fmt.Println(TypeOf(&s).Is("*string")) - fmt.Println(TypeOf(&s).Is(&s)) + fmt.Println(generic.TypeOf(s).Indirect().Is(reflect.String)) + fmt.Println(generic.TypeOf(&s).Is(reflect.String)) + fmt.Println(generic.TypeOf(&s).Indirect().Is(reflect.String)) + fmt.Println(generic.TypeOf(&s).Is("*string")) + fmt.Println(generic.TypeOf(&s).Is(&s)) } diff --git a/lib/intl/date_test.go b/lib/intl/date_test.go index ec7349a..74b959a 100644 --- a/lib/intl/date_test.go +++ b/lib/intl/date_test.go @@ -1,39 +1,40 @@ -package intl +package intl_test import ( + "github.com/getevo/evo-ng/lib/intl" "github.com/stretchr/testify/assert" "testing" "time" ) func TestDate(t *testing.T) { - assert.Equal(t, "2006/06/08", Date("2006/06/08").Time().Format("2006/01/02")) - assert.Equal(t, "2006/06/08", Date("2006", "06", "08").Time().Format("2006/01/02")) - assert.Equal(t, "2006/06/08", Date(2006, 6, 8).Time().Format("2006/01/02")) + assert.Equal(t, "2006/06/08", intl.Date("2006/06/08").Time().Format("2006/01/02")) + assert.Equal(t, "2006/06/08", intl.Date("2006", "06", "08").Time().Format("2006/01/02")) + assert.Equal(t, "2006/06/08", intl.Date(2006, 6, 8).Time().Format("2006/01/02")) - assert.Equal(t, "2006/06/08 10:45:30", Date("2006/06/08 10:45:30").Time().Format("2006/01/02 15:04:05")) - assert.Equal(t, "2006/06/08 10:45:30", Date(2006, 6, 8, 10, 45, 30).Time().Format("2006/01/02 15:04:05")) - assert.Equal(t, int64(1149763530000000020), Date(2006, 6, 8, 10, 45, 30, 20).Time().UnixNano()) + assert.Equal(t, "2006/06/08 10:45:30", intl.Date("2006/06/08 10:45:30").Time().Format("2006/01/02 15:04:05")) + assert.Equal(t, "2006/06/08 10:45:30", intl.Date(2006, 6, 8, 10, 45, 30).Time().Format("2006/01/02 15:04:05")) + assert.Equal(t, int64(1149763530000000020), intl.Date(2006, 6, 8, 10, 45, 30, 20).Time().UnixNano()) - assert.Equal(t, Date().Time(), time.Now()) + assert.Equal(t, intl.Date().Time(), time.Now()) var l, _ = time.LoadLocation("Asia/Tehran") - assert.Equal(t, "2006/06/08 07:15:30", Date(2006, 6, 8, 10, 45, 30, 20, l).Time().UTC().Format("2006/01/02 15:04:05")) - assert.Equal(t, "2006/06/08 07:15:30", Date(2006, 6, 8, 10, 45, 30, 20, *l).Time().UTC().Format("2006/01/02 15:04:05")) + assert.Equal(t, "2006/06/08 07:15:30", intl.Date(2006, 6, 8, 10, 45, 30, 20, l).Time().UTC().Format("2006/01/02 15:04:05")) + assert.Equal(t, "2006/06/08 07:15:30", intl.Date(2006, 6, 8, 10, 45, 30, 20, *l).Time().UTC().Format("2006/01/02 15:04:05")) //t.Error() // to indicate test failed - AddLocale("en-GB", "en-US", "it-IT", "fa-IR", "es-ES", "ru-RU") - var locale = GuessLocale("it") + intl.AddLocale("en-GB", "en-US", "it-IT", "fa-IR", "es-ES", "ru-RU") + var locale = intl.GuessLocale("it") assert.Equal(t, locale.String(), "it-IT") - assert.Equal(t, "Giovedì 06 Giu, 2006", Date(2006, 6, 8).Format("Monday 01 Jan, 2006", "it-IT")) - assert.Equal(t, "Giovedì 06 Giu, 2006", Date(2006, 6, 8).Format("Monday 01 Jan, 2006", "it")) - assert.Equal(t, "Giovedì 06 Giu, 2006", Date(2006, 6, 8).Format("Monday 01 Jan, 2006", locale)) - assert.Equal(t, "Четверг 06 Июн, 2006", Date(2006, 6, 8).Format("Monday 01 Jan, 2006", "ru")) + assert.Equal(t, "Giovedì 06 Giu, 2006", intl.Date(2006, 6, 8).Format("Monday 01 Jan, 2006", "it-IT")) + assert.Equal(t, "Giovedì 06 Giu, 2006", intl.Date(2006, 6, 8).Format("Monday 01 Jan, 2006", "it")) + assert.Equal(t, "Giovedì 06 Giu, 2006", intl.Date(2006, 6, 8).Format("Monday 01 Jan, 2006", locale)) + assert.Equal(t, "Четверг 06 Июн, 2006", intl.Date(2006, 6, 8).Format("Monday 01 Jan, 2006", "ru")) - var base = Date(2006, 6, 8, 10, 45, 30, 20) + var base = intl.Date(2006, 6, 8, 10, 45, 30, 20) assert.Equal(t, "2006/06/04", base.SetDay(4).Format("2006/01/02")) assert.Equal(t, "2022/06/08", base.SetYear(2022).Format("2006/01/02"))